【发布时间】:2011-12-27 02:06:56
【问题描述】:
我有一个具有复杂构建过程的大型软件项目,其工作方式如下:
- 编译各个源文件。
- 使用
ld -r将每个模块的目标文件部分链接到另一个.o。 - 使用
objcopy -G隐藏每个模块中的私有符号。 - 将模块对象部分链接在一起,再次使用
ld -r。 - 将模块链接到一个共享对象中。
第 3 步是允许未导出到项目其余部分的模块私有全局变量所必需的。
这一切都适用于 ARM 和 IA32。不幸的是,现在我必须在 mips 上运行(特别是用于 Android 的 mipsel-linux-gnu)。并且 MIPS 共享对象 ABI 比其他平台上的复杂得多,并且无法正常工作。
发生的情况是第 5 步失败并出现此错误:
CALL16 reloc at 0x1234 not against global symbol
这似乎是因为编译器生成 CALL16 重定位以调用另一个编译单元中的函数,但 CALL16 只允许您调用全局符号 --- 由于第 3 步,我们试图调用的一些符号不再是全球性的。
此时我可以看到几个可能的选项:
- 说服链接器在第 2 步将 CALL16 重定位解析为正常的编译单元内 PC 相关调用。
- 同上,但在第 4 步或第 5 步。
- 告诉编译器不要为编译单元间函数调用生成 CALL16 重定位。
- 其他。
恐怕由于外部要求,禁用第 3 步不是一个选项。
我真正非常想做的是生成绝对代码,在加载时将其修补到正确的地址;它更小、更快、非常更简单,而且我们不需要在进程之间共享库。不幸的是,Android 的 dlopen() 似乎不支持这一点。
目前我已经超出了我的深度。有人有什么建议吗?
这是 gcc 4.4.5(来自 Emdebian),binutils 2.20.1。目标 BFD 是 elf32-tradlittlemips。主机操作系统是 Linux,我正在为 Android 进行交叉编译。
附录
我也从第 4 步收到这样的警告。
$MODULE.o: Can't find matching LO16 reloc against `$SYMBOLNAME' for R_MIPS_GOT16 at 0x18 in section `.text.$SYMBOLNAME'
查看第4步输入的反汇编,我可以看到编译器生成的代码是这样的:
50: 8f9e0000 lw s8,0(gp)
50: R_MIPS_GOT16 $SYMBOLNAME
54: 8fd9001c lw t9,28(s8)
58: 0320f809 jalr t9
5c: 00a02021 move a0,a1
GOT16 不是固定到地址的高半部分,并且应该跟一个 LO16 的低半部分吗?但是 code 看起来像是在尝试进行 GOT 间接寻址。这让我很困惑。我不知道这是否与我之前的问题有关,或者是不同的问题,或者根本不是问题......
更新
显然 MIPS 只是 不支持隐藏的全局符号!
我们已经通过修改应该隐藏的符号名称来解决这个问题,这样没人知道它们是什么。这极大地推动了外部要求,但我通过指出这是获得可交付产品的唯一途径来出售管理人员。
这完全令人毛骨悚然(并且涉及到一些非常令人作呕的 makefile 工作要做),所以我宁愿想要一个更好的解决方案,如果有人有的话......
【问题讨论】:
标签: linker shared-libraries mips elf binutils