web-dev-qa-db-fra.com

Le sens de RET en assemblée

Je suis très nouveau à l’Assemblée et je ne comprends pas ce que cela signifie exactement quand, à la fin d’une procédure, vous écrivez un nombre avec la déclaration ret

Comme ça:

Function Proc
Push ax cx
.
...body...
.
pop cx ax
ret 2 
Function endp

Je comprends que cela a quelque chose à voir avec l'endroit où le pointeur de pile devrait revenir à la fin de la fonction? 

S'il vous plaît, cela m'aiderait vraiment si vous pouviez l'expliquer facilement.

20
Rotem Mayo

Oui, mais ret 2 supprime également 2 octets de paramètres de la pile. Vraisemblablement, votre fonction s'appelait comme:

Push some_parameter
call Function

À ce stade, une fonction cdecl - une fonction "appelant nettoyant" (généralement utilisée par C) - aurait besoin de add sp, 2 pour "nettoyer la pile", en supprimant le paramètre. Une telle fonction aboutirait à un simple ret.

Une fonction stdcall, qui correspond à ce que vous avez, est une fonction "appelée - le nettoyé" (utilisée par les API Windows, par exemple) ne nécessite pas le add sp, 2 - elle a été effectuée par le ret 2.

Si vous ne le connaissez pas, call place l'adresse de retour sur la pile (et ret le supprime), de sorte que vous ne pouvez pas simplement pop obtenir le paramètre dans votre fonction.

19
Frank Kotler

Disons que j'ai une procédure pour ajouter deux mots et laisser la somme dans EAX. Les mots sont des arguments que je veux transmettre à la procédure sur la pile. c'est à dire:

Push Word1
Push Word2
call addtwob

La procédure ressemblerait à quelque chose comme:

addtwob proc

Push ebp
mov  ebp,esp
mov  eax, [ebp+6]    
add  eax, [ebp+8]
pop ebp
ret 4

Endp

[ebp+6] et [ebp+8] adresse Word2 et Word1 sur la pile .ret 4 retourne comme d'habitude mais ajoute ensuite 4 au pointeur de pile (esp) afin que vous n'ayez pas à pop Word2pop Word1 quitter la pile après être revenu de l'appel nettoie/équilibre la pile sans avoir à faire apparaître les poussées précédentes.

16
Nhat M Le

Comme alex l’a dit, c’est RETURN . Dans x86 Assembly, lorsque le compilateur atteint cette ligne (à la fin d’un sous-programme, par exemple), la valeur last est supprimée de la pile, ce qui supposé être l'adresse de retour, et l'a assignée au registre IP. Vous pouvez mieux comprendre cela en écrivant un code assembleur simple et en le compilant avec Turbo Debugger. Il y a une interface graphique pour l'assembleur si vous êtes novice dans ce domaine. Vous pouvez trouver l'interface graphique ici .

Lorsque vous sautez et insérez des valeurs de et vers la pile lorsque vous êtes dans un sous-programme, vous devez stocker l'adresse de retour, car à la fin du sous-programme, vous devez le repousser dans la pile avant la ligne return.

Bonne chance!

8
c0ldsh3ll

Cela signifie RETURN, comme un return dans les langages de haut niveau.

Sur la plupart des machines, la valeur précédente du compteur de programme apparaît avant d'entrer dans la sous-routine de la pile et de la copier dans le registre du PC.

Pour x86, l'argument est le nombre de paramètres de la pile. Cela ne s'applique que si la convention utilisée consiste à laisser le sous-programme gérer la réinitialisation de la pile.

3
alex

Vous semblez vous interroger sur un retour sur proche avec un opérande pour x86_64. L'algorithme suivi par le matériel lorsque le processeur rencontre un processeur proche de RET est présenté dans Manuel de référence du jeu d'instructions Intel est la suivante;

(* Near return *)
IF instruction = near return
    THEN;
    IF OperandSize = 32
        THEN
        IF top 4 bytes of stack not within stack limits
            THEN #SS(0); FI; //throw protected mode exception
        EIP ← Pop(); 
        ELSE
        IF OperandSize = 64
            THEN
            IF top 8 bytes of stack not within stack limits
                THEN #SS(0); FI; //throw protected mode exception
            RIP ← Pop();
            ELSE (* OperandSize = 16 *)
            IF top 2 bytes of stack not within stack limits
                THEN #SS(0); FI; //throw protected mode exception
            tempEIP ← Pop();
            tempEIP ← tempEIP AND 0000FFFFH;
            IF tempEIP not within code segment limits
                THEN #GP(0); FI; //throw protected mode exception
            EIP ← tempEIP;
        FI;
    FI;
    IF instruction has immediate operand
        THEN (* Release parameters from stack *)
        IF StackAddressSize = 32
            THEN
            ESP ← ESP + SRC;
            ELSE
            IF StackAddressSize = 64
                THEN
                RSP ← RSP + SRC;
                ELSE (* StackAddressSize = 16 *)
            SP ← SP + SRC;
            FI;
        FI;
    FI;
FI;
  • Selon cet algorithme, chaque fois qu'un retour proche est rencontré, l'adresse de retour est vérifiée si elle se trouve dans les limites SS. Le haut de la pile est inséré dans RIP ou EIP en fonction de la taille de l'opérande si l'adresse de retour est valide.

  • Si la taille de l'opérande est de 16 bits, un emplacement temporaire contient l'adresse de retour remplie, qui est ANDed avec la valeur 0x0000FFFF et chargée dans l'EIP après vérification des limites CS. 

  • Pendant que votre question demande ce qui se passe s'il y a un opérande à l'opcode d'instruction proche de RET. Cela dépend de la taille de l'adresse de la pile. En fonction de cette taille, RSP ESP ou SP est augmenté d'opérande, puis l'exécution de l'instruction near RET est terminée sur le matériel. 

1
gokhanbas.eee