gcc 编译为汇编代码
原始C++代码如下:
#include "stdio.h"
class Animal {
public:
virtual void name() { printf("I'm Animal\n"); }
};
class Cat : public Animal {
public:
virtual void name() override { printf("I'm Cat\n"); }
};
void func(Animal *animal) {
animal->name();
}
int main(void) {
func(new Animal());
func(new Cat());
return 0;
}
编译成汇编代码:
g++ -S test.cpp -o test.s
查看:
cat test.s
部分结果:
main:
.LFB3:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
pushq %rbx
subq $8, %rsp
.cfi_offset 3, -24
你发现你完全看不懂
使用 as 展示汇编代码
另一种更好的做法是使用as
:
编译成汇编代码:
g++ -S -fverbose-asm -g test.cpp -o test.s
查看:
as -alhnd test.s
现在是把代码和汇编代码对应起来了:
16:test.cpp ****
17:test.cpp **** int main(void) {
202 .loc 1 17 16
.........
212 # test.cpp:18: func(new Animal());
18:test.cpp **** func(new Animal());
213 .loc 1 18 21
214 002b BF080000 movl $8, %edi #,
214 00
215 0030 E8000000 call _Znwm #
215 00
216 0035 4889C3 movq %rax, %rbx # tmp86, _3
217 0038 48C70300 movq $0, (%rbx) #, MEM[(struct Animal *)_4]._vptr.Animal
217 000000
218 003f 4889DF movq %rbx, %rdi # _3,
219 0042 E8000000 call _ZN6AnimalC1Ev #
219 00
220 # test.cpp:18: func(new Animal());
这种情况看汇编代码比刚才更清楚一些。
使用 objdump 进行反汇编
如果直接编成机器码,需要使用objdump
进行反汇编:
g++ -save-temps -fverbose-asm -g -o test test.cpp
objdump -S --disassemble test
效果如下:
0000000000400654 <main>:
int main(void) {
400654: 55 push %rbp
400655: 48 89 e5 mov %rsp,%rbp
400658: 53 push %rbx
400659: 48 83 ec 08 sub $0x8,%rsp
func(new Animal());
40065d: bf 08 00 00 00 mov $0x8,%edi
400662: e8 d9 fe ff ff callq 400540 <_Znwm@plt>
400667: 48 89 c3 mov %rax,%rbx
40066a: 48 c7 03 00 00 00 00 movq $0x0,(%rbx)
400671: 48 89 df mov %rbx,%rdi
400674: e8 6d 00 00 00 callq 4006e6 <_ZN6AnimalC1Ev>
400679: 48 89 df mov %rbx,%rdi
40067c: e8 b1 ff ff ff callq 400632 <_Z4funcP6Animal>
感觉使用objdump
效果最好,但还有效果更好的。
使用 godbolt 可视化结果
这个网站: https://godbolt.org
真的非常好用,效果如下:
非常炫酷,而且一一对应。
参考: