我有一个复杂的构建过程的大型软件项目,其工作原理如下:
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,我们试图调用的一些符号不再是全球性的。
此时我可以看到几种可能的选择:
由于外部要求,我担心禁用第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吗?但代码看起来像是在试图进行GOT间接。这让我很困惑。我不知道这是否与我之前的问题有关,或者是一个不同的问题,或者根本不是问题......
更新
显然MIPS只是不支持隐藏的全局符号!
我们通过修改应该隐藏的符号的名称来解决这个问题,这样就没人知道它们是什么了。这推动了外部需求相当多,但我通过指出这是获得可交付产品的唯一途径来销售管理。
这完全是令人毛骨悚然的(并且涉及一些非常恶心的makefile工作),所以我宁愿选择一个更好的解决方案,如果有人有...
答案 0 :(得分:1)
我不确定您遇到的具体GOT问题。 binutils中的GOT,LO16 / HI16内容存在很多错误和问题。我认为大多数已经在您使用的版本中修复,除非您的目标是MIPS16(您似乎没有这样做)。 LO16实际上只是必需的,除了MIPS16之外,由于你有32位寄存器,你将从GOT中拉出完整的26位偏移量。 LO16不是必需的,但仍然是某些ABI / API正式要求的,但它最多只是一个警告(如果您正在使用它,可以尝试在该阶段删除-Werror)。我只是老老实实地理解那部分的基本知识,但是你的其他情况我有一些建议,如果不是答案(很难确定你的设置是否复杂)。
在MIPS(以及我熟悉的大多数程序集)中,您具有基本的三个级别的可见性:本地,全局和弱。另外,你有共享对象的comm。当然,GNU喜欢让事情变得更复杂并且增加更多。 gas提供受保护,隐藏和内部(最低限度,很难跟上所有扩展)。通过所有这些步骤,您手动摆弄可见性的设置似乎是不必要的。
如果您可以删除变量的中间全局性,则应删除您需要将它们设置为全局,这只能用于简化您以后遇到的任何GOT问题。
整体问题有点令人困惑。我不确定隐藏的全局符号是什么意思,这有点矛盾(当然可移植性和特定项目给出了疯狂的问题和限制)。您似乎需要在一个阶段交叉装配单元符号,但不是后期阶段。如果不使用GNU扩展(在我的书中最好避免使用),您可能希望将步骤1-2中的全局变量替换为comm和/或weakglobals。您总是可以使用使用预处理器技巧来避免在舞台上有多个子单元(丑陋,但这是该级别的可移植代码)。
你真的有1)子模块的设置2)子模块 - >模块3-5)模块 - >共享库。简化那不能伤害。您可以随时插入2)或3-5)C级接口,以便找到GCC将为您的架构生成的组件,并将其用作打破清晰界面可视性的基础。
希望我能给你一个量身定制的解决方案,但如果没有你的完整项目,这是非常不可能的。我可以放心,虽然MIPS位置(特别是工具链)存在问题,但可见性选项(特别是如果您使用gas,libbfd和gcc)是相同的。
答案 1 :(得分:0)
你的binutils太旧了。 2.23中的一些变更集可能会解决您的问题,例如“隐藏没有PLT的符号,也没有GOT参考”。