Ce n'subl faire ici?
Donc... je suis de la compilation en assembleur, avec gcc -S -O2 -m32:
void h(int y){int x; x=y+1; f(y); f(2); }
Et il me donne les éléments suivants:
.file "sample.c"
.text
.p2align 4,,15
.globl h
.type h, @function
h:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call f
movl $2, 8(%ebp)
leave
jmp f
.size h, .-h
.ident "GCC: (GNU) 4.4.3 20100127 (Red Hat 4.4.3-4)"
.section .note.GNU-stack,"",@progbits
Maintenant je sais ce que pushl et movel: ils stockent l'image actuelle du pointeur sur la pile, puis définissez la valeur de l'image de registre de pointeur de la valeur du Pointeur de Pile.
- Mais je n'ai aucune idée de ce que le subl $24, %esp est. J'ai compris qu'il se déplace le pointeur de pile vers le bas par 24 octets. - Il Correct?
- Qu'est-ce que immed par le chemin?
- Pourquoi ne movl 8(%ebp), %eax l'utilisation de 8? Est-il 8 octets? Est-ce pour tenir compte de la valeur de retour + argument y à h? Ou suis-je complètement à côté de la ici. Cela signifie donc, regarder en arrière 8 octets à partir du pointeur de pile?
- Ce n' movl $2, 8(%ebp) faire? Il copie contant 2 à l'emplacement 8 octets avant le pointeur de cadre. A l'image du pointeur de changement quand on appelle f? Si oui - puis 8(%ebp) points à l'emplacement d'argument pour f.
- Ce qui laisse faire? Comment peut-il "supprimer" un cadre de pile? Je veux dire, vous ne pouvez pas tout simplement supprimer un morceau de la mémoire. Dans la doc il est dit qu'il ne mov esp, ebp), de la pop ebp.
Merci!
Fait intéressant, la réponse ci-dessous a été marqué comme acceptable, même si il ne fait pas de donner une explication à la question 1. Ici c'est une autre question/réponse qui donne une explication à 1.
OriginalL'auteur Andriy Drozdyuk | 2010-03-17
Vous devez vous connecter pour publier un commentaire.
Le compilateur est de réserver l'espace sur la pile pour les habitants et tous les autres besoins qu'il pourrait avoir. Je ne suis pas sûr désinvolte pourquoi il est réservataire de 24 octets (il ne semble pas le besoin ou l'utiliser tous).
Lors de l'appel de la fonction
f()
, au lieu d'utiliser une instruction push pour mettre le paramètre sur la pile, il utilise un simplemovl
à la dernière position réservés:Plus intéressant (à mon avis) ça se passe ici est de savoir comment le compilateur se charge de l'appel à
f(2)
:Pour répondre à votre question, "immed par le chemin?" - c'est ce que l'instruction de référence utilise pour indiquer que la valeur est codée dans l'instruction opcode au lieu de venir de quelque part d'autre, comme un registre ou d'emplacement de mémoire.
en soustrayant de la
esp
registre essentiellement de "réserves" de l'espace sur la pile. C'est comme si vous avez poussé 24 octets, la valeur de trucs (6 valeurs de 32 bits) sur la pile, à la différence que vous ne pouvez pas compter sur ce que ces 'poussé' des valeurs sur la pile sont - tout ce que vous savez est que vous pouvez l'utiliser de la mémoire sans se soucier subséquente d'un poussoir pour le remplacer.Il soustrait parce que la pile grandit "vers le bas" dans la mémoire. 'immed' est une valeur immédiate, comme dans beaucoup de $24 dans la ligne que vous citez.
Notez également que le compilateur a fait deux optimisations: L'affectation de x est supprimée, car la valeur n'est pas utilisée. Le deuxième appel à f est transformé en un jmp-instruction parce qu'il n'a pas besoin de revenir en arrière à l'h de la fonction lorsque l'appel est terminé.
Donc je mettre à jour mes question avec plus de... questions. Désolé.
OriginalL'auteur Michael Burr
Afin de répondre à ces questions numérotées:
1)
subl $24,%esp
signifie
esp = esp - 24
GNU utilise COMME AT&T de la syntaxe, qui est à l'opposé de la syntaxe Intel. AT&T est la destination sur la droite, Intel a la destination sur la gauche. Aussi AT&T est explicite quant à la taille de l'argumentation. Intel tente de déduire ou vous oblige à être explicite.
La pile grandit vers le bas dans la mémoire, la mémoire et après esp est le contenu de la pile, les adresses inférieur esp sont pas utilisées espace de pile. esp points à la dernière chose qui a poussé sur la pile.
2) d'instructions x86 codant pour la plupart de l':
il n'y a pas de mémoire à la mémoire d'instructions de format. (Strictement parlant, vous pouvez faire de la mémoire à la mémoire des opérations avec
movs
ou parpush mem
,pop mem
, mais ni prendre deux opérandes mémoire sur la même instruction)"Immédiate" signifie que la valeur est codée droit à l'instruction. Par exemple, pour stocker 15 à l'adresse dans ebx:
movl $15,(%ebx)
15 est un "immédiate" de la valeur.
Les parenthèses utiliser le registre comme un pointeur vers la mémoire.
3)
movl 8(%ebp),%eax
moyens,
esp est le pointeur de pile.
En mode 32 bits, chaque push et pop sur la pile est de 4 octets. Généralement, la plupart des variables de prendre les 4 octets de toute façon. Alors on pourrait dire 8(%ebp) signifie, en commençant par le haut de la pile, de me donner la valeur 2 (4 x 2 = 8) int dans la pile.
Généralement, code 32 bits utilise ebp point pour le début de l'variables locales à une fonction. En 16-bit x86 code, il n'y avait pas moyen d'utiliser le pointeur de pile comme un pointeur (difficile à croire, non?). Donc, ce que les gens ne copie a été
sp
àbp
et l'utilisation de la bp que le pointeur de l'image. C'est devenu complètement inutile lorsque le mode 32-bit est sorti (80386), il y avait un moyen d'utiliser le pointeur de pile directement. Malheureusement, ebp rend le débogage plus facile nous avons donc fini de continuer à l'utiliser ebp dans le code 32 bits (c'est trivial à faire un vidage de pile si ebp est utilisé).Heureusement, amd64 nous a donné une nouvelle ABI qui n'utilise pas de ebp comme un pointeur de cadre, de code 64 bits utilise généralement esp pour accéder aux variables locales, ebp est disponible pour stocker une variable.
4) Expliqué ci-dessus
5)
leave
est un ancien de l'instruction que, tout simplement, nemovl %ebp,%esp
etpopl %ebp
et permet d'économiser quelques octets de code. Ce qu'il fait n'est d'annuler les modifications de la pile et de la restauration de l'appelant ebp. La fonction appelée doit préserverebp
dans le x86 ABI.À l'entrée de la fonction, le compilateur n'a subl $24,%esp pour faire de la place pour les variables locales et, parfois, de stockage temporaire qu'il n'ont pas assez de registres à tenir.
La meilleure façon de "imagine" de la frame de pile dans votre esprit est de le voir comme une structure assis sur la pile. Les premiers membres de l'imaginaire de la structure sont les plus récemment "poussé" des valeurs. Ainsi, lorsque vous pousser à une pile, d'imaginer l'insertion d'un nouveau membre au début de la structure, tandis qu'aucun des autres membres de déplacés. Lorsque vous "pop" de la pile, vous obtenez la valeur du premier membre de l'imaginaire struct, et que la (première) ligne de la structure disparaît de l'existence.
Cadre de la pile de la manipulation est la plupart du temps simplement en déplaçant le pointeur de pile pour faire plus ou moins de place dans l'imaginaire struct nous appelons le cadre de la pile. En soustrayant de le pointeur de pile met juste plusieurs imaginaire membres au début de la structure en une seule étape. Ajouter le pointeur de pile fait le premier de nombreux membres disparaissent.
La fin du code que vous avez posté n'est pas typique. Que
jmp
est généralement unret
. Le compilateur était intelligent à ce sujet et a fait une "queue d'appel d'optimisation", ce qui signifie qu'il nettoie tout ce qu'il a fait pour la pile et les sauts def
. Lorsquef(2)
retourne, il retourne en fait directement à l'appelant (pas de retour pour le code que vous avez posté)OriginalL'auteur doug65536