32位x86代码是否需要针对共享库文件进行特殊的PIC编译?

Joh*_*itb 13 c linux shared-libraries elf pic

如果要将目标文件作为共享库(.so)加载,则编译代码到目标文件需要与位置无关,因为在不同进程中加载​​共享对象文件的基本虚拟地址可能不同.

现在,当我尝试在32位x86计算机上加载.so没有-fpicGCC选项编译和链接的文件时,我没有遇到错误,而在64位x86计算机上它失败了.

我发现的随机网站说我不需要-fpic在32位上,因为-fpic根据X86 32位ABI 编译而没有巧合的代码也是以与位置无关的方式使用的.但我仍然发现软件在32位版本中附带了不同版本的库:一个用于PIC,另一个用于非PIC.例如,intel编译器随附,libirc.a并且libirc_pic.a后者被编译为与位置无关的模式(如果想要将该.a文件链接到.so文件中).

我想知道使用-fpic和不使用它的确切区别是32位代码,以及为什么有些软件包(如intel编译器)仍然附带了不同版本的库?

R..*_*R.. 10

并不是非PIC代码在x86(32位)上"巧合"工作.这就是x86的动态链接器支持使其工作所需的必要"textrels".这在内存消耗和启动时间方面成本非常高,因为基本上整个代码段必须在加载时修补(因此变成不可共享的内存).

动态链接维护者声称x86_64不支持非PIC共享库,因为架构中存在基本问题(立即地址位移不能大于32位)但是这个问题可以通过总是加载来轻松解决第一个4gb虚拟地址空间中的库.当然PIC代码在x86_64上非常便宜(PIC不像32位x86那样具有性能杀手),所以它们可能是正确的,以防止它不受支持并阻止傻瓜制作非PIC库......

  • PIC代码需要一个额外的寄存器来保存基址.在x86上,你已经有太少的寄存器,所以保留一个寄存器会使编译器更频繁地将寄存器溢出到内存中. (6认同)
  • PIC是x86上的性能杀手,因为加载GOT寄存器很昂贵.它需要一个函数调用并从堆栈中读取/保存返回地址.x86_64具有`eip`-相对寻址,因此不需要GOT寄存器. (2认同)

Ben*_*igt 0

不同进程加载共享目标文件的虚拟基地址可能不同

由于共享对象通常加载在其首选地址,因此它们可能看起来工作正常。但这fPIC对于所有共享代码来说是个好主意。

我相信该库通常不存在两个版本的原因是许多发行版都将其用作fPIC所有代码的默认版本。

  • 共享对象通常链接到地址 0 处加载,并且它们绝对不会加载到那里。 (3认同)