@
LotusChuan 你说的这种是基于 PLT 的相对寻址( R_X86_64_PLT32 ),用于 shared 库的。
OP 说的 R_X86_64_PC32 是基于程序计数器(当前代码执行地址)的相对寻址,是用于可执行文件内部的,这种相对寻址不用修改任何东西。用这个的原因主要有两部分
1. 现在的操作系统为了安全,不仅 shared 库是随机地址加载(基于 PLT ,动态链接的时候需要修改程序里的基地址;这个特性称为 Position-independent code, PIC ),就连可执行文件本身的代码段、数据段也是随机加载(整体上加了一个随机偏移量,相对当前执行代码的位置不变,所以可以用基于 PC 的相对寻址,不用修改任何基地址;这个特性称为 Position-independent executable, PIE )
2. R_X86_64_32 绝对寻址,全称是 32 位绝对寻址,使用的地址长度只有 32 位,能寻址的范围定死在 0x0~0xffffffff ,如果用这种的话程序的全局部分(代码段+数据段)就只能使用低 4G 的虚拟地址空间了;而 R_X86_64_PC32 虽然寻址范围也只有这么大,但它的寻址窗口是随着当前执行代码的位置滑动的,整体上可以寻址范围更大。
至于为什么只有这几种寻址方式,是因为 x86 指令集里寻址的偏移量就只有 32 位。
如果需要用 64 位绝对寻址的话,就需要通过寄存器来相对寻址,原来 1 条指令变成 2 条(先把 64 位地址加载到某个通用寄存器,再执行想要的计算),效率比较低,所以只有必要的情况才会用这种方式。默认情况下程序都是用的上述几种 32 位偏移量的方式。