共享库是否与应用程序使用相同的堆?

假设我在Linux中有一个使用共享库( .so文件)的应用程序。 我的问题是,这些库中的代码是否将分配与主应用程序相同的堆内存,或者他们使用自己的堆?

因此,例如, .so文件中的某个函数调用malloc ,它会使用与应用程序相同的堆pipe理器还是另一个? 另外,那些共享内存中的全局数据呢? 它在哪儿撒谎? 我知道应用程序位于bss和数据段,但不知道这些共享对象文件的位置。

我的问题是,这些库中的代码是否将分配与主应用程序相同的堆内存,或者他们使用自己的堆?

如果库使用与应用程序相同的malloc/free (例如,来自glibc ) – 那么是的,程序和所有库都将使用单个堆。

如果库直接使用mmap ,它可以分配不是程序自身使用的内存的内存。

因此,例如,.so文件中的某个函数调用malloc,它会使用与应用程序相同的堆管理器还是另一个?

如果.so函数调用malloc,则此malloc与从程序调用的malloc相同。 你可以在Linux / glibc(> 2.1)中看到符号绑定日志

  LD_DEBUG=bindings ./your_program 

是的,堆管理器的几个实例(具有默认配置)不能在不知道彼此的情况下共存(问题在于保持brk分配的堆大小在实例之间同步)。 但是有几个实例可以共存的配置。

大多数经典的malloc实现(ptmalloc *,dlmalloc等)可以使用两种从系统获取内存的方法: brkmmap 。 Brk是经典的堆,这是线性的,可以增长或缩小。 Mmap允许在任何地方获得大量的内存; 你可以以任何顺序将这个内存返回给系统(释放它)。

当malloc被建立时,brk方法可以被禁用。 然后,malloc将只使用mmap s来模拟线性堆,甚至会禁用经典的线性堆,而所有的分配将由不连续的mmaped fragmens组成。

所以,一些库可以拥有自己的内存管理器,比如禁用brk编译的malloc或者非malloc内存管理器。 这个管理器应该有除mallocfree以外的函数名,例如malloc1free1或者不应该显示/导出这个名字给动态链接器。

另外,那些共享内存中的全局数据呢? 它在哪儿撒谎? 我知道应用程序位于bss和数据段,但不知道这些共享对象文件的位置。

你应该考虑关于程序和.so就像ELF文件一样。 每个ELF文件都有“程序头文件”( readelf -l elf_file )。 数据从ELF加载到内存的方式取决于程序头的类型。 如果类型为“ LOAD ”,文件的相应部分将被私有地mmap (Sic!)到内存。 通常有2个LOAD段; 第一个用于R + X(读取+执行)标志的代码,第二个用于R + W(读取+写入)标志的数据。 .bss.data (全局数据)部分都放在LOAD类型的段中,并带有写启用标志。

可执行文件和共享库都有LOAD段。 一些段具有memory_size> file_size。 这意味着分段将在内存中扩展; 第一部分将填充ELF文件中的数据,第二部分的size(memory_size-file_size)将使用mmap(/dev/zero)memset(0)填充零(对于*bss部分memset(0)

当内核或动态链接器加载ELF文件到内存中时,他们不会考虑共享。 例如,您想要两次启动相同的程序。 第一个进程将使用mmap加载ELF文件的只读部分; 第二个进程将执行相同的mmap(如果aslr处于活动状态 – 第二个mmap将进入不同的虚拟地址)。 它是页面缓存(VFS子系统)的任务,用于将单个数据副本保留在物理内存中(使用COPY-WRITE或COW)。 而mmap只会将每个进程的虚拟地址映射到单一的物理位置。 如果有任何进程会改变内存页面; 它将在写入唯一私有物理内存时被复制。

对于内核的ELF加载器( elf_mapload_elf_binary ),ld.so和linux-kernel/fs/binfmt_elf.c加载代码位于glibc/elf/dl-load.cload_elf_binary )中。 搜索PT_LOAD

所以,全局数据和bss数据总是在每个进程中私有化,并且使用COW进行保护。

堆和栈在运行时分配到brk + mmap(heap)中,并由OS内核在类似brk的进程中自动分配(用于主线程的堆栈)。 附加线程的堆栈在pthread_create中用mmap分配。

符号表在Linux中的整个过程中共享。 malloc()对于进程的任何部分都与其他所有部分相同。 所以是的,如果一个进程的所有部分通过malloc()等访问堆,那么他们将共享相同的堆。