通过 gdb 查看程序的汇编代码,比较宏和宏函数的工作效率。
更精彩内容,可以关注我的博客:wenfh2020.com
程序
例子中的最大值实现,宏和函数逻辑基本相同。宏在源码预编译阶段,被替换为代码,增加了代码的体积;函数多了参数传递,函数进栈和出栈等逻辑,自然资源消耗要比宏多。
- 测试代码
#define _max(x, y) (x) > (y) ? (x) : (y)
int max_func(int x, int y) {
return x > y ? x : y;
}
int main() {
int aaa, bbb, ccc, ddd, eee, mmm;
aaa = 1;
bbb = 2;
eee = 3;
mmm = 4;
ccc = max_func(aaa, bbb);
ddd = _max(aaa, bbb);
eee = ddd;
}
预编译后,宏被替换为源码。
gcc -E test.cpp -o test.i
int max_func(int x, int y) { return x > y ? x : y; }
int main() {
int aaa, bbb, ccc, ddd, eee, mmm;
aaa = 1;
bbb = 2;
eee = 3;
mmm = 4;
ccc = max_func(aaa, bbb);
ddd = (aaa) > (bbb) ? (aaa) : (bbb);
eee = ddd;
}
- 编译源码为 elf 文件进行 gdb 调试
gcc -g test.cpp -o test
- 通过 gdb 命令查看程序汇编代码
layout asm
0x4004ed <max_func(int, int)> push %rbp
0x4004ee <max_func(int, int)+1> mov %rsp,%rbp
0x4004f1 <max_func(int, int)+4> mov %edi,-0x4(%rbp)
0x4004f4 <max_func(int, int)+7> mov %esi,-0x8(%rbp)
0x4004f7 <max_func(int, int)+10> mov -0x4(%rbp),%eax
0x4004fa <max_func(int, int)+13> cmp -0x8(%rbp),%eax
0x4004fd <max_func(int, int)+16> jle 0x400504 <max_func(int, int)+23>
0x4004ff <max_func(int, int)+18> mov -0x4(%rbp),%eax
0x400502 <max_func(int, int)+21> jmp 0x400507 <max_func(int, int)+26>
0x400504 <max_func(int, int)+23> mov -0x8(%rbp),%eax
0x400507 <max_func(int, int)+26> pop %rbp
0x400508 <max_func(int, int)+27> retq
0x400509 <main()> push %rbp
0x40050a <main()+1> mov %rsp,%rbp
0x40050d <main()+4> sub $0x20,%rsp
0x400511 <main()+8> movl $0x1,-0x4(%rbp)
0x400518 <main()+15> movl $0x2,-0x8(%rbp)
0x40051f <main()+22> movl $0x3,-0xc(%rbp)
0x400526 <main()+29> movl $0x4,-0x10(%rbp)
0x40052d <main()+36> mov -0x8(%rbp),%edx
0x400530 <main()+39> mov -0x4(%rbp),%eax
0x400533 <main()+42> mov %edx,%esi
0x400535 <main()+44> mov %eax,%edi
0x400537 <main()+46> callq 0x4004ed <max_func(int, int)>
0x40053c <main()+51> mov %eax,-0x14(%rbp)
0x40053f <main()+54> mov -0x4(%rbp),%eax
0x400542 <main()+57> cmp -0x8(%rbp),%eax
0x400545 <main()+60> jle 0x40054c <main()+67>
0x400547 <main()+62> mov -0x4(%rbp),%eax
0x40054a <main()+65> jmp 0x40054f <main()+70>
0x40054c <main()+67> mov -0x8(%rbp),%eax
0x40054f <main()+70> mov %eax,-0x18(%rbp)
0x400552 <main()+73> mov -0x18(%rbp),%eax
0x400555 <main()+76> mov %eax,-0xc(%rbp)
0x400558 <main()+79> mov $0x0,%eax
0x40055d <main()+84> leaveq
0x40055e <main()+85> retq
汇编知识
测试中出现的汇编知识。
寄存器
寄存器 | 描述 |
---|---|
rbp | 64 bit 栈基址寄存器—指向栈底顶 |
ebp | 32 bit 栈基址寄存器—指向栈底 |
bp | 16 bit 栈基址寄存器—指向栈底 |
rsp | 64 bit 栈寄存器—指向栈顶 |
esp | 32 bit 栈寄存器—指向栈顶 |
sp | 16 bit 栈寄存器—指向栈顶 |
eax | 32 bit 通用寄存器 |
rip | 64 bit 地址偏移寄存器 |
汇编指令
命令 | 描述 |
---|---|
jmp | 无条件段内直接转移指令 |
sub | 减法指令 |
jle | 条件转移指令 |
mov | 传送指令 |
cmp | 比较指令 |
push | 进栈指令 |
pop | 出栈指令 |
ret | 段内过程返回指令,使子程序结束,继续执行主程序 |
callq | 相当于 pushq %rip; jmpq addr |
leaveq | 相当于 movq %rbp; %rsp popq %rbp |
retq | 相当于 popq %rip |
callq,leaveq,retq 中的q是指64位操作数