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.
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.
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 Word2
pop 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.
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!
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.
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.