反汇编查看宏函数/函数调用原理

2020-02-15

通过 gdb 查看程序的汇编代码,理解宏函数和函数的工作原理。


1. 程序

源码反汇编

例子中的最大值实现,宏函数和函数逻辑基本相同。宏在源码预编译阶段,被替换为代码,增加了代码的体积;而函数调用多了参数传递,函数进栈和出栈等逻辑,自然资源消耗要比宏多。

  • 测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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;
}

预编译后,宏被替换为源码。

1
gcc -E test.cpp -o test.i
1
2
3
4
5
6
7
8
9
10
11
12
13
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 调试
1
gcc -g test.cpp -o test
  • 通过 gdb 命令查看程序汇编代码
1
layout asm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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

2. 参考