在Linux中共享可执行内存页面?

时间:2012-04-11 00:52:47

标签: linux shared-libraries shared-memory ld dyld

是否可以在Linux上共享可执行页面以保留空间?我知道有共享内存API可用于在不同进程之间共享内存,但我不认为这是用于那个。

基本上,我希望有一个共享内存区域,可以加载一些常用的共享库。我想让动态链接器链接到预加载(只读)图像,而不是必须将所有共享库图像加载到每个进程(这似乎是浪费)。

这在Linux内核上是否可行? Darwin内核使用Mach VM的一个功能实现这一点,称为 commpages (dyld共享缓存存储在那里)。每个过程都可以访问和共享组合。

为了澄清,我知道共享对象(库)是什么。目前,动态链接器在Linux上执行的操作是将所有必需的库加载到程序的地址空间中,这意味着每个链接libc的应用程序(例如)将在其地址空间的某处具有libc的映像。在Darwin上,可以通过在一组共享内存页上使用libc的可执行文件(以及其他只读)部分来消除此问题。共享图像的可写部分仍然是分开的。

编辑:我知道ELF格式不支持分离共享库的DATA和TEXT段。我没有使用ELF,我正在使用不同的二进制格式(使用我自己的binfmt内核模块和我自己的动态链接器)。如果Linux内核支持类似commpage的功能,我很感兴趣。

编辑2:我能想到的唯一方法就是在内核中分配一大块内存并将其映射到每个执行的二进制文件中。第一次执行任何二进制文件时,动态链接器可以取消保护它,用所需数据填充它并保护它。然后不知何故,内核必须确保内存段不被其他任何东西修改,因为它会打开一个巨大的安全漏洞。另一个

2 个答案:

答案 0 :(得分:5)

正如geekosaur所说,Linux已经做到了。

在应用程序启动时,动态链接器(ld.so)mmap()是共享库。 它为每个库执行多次调用mmap()

  • mmap(PROT_READ|PROT_EXEC)表示可执行部分(即.text)
  • mmap(PROT_READ|PROT_WRITE)表示数据(即.data和.bss)

(您可以使用strace自行检查。)

内核是一个聪明的一点代码,它意识到已经映射了由offset和inode标识的可执行部分(通过fd已知)。因为它是只读的,所以没有必要为它分配更多的内存。

这也意味着如果你有任何其他文件mmap()只能从多个应用程序中读取,那么内存也只会消耗一次。

答案 1 :(得分:4)

Linux已经做到了;事实上,这就是共享的对象是关于/ for。