Logo
Section 1 / 3

GDB 反汇编输出 – 无优化

学习如何在不进行代码优化的情况下编译、加载并执行 GDB 反汇编程序。

导入

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

运行上述命令后,输出应如下所示:

...
将目标代码加载到GDB中

接下来,我们在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

内存、寄存器与简单算术

GDB 反汇编输出 – 优化