Bagaimana caranya?
Jika saya ingin menganalisis bagaimana sesuatu dikompilasi, bagaimana saya mendapatkan kode assembly yang dipancarkan?
Bagaimana caranya?
Jika saya ingin menganalisis bagaimana sesuatu dikompilasi, bagaimana saya mendapatkan kode assembly yang dipancarkan?
Jawaban:
Gunakan -S
opsi 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 -o
opsi.
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 --disassemble
opsi (atau -d
untuk bentuk disingkat).
objdump -S --disassemble helloworld > helloworld.dump
Opsi ini berfungsi paling baik jika opsi debugging diaktifkan untuk file objek ( -g
pada waktu kompilasi) dan file belum dilucuti.
Menjalankan file helloworld
akan memberi Anda beberapa indikasi tentang tingkat detail yang akan Anda dapatkan dengan menggunakan objdump.
.intel_syntax
adalah tidak kompatibel dengan NASM . Ini lebih seperti MASM (misalnya mov eax, symbol
beban, tidak seperti di NASM yang merupakan mov r32, imm32
alamatnya), 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 | less
atau gcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | less
bermanfaat. (Lihat juga Bagaimana menghapus "noise" dari GCC / output rakitan? ). -masm=intel
bekerja dengan dentang juga.
gcc -O -fverbose-asm -S
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).
as
di OS X tidak tahu flag-flag ini. Namun, jika ya, Anda mungkin bisa menggunakan satu-line ini -Wa
untuk meneruskan opsi as
.
g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lst
akan menjadi versi singkat ini.
gcc -c -g -Wa,-ahl=test.s test.c
ataugcc -c -g -Wa,-a,-ad test.c > test.txt
-O0
? Itu penuh dengan banyak / toko yang membuatnya sulit untuk melacak nilai, dan tidak memberi tahu Anda seberapa efisien kode yang dioptimalkan.
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)
-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.)
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.
mov eax,ds:0x804b794
tidak terlalu NASMish. Juga, kadang-kadang itu hanya menghapus informasi yang berguna: movzx eax,[edx+0x1]
membuat pembaca menebak apakah operan memori itu byte
atau tidak word
.
objconv
. 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).
Seperti yang semua orang tunjukkan, gunakan -S
opsi untuk GCC. Saya juga ingin menambahkan bahwa hasilnya dapat bervariasi (liar!) Tergantung pada apakah Anda menambahkan opsi pengoptimalan ( -O0
tidak ada, -O2
untuk 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!
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.
Saya tidak melihat kemungkinan ini di antara jawaban, mungkin karena pertanyaannya adalah dari tahun 2008, tetapi pada tahun 2018 Anda dapat menggunakan situs web online Matt Goldbolt https://godbolt.org
Anda juga dapat klon git secara lokal dan menjalankan proyeknya https://github.com/mattgodbolt/compiler-explorer
-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 -o
output 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.
Gunakan opsi -S:
gcc -S program.c
Dari: http://www.delorie.com/djgpp/v2faq/faq8_20.html
gcc -c -g -Wa, -a, -ad [opsi GCC lain] foo.c> foo.lst
sebagai alternatif dari jawaban PhirePhly Atau gunakan saja -S seperti yang dikatakan semua orang.
Berikut adalah langkah-langkah untuk melihat / mencetak kode rakitan dari setiap program C pada Windows Anda
konsol / terminal / command prompt:
Tulis program C dalam editor kode C seperti kode kunci dan simpan dengan ekstensi .c
Kompilasi dan jalankan.
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.
Gunakan "-S" sebagai opsi. Ini menampilkan output perakitan di terminal.
gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less
. -S
dengan sendirinya menciptakan foo.s
.
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
Berikut adalah solusi untuk C menggunakan gcc:
gcc -S program.c && gcc program.c -o output
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.
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: -}