web-dev-qa-db-fra.com

Comment obtenez-vous la sortie de l'assembleur à partir de la source C/C++ dans gcc?

Comment est-que quelqu'un peut faire ça?

Si je veux analyser comment quelque chose est en train d'être compilé, comment pourrais-je obtenir le code d'assembly émis?

313
Doug T.

Utilisez l'option -S pour 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 l'exécution de l'assembleur.

Par défaut, cela produira un fichier helloworld.s. Le fichier de sortie peut toujours être défini à l'aide de l'option -o.

gcc -S -o my_asm_output.s helloworld.c

Bien entendu, cela ne fonctionne que si vous avez la source d'origine . Une alternative si vous ne possédez que le fichier objet résultant est d'utiliser objdump en définissant l'option --disassemble (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é.

Lancer file helloworld vous indiquera le niveau de détail que vous obtiendrez en utilisant objdump.

365
Andrew Edgecombe

Cela générera le code asm 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:
c++ -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 15ème page globale du PDF).

160
PhirePhly

La ligne de commande suivante provient de le 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 sous Win-XP, avec une routine contenant une conversion 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'

La sortie est un code généré assemblé qui est remplacé par 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)
44
Cr McDonough

Utilisez le commutateur -S 

g++ -S main.cpp

ou aussi avec gcc

gcc -S main.c

Voir aussi ceci

22
Doug T.

Si ce que vous voulez voir dépend de la liaison de la sortie, objdump sur le fichier objet/exécutable 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 par défaut objdump en syntaxe plus lisible: nasm:

#!/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 suppose que cela peut également être utilisé sur la sortie de gcc -S.

12
Dark Shikari

Comme tout le monde l’a dit, utilisez l’option -S ..__ Si vous utilisez l’option -save-temps, vous pouvez également obtenir un fichier prétraité ( .i), un fichier Assembly (. S) et un fichier objet (*. o). (Obtenez chacun d'eux en utilisant -E, -S et -c.)

8
METADATA

Comme tout le monde l’a fait remarquer, utilisez l’option -S pour GCC. J'aimerais également ajouter que les résultats peuvent varier (énormément!) Selon que vous ajoutez ou non des options d'optimisation (-O0 pour aucun, -O2 pour une optimisation agressive).

Sur les architectures RISC en particulier, le compilateur va souvent transformer le code presque au-delà de la reconnaissance en faisant de l'optimisation. C'est impressionnant et fascinant de regarder les résultats!

7
Dan Lenski

Comme mentionné précédemment, regardez le drapeau -S.

Cela vaut également la peine de regarder la famille de drapeaux '-fdump-tree', en particulier '-fdump-tree-all', qui vous permet de voir certaines formes intermédiaires de gcc. Celles-ci peuvent souvent être plus lisibles que l'assembleur (du moins pour moi) et vous permettent de voir comment les passes d'optimisation fonctionnent.

7
Chris Jefferson

Utilisez l'option -S:

gcc -S program.c
6
Jeremy Ruten

Si vous recherchez un assemblage LLVM:

llvm-gcc -emit-llvm -S hello.c
6
mcandre

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 cloner et exécuter son projet https://github.com/mattgodbolt/compiler-Explorer

5
Antonin GAVREL

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 le dit.

4
Anonymous

 Output of these commnads

Voici les étapes à suivre pour voir/imprimer le code d'assemblage de tout programme C sur votre Windows 

console/terminal/invite de commande:

  1. Ecrivez un programme C dans un éditeur de code C tel que codeblocks et enregistrez-le avec une extension .c

  2. Compiler et l'exécuter.

  3. Une fois exécuté avec succès, allez dans le dossier où vous avez installé votre compilateur gcc et donnez le 

    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 -S D:\Aa_C_Certified\alternate_letters.c 

    Ceci sort un fichier '.s' du fichier '.c' original

4 Après cela, tapez la commande suivante

C;\gcc> cpp nomfichier.s ENTREE

Exemple de commande (comme dans mon cas)

C;\gcc> cpp alternate_letters.s 

Ceci imprimera/affichera le code de langue d'assemblage complet de votre programme C.

2
Ashutosh K Singh

-save-temps

Cela a été mentionné à https://stackoverflow.com/a/17083009/895245 , mais laissez-moi en donner un exemple supplémentaire. Quand tu fais:

_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 en cours contient également les fichiers suivants:

  • _main.i_ est un bonus et contient le fichier préfabriqué souhaité:

    _# 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'assembly 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, utilisez plutôt:

_ -save-temps=obj
_

qui enregistre les fichiers intermédiaires dans le même répertoire que la sortie de l’objet _-o_ au lieu du répertoire de travail en cours, évitant ainsi des conflits potentiels de noms de bases.

L’avantage de cette option par rapport à _-S_ est qu’il est facile de l’ajouter à n’importe quel script de construction, sans trop interférer dans la construction elle-même.

Une autre chose intéressante à propos de cette option est si vous ajoutez _-v_:

_gcc -save-temps -c -o main.o -v main.c
_

il montre en fait les fichiers explicites utilisés à la place des horribles 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é sous Ubuntu 19.04 AMD64, GCC 8.3.0.

Utilisez "-S" en option. Il affiche la sortie de l’Assemblée dans le terminal.

1
Pizearke

récemment, je voulais savoir l'Assemblée de chaque fonction dans un programme
C'est comme ça 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
1
Abhishek D K

Voici une solution pour C utilisant gcc:

gcc -S program.c && gcc program.c -o output
  1. Ici, la première partie stocke la sortie Assembly du programme dans le même nom de fichier que Programme mais avec l'extension .s modifiée, vous pouvez l'ouvrir comme n'importe quel fichier texte normal.

  2. 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é.

Program.c utilisé ci-dessus est le nom de votre programme et output est le nom de l'exécutable que vous voulez générer.

BTW c'est mon premier post sur StackOverFlow: -}

0
Himanshu Pal