5

我编写了几个程序,发现当以 64 位编译时,内存映射段(例如共享对象和共享内存所在的位置)总是位于 7f9aca84a000-7fff88400000 附近的某个位置,但从不完全相同。

我想知道在 x86_64 架构(ELF64)上这个内存段是否有固定的起始地址,或者这个段的最大和最小范围是多少?

这就是我问这个问题的原因。我们正在将系统从 Tru64 UNIX 迁移到 Linux。该系统使用IPC Sys V共享内存的复杂固定内存映射,并使用链表在该段内从结构到另一个结构。由于这段代码的大小和复杂性,以及我们手头有限的时间,我们正试图找到一种可靠的方法来修复共享内存的开始(有效地使用带有指定地址的 shmat 来附加段)。使用 64 位,虚拟地址空间是如此巨大(48 位有效可能的地址),以至于选择“安全”固定地址比 32 位更容易且风险更小。

4

3 回答 3

4

mmaped 段是否有固定的起始地址?

不。Linux 支持 ASLR(地址空间布局随机化),这意味着程序中的地址具有一定的随机性。这是为了使一些漏洞利用不太可能成功。此外,可能一些内核补丁实现了不同的 ASLR 策略(它们对常规 x86 执行),想想 PaX、exec-shield,......

因此,如果您想使用固定地址,则可以使用 MAP_FIXED,正如@Ethereal 推荐的那样。

于 2011-10-11T19:29:35.923 回答
4

x86-64 内存映射布局在arch/x86/mm/mmap.c. 如您所见,使用了两种策略:自上而下和自下而上。

自上而下的分配是默认设置。它从堆栈的最大范围(由堆栈 rlimit 定义)以下 128MB 开始,通过随机偏移量进行调整,然后从那里向下分配内存中的后续映射。

自下而上的分配是后备。在以下情况下使用它:

  • 堆栈 rlimit 是无限的;
  • 该过程具有ADDR_COMPAT_LAYOUT个性集;或者
  • vm.legacy_va_layoutsysctl 非零。

在自下而上的分配下,映射区域被分配逐渐更高的地址,从 开始TASK_SIZE / 3,通过随机偏移量进行调整。 TASK_SIZE在 x86-64 上是0x800000000000,因此自下而上的分配将在0x2AAAAAAAAAAA.

我会为您的固定映射建议一个合适的孔,在任何一种分配策略下都应该没问题2 * TASK_SIZE / 3- 我会使用0x500000000000.

于 2011-10-12T02:13:14.783 回答
3

我没有直接的答案给你(还没有!),但我可以说我已经成功地将内存映射到更高的内存范围之外。例如:

#include <stdio.h>
#include <sys/mman.h>
#include <stdint.h>

#define ADDRESS 0x700000000

int main(int argc, char *argv[]) {
    uint64_t *map = mmap((void *)ADDRESS, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);

    map[0] = 64;

    printf("Value: %lu\n", map[0]);

    munmap(map, 4096);

    return 0;
}

恐怕我现在没有时间看内核源代码,但我以后一定会看的。我一直想知道这个问题的答案是什么。. .

于 2011-10-11T16:19:25.380 回答