我有一个复杂的构建过程中一个很大的软件项目,其工作原理是这样:MIPS,ELF和部分连接
- 编译单独的源文件。
- 使用
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的LO16?但代码看起来像它试图做一个GOT间接寻址。这让我感到困惑。我不知道这是否与我先前的问题,或者是一个不同的问题,或者是不是在所有问题......
更新
显然MIPS根本不支持隐藏全球符号!
我们已经通过改变应该隐藏的符号的名称来绕过它,以便没有人知道它们是什么。这大大推动了外部需求,但是我通过指出这是获得可运送产品的唯一方式,从而将管理层卖给了它。
这是完全可怕的(并且涉及到一些深恶心的makefile工作要做),所以我宁愿像一个更好的解决办法,如果任何人有一个...