Bagaimana Anda mendapatkan output assembler dari sumber C / C ++ di gcc?


Jawaban:


422

Gunakan -Sopsi untuk gcc (atau g ++).

gcc -S helloworld.c

Ini akan menjalankan preprocessor (cpp) di helloworld.c, melakukan kompilasi awal dan kemudian berhenti sebelum assembler dijalankan.

Secara default ini akan menghasilkan file helloworld.s. File output masih dapat diatur dengan menggunakan -oopsi.

gcc -S -o my_asm_output.s helloworld.c

Tentu saja ini hanya berfungsi jika Anda memiliki sumber aslinya. Alternatif jika Anda hanya memiliki file objek yang dihasilkan untuk digunakan objdump, dengan mengatur --disassembleopsi (atau -duntuk bentuk disingkat).

objdump -S --disassemble helloworld > helloworld.dump

Opsi ini berfungsi paling baik jika opsi debugging diaktifkan untuk file objek ( -gpada waktu kompilasi) dan file belum dilucuti.

Menjalankan file helloworldakan memberi Anda beberapa indikasi tentang tingkat detail yang akan Anda dapatkan dengan menggunakan objdump.


3
Meskipun ini benar, saya menemukan hasil dari jawaban Cr McDonough lebih bermanfaat.
Rhys Ulerich

3
tambahan gunakan: objdump -M intel -S --disassemble helloworld> helloworld.dump untuk mendapatkan objek dump di sintaks intel yang kompatibel dengan nasm di linux.
touchStone

2
Jika Anda memiliki fungsi tunggal untuk mengoptimalkan / memeriksa, maka Anda dapat mencoba interaktif C ++ Compiler online yaitu godbolt
fiorentinoing

1
@touchStone: GAS .intel_syntaxadalah tidak kompatibel dengan NASM . Ini lebih seperti MASM (misalnya mov eax, symbolbeban, tidak seperti di NASM yang merupakan mov r32, imm32alamatnya), tetapi tidak sepenuhnya kompatibel dengan MASM. Saya sangat merekomendasikan ini sebagai format yang bagus untuk dibaca, terutama jika Anda suka menulis dalam sintaks NASM. objdump -drwC -Mintel | lessatau gcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | lessbermanfaat. (Lihat juga Bagaimana menghapus "noise" dari GCC / output rakitan? ). -masm=intelbekerja dengan dentang juga.
Peter Cordes

3
Penggunaan yang lebih baikgcc -O -fverbose-asm -S
Basile Starynkevitch

173

Ini akan menghasilkan kode rakitan dengan kode C + nomor baris terjalin, untuk lebih mudah melihat baris mana yang menghasilkan kode apa:

# 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

Ditemukan dalam Algoritma untuk programmer , halaman 3 (yang merupakan halaman ke 15 keseluruhan dari PDF).


3
(Itu sebenarnya pada halaman (bernomor) 3 (yang merupakan halaman ke-15 dari PDF)
Grumdrig

1
Sayangnya, asdi OS X tidak tahu flag-flag ini. Namun, jika ya, Anda mungkin bisa menggunakan satu-line ini -Wauntuk meneruskan opsi as.
Grumdrig

23
g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lstakan menjadi versi singkat ini.
legends2k

4
Anda juga dapat menggunakan gcc -c -g -Wa,-ahl=test.s test.cataugcc -c -g -Wa,-a,-ad test.c > test.txt
phuclv

1
Sebuah posting blog yang menjelaskan ini lebih rinci, termasuk versi satu-perintah seperti legenda dan Lu'u diposting. Tapi mengapa -O0? Itu penuh dengan banyak / toko yang membuatnya sulit untuk melacak nilai, dan tidak memberi tahu Anda seberapa efisien kode yang dioptimalkan.
Peter Cordes

51

Baris perintah berikut ini dari blog Christian Garbin

g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt

Saya menjalankan G ++ dari jendela DOS pada Win-XP, terhadap rutin yang berisi pemeran tersirat

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'

Keluarannya adalah kode yang dihasilkan assassembed diselingi dengan kode C ++ asli (kode C ++ ditampilkan sebagai komentar dalam aliran asm yang dihasilkan)

  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)

@Paladin - Belum tentu. OP adalah tentang mendapatkan setara assembler output dari kode sumber C / C ++, ini mendapat Listing, yang saya setuju lebih berguna untuk memahami apa yang dilakukan kompiler dan pengoptimal. Tapi itu akan menyebabkan assembler itu sendiri muntah, karena tidak mengharapkan nomor baris, dan menyusun byte dari total yang dia tinggalkan dari instruksi perakitan.
Jesse Chisholm

Gunakan setidaknya -O2, atau opsi pengoptimalan apa pun yang sebenarnya Anda gunakan saat membangun proyek Anda, jika Anda ingin melihat bagaimana gcc mengoptimalkan kode Anda. (Atau jika Anda menggunakan KPP, seperti yang seharusnya, maka Anda harus membongkar output linker untuk melihat apa yang benar-benar Anda dapatkan.)
Peter Cordes

27

Gunakan tombol -S

g++ -S main.cpp

atau juga dengan gcc

gcc -S main.c

Lihat juga ini


7
Periksa FAQ: "Bertanya juga baik-baik saja untuk bertanya dan menjawab pertanyaan pemrograman Anda sendiri". Intinya adalah bahwa sekarang StackOverflow berisi Q&A sebagai sumber daya bagi orang lain.
Steve Jessop

Dan mungkin orang lain akan datang dan mengejutkan Anda dengan jawaban yang lebih baik, meskipun jawaban saya mungkin sedikit bertele-tele ...
PhirePhly

Bahkan ada jawaban tombol pertanyaan Anda sendiri.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

13

Jika apa yang ingin Anda lihat tergantung pada penautan output, maka objdump pada file objek output / executable juga dapat berguna selain gcc -S yang disebutkan di atas. Berikut ini skrip yang sangat berguna dari Loren Merritt yang mengubah sintaks objdump default menjadi sintaks nasm yang lebih mudah dibaca:

#!/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;

Saya menduga ini juga dapat digunakan pada output gcc -S.


2
Namun, skrip ini adalah hack kotor yang tidak sepenuhnya mengonversi sintaksis. Misalnya mov eax,ds:0x804b794tidak terlalu NASMish. Juga, kadang-kadang itu hanya menghapus informasi yang berguna: movzx eax,[edx+0x1]membuat pembaca menebak apakah operan memori itu byteatau tidak word.
Ruslan

Untuk membongkar sintaks NASM sejak awal, gunakan Agner Fog'sobjconv . Anda bisa membuatnya untuk membongkar ke stdout dengan file output = /dev/stdout, sehingga Anda dapat pipa keless untuk dilihat. Ada juga ndisasm, tetapi hanya membongkar binari datar, dan tidak tahu tentang file objek (ELF / PE).
Peter Cordes

9

Seperti yang semua orang tunjukkan, gunakan -Sopsi untuk GCC. Saya juga ingin menambahkan bahwa hasilnya dapat bervariasi (liar!) Tergantung pada apakah Anda menambahkan opsi pengoptimalan ( -O0tidak ada, -O2untuk pengoptimalan yang agresif).

Pada arsitektur RISC pada khususnya, kompiler akan sering mengubah kode hampir tidak dapat dikenali dalam melakukan optimasi. Sangat mengesankan dan menarik untuk melihat hasilnya!


9

Nah, seperti kata semua orang, gunakan opsi -S. Jika Anda menggunakan opsi -simpan-temps, Anda juga bisa mendapatkan file preprocessed ( .i), file assembly ( .s) dan file objek (*. O). (dapatkan masing-masing dengan menggunakan -E, -S, dan -c.)


8

Seperti disebutkan sebelumnya, lihat bendera -S.

Perlu juga melihat keluarga flag '-fdump-tree', khususnya '-fdump-tree-all', yang memungkinkan Anda melihat beberapa bentuk peralihan gcc. Ini sering kali lebih mudah dibaca daripada assembler (setidaknya bagi saya), dan biarkan Anda melihat bagaimana optimasi berjalan.


8

Jika Anda mencari perakitan LLVM:

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


8

-save-temps

Ini disebutkan di https://stackoverflow.com/a/17083009/895245 tetapi biarkan saya mencontohkan lebih lanjut.

Keuntungan besar dari opsi ini berakhir -S ini adalah sangat mudah untuk menambahkannya ke skrip build apa pun, tanpa banyak campur tangan dalam build itu sendiri.

Saat kamu melakukan:

gcc -save-temps -c -o main.o main.c

main.c

#define INC 1

int myfunc(int i) {
    return i + INC;
}

dan sekarang, selain output normal main.o, direktori kerja saat ini juga berisi file-file berikut:

  • main.i adalah bonus dan berisi file preprossessed:

    # 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 mengandung rakitan yang dihasilkan yang diinginkan:

        .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

Jika Anda ingin melakukannya untuk banyak file, pertimbangkan untuk menggunakan:

 -save-temps=obj

yang menyimpan file-file antara ke direktori yang sama dengan -ooutput objek alih-alih direktori kerja saat ini, sehingga menghindari kemungkinan konflik nama nama.

Hal keren lainnya tentang opsi ini adalah jika Anda menambahkan -v:

gcc -save-temps -c -o main.o -v main.c

itu benar-benar menunjukkan file eksplisit yang digunakan alih-alih temporari jelek di bawah /tmp, sehingga mudah untuk mengetahui apa yang sedang terjadi, yang meliputi langkah preprocessing / kompilasi / perakitan:

/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

Diuji di Ubuntu 19.04 amd64, GCC 8.3.0.




3

Output dari commnads ini

Berikut adalah langkah-langkah untuk melihat / mencetak kode rakitan dari setiap program C pada Windows Anda

konsol / terminal / command prompt:

  1. Tulis program C dalam editor kode C seperti kode kunci dan simpan dengan ekstensi .c

  2. Kompilasi dan jalankan.

  3. Setelah berjalan dengan sukses, buka folder tempat Anda menginstal kompiler gcc Anda dan berikan

    mengikuti perintah untuk mendapatkan file '.s' dari file '.c'

    C: \ gcc> gcc -S lintasan lengkap file C ENTER

    Contoh perintah (seperti dalam kasus saya)

    C: \ gcc> gcc -SD: \ Aa_C_Certified \ alternate_letters.c

    Ini menghasilkan file '.s' dari file '.c' yang asli

4. Setelah ini, ketikkan perintah berikut

C; \ gcc> cpp filename.s ENTER

Contoh perintah (seperti dalam kasus saya)

C; \ gcc> cpp alternate_letters.s

Ini akan mencetak / menampilkan seluruh kode bahasa Assembly program C. Anda.


2

Gunakan "-S" sebagai opsi. Ini menampilkan output perakitan di terminal.


Untuk ditampilkan di terminal, gunakan gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less. -Sdengan sendirinya menciptakan foo.s.
Peter Cordes

2

Baru-baru ini saya ingin mengetahui perakitan dari masing-masing fungsi dalam suatu program.
Ini adalah bagaimana saya melakukannya.

$ 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

2

Berikut adalah solusi untuk C menggunakan gcc:

gcc -S program.c && gcc program.c -o output
  1. Di sini bagian pertama menyimpan output rakitan program dalam nama file yang sama dengan Program tetapi dengan ekstensi .s yang diubah , Anda dapat membukanya sebagai file teks biasa.

  2. Bagian kedua di sini mengkompilasi program Anda untuk penggunaan aktual dan menghasilkan executable untuk Program Anda dengan nama file yang ditentukan.

The program.c digunakan di atas adalah nama program dan keluaran adalah nama executable Anda ingin menghasilkan.

BTW Ini posting pertama saya di StackOverFlow: -}

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.