Comment est-que quelqu'un peut faire ça?
Si je veux analyser comment quelque chose est compilé, comment puis-je obtenir le code assembleur émis?
Comment est-que quelqu'un peut faire ça?
Si je veux analyser comment quelque chose est compilé, comment puis-je obtenir le code assembleur émis?
Réponses:
Utilisez l' -S
option gcc (ou g ++).
gcc -S helloworld.c
Cela exécutera le préprocesseur (cpp) sur helloworld.c, effectuera la compilation initiale puis s'arrêtera avant que l'assembleur ne soit exécuté.
Par défaut, cela produira un fichier helloworld.s
. Le fichier de sortie peut toujours être défini à l'aide de l' -o
option.
gcc -S -o my_asm_output.s helloworld.c
Bien sûr, cela ne fonctionne que si vous avez la source d'origine. Une alternative si vous ne disposez que du fichier objet résultant est d'utiliser objdump
, en définissant l' --disassemble
option (ou -d
pour la forme abrégée).
objdump -S --disassemble helloworld > helloworld.dump
Cette option fonctionne mieux si l'option de débogage est activée pour le fichier objet ( -g
au moment de la compilation) et que le fichier n'a pas été supprimé.
L'exécution file helloworld
vous donnera une indication du niveau de détail que vous obtiendrez en utilisant objdump.
.intel_syntax
n'est pas compatible avec NASM . C'est plus comme MASM (par exemple, mov eax, symbol
c'est une charge, contrairement à NASM où c'est une mov r32, imm32
adresse), mais pas totalement compatible avec MASM non plus. Je le recommande fortement comme format agréable à lire, surtout si vous aimez écrire en syntaxe NASM. objdump -drwC -Mintel | less
ou gcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | less
sont utiles. (Voir aussi Comment supprimer le «bruit» de la sortie de l'assemblage GCC / clang? ). -masm=intel
fonctionne aussi avec clang.
gcc -O -fverbose-asm -S
Cela générera du code d'assemblage avec le code C + les numéros de ligne entrelacés, pour voir plus facilement quelles lignes génèrent quel code:
# create assembler code:
g++ -S -fverbose-asm -g -O2 test.cc -o test.s
# create asm interlaced with source lines:
as -alhnd test.s > test.lst
Trouvé dans Algorithmes pour les programmeurs , page 3 (qui est la 15e page globale du PDF).
as
sur OS X ne connaît pas ces drapeaux. Si c'était le cas, vous pourriez probablement utiliser cette ligne sur une ligne -Wa
pour passer des options à as
.
g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lst
serait la version abrégée de cela.
gcc -c -g -Wa,-ahl=test.s test.c
ougcc -c -g -Wa,-a,-ad test.c > test.txt
-O0
? C'est plein de charges / magasins qui rendent difficile le suivi d'une valeur et ne vous dit rien sur l'efficacité du code optimisé.
La ligne de commande suivante provient du blog de Christian Garbin
g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
J'ai exécuté G ++ à partir d'une fenêtre DOS sur Win-XP, contre une routine qui contient un cast implicite
c:\gpp_code>g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
horton_ex2_05.cpp: In function `int main()':
horton_ex2_05.cpp:92: warning: assignment to `int' from `double'
Le résultat est un code généré assemblé, intercalé avec le code C ++ d'origine (le code C ++ est affiché sous forme de commentaires dans le flux asm généré)
16:horton_ex2_05.cpp **** using std::setw;
17:horton_ex2_05.cpp ****
18:horton_ex2_05.cpp **** void disp_Time_Line (void);
19:horton_ex2_05.cpp ****
20:horton_ex2_05.cpp **** int main(void)
21:horton_ex2_05.cpp **** {
164 %ebp
165 subl $128,%esp
?GAS LISTING C:\DOCUME~1\CRAIGM~1\LOCALS~1\Temp\ccx52rCc.s
166 0128 55 call ___main
167 0129 89E5 .stabn 68,0,21,LM2-_main
168 012b 81EC8000 LM2:
168 0000
169 0131 E8000000 LBB2:
169 00
170 .stabn 68,0,25,LM3-_main
171 LM3:
172 movl $0,-16(%ebp)
-O2
, ou les options d'optimisation que vous utilisez réellement lors de la construction de votre projet, si vous voulez voir comment gcc optimise votre code. (Ou si vous utilisez LTO, comme vous le devriez, alors vous devez démonter la sortie de l'éditeur de liens pour voir ce que vous obtenez vraiment.)
Si ce que vous voulez voir dépend de la liaison de la sortie, objdump sur le fichier / exécutable de l'objet de sortie peut également être utile en plus du gcc -S susmentionné. Voici un script très utile de Loren Merritt qui convertit la syntaxe objdump par défaut en syntaxe nasm plus lisible:
#!/usr/bin/perl -w
$ptr='(BYTE|WORD|DWORD|QWORD|XMMWORD) PTR ';
$reg='(?:[er]?(?:[abcd]x|[sd]i|[sb]p)|[abcd][hl]|r1?[0-589][dwb]?|mm[0-7]|xmm1?[0-9])';
open FH, '-|', '/usr/bin/objdump', '-w', '-M', 'intel', @ARGV or die;
$prev = "";
while(<FH>){
if(/$ptr/o) {
s/$ptr(\[[^\[\]]+\],$reg)/$2/o or
s/($reg,)$ptr(\[[^\[\]]+\])/$1$3/o or
s/$ptr/lc $1/oe;
}
if($prev =~ /\t(repz )?ret / and
$_ =~ /\tnop |\txchg *ax,ax$/) {
# drop this line
} else {
print $prev;
$prev = $_;
}
}
print $prev;
close FH;
Je soupçonne que cela peut également être utilisé sur la sortie de gcc -S.
mov eax,ds:0x804b794
n'est pas très NASMish. En outre, parfois, il supprime simplement des informations utiles: movzx eax,[edx+0x1]
laisse le lecteur deviner si l'opérande mémoire était byte
ou word
.
objconv
. Vous pouvez le faire démonter vers stdout avec le fichier de sortie = /dev/stdout
, afin que vous puissiez le diriger vers l' less
affichage. Il y en a aussi ndisasm
, mais il ne démonte que les binaires plats et ne connaît pas les fichiers objets (ELF / PE).
Comme tout le monde l'a souligné, utilisez l' -S
option GCC. Je voudrais également ajouter que les résultats peuvent varier (énormément!) Selon que vous ajoutez ou non des options d'optimisation ( -O0
pour aucune, -O2
pour une optimisation agressive).
Sur les architectures RISC en particulier, le compilateur transforme souvent le code presque au-delà de la reconnaissance lors de l'optimisation. C'est impressionnant et fascinant de regarder les résultats!
Comme mentionné précédemment, regardez le drapeau -S.
Il convient également de regarder la famille de drapeaux '-fdump-tree', en particulier '-fdump-tree-all', qui vous permet de voir certaines des formes intermédiaires de gcc. Ceux-ci peuvent souvent être plus lisibles que l'assembleur (du moins pour moi) et vous permettent de voir comment les passes d'optimisation fonctionnent.
Je ne vois pas cette possibilité parmi les réponses, probablement parce que la question date de 2008, mais en 2018, vous pouvez utiliser le site Web en ligne de Matt Goldbolt https://godbolt.org
Vous pouvez également localement git cloner et exécuter son projet https://github.com/mattgodbolt/compiler-explorer
-save-temps
Cela a été mentionné sur https://stackoverflow.com/a/17083009/895245, mais permettez-moi de l'illustrer davantage.
Le gros avantage de cette option -S
est qu'il est très facile de l'ajouter à n'importe quel script de build, sans interférer beaucoup dans la build elle-même.
Quand vous faites:
gcc -save-temps -c -o main.o main.c
principal c
#define INC 1
int myfunc(int i) {
return i + INC;
}
et maintenant, en plus de la sortie normale main.o
, le répertoire de travail actuel contient également les fichiers suivants:
main.i
est un bonus et contient le fichier pré-traité:
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "main.c"
int myfunc(int i) {
return i + 1;
}
main.s
contient l'assemblage généré souhaité:
.file "main.c"
.text
.globl myfunc
.type myfunc, @function
myfunc:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
addl $1, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size myfunc, .-myfunc
.ident "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
.section .note.GNU-stack,"",@progbits
Si vous souhaitez le faire pour un grand nombre de fichiers, envisagez d'utiliser à la place:
-save-temps=obj
qui enregistre les fichiers intermédiaires dans le même répertoire que la -o
sortie de l' objet au lieu du répertoire de travail actuel, évitant ainsi les conflits potentiels de nom de base.
Une autre chose intéressante à propos de cette option est que si vous ajoutez -v
:
gcc -save-temps -c -o main.o -v main.c
il montre en fait les fichiers explicites utilisés au lieu de laids temporaires sous /tmp
, il est donc facile de savoir exactement ce qui se passe, ce qui inclut les étapes de prétraitement / compilation / assemblage:
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s
Testé dans Ubuntu 19.04 amd64, GCC 8.3.0.
Utilisez l'option -S:
gcc -S program.c
De: http://www.delorie.com/djgpp/v2faq/faq8_20.html
gcc -c -g -Wa, -a, -ad [autres options GCC] foo.c> foo.lst
en alternative à la réponse de PhirePhly Ou utilisez simplement -S comme tout le monde l'a dit.
Voici les étapes pour voir / imprimer le code d'assemblage de n'importe quel programme C sur votre Windows
console / terminal / invite de commande:
Écrivez un programme C dans un éditeur de code C comme des blocs de code et enregistrez-le avec une extension .c
Compilez-le et exécutez-le.
Une fois exécuté avec succès, allez dans le dossier où vous avez installé votre compilateur gcc et donnez
commande suivante pour obtenir un fichier '.s' du fichier '.c'
C: \ gcc> gcc -S chemin complet du fichier C ENTER
Un exemple de commande (comme dans mon cas)
C: \ gcc> gcc -SD: \ Aa_C_Certified \ alternative_letters.c
Cela génère un fichier «.s» du fichier «.c» d'origine
4. Après cela, tapez la commande suivante
C; \ gcc> cpp filename.s ENTER
Exemple de commande (comme dans mon cas)
C; \ gcc> cpp Alternate_letters.s
Cela imprimera / affichera le code du langage d'assemblage complet de votre programme C.
Utilisez "-S" en option. Il affiche la sortie de l'assemblage dans le terminal.
gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less
. -S
à lui seul crée foo.s
.
récemment, je voulais connaître l'assemblage de chaque fonction dans un programme,
c'est ainsi que je l'ai fait.
$ gcc main.c // main.c source file
$ gdb a.exe // gdb a.out in linux
(gdb) disass main // note here main is a function
// similary it can be done for other functions
Voici une solution pour C utilisant gcc:
gcc -S program.c && gcc program.c -o output
Ici, la première partie stocke la sortie d'assembly du programme dans le même nom de fichier que Program mais avec une extension .s modifiée , vous pouvez l'ouvrir comme n'importe quel fichier texte normal.
La deuxième partie ici compile votre programme pour une utilisation réelle et génère un exécutable pour votre programme avec un nom de fichier spécifié.
Le programme.c utilisé ci-dessus est le nom de votre programme et la sortie est le nom de l'exécutable que vous souhaitez générer.
BTW C'est mon premier post sur StackOverFlow: -}