web-dev-qa-db-fra.com

Utiliser GCC pour produire un assemblage lisible?

Je me demandais comment utiliser GCC sur mon fichier source C pour vider une version mnémonique du code machine afin que je puisse voir en quoi mon code était compilé. Vous pouvez le faire avec Java mais je n’ai pas trouvé de solution avec GCC.

J'essaie de réécrire une méthode C dans Assembly et voir comment GCC y parviendrait serait d'une grande aide.

231
James

Si vous compilez avec des symboles de débogage, vous pouvez utiliser objdump pour produire un désassemblage plus lisible.

>objdump --help
[...]
-S, --source             Intermix source code with disassembly
-l, --line-numbers       Include line numbers and filenames in output

objdump -drwC -Mintel is Nice:

  • -r affiche les noms des symboles sur les relocalisations (vous verrez donc puts dans l'instruction call ci-dessous)
  • -R affiche les relocalisations/noms de symboles à liaison dynamique (utile dans les bibliothèques partagées)
  • -C démêle les noms de symbole C++
  • -w est le mode "Wide": il ne met pas à la ligne les octets de code machine
  • -Mintel: utilise la syntaxe .intel_syntax noprefix de GAS/binutils de type MASM, à la place de AT & T
  • -S: entrelace les lignes source avec désassemblage.

Vous pouvez mettre quelque chose comme alias disas="objdump -drwCS -Mintel" dans votre ~/.bashrc


Exemple:

> gcc -g -c test.c
> objdump -d -M intel -S test.o

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
#include <stdio.h>

int main(void)
{
   0:   55                      Push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   83 e4 f0                and    esp,0xfffffff0
   6:   83 ec 10                sub    esp,0x10
    puts("test");
   9:   c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
  10:   e8 fc ff ff ff          call   11 <main+0x11>

    return 0;
  15:   b8 00 00 00 00          mov    eax,0x0
}
  1a:   c9                      leave  
  1b:   c3                      ret
312
Bastien Léonard

J'aimerais ajouter à ces réponses que si vous donnez à gcc le drapeau -fverbose-asm, l'assembleur qu'il émet sera beaucoup plus clair à lire.

95
kmm

Utilisez le commutateur -S (note: majuscule S) sur GCC, qui émettra le code d'assemblage dans un fichier portant l'extension .s. Par exemple, la commande suivante:

gcc -O2 -S foo.c

laissera le code d'assemblage généré sur le fichier foo.s.

Arraché directement de http://www.delorie.com/djgpp/v2faq/faq8_20.html (mais en supprimant les _ (codes erronés) -c)

73
Andrew Keeton

L'utilisation du commutateur -S vers GCC sur les systèmes x86 génère une sauvegarde de la syntaxe AT & T, qui peut être spécifiée avec le commutateur -masm=att, comme suit:

gcc -S -masm=att code.c

Alors que si vous souhaitez produire un cliché en syntaxe Intel, vous pouvez utiliser le commutateur -masm=intel, comme suit:

gcc -S -masm=intel code.c

(Les deux produisent des dumps de code.c dans leurs différentes syntaxes, dans le fichier code.s respectivement)

Afin de produire des effets similaires avec objdump, vous souhaiterez utiliser le commutateur --disassembler-options=intel/att, avec un exemple (avec des copies de code pour illustrer les différences de syntaxe):

 $ objdump -d --disassembler-options=att code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    0x4(%esp),%ecx
 80483c8:   83 e4 f0                and    $0xfffffff0,%esp
 80483cb:   ff 71 fc                pushl  -0x4(%ecx)
 80483ce:   55                      Push   %ebp
 80483cf:   89 e5                   mov    %esp,%ebp
 80483d1:   51                      Push   %ecx
 80483d2:   83 ec 04                sub    $0x4,%esp
 80483d5:   c7 04 24 b0 84 04 08    movl   $0x80484b0,(%esp)
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    $0x0,%eax
 80483e6:   83 c4 04                add    $0x4,%esp 
 80483e9:   59                      pop    %ecx
 80483ea:   5d                      pop    %ebp
 80483eb:   8d 61 fc                lea    -0x4(%ecx),%esp
 80483ee:   c3                      ret
 80483ef:   90                      nop

et

$ objdump -d --disassembler-options=intel code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    ecx,[esp+0x4]
 80483c8:   83 e4 f0                and    esp,0xfffffff0
 80483cb:   ff 71 fc                Push   DWORD PTR [ecx-0x4]
 80483ce:   55                      Push   ebp
 80483cf:   89 e5                   mov    ebp,esp
 80483d1:   51                      Push   ecx
 80483d2:   83 ec 04                sub    esp,0x4
 80483d5:   c7 04 24 b0 84 04 08    mov    DWORD PTR [esp],0x80484b0
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    eax,0x0
 80483e6:   83 c4 04                add    esp,0x4
 80483e9:   59                      pop    ecx
 80483ea:   5d                      pop    ebp
 80483eb:   8d 61 fc                lea    esp,[ecx-0x4]
 80483ee:   c3                      ret    
 80483ef:   90                      nop
49
amaterasu

godbolt est un outil très utile, leur liste n’a que des compilateurs C++ mais vous pouvez utiliser le drapeau -x c pour le traiter en tant que code C. Il générera ensuite une liste Assembly pour votre code côte à côte et vous pouvez utiliser l’option Colourise pour générer des barres de couleur afin d’indiquer visuellement le code source mappé sur l’Assemblée générée. Par exemple le code suivant:

#include <stdio.h>

void func()
{
  printf( "hello world\n" ) ;
}

en utilisant la ligne de commande suivante:

-x c -std=c99 -O3

et Colourise générerait ce qui suit:

enter image description here

34
Shafik Yaghmour

Avez-vous essayé gcc -S -fverbose-asm -O source.c puis avez-vous consulté le fichier assembleur source.s généré?

Le code assembleur généré va dans source.s (vous pouvez le remplacer par -o nom_fichier_assembleur ); l'option -fverbose-asm demande au compilateur d'émettre des commentaires d'assembleur "expliquant" le code assembleur généré. L'option -O demande au compilateur d'optimiser un bit (il pourrait en optimiser davantage avec -O2 ou -O3).

Si vous voulez comprendre ce que gcc fait, essayez de passer -fdump-tree-all mais soyez prudent: vous obtiendrez des centaines de fichiers de vidage.

BTW, GCC est extensible via plugins ou avec MELT (langage spécifique au domaine de haut niveau pour étendre GCC; que j'ai abandonné en 2017)

22

Vous pouvez utiliser gdb pour cela comme objdump.

Cet extrait est tiré de http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64


Voici un exemple montrant une source mixte + Assembly pour Intel x86:

 (gdb) disas/m main 
 Dump du code assembleur pour la fonction main: 
 5 {
 0x08048330: Appuyez sur% ebp 
 0x08048331: mov % esp,% ebp 
 0x08048333: sub $ 0x8,% esp 
 0x08048336: et $ 0xfffffff0,% esp 
 0x08048339: sub $ 0x10,% esp 
 
 6 printf ("Hello.\N"); 
 0x0804833c: movl $ 0x8048440, (% esp) 
 0x08048343: appelez 0x8048284 
 
 7 return 0; 
 8} 
 0x08048348: mov $ 0x0,% eax 
 0x0804834d: laissez 
 0x0804834e: ret 
 
 Fin d'assembleur dump. 
19
Vishal Sagar

Utilisez le commutateur -S (note: majuscule S) sur GCC, qui émettra le code d'assemblage dans un fichier portant l'extension .s. Par exemple, la commande suivante:

gcc -O2 -S -c toto.c

13
codymanix

Je n'ai pas essayé de gcc, mais en cas de g ++. La commande ci-dessous fonctionne pour moi. -g pour la construction de débogage et -Wa, -adhln est passé à l'assembleur pour la liste avec le code source

g ++ -g -Wa, -adhln src.cpp

4
DAG