【发布时间】:2019-08-07 12:48:12
【问题描述】:
假设C 中有一个简单的hello world,使用gcc -c 编译为目标文件并使用objdump 反汇编,如下所示:
_main:
0: 55 pushq %rbp
1: 48 89 e5 movq %rsp, %rbp
4: c7 45 fc 00 00 00 00 movl $0, -4(%rbp)
b: c7 45 f8 05 00 00 00 movl $5, -8(%rbp)
12: 8b 05 00 00 00 00 movl (%rip), %eax
你可以看到内存地址是0, 1, 4, ..等等。它们不是实际地址。
链接目标文件并反汇编如下所示:
_main:
100000f90: 55 pushq %rbp
100000f91: 48 89 e5 movq %rsp, %rbp
100000f94: c7 45 fc 00 00 00 00 movl $0, -4(%rbp)
100000f9b: c7 45 f8 05 00 00 00 movl $5, -8(%rbp)
100000fa2: 8b 05 58 00 00 00 movl 88(%rip), %eax
我的问题是,100000f90 是虚拟内存字节的实际地址还是偏移量?
链接器如何在执行之前给出实际地址?如果执行时该内存地址不可用怎么办?如果我在另一台内存少得多的机器上执行它会怎样(可能在这里开始分页)。
分配实际地址不是加载器的工作吗?
链接器是否为最终的可执行文件生成实际地址?
【问题讨论】:
-
是虚拟内存。无论您拥有多少物理内存,它始终在给定架构上可用。可能有特殊情况,例如如果您调整您的 32 位操作系统以使用 3G/1G 拆分,那么理论上您可以将您的东西放在普通操作系统无法加载的 2G 以上。 x86-64 也有不同的 VM 大小,但有已知的安全范围。
-
是的,在位置依赖可执行文件中,静态代码/数据地址是链接时常量。请参阅32-bit absolute addresses no longer allowed in x86-64 Linux? 了解更多关于 PIE 可执行文件的信息,其中不是,需要使用 RIP 相对寻址的位置无关代码,即使将地址放入寄存器,而不是 5 字节
mov $symbol, %edi. -
这是 OS X,对吧?链接器选择了低 2GiB 虚拟地址空间之外的基地址,但看起来有 是默认加载地址。
-
链接器链接到它被告知的地址。由您直接或间接进行。如果在您的计算机上使用非交叉编译器,并且编译器可以工作,那么这就是您的可执行文件的地址空间,这可能是虚拟的,因为这是在操作系统上运行的应用程序,是吗?链接器并不聪明,就像编译器一样,他们做你告诉他们的事情,他们非常愚蠢。
-
将
otool -lV应用于您的可执行文件可能很有启发性。这将显示链接器加载命令。代码在__TEXT段中。加载命令为段指定一个“加载(虚拟)地址”。这可能会受到链接命令选项的影响或留给链接器默认值。对于位置无关的可执行文件,加载器可以加载到不同的地址;否则,它将加载到指定的地址。
标签: macos assembly linker executable virtual-memory