TLDR;PLT 通过传递调用动态链接器:
此外PLTGOT[1]
标识共享对象/可执行文件。
动态链接器使用它来查找重定位条目 ( plt_relocation_table[n]
) 和符号 ( printf
)。
PLT入口代码说明
这在ELF for ARM 的 A.3 节中(以某种方式)进行了解释:
8320: e28fc600 添加 ip, pc, #0, 12
8324: e28cca08 添加 ip, ip, #8, 20 ; 0x8000
8328:e5bcf344 ldr 电脑,[ip,#836]!; 0x344
解释如下:
添加 ip, pc, #-8:PC_OFFSET_27_20:__PLTGOT(X)
; R_ARM_ALU_PC_G0_NC(__PLTGOT(X))
添加 ip, ip, #-4:PC_OFFSET_19_12: __PLTGOT(X)
;R_ARM_ALU_PC_G1_NC(__PLTGOT(X))
LDR 电脑,[ip,#0:PC_OFFSET_11_0:__PLTGOT(X)]!
; R_ARM_LDR_PC_G2(__PLTGOT(X))
这些指令做了两件事:
该规范指出:
对最终 LDR 的回写确保 ip 包含 PLTGOT 条目的地址。这对于增量动态链接至关重要。
“回写”是使用“!” 在最后一条指令中:这用于使用最终偏移量更新 IP 寄存器(#836)。这样,IP 在 PLT 条目的末尾包含了 GOT 条目的地址。
动态链接器在 IP 中具有 GOT 条目的地址:
它可以找到共享对象或可执行文件;
它可以找到正确的重定位条目。
此重定位条目引用目标函数的符号(printf
在您的情况下):
偏移信息类型 Sym。价值符号。姓名
0001066c 00000116 R_ARM_JUMP_SLOT 00000000 printf
ARM 架构的基础平台 ABI指出:
当平台支持惰性函数绑定(如 ARM Linux 那样)时,此 ABI 需要 ip 来寻址 PLT 通过它调用的点处的相应 PLTGOT 条目。(要求 PLT 表现得好像它以 LDR pc, [ip] 结尾)。
从 GOT 中查找重定位条目
现在从GOT地址中找到重定位入口的方式还不清楚。可以使用二进制搜索,但不方便。GNU ld.so 是这样做的(glibc/sysdeps/arm/dl-trampoline.S):
dl_runtime_resolve:
cfi_adjust_cfa_offset (4)
cfi_rel_offset (lr, 0)
@ we get called with
@ stack[0] contains the return address from this call
@ ip contains &GOT[n+3] (pointer to function)
@ lr points to &GOT[2]
@ Save arguments. We save r4 to realign the stack.
push {r0-r4}
cfi_adjust_cfa_offset (20)
cfi_rel_offset (r0, 0)
cfi_rel_offset (r1, 4)
cfi_rel_offset (r2, 8)
cfi_rel_offset (r3, 12)
@ get pointer to linker struct
ldr r0, [lr, #-4]
@ prepare to call _dl_fixup()
@ change &GOT[n+3] into 8*n NOTE: reloc are 8 bytes each
sub r1, ip, lr
sub r1, r1, #4
add r1, r1, r1
[...]
第二个 GOT 条目的地址在 LR 中。我想这是 donebyt .PLT0
:
00015b84:
15b84: e52de004 推 {lr} ; (str lr,[sp,#-4]!)
15b88:e59fe004 ldr lr,[pc,#4];15b94
15b8c:e08fe00e 添加 lr、pc、lr
15b90:e5bef008 ldr 电脑,[lr,#8]!
15b94: 0012f46c andseq pc, r2, ip, ror #8
从这两个 GOT 地址中,动态链接器可以找到 GOT 偏移量和 PLT 重定位表中的偏移量。
从&GOT[2]
中,动态链接器可以找到 PLTGOT ( GOT[1]
) 的第二个条目,其中包含链接器结构的地址(动态链接器用来重新识别此共享对象/可执行文件的引用)。
我没有在哪里指定:它似乎不是基本 ARM ABI 规范的一部分。