我编写了几个程序,发现在64位编译时,内存映射段(例如保存共享对象和共享内存)总是位于7f9aca84a000-7fff88400000左右但从未完全相同。
我想知道x86_64架构(ELF64)上的内存段是否有固定的起始地址,或者该段的最大和最小范围是多少?
这就是我提出这个问题的原因。我们正在将系统从Tru64 UNIX迁移到Linux。该系统使用IPC Sys V共享内存的复杂固定内存映射,并使用链表在该段内从结构转到另一个。由于这段代码的大小和复杂性,以及我们手头有限的时间,我们正在尝试找到一种强大的方法来修复共享内存的开始(有效地使用带有指定地址的shmat来附加段)。 对于64位,虚拟地址空间是如此巨大(48位有效可能的地址),选择“安全”固定地址比32位更容易,风险更小。
答案 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_SIZE
为0x800000000000
,因此自下而上的分配将从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;
}
我担心此刻我没有时间浏览内核源代码,但我一定会稍后再看看。我一直想知道这个问题的答案是什么。 。