Linker MIPS、ELF和部分链接
我有一个大型软件项目,其构建过程非常复杂,其工作原理如下:Linker MIPS、ELF和部分链接,linker,shared-libraries,mips,elf,binutils,Linker,Shared Libraries,Mips,Elf,Binutils,我有一个大型软件项目,其构建过程非常复杂,其工作原理如下: 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 编译单个源文件 使用ld-
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
ld-r
将每个模块的对象文件部分链接到另一个.o中objcopy-G
隐藏每个模块中的专用符号ld-r
将模块对象部分链接在一起CALL16 reloc at 0x1234 not against global symbol
这似乎是因为编译器生成CALL16重定位来调用另一个编译单元中的函数,但CALL16只允许您调用全局符号——而且由于步骤3,我们尝试调用的一些符号不再是全局的
在这一点上,我可以看到几个可能的选择:
- 在步骤2,说服链接器将CALL16重定位解析为正常的编译单元内部PC相对调用
- 同上,但在步骤4或5
- 告诉编译器不要为编译单元间函数调用生成CALL16重定位
- 其他的
dlopen()
似乎不支持这一点
目前我的能力已经超出了我的能力范围。有人有什么建议吗
这是gcc 4.4.5(来自Emdebian),binutils 2.20.1。目标BFD是elf32 Tradlemips。主机操作系统是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吗?但是代码看起来像是在做一个GET间接寻址。这让我困惑。我不知道这是否与我之前的问题有关,或者是另一个问题,或者根本不是问题
更新
显然,MIPS根本不支持隐藏的全局符号
我们通过弄乱应该隐藏的符号的名称来绕过它,这样就没有人能分辨出它们是什么。这在很大程度上推动了外部需求,但我通过指出这是获得可交付产品的唯一途径来推销管理层
这太可怕了(还涉及到一些非常讨厌的makefile工作),所以我希望有一个更好的解决方案,如果有人有一个…我不确定您遇到的具体问题。binutils中的GOT、LO16/HI16内容存在很多错误和问题。我认为大多数已经在您使用的版本中修复,除非您针对的是MIPS16(您似乎没有这样做)。LO16实际上只有在那里才是必要的,除了MIPS16之外,因为您有32位寄存器,所以要从GOT中提取完整的26位偏移量。LO16是不需要的,但仍然是一些ABI/API正式要求的,但它被篡改为最多一个警告(如果您正在使用它,您可以尝试在该阶段删除-Werror)。老实说,我只了解这一部分的基本情况,对于你的其他情况,我有一些建议,如果没有答案的话(考虑到你的设置的复杂性,很难确定) 在MIPS(以及我熟悉的大多数程序集)中,您有三个基本的可见性级别:本地、全局和弱。此外,您还有用于共享对象的comm。当然,GNU喜欢让事情变得更复杂,增加更多。gas提供了受保护、隐藏和内部(最低限度,很难跟上所有扩展)。有了所有这些,手动设置可见性的步骤似乎是不必要的 如果您可以删除变量的中间全局性,那么它应该可以删除您需要使它们成为非全局性的变量,这只能简化您以后遇到的任何GET问题 总体问题有点令人困惑。我不确定你所说的隐藏的全局符号是什么意思,这有点矛盾(当然,可移植性和特定的项目会带来疯狂的问题和限制)。您似乎希望在某个阶段使用跨部件单元符号,但不希望在以后的阶段使用跨部件单元符号。在不使用GNU扩展的情况下(在我的书中最好避免),您可能希望用comm和/或weakglobals替换步骤1-2中的globals。您可以始终使用预处理器技巧来避免在阶段中使用多个子单元(虽然很难看,但这是此级别的可移植代码) 你真的有一个1)子模块2)子模块->模块3-5)模块->共享库的设置。简化这不会有什么坏处。您总是可以在2)或3-5)处插入C级接口,只是为了找到GCC将为您的体系结构生成的组件,并将其用作将可见性分解为干净接口的基础
希望我能给你一个量身定做的解决方案,但如果没有你的整个项目,这是不可能的。我可以保证,虽然MIPS位置(特别是工具链)有问题,但可见性选项(特别是在使用gas、libbfd和gcc时)是相同的 你的头发太老了。2.23中的一些变更集可能会解决您的问题,例如“隐藏没有PLT的符号,也不获取引用”