c - 链接器如何生成最终的虚拟内存地址?

标签 c memory memory-management linker virtual-memory

假设这个简单的代码:

int main(){return 0;}

使用objdump我们可以看到内存地址:

0000000100003fa0 _main:
100003fa0: 55                           pushq   %rbp
100003fa1: 48 89 e5                     movq    %rsp, %rbp
100003fa4: 31 c0                        xorl    %eax, %eax
100003fa6: c7 45 fc 00 00 00 00         movl    $0, -4(%rbp)
100003fad: 5d                           popq    %rbp
100003fae: c3                           retq

我知道0x100003fa0(作为示例)是虚拟内存地址。 当我的程序加载时,操作系统会将其映射到物理内存。

2 个问题:

1- main 的起始地址可以是随机的吗?因为它们是虚拟的我猜可能是 虚拟内存会处理其余的任何值吗?即我可以从字面上从 0x1 开始(不是 0x0,因为它是为 null 保留的)?

2- 链接器如何得出初始地址? (同样起始地址是随机的吗?)

最佳答案

Can the initial address of main be random? as they are virtual I'm guessing it can be any value as the virtual memory will take care of the rest? i.e I can start literally from 0x1 (not 0x0 as it's reserved for null)?

内存是虚拟的并不意味着所有的虚拟地址空间都是你的,可以随意使用。在大多数操作系统上,可执行模块(程序和库)需要使用地址空间的子集,否则加载器将拒绝加载它们。当然,这高度依赖于平台。

所以地址可以是任何你想要的,只要它在特定于平台的范围内即可。我怀疑任何平台都会允许 0x1,不仅因为某些平台需要将代码与大于字节的内容对齐。

此外,在许多平台上,地址只是提示:如果可以按原样使用它们,则加载程序不必重新定位二进制文​​件中的给定部分。否则,它会将其移动到可用地址空间的 block 中。这很常见,例如在 Windows 上,32 位二进制文​​件(例如 DLL)具有基地址:如果可用,加载程序可以更快地加载二进制文件。因此,在“初始地址”为 0x1 的假设情况下,假设对齐不是问题,该地址最终将被移动到地址空间中的其他位置。

还值得注意的是,“初始地址”是一个不太具体的术语。可执行文件启动时加载的二进制模块由类似于节的内容组成。每个部分都有自己的基地址,也可能有内部(相对)地址或列表中的地址引用。此外,一个或多个可执行部分也将有一个“入口”地址。加载程序将使用这些地址来执行初始化代码(例如 Windows 上的 DllMain 概念) - 该代码总是快速返回。最终,其中一个没有其他依赖的部分将有一个适当命名的入口点,并且将是您编写的“实际”程序 - 该部分将继续运行并仅在程序退出时返回。那时,控制权可能会返回到加载程序,加载程序将注意到没有其他内容要执行,并且该进程将被拆除。所有这些的细节都高度依赖于平台 - 我只是给出一个高级概述,实际上并没有在任何特定平台上这样做。

How does the linker come up with the initial address? (again is the starting address random?)

链接器不知道自己要做什么。当您链接程序时,链接器会收到平台本身附带的多个文件。这些文件是链接器脚本和使代码能够启动所需的各种静态库。链接器脚本为链接器提供了可以分配地址的约束。所以这又是高度特定于平台的。链接器可以以完全确定的方式分配地址,即。相同的输入总是产生相同的输出,或者可以被告知随机分配某些类型的地址(当然以非重叠的方式)。这就是所谓的 ASLR(地址空间随机化)。

关于c - 链接器如何生成最终的虚拟内存地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65983756/

相关文章:

PHP 内存耗尽 (json_decode)

memory-management - 适用于无需动态内存分配的开发的语言

c++ - new分配了多少字节?

c - 什么是 LLVM,为什么突然间如此流行?

c - 格式化输出列表

c - 为什么这些构造使用前后递增的未定义行为?

c++ - Memset 内存溢出

c - 尝试在 C 程序中声明 5D 数组时出现段错误

javascript - 这个内存泄露是怎么造成的?

c - 在 C 中使用 MPI_Isend 发送多个非阻塞消息并使用 MPI_Recv 接收时出现问题