2012-01-15 95 views
15

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

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

+0

您是否问与共享库的部分是否与原始可执行文件的部分聚合动态链接? – 2012-01-15 01:17:44

+1

共享库BSS和数据段将与应用程序的其余BSS和数据段在某种程度上分开,但这些都是由系统为您处理的。 – 2012-01-15 02:25:55

回答

25

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

如果库使用相同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模拟线性堆,甚至会禁用经典线性堆,并且所有分配都将由不连续的虚拟碎片组成。

因此,某些图书馆可以拥有自己的内存管理器,例如, malloc编译为brk已禁用或使用非malloc内存管理器。此管理器应具有除mallocfree以外的函数名称,例如malloc1free1,或者不应将此名称显示/导出到动态链接器。

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

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

可执行文件和共享库都有LOAD段。一些段具有memory_size> file_size。这意味着该分段将在内存中扩展;它的第一部分将被填充有从ELF文件和大小(memory_size-FILE_SIZE)的所述第二部分中的数据将被填充零(为*bss部分),采用mmap(/dev/zero)memset(0)

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

加载代码为glibc/elf/dl-load.c_dl_map_object_from_fd)为ld.so和linux-kernel/fs/binfmt_elf.c为内核的ELF装载机(elf_mapload_elf_binary)。搜索PT_LOAD

因此,全局数据和bss数据总是在每个进程中进行私有配置,并且使用COW进行保护。

堆和栈在运行时用brk + mmap(heap)和OS内核在类似brk的进程(用于主线程堆栈)中自动分配。其他线程的堆栈在pthread_create中分配为mmap

+0

谢谢,你的回答非常有帮助。 – MetallicPriest 2012-01-15 10:32:03

+0

MetallicPriest,哪一部分更有帮助? – osgx 2012-01-15 10:56:48

+0

osgx - 第二个更有帮助。 – MetallicPriest 2012-01-15 15:32:01

8

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

+0

+1我们可能会提到在malloc的上下文之外调用brk,以及这样做的后果。您可以让部分库代码和本地代码不“知道”现有的堆边界。分类的精神分裂症堆。不好。 – 2012-01-15 03:29:01

+0

malloc可以通过'brk'和'mmap'分配内存。只有malloc库的单个实例可以用brk管理内存;但是如果有另一个malloc实例被链接,它可以使用mmap来模拟单独的堆。 – osgx 2012-01-15 09:21:57

相关问题