我有一个具有复杂构建过程的大型软件项目,其工作方式如下:
- 编译单个源文件。
- 使用 .将每个模块的部分目标文件链接到另一个 .o 中
ld -r
。 - 使用 . 隐藏每个模块中的私有符号
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 步不是一个选项。
我真正非常想做的是生成绝对代码,这些代码在加载时被修补到正确的地址;它更小、更快、更简单,而且我们不需要在进程之间共享库。不幸的是,Androiddlopen()
似乎不支持这一点。
目前我已经超出了我的深度。有人有什么建议吗?
这是 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 吗?但是代码看起来像是在尝试做一个 GOT 间接。这让我很困惑。我不知道这是否与我之前的问题有关,或者是不同的问题,或者根本不是问题......
更新
显然 MIPS 根本不支持隐藏的全局符号!
我们已经通过修改应该隐藏的符号名称来绕过它,这样没人知道它们是什么。这极大地推动了外部要求,但我通过指出这是获得可交付产品的唯一途径来出售管理人员。
这完全令人毛骨悚然(并且涉及一些令人作呕的makefile工作),所以我宁愿想要一个更好的解决方案,如果有人有一个......