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

如何将--relocatable生成的二进制目标文件链接到PIE可执行文件并正常运行?

解决PIE模式下嵌入二进制文件的符号问题

这个问题的核心在于PIE(位置无关可执行文件)模式下,GCC对ld生成的绝对符号处理逻辑和Clang存在差异,咱们一步步拆解原因并找到通用解决方案:

问题根源

当你用ld -r -b binary把文本文件转成目标文件时,符号表中的_binary__tmp_stuff_txt_size是一个绝对符号(标记为ABS)——它的实际值就是文件的大小,但它并不是一个指向内存地址的符号。

在非PIE模式下,直接把它强制转成size_t能正常工作,因为此时绝对符号的"地址"就等于它的数值本身。但在PIE模式下,GCC会把这个符号当作一个绝对内存地址来解析,而PIE进程的地址空间是随机化的,这个绝对地址根本无效,所以你会得到垃圾值,最终触发段错误。

Clang之所以能正常运行,是因为它对这类绝对符号做了特殊处理,直接取了符号的数值而非地址,但这属于编译器的行为差异,不是标准的可移植写法。

通用解决方案:用_end - _start计算大小

不要依赖_binary_*_size这个绝对符号,改用_binary__tmp_stuff_txt_end和_binary__tmp_stuff_txt_start的差值来计算文件大小。这两个符号都位于.data段,在PIE模式下是位置无关的偏移量,相减时基址会被抵消,结果完全不受地址随机化影响。

修改后的代码如下:

extern char _binary__tmp_stuff_txt_start[];
extern char _binary__tmp_stuff_txt_end[];

int f(void) {
    size_t size = (size_t)(_binary__tmp_stuff_txt_end - _binary__tmp_stuff_txt_start);
    do_stuff(size, _binary__tmp_stuff_txt_start);
}

为什么这个方案靠谱?

  • _binary__tmp_stuff_txt_start指向嵌入数据的起始位置,_binary__tmp_stuff_txt_end指向数据结束后的第一个字节,两者的差值正好是数据的准确字节数。
  • 无论是否开启PIE,这两个符号都是相对于进程基址的偏移量,相减操作会自动抵消基址的影响,结果始终正确。
  • 这个写法是跨GCC/Clang、跨PIE/非PIE模式的通用方案,完全避免了编译器行为差异带来的问题。

额外验证(可选)

你可以再看一眼符号表确认差异:

objdump -t /tmp/stuff.o

_binary__tmp_stuff_txt_start和_binary__tmp_stuff_txt_end都属于.data段(位置相关符号),而_binary__tmp_stuff_txt_size是ABS段的绝对符号——这就是为什么后者在PIE下会出问题的关键。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 14:47:40