Comprendre le code d'assemblage généré par un simple programme C
J'essaie de comprendre le niveau de l'assemblée de code pour un simple programme en C de l'inspecter avec gdb désassembleur.
Qui suit est le code C:
#include <stdio.h>
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
void main() {
function(1,2,3);
}
Suivant est le démontage, le code pour les deux main
et function
gdb) disass main
Dump of assembler code for function main:
0x08048428 <main+0>: push %ebp
0x08048429 <main+1>: mov %esp,%ebp
0x0804842b <main+3>: and $0xfffffff0,%esp
0x0804842e <main+6>: sub $0x10,%esp
0x08048431 <main+9>: movl $0x3,0x8(%esp)
0x08048439 <main+17>: movl $0x2,0x4(%esp)
0x08048441 <main+25>: movl $0x1,(%esp)
0x08048448 <main+32>: call 0x8048404 <function>
0x0804844d <main+37>: leave
0x0804844e <main+38>: ret
End of assembler dump.
(gdb) disass function
Dump of assembler code for function function:
0x08048404 <function+0>: push %ebp
0x08048405 <function+1>: mov %esp,%ebp
0x08048407 <function+3>: sub $0x28,%esp
0x0804840a <function+6>: mov %gs:0x14,%eax
0x08048410 <function+12>: mov %eax,-0xc(%ebp)
0x08048413 <function+15>: xor %eax,%eax
0x08048415 <function+17>: mov -0xc(%ebp),%eax
0x08048418 <function+20>: xor %gs:0x14,%eax
0x0804841f <function+27>: je 0x8048426 <function+34>
0x08048421 <function+29>: call 0x8048340 <__stack_chk_fail@plt>
0x08048426 <function+34>: leave
0x08048427 <function+35>: ret
End of assembler dump.
Je suis à la recherche de réponses pour les choses suivantes :
- comment l'aborder est de travailler , je veux dire (principal+0) , (+1), (principal+3)
- Dans la main, pourquoi est $0xfffffff0,%esp utilisé
- Dans la fonction, pourquoi est %gs:0x14,%eax , %eax,-0xc(%ebp) utilisé.
- Si quelqu'un peut expliquer , étape par étape passe, qui sera grandement apprécié.
source d'informationauteur Adi
Vous devez vous connecter pour publier un commentaire.
Pax a produit une réponse définitive. Toutefois, pour être complet, je pensais que je voudrais ajouter une note sur l'obtention de GCC lui-même pour vous montrer le montage, il génère.
La
-S
option de GCC dit-il arrêter la compilation et l'écriture de l'assemblée à un fichier. Normalement, il se passe de ce fichier à l'assembleur ou pour certaines cibles écrit le fichier de l'objet directement lui-même.Pour l'exemple de code dans la question:
la commande
gcc -S q3654898.c
crée un fichier nommé q3654898.s:Une chose qui est évident, c'est que mon GCC (gcc (GCC) 3.4.5 (mingw-vista spécial r3)) n'inclut pas la pile de vérifier le code par défaut. J'imagine qu'il y a une option de ligne de commande, ou que si je n'ai jamais eu l'occasion de pousser mon MinGW installer jusqu'à un plus actuelle de la GCC qu'il le pouvait.
Edit: Poussé à le faire par Pax, voici une autre façon d'obtenir GCC de faire plus de travail.
Ici, nous voyons une sortie liste produite par l'assembleur. (Son nom est
GAS
parce que c'est la version Gnu de la classique *nix assembleuras
. Il y a de l'humour là, quelque part.)Chaque ligne a la plupart des champs suivants: un numéro de ligne, une adresse de la section en cours d'octets stockés à cette adresse, et le texte source de l'assemblée fichier source.
Les adresses sont les décalages dans la partie de chaque section fournies par ce module. Ce module a seulement contenu dans le
.text
section qui stocke le code exécutable. Vous trouverez généralement la mention des sections nommé.data
et.bss
. Beaucoup d'autres noms sont utilisés et certains ont des besoins spéciaux. Lisez le manuel de l'éditeur de liens si vous voulez vraiment le savoir.Il sera préférable d'essayer de le -fno-stack-protector drapeau avec gcc pour désactiver les canaries et de voir vos résultats.
Je tiens à ajouter que pour des choses simples, GCC assemblée de sortie est souvent plus facile à lire si vous mettez un peu d'optimisation. Voici l'exemple de code à nouveau...
c'est ce que je reçois sans optimisation (OSX 10.6, gcc 4.2.1+Pomme patchs)
Ouf, un diable d'une bouchée! Mais regardez ce qui se passe avec
-O
sur la ligne de commande...Bien sûr, vous courez le risque que votre code soit rendue complètement méconnaissable, notamment à des niveaux d'optimisation et avec plus de trucs compliqués. Même ici, nous voyons que l'appel à
function
a été rejeté comme inutile. Mais je trouve que ne pas avoir à lire à travers des dizaines de inutiles pile déversements est généralement plus que la valeur d'un peu plus de me gratter la tête au-dessus du flux de contrôle.