คนเราจะทำสิ่งนี้ได้อย่างไร
หากฉันต้องการวิเคราะห์ว่ามีบางสิ่งที่รวบรวมได้ฉันจะได้รับรหัสแอสเซมบลีที่ปล่อยออกมาได้อย่างไร
คนเราจะทำสิ่งนี้ได้อย่างไร
หากฉันต้องการวิเคราะห์ว่ามีบางสิ่งที่รวบรวมได้ฉันจะได้รับรหัสแอสเซมบลีที่ปล่อยออกมาได้อย่างไร
คำตอบ:
ใช้-S
ตัวเลือกเพื่อ gcc (หรือ g ++)
gcc -S helloworld.c
สิ่งนี้จะรันตัวประมวลผลล่วงหน้า (cpp) บน helloworld.c ทำการคอมไพล์เริ่มต้นแล้วหยุดก่อนที่แอสเซมเบลอร์จะทำงาน
helloworld.s
โดยค่าเริ่มต้นนี้จะส่งออกไฟล์ ไฟล์เอาต์พุตสามารถตั้งค่าได้โดยใช้-o
ตัวเลือก
gcc -S -o my_asm_output.s helloworld.c
แน่นอนว่าใช้งานได้เฉพาะถ้าคุณมีแหล่งที่มาดั้งเดิม ทางเลือกอื่นถ้าคุณมีไฟล์ออบเจ็กต์ผลลัพธ์เท่านั้นobjdump
โดยใช้--disassemble
ตัวเลือก (หรือ-d
สำหรับแบบย่อ)
objdump -S --disassemble helloworld > helloworld.dump
ตัวเลือกนี้ทำงานได้ดีที่สุดหากเปิดใช้งานตัวเลือกการดีบักสำหรับไฟล์ออบเจ็กต์ ( -g
ณ เวลารวบรวม) และไฟล์ยังไม่ได้รับการแยก
การวิ่งfile helloworld
จะให้ข้อบ่งชี้ระดับของรายละเอียดที่คุณจะได้รับจากการใช้ objdump
.intel_syntax
คือไม่เข้ากันได้กับ NASM มันเหมือน MASM (เช่นmov eax, symbol
โหลดเหมือนใน NASM ซึ่งเป็นmov r32, imm32
ที่อยู่) แต่ก็ไม่เข้ากันได้กับ MASM อย่างสมบูรณ์เช่นกัน ฉันขอแนะนำเป็นรูปแบบที่ดีในการอ่านโดยเฉพาะถ้าคุณชอบที่จะเขียนในไวยากรณ์ของ NASM objdump -drwC -Mintel | less
หรือgcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | less
มีประโยชน์ (ดูเพิ่มเติมวิธีการลบ“ สัญญาณรบกวน” ออกจากชุดประกอบ GCC / เสียงดังกราวด์? ) -masm=intel
ทำงานร่วมกับเสียงดังกราวได้เช่นกัน
gcc -O -fverbose-asm -S
สิ่งนี้จะสร้างแอสเซมบลีโค้ดด้วยรหัส C + หมายเลขบรรทัดผสมกันเพื่อให้ง่ายต่อการดูว่าบรรทัดใดสร้างโค้ดใด
# 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
พบในอัลกอริทึมสำหรับโปรแกรมเมอร์หน้า 3 (ซึ่งเป็นหน้า 15 โดยรวมของ PDF)
as
บน OS X ไม่รู้จักการตั้งค่าสถานะเหล่านี้ ถ้ามันไม่ได้แม้ว่าคุณอาจอาจเป็นหนึ่งในสายนี้โดยใช้การส่งผ่านตัวเลือกในการ-Wa
as
g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lst
จะเป็นรุ่นมือสั้นของนี้
gcc -c -g -Wa,-ahl=test.s test.c
หรือgcc -c -g -Wa,-a,-ad test.c > test.txt
-O0
? เต็มไปด้วยโหลด / ร้านค้าที่ทำให้ยากต่อการติดตามค่าและไม่ได้บอกอะไรคุณเกี่ยวกับประสิทธิภาพของรหัสที่เพิ่มประสิทธิภาพ
บรรทัดคำสั่งต่อไปนี้มาจากบล็อกของ Christian Garbin
g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
ฉันรัน G ++ จากหน้าต่าง DOS บน Win-XP เทียบกับชุดคำสั่งที่มีการส่งโดยนัย
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'
เอาท์พุทจะประกอบขึ้นเป็นรหัสที่สร้างซ้ำกับรหัส C ++ เดิม (รหัส C ++ แสดงเป็นความคิดเห็นในกระแสข้อมูล asm ที่สร้างขึ้น)
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
หรือตัวเลือกการเพิ่มประสิทธิภาพใด ๆ ที่คุณใช้จริงเมื่อสร้างโครงการของคุณหากคุณต้องการดูว่า gcc เพิ่มประสิทธิภาพโค้ดของคุณอย่างไร (หรือถ้าคุณใช้ LTO อย่างที่ควรจะเป็นคุณต้องถอดแยก linker output ออกเพื่อดูว่าคุณได้อะไรจริงๆ)
หากสิ่งที่คุณต้องการดูขึ้นอยู่กับการเชื่อมโยงของเอาต์พุตแล้ว objdump ในไฟล์อ็อบเจกต์เอาต์พุต / ไฟล์เรียกทำงานอาจมีประโยชน์นอกเหนือจาก gcc -S ที่กล่าวมาข้างต้น นี่เป็นสคริปต์ที่มีประโยชน์มากโดย Loren Merritt ที่แปลงไวยากรณ์เริ่มต้น objdump เป็นไวยากรณ์ 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;
ฉันสงสัยว่าสิ่งนี้สามารถใช้กับผลลัพธ์ของ gcc -S ได้
mov eax,ds:0x804b794
ไม่ใช่ NASMish มาก นอกจากนี้บางครั้งมันก็แถบข้อมูลที่มีประโยชน์: movzx eax,[edx+0x1]
ใบผู้อ่านที่จะคาดเดาว่าจะเป็นหน่วยความจำตัวถูกดำเนินการเป็นหรือbyte
word
objconv
หมอก คุณสามารถเอามันไปถอดแยกเพื่อ stdout ด้วยไฟล์เอาต์พุต = /dev/stdout
เพื่อให้คุณสามารถไพพ์เข้าไปless
ดูได้ นอกจากนี้ยังมีndisasm
แต่มันแยกส่วนไบนารีแบบแบนเท่านั้นและไม่ทราบเกี่ยวกับไฟล์วัตถุ (ELF / PE)
ตามที่ทุกคนได้ชี้ให้ใช้-S
ตัวเลือกเพื่อ GCC ฉันต้องการเพิ่มว่าผลลัพธ์อาจแตกต่างกันไป (ขึ้นอยู่กับว่า!) ขึ้นอยู่กับว่าคุณเพิ่มตัวเลือกการเพิ่มประสิทธิภาพ ( -O0
ไม่ใช้-O2
สำหรับการเพิ่มประสิทธิภาพแบบก้าวร้าว) หรือไม่
โดยเฉพาะอย่างยิ่งในสถาปัตยกรรม RISC คอมไพเลอร์มักจะแปลงรหัสจนเกินกว่าจะจดจำในการปรับให้เหมาะสม มันน่าประทับใจและน่าสนใจที่จะดูผลลัพธ์!
อย่างที่ทุกคนบอกว่าใช้ตัวเลือก -S หากคุณใช้ตัวเลือก -save-temps คุณสามารถรับไฟล์ที่ประมวลผลล่วงหน้า ( .i), ไฟล์ประกอบ ( .s) และไฟล์วัตถุ (*. o) (รับแต่ละรายการโดยใช้ -E, -S และ -c.)
ตามที่กล่าวไว้ก่อนหน้านี้ให้ดูที่แฟล็ก -S
นอกจากนี้ยังควรดูที่ตระกูลแฟล็ก '-fdump-tree' โดยเฉพาะ '-fdump-tree-all' ซึ่งช่วยให้คุณเห็นรูปแบบกลางของ gcc บางส่วน บ่อยครั้งที่สิ่งเหล่านี้สามารถอ่านได้มากกว่าแอสเซมเบลอร์ (อย่างน้อยสำหรับฉัน) และให้คุณดูว่าการเพิ่มประสิทธิภาพทำงานอย่างไร
หากคุณกำลังมองหาแอสเซมบลี LLVM:
llvm-gcc -emit-llvm -S hello.c
ฉันไม่เห็นความเป็นไปได้นี้ในคำตอบอาจเป็นเพราะคำถามนั้นมาจากปี 2008 แต่ในปี 2561 คุณสามารถใช้เว็บไซต์ออนไลน์ของ Matt Goldbolt https://godbolt.org
คุณสามารถคอมไพล์ git แบบโลคัลและรันโปรเจ็กต์ของเขาได้ที่https://github.com/mattgodbolt/compiler-explorer
-save-temps
สิ่งนี้ถูกกล่าวถึงที่https://stackoverflow.com/a/17083009/895245แต่ให้ฉันเป็นตัวอย่างเพิ่มเติม
ข้อได้เปรียบที่ยิ่งใหญ่ของตัวเลือกนี้-S
คือมันง่ายมากที่จะเพิ่มไปยังสคริปต์การสร้างใด ๆ โดยไม่รบกวนการสร้างมาก
เมื่อคุณทำ:
gcc -save-temps -c -o main.o main.c
main.c
#define INC 1
int myfunc(int i) {
return i + INC;
}
และตอนนี้นอกเหนือจากเอาต์พุตปกติmain.o
ไดเร็กทอรีการทำงานปัจจุบันยังมีไฟล์ต่อไปนี้:
main.i
เป็นโบนัสและมีไฟล์ที่เตรียมไว้:
# 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
มีชุดประกอบที่ต้องการ:
.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
หากคุณต้องการทำกับไฟล์จำนวนมากให้ลองใช้แทน:
-save-temps=obj
ซึ่งบันทึกไฟล์กลางไปยังไดเรกทอรีเดียวกันกับ-o
วัตถุออกแทนไดเรกทอรีการทำงานปัจจุบันจึงหลีกเลี่ยงความขัดแย้งพื้นฐานที่อาจเกิดขึ้น
อีกสิ่งที่ยอดเยี่ยมเกี่ยวกับตัวเลือกนี้คือถ้าคุณเพิ่ม-v
:
gcc -save-temps -c -o main.o -v main.c
มันแสดงให้เห็นถึงไฟล์ที่ชัดเจนที่ถูกใช้แทนขมับใต้น่าเกลียด/tmp
ดังนั้นจึงเป็นเรื่องง่ายที่จะรู้ว่าสิ่งที่เกิดขึ้นซึ่งรวมถึงขั้นตอนการประมวลผล / การรวบรวม / การชุมนุม / preprocessing
/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
ทดสอบใน Ubuntu 19.04 amd64, GCC 8.3.0
ใช้ตัวเลือก -S:
gcc -S program.c
จาก: http://www.delorie.com/djgpp/v2faq/faq8_20.html
gcc -c -g -Wa, -a, -ad [ตัวเลือก GCC อื่น ๆ ] foo.c> foo.lst
แทนคำตอบของ PhirePhly หรือเพียงแค่ใช้ -S ตามที่ทุกคนพูด
นี่คือขั้นตอนในการดู / พิมพ์รหัสการประกอบของโปรแกรม C ใด ๆ บน Windows ของคุณ
พร้อมท์คอนโซล / เทอร์มินัล / คำสั่ง:
เขียนโปรแกรม C ในโปรแกรมแก้ไขรหัส C เช่น codeblocks และบันทึกด้วย extention .c
รวบรวมและเรียกใช้
เมื่อทำงานสำเร็จให้ไปที่โฟลเดอร์ที่คุณได้ติดตั้งคอมไพเลอร์ gcc และให้
ทำตามคำสั่งเพื่อรับไฟล์ '.s' ของไฟล์ '.c'
C: \ gcc> gcc -S พา ธ ที่สมบูรณ์ของไฟล์ C ENTER
คำสั่งตัวอย่าง (ในกรณีของฉัน)
C: \ gcc> gcc -SD: \ Aa_C_Certified \ alternate_letters.c
เอาต์พุตนี้เป็นไฟล์ '.s' ของไฟล์ '.c' ดั้งเดิม
4. หลังจากนี้ให้พิมพ์คำสั่งต่อไปนี้
C; \ gcc> cpp filename.s ENTER
คำสั่งตัวอย่าง (ในกรณีของฉัน)
C; \ gcc> cpp Alternate_letters.s
สิ่งนี้จะพิมพ์ / ส่งออกรหัสภาษาแอสเซมบลีทั้งหมดของโปรแกรม C ของคุณ
ใช้ "-S" เป็นตัวเลือก มันจะแสดงผลการชุมนุมใน terminal
gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less
ที่จะแสดงในขั้วใช้ ในตัวเองสร้าง-S
foo.s
เมื่อเร็ว ๆ นี้ฉันต้องการทราบการประกอบของแต่ละฟังก์ชั่นในโปรแกรม
นี่เป็นวิธีที่ฉันทำ
$ 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
นี่คือทางออกสำหรับ C ที่ใช้ gcc:
gcc -S program.c && gcc program.c -o output
ที่นี่ส่วนแรกเก็บเอาท์พุทแอสเซมบลีของโปรแกรมในชื่อไฟล์เดียวกับโปรแกรม แต่ด้วยนามสกุล. s ที่เปลี่ยนแปลงคุณสามารถเปิดเป็นไฟล์ข้อความทั่วไปได้
ส่วนที่สองที่นี่รวบรวมโปรแกรมของคุณสำหรับการใช้งานจริงและสร้างไฟล์ปฏิบัติการสำหรับโปรแกรมของคุณด้วยชื่อไฟล์ที่ระบุ
program.cใช้ข้างต้นเป็นชื่อของโปรแกรมของคุณและเอาท์พุทเป็นชื่อของปฏิบัติการที่คุณต้องการในการสร้าง
BTW มันเป็นโพสต์แรกของฉันใน StackOverFlow: -}