通過 gdb 查看程序的彙編代碼,比較宏和宏函數的工作效率。
程序
例子中的最大值實現,宏和函數邏輯基本相同。宏在源碼預編譯階段,被替換爲代碼,增加了代碼的體積;函數多了參數傳遞,函數進棧和出棧等邏輯,自然資源消耗要比宏多。
- 測試代碼
#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位操作數