osg*_*sgx 30
我的问题是这些库中的代码是否会在与主应用程序相同的堆中分配内存,还是使用自己的堆?
如果库使用与malloc/free应用程序相同的(例如,来自glibc) - 那么是的,程序和所有库将使用单个堆.
如果库mmap直接使用,它可以分配内存,而不是程序本身使用的内存.
因此,例如,.so文件中的某些函数调用malloc,它是否会使用与应用程序相同的堆管理器或另一个?
如果.so中的函数调用malloc,则此malloc与从program调用的malloc相同.您可以在Linux/glibc(> 2.1)中看到符号绑定日志
LD_DEBUG=bindings ./your_program
Run Code Online (Sandbox Code Playgroud)
是的,堆管理器的几个实例(具有默认配置)不能在不了解彼此的情况下共存(问题在于保持brk分配的堆大小在实例之间同步).但是,当多个实例可以共存时,可以进行配置.
大多数经典的malloc实现(ptmalloc*,dlmalloc等)可以使用两种从系统获取内存的方法:brk和mmap.Brk是经典的堆,它是线性的,可以增长或缩小.Mmap允许在任何地方获得大量内存; 并且您可以按任何顺序将此内存返回给系统(释放它).
构建malloc时,可以禁用brk方法.然后malloc将仅使用mmaps 模拟线性堆,甚至将禁用经典线性堆,并且所有分配将由不连续的mmaped fragmens进行.
因此,某些库可以拥有自己的内存管理器,例如malloc使用brkdisabled或使用非malloc内存管理器编译.此管理器应具有除malloc和之外的函数名称free,例如malloc1和/ free1或不应将此名称显示/导出到动态链接器.
此外,那些共享内存中的全局数据如何呢?它在哪里?我知道它的应用程序位于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文件的数据,而第二部分的大小(memory_size-file_size)将填充为零(对于*bss部分),使用mmap(/dev/zero)和memset(0)
当内核或动态链接器将ELF文件加载到内存中时,它们不会考虑共享.例如,您想要两次启动相同的程序.第一个进程将使用mmap加载ELF文件的只读部分; 第二个进程将执行相同的mmap(如果aslr处于活动状态 - 第二个mmap将进入不同的虚拟地址).页面缓存(VFS子系统)的任务是将数据的单个副本保存在物理内存中(使用COPY-on-WRITE也称为COW); 而mmap只会将每个进程中虚拟地址的映射设置为单个物理位置.如果任何进程将更改内存页面; 它将被写入唯一的私有物理内存时被复制.
加载代码在glibc/elf/dl-load.c(_dl_map_object_from_fd)中为ld.so和linux-kernel/fs/binfmt_elf.c内核的ELF加载器(elf_map,load_elf_binary).搜索一下PT_LOAD.
因此,全局数据和bss数据在每个进程中始终是私有的mmaped,并且它们受COW保护.
堆栈和堆栈在运行时使用brk + mmap(堆)和OS内核在类似brk的进程中自动分配(用于主线程堆栈).其他线程的堆栈分配与mmap在pthread_create.
Ign*_*ams 10
符号表在Linux中的整个过程中共享.malloc()对于该过程的任何部分,与所有其他部分相同.所以是的,如果一个进程的所有部分都通过malloc()et alia 访问堆,那么它们将共享同一个堆.
| 归档时间: |
|
| 查看次数: |
8409 次 |
| 最近记录: |