为什么汇编器转储中的地址与寄存器的地址不同?

时间:2018-11-15 00:41:37

标签: gcc assembly x86 gdb

我有一个非常基本的程序,可以使用

进行编译
gcc -m32 -g -o hello32.out hello.c

当我在gdb中运行反汇编main时,得到以下输出:

0x0000051d <+0>:    lea    ecx,[esp+0x4]
0x00000521 <+4>:    and    esp,0xfffffff0
0x00000524 <+7>:    push   DWORD PTR [ecx-0x4]
0x00000527 <+10>:   push   ebp
0x00000528 <+11>:   mov    ebp,esp
0x0000052a <+13>:   push   ebx
0x0000052b <+14>:   push   ecx
0x0000052c <+15>:   sub    esp,0x10
0x0000052f <+18>:   call   0x420 <__x86.get_pc_thunk.bx>
0x00000534 <+23>:   add    ebx,0x1aa4
0x0000053a <+29>:   mov    DWORD PTR [ebp-0xc],0x0
... [truncated for brevity]

但是,当我跑步时

(gdb) break main
(gdb) run
(gdb) info register eip

我知道

eip            0x5655553a   0x5655553a <main+29>

为什么main + 29在汇编器转储中显示为0x0000053a,而在给定eip地址时却显示为0x5655553a?

1 个答案:

答案 0 :(得分:2)

您的GCC默认情况下使PIE可执行,因此文件中没有固定的基地址(反汇编显示它相对于0,即偏移量而不是绝对地址)。

一旦内核的ELF程序加载器从可执行文件创建了一个正在运行的进程(并选择了一个虚拟地址作为基础),GDB就会向您显示实际的运行时虚拟地址。

使用-fno-pie -no-pie 构建以获取与位置相关的可执行文件,其中从可执行文件元数据中可以获知运行时地址。 (对于i386代码,您绝对应该使用-fno-pie:如果没有RIP相对地址,则位置无关代码的额外性能/代码大小成本要比x86-64差得多。)


相关:32-bit absolute addresses no longer allowed in x86-64 Linux?进一步了解PIE(32位和64位x86,以及一般情况)。

GDB - Address of breakpoint与此相似,但不完全相同。