ELF64 / x86_64和内存映射段的起始地址(用于共享对象)

时间:2011-10-11 16:02:29

标签: c linux shared-memory memory-mapping memory-layout

我编写了几个程序,发现在64位编译时,内存映射段(例如保存共享对象和共享内存)总是位于7f9aca84a000-7fff88400000左右但从未完全相同。

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

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

3 个答案:

答案 0 :(得分:4)

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

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

因此,如果您想使用固定地址,您可以使用MAP_FIXED,因为@Ethereal推荐使用。

答案 1 :(得分:4)

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

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

自下而上的分配是后备。它用于:

  • 堆栈限制无限制;
  • 该过程具有ADDR_COMPAT_LAYOUT个性设置;或
  • vm.legacy_va_layout sysctl非零。

在自下而上的分配中,映射区域被逐渐分配更高的地址,从TASK_SIZE / 3开始,由随机偏移量调整。 x86-64上的TASK_SIZE0x800000000000,因此自下而上的分配将从0x2AAAAAAAAAAA左右开始。

我建议你的固定映射有一个合适的漏洞,在任一分配策略下都应该可以2 * TASK_SIZE / 3 - 我会使用0x500000000000

答案 2 :(得分: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;
}

我担心此刻我没有时间浏览内核源代码,但我一定会稍后再看看。我一直想知道这个问题的答案是什么。 。