GDB 反汇编输出 – 无优化
学习如何在不进行代码优化的情况下编译、加载并执行 GDB 反汇编程序。
C/C++程序中的算术示例
让我们将我们的算术程序重写为C/C++。对应的汇编语言指令已添加在注释中:
1int a, b; 2 3int main(int argc, char* argv[]) 4{ 5 // 将值赋给变量a 6 a = 1; // adr x0,a 7 // mov w1, #1 8 // str w1, [x0] 9 10 // 将值赋给变量b 11 b = 1; // adr x0,b 12 // mov w1, #1 13 // str w1, [x0] 14 15 // 将b和a相加,结果存入变量b 16 b = b + a; // adr x0,b 17 // ldr w1, [x0] 18 // adr x0, a 19 // ldr w0, [x0] 20 // add w1, w1, w0 21 // adr x0, b 22 // str w1, [x0] 23 24 // 将变量a自增1 25 ++a; // adr x0, a 26 // ldr w1, [x0] 27 // add w1, w1, #1 28 // str w1, [x0] 29 30 // 将b乘以a,结果存入b 31 b = b * a; // adr x0,b 32 // ldr w1, [x0] 33 // adr x0, a 34 // ldr w0, [x0] 35 // mul w1, w1, w0 36 // adr x0, b 37 // str w1, [x0] 38 // 结果:[a] = 2 且 [b] = 4 39 40 // 返回0表示程序成功执行 41 return 0; 42}
下图展示了源代码的工作流程:
无优化模式下的反汇编
如果我们在无优化模式下重新编译程序,调试时会更容易追踪程序的运行过程。
注意: 您可以在本课末尾提供的编码沙箱中练习所有命令。
编译
如果我们以无优化模式(默认)编译并链接程序,如下所示,我们将得到一个可执行二进制模块,可以加载到GDB中并检查汇编代码。
1gcc ArithmeticProjectC.cpp -o ArithmeticProjectC
首先,使用程序作为参数运行GDB:
1gdb ./ArithmeticProjectC
运行上述命令后,输出应如下所示:
接下来,我们在main C/C++函数中设置断点,以便程序执行在此处暂停,使我们有机会检查内存和寄存器。可以使用符号名称或函数名如main,而无需使用代码的内存地址:
1break main
在GDB环境中运行break main后,我们会得到以下结果:
1Breakpoint 1 at 0x734
在启动调试程序之前,GDB必须禁用内核的地址空间随机化,以避免相同内存地址被重新分配。以下命令用于禁用此功能:
1set disable-randomization off
然后,运行以下命令执行程序,程序将在之前设置的断点处停止:
1run
我们可以预期得到如下结果:
1Starting program: /Chapters/Chapter3/ArithmeticProjectC 2 3Breakpoint 1, 0x0000aaaaab9c0734 in main() 4(gdb)
现在,使用disass命令反汇编main函数:
1disass main
在GDB中运行disass main后,我们得到以下输出:
1Dump of assembler code for function main: 2 0x0000aaaac463071c <+0>: sub sp, sp, #0x10 3 0x0000aaaac4630720 <+4>: str w0, [sp, #12] 4 0x0000aaaac4630724 <+8>: str x1, [sp] 5 0x0000aaaac4630728 <+12>: adrp x0, 0xaaaac4641000 6 0x0000aaaac463072c <+16>: add x0, x0, #0x14 7 0x0000aaaac4630730 <+20>: mov w1, #0x1 // #1 8=> 0x0000aaaac4630734 <+24>: str w1, [x0] 9 0x0000aaaac4630738 <+28>: adrp x0, 0xaaaac4641000 10 0x0000aaaac463073c <+32>: add x0, x0, #0x18 11 0x0000aaaac4630740 <+36>: mov w1, #0x1 // #1 12 0x0000aaaac4630744 <+40>: str w1, [x0] 13 0x0000aaaac4630748 <+44>: adrp x0, 0xaaaac4641000 14 0x0000aaaac463074c <+48>: add x0, x0, #0x18 15 0x0000aaaac4630750 <+52>: ldr w1, [x0] 16 0x0000aaaac4630754 <+56>: adrp x0, 0xaaaac4641000 17 0x0000aaaac4630758 <+60>: add x0, x0, #0x14 18 0x0000aaaac463075c <+64>: ldr w0, [x0] 19 0x0000aaaac4630760 <+68>: add w1, w1, w0 20 0x0000aaaac4630764 <+72>: adrp x0, 0xaaaac4641000 21 0x0000aaaac4630768 <+76>: add x0, x0, #0x18 22--Type <RET> for more, q to quit, c to continue without paging--
当我们按下 q 时,会退出分页显示(不再查看其余输出)。但当我们按下 c 继续时,输出如下:
1--Type <RET> for more, q to quit, c to continue without paging--c 2 0x000000000000076c <+80>: str w1, [x0] 3 0x0000000000000770 <+84>: adrp x0, 0x11000 4 0x0000000000000774 <+88>: add x0, x0, #0x14 5 0x0000000000000778 <+92>: ldr w0, [x0] 6 0x000000000000077c <+96>: add w1, w0, #0x1 7 0x0000000000000780 <+100>: adrp x0, 0x11000 8 0x0000000000000784 <+104>: add x0, x0, #0x14 9 0x0000000000000788 <+108>: str w1, [x0] 10 0x000000000000078c <+112>: adrp x0, 0x11000 11 0x0000000000000790 <+116>: add x0, x0, #0x18 12 0x0000000000000794 <+120>: ldr w1, [x0] 13 0x0000000000000798 <+124>: adrp x0, 0x11000 14 0x000000000000079c <+128>: add x0, x0, #0x14 15 0x00000000000007a0 <+132>: ldr w0, [x0] 16 0x00000000000007a4 <+136>: mul w1, w1, w0 17 0x00000000000007a8 <+140>: adrp x0, 0x11000 18 0x00000000000007ac <+144>: add x0, x0, #0x18 19 0x00000000000007b0 <+148>: str w1, [x0] 20 0x00000000000007b4 <+152>: mov w0, #0x0 // #0 21 0x00000000000007b8 <+156>: add sp, sp, #0x10 22 0x00000000000007bc <+160>: ret 23End of assembler dump. 24(gdb)
我们再次列出与C/C++代码相对应的格式化反汇编输出部分:
1 0x0000000000000728 <+12>: adrp x0, 0x11000 2 0x000000000000072c <+16>: add x0, x0, #0x14 3 0x0000000000000730 <+20>: mov w1, #0x1 // #1 4 0x0000000000000734 <+24>: str w1, [x0] 5 0x0000000000000738 <+28>: adrp x0, 0x11000 6 0x000000000000073c <+32>: add x0, x0, #0x18 7 0x0000000000000740 <+36>: mov w1, #0x1 // #1 8 0x0000000000000744 <+40>: str w1, [x0] 9 0x0000000000000748 <+44>: adrp x0, 0x11000 10 0x000000000000074c <+48>: add x0, x0, #0x18 11 0x0000000000000750 <+52>: ldr w1, [x0] 12 0x0000000000000754 <+56>: adrp x0, 0x11000 13 0x0000000000000758 <+60>: add x0, x0, #0x14 14 0x000000000000075c <+64>: ldr w0, [x0] 15 0x0000000000000760 <+68>: add w1, w1, w0 16 0x0000000000000764 <+72>: adrp x0, 0x11000 17 0x0000000000000768 <+76>: add x0, x0, #0x18 18 0x000000000000076c <+80>: str w1, [x0] 19 0x0000000000000770 <+84>: adrp x0, 0x11000 20 0x0000000000000774 <+88>: add x0, x0, #0x14 21 0x0000000000000778 <+92>: ldr w0, [x0] 22 0x000000000000077c <+96>: add w1, w0, #0x1 23 0x0000000000000780 <+100>: adrp x0, 0x11000 24 0x0000000000000784 <+104>: add x0, x0, #0x14 25 0x0000000000000788 <+108>: str w1, [x0] 26 0x000000000000078c <+112>: adrp x0, 0x11000 27 0x0000000000000790 <+116>: add x0, x0, #0x18 28 0x0000000000000794 <+120>: ldr w1, [x0] 29 0x0000000000000798 <+124>: adrp x0, 0x11000 30 0x000000000000079c <+128>: add x0, x0, #0x14 31 0x00000000000007a0 <+132>: ldr w0, [x0] 32 0x00000000000007a4 <+136>: mul w1, w1, w0 33 0x00000000000007a8 <+140>: adrp x0, 0x11000 34 0x00000000000007ac <+144>: add x0, x0, #0x18 35 0x00000000000007b0 <+148>: str w1, [x0]
在下面的代码中,我们在注释中添加了对应的伪代码:
注意: 不同系统上可能会看到不同的内存地址。
1 0x0000000000000728 <+12>: adrp x0, 0x11000 // [a] <- 1 2 0x000000000000072c <+16>: add x0, x0, #0x14 3 0x0000000000000730 <+20>: mov w1, #0x1 4 0x0000000000000734 <+24>: str w1, [x0] 5 0x0000000000000738 <+28>: adrp x0, 0x11000 // [b] <- 1 6 0x000000000000073c <+32>: add x0, x0, #0x18 7 0x0000000000000740 <+36>: mov w1, #0x1 8 0x0000000000000744 <+40>: str w1, [x0] 9 0x0000000000000748 <+44>: adrp x0, 0x11000 // [b] <- [b] + [a] 10 0x000000000000074c <+48>: add x0, x0, #0x18 11 0x0000000000000750 <+52>: ldr w1, [x0] 12 0x0000000000000754 <+56>: adrp x0, 0x11000 13 0x0000000000000758 <+60>: add x0, x0, #0x14 14 0x000000000000075c <+64>: ldr w0, [x0] 15 0x0000000000000760 <+68>: add w1, w1, w0 16 0x0000000000000764 <+72>: adrp x0, 0x11000 17 0x0000000000000768 <+76>: add x0, x0, #0x18 18 0x000000000000076c <+80>: str w1, [x0] 19 0x0000000000000770 <+84>: adrp x0, 0x11000 // [a] <- [a] + 1 20 0x0000000000000774 <+88>: add x0, x0, #0x14 21 0x0000000000000778 <+92>: ldr w0, [x0] 22 0x000000000000077c <+96>: add w1, w0, #0x1 23 0x0000000000000780 <+100>: adrp x0, 0x11000 24 0x0000000000000784 <+104>: add x0, x0, #0x14 25 0x0000000000000788 <+108>: str w1, [x0] 26 0x000000000000078c <+112>: adrp x0, 0x11000 // [b] <- [b] * [a] 27 0x0000000000000790 <+116>: add x0, x0, #0x18 28 0x0000000000000794 <+120>: ldr w1, [x0] 29 0x0000000000000798 <+124>: adrp x0, 0x11000 30 0x000000000000079c <+128>: add x0, x0, #0x14 31 0x00000000000007a0 <+132>: ldr w0, [x0] 32 0x00000000000007a4 <+136>: mul w1, w1, w0 33 0x00000000000007a8 <+140>: adrp x0, 0x11000 34 0x00000000000007ac <+144>: add x0, x0, #0x18 35 0x00000000000007b0 <+148>: str w1, [x0]
现在,我们可以退出GDB:
1q
输入此命令后,将得到以下输出:
1A debugging session is active. 2 3 Inferior 1 [process 38] will be killed. 4 5Quit anyway? (y or n) y
命令总结
在本课中,我们学习了如何在不进行代码优化的情况下运行程序。为此,我们按以下顺序执行命令。
- 编译和链接程序的命令如下:
1gcc ArithmeticProjectC.cpp -o ArithmeticProjectC
- 运行GDB并启动程序的命令如下:
1gdb ./ArithmeticProjectC
- 在程序中插入断点的命令如下:
1break main
- 禁用程序随机化的命令如下:
1set disable-randomization off
- 执行程序的命令如下:
1run
- 反汇编程序的命令如下:
1disass main
- 退出分页显示的命令如下:
1q
- 继续函数执行的命令如下:
1c
- 函数完全执行后,使用以下命令退出GDB环境:
1q
自己动手试试
让我们尝试在无优化模式下运行代码,并查看以下窗口中的GDB反汇编输出:
No configuration found for ID: fc7d04118f2ef04fc0434eddf90b17bd015f8cff07a3f909e7bbe5f0a69ae935