2011-11-11 70 views
4

我有一个复杂的构建过程中一个很大的软件项目,其工作原理是这样:MIPS,ELF和部分连接

  1. 编译单独的源文件。
  2. 使用ld -r将每个模块的目标文件部分链接到另一个.o。
  3. 使用objcopy -G隐藏每个模块中的私有符号。
  4. 部分链接模块对象,再次使用ld -r
  5. 将模块链接到共享对象中。

需要执行步骤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工作要做),所以我宁愿像一个更好的解决办法,如果任何人有一个...

回答

1

我不知道有关特定GOT您遇到的问题。在binutils中有很多bug和GOT,LO16/HI16等问题。我认为大多数已被修正在你使用的版本中,除非你的目标是MIPS16(你似乎没有这样做)。因为你有32位寄存器,所以LO16实际上只在那里需要,除了MIPS16之外,你将GOT的全部26位偏移量拉出。 LO16不是必需的,但仍然是一些ABI/API正式要求的,但它最多只能是一个警告(如果您正在使用它,您可以尝试删除该阶段的错误)。我只是老老实实地理解那部分的基础知识,其余的情况我都有一些建议,如果不是答案(很难确定你的设置是否复杂)。在MIPS(以及我熟悉的大多数程序集)中,您具有基本的三个可见性级别:本地,全局和弱点。另外你还有通讯共享对象。当然,GNU喜欢让事情更复杂,并增加更多。天然气提供受保护的,隐藏的和内部的(最低限度,很难跟上所有的扩展)。通过所有这些步骤,手动摆弄可见性的设置看起来没有必要。

如果您可以删除变量的中间全局性,则应删除您需要使其成为全局变量,这只能用于简化稍后遇到的任何GOT问题。

整体问题有点混乱。我不确定隐藏的全局符号是什么意思,这有点矛盾(当然,可移植性和特定项目会带来疯狂的问题和限制)。你似乎想要在一个阶段交叉装配单元符号,但不是在以后的阶段。如果不使用GNU扩展(在我的书中最好避免的),你可能需要用comm和/或weakglobals替换步骤1-2中的全局变量。你总是可以使用使用预处理器欺骗来避免在舞台上有多个子单元(丑陋,但这是这个级别的可移植代码)。

你真的有一个设置1)子模块2)子模块 - >模块3-5)模块 - >共享库。简化不能伤害。您可以始终在2)或3-5)处插入一个C级接口,以查找GCC将为您的架构生成的装配,并将其用作打开清晰接口的基础。

希望我可以给你一个量身定制的解决方案,但如果没有你的完整项目,这是不可能的。我可以放心的是,虽然MIPS的位置(特别是工具链)有问题,但可见性选项(特别是在使用gas,libbfd和gcc时)是相同的。

0

你的binutils太旧了。 2.23中的一些变更集可能会解决您的问题,如“隐藏没有PLT或GOT引用的符号”。