You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将ld.so在虚拟内存中移至更高地址?

问题

我的工具需要重建另一个进程的部分内存布局。为实现可靠重建,我创建了一个存根/包装器,关闭ASLR,仅链接libdl和libc以最小化占用空间,随后使用MAP_FIXED_NOREPLACE通过mmap()分配所需地址范围。成功分配后,包装器通过dlopen()加载其余代码以处理内存。

最近,工具遇到的内存布局开始占用包装器中libdl和libc的内存区域,导致mmap()失败。mmap()执行时包装器的内存映射如下:

00401000-00402000 r-xp 00001000 08:11 52960164                           /wrapper
00402000-00403000 r--p 00002000 08:11 52960164                           /wrapper
00403000-00404000 r--p 00002000 08:11 52960164                           /wrapper
00404000-00405000 rw-p 00003000 08:11 52960164                           /wrapper
7ffff7db0000-7ffff7db3000 rw-p 00000000 00:00 0 
7ffff7db3000-7ffff7dd5000 r--p 00000000 08:02 786706                     /lib/x86_64-linux-gnu/libc-2.31.so
7ffff7dd5000-7ffff7f4d000 r-xp 00022000 08:02 786706                     /lib/x86_64-linux-gnu/libc-2.31.so
7ffff7f4d000-7ffff7f9b000 r--p 0019a000 08:02 786706                     /lib/x86_64-linux-gnu/libc-2.31.so
7ffff7f9b000-7ffff7f9f000 r--p 001e7000 08:02 786706                     /lib/x86_64-linux-gnu/libc-2.31.so
7ffff7f9f000-7ffff7fa1000 rw-p 001eb000 08:02 786706                     /lib/x86_64-linux-gnu/libc-2.31.so
7ffff7fa1000-7ffff7fa5000 rw-p 00000000 00:00 0 
7ffff7fa5000-7ffff7fa6000 r--p 00000000 08:02 786744                     /lib/x86_64-linux-gnu/libdl-2.31.so
7ffff7fa6000-7ffff7fa8000 r-xp 00001000 08:02 786744                     /lib/x86_64-linux-gnu/libdl-2.31.so
7ffff7fa8000-7ffff7fa9000 r--p 00003000 08:02 786744                     /lib/x86_64-linux-gnu/libdl-2.31.so
7ffff7fa9000-7ffff7faa000 r--p 00003000 08:02 786744                     /lib/x86_64-linux-gnu/libdl-2.31.so
7ffff7faa000-7ffff7fab000 rw-p 00004000 08:02 786744                     /lib/x86_64-linux-gnu/libdl-2.31.so
7ffff7fab000-7ffff7fad000 rw-p 00000000 00:00 0 
7ffff7fc9000-7ffff7fcd000 r--p 00000000 00:00 0                          [vvar]
7ffff7fcd000-7ffff7fcf000 r-xp 00000000 00:00 0                          [vdso]
7ffff7fcf000-7ffff7fd0000 r--p 00000000 08:02 786696                     /lib/x86_64-linux-gnu/ld-2.31.so
7ffff7fd0000-7ffff7ff3000 r-xp 00001000 08:02 786696                     /lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ff3000-7ffff7ffb000 r--p 00024000 08:02 786696                     /lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ffc000-7ffff7ffd000 r--p 0002c000 08:02 786696                     /lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ffd000-7ffff7ffe000 rw-p 0002d000 08:02 786696                     /lib/x86_64-linux-gnu/ld-2.31.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

观察该布局可知,系统为栈向下增长预留了大量空间,ld.so使用的最高地址是栈增长的上限。由于我的工具不需要大量栈空间,因此想知道:是否有办法将ld.so移至更高地址,从而让其他库也加载到更高位置,避免与我需要预留的内存区域重叠?

解决方案

以下是几个可行的方法,按实现复杂度从低到高排序:

1. 缩小栈空间限制

栈的预留空间会挤压动态库的加载地址范围,你可以手动缩小栈大小,让ld.so和依赖库能加载到更高地址:

  • 启动前临时设置:在启动包装器前执行ulimit -s 4096(将栈大小设为4MB,可根据需求调整),这样栈的起始地址会向上偏移,留给动态库的空间会增加。
  • 代码中永久设置:在包装器的初始化代码中调用setrlimit()系统调用,直接限制栈大小:
    #include <sys/resource.h>
    // ...
    struct rlimit stack_limit;
    stack_limit.rlim_cur = 4 * 1024 * 1024; // 4MB
    stack_limit.rlim_max = 4 * 1024 * 1024;
    setrlimit(RLIMIT_STACK, &stack_limit);
    

2. 编译时指定程序加载基址

关闭ASLR后,你可以通过链接器参数强制包装器本身加载到更高地址,依赖的libc、libdl也会随之调整加载位置:

  • 编译时添加链接器参数:-Wl,-Ttext-segment=0x7ffff0000000(地址可根据你的预留区域调整,确保避开需要的内存范围)。这个参数会指定程序文本段的起始地址,让整个程序和依赖库往更高地址偏移。

3. 使用自定义链接脚本

编写ELF链接脚本,精确控制程序和动态库的加载地址范围,完全避开你需要预留的内存区域。示例脚本片段:

SECTIONS {
  . = 0x7ffff0000000; /* 设置程序基址 */
  .text : { *(.text) }
  .data : { *(.data) }
  .bss : { *(.bss) }
}
PHDRS {
  load PT_LOAD;
}

编译时通过-Wl,-T,your_script.ld参数指定该脚本。

4. 手动加载动态库(完全控制)

如果上述方法仍无法满足需求,可以让包装器完全不依赖libc和libdl,改为手动加载这些库:

  1. 编译一个完全静态链接的最小包装器(仅依赖内核系统调用)。
  2. 在包装器中先调用mmap()分配好需要预留的内存区域。
  3. 手动mmap()加载ld.so、libc、libdl到你指定的更高地址。
  4. 手动处理重定位,调用dlopen()加载后续代码。
    这个方法复杂度最高,但能实现完全的地址控制。

内容的提问来源于stack exchange,提问作者Grisby_2133

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 08:49:54