问题描述
我对Linux上的动态链接有疑问.请考虑以下ARM二进制文件的拆卸.
I have a question about dynamic linking on Linux. Consider the following disassembly of an ARM binary.
8300 <printf@plt-0x40>:
....
8320: e28fc600 add ip, pc, #0, 12
8324: e28cca08 add ip, ip, #8, 20 ; 0x8000
8328: e5bcf344 ldr pc, [ip, #836]! ; 0x344
....
83fc <main>:
...
8424:ebffffbd bl 8320 <_init+0x2c>
主函数在8424处调用printf:bl8320.8320是上面显示的.plt中的地址.现在,.plt中的代码将调用动态链接器以调用printf例程.我的问题是动态链接程序如何能够说这是对printf的调用?
Main function calls printf at 8424: bl 8320. 8320 is an address in the .plt shown above. Now the code in .plt makes call to dynamic linker to invoke printf routine. My question is how the dynamic linker will be able to say that it is a call to printf?
推荐答案
TLDR; PLT通过传递以下内容来调用动态链接器:
TLDR; The PLT calls the dynamic linker by passing:
-
IP(
&PLTGOT[n+3]
)中GOT条目的地址;
the address of the GOT entry in IP (
&PLTGOT[n+3]
);
&PLTGOT[2]
在LR中;
此外,PLTGOT[1]
标识共享对象/可执行文件.
Moreover PLTGOT[1]
identifies the shared-object/executable.
动态链接器使用它来查找重定位条目(plt_relocation_table[n]
),从而找到符号(printf
).
The dynamic linker use this to find the relocation entry (plt_relocation_table[n]
) and thus the symbol (printf
).
(以某种方式)在部分中对此进行了解释. ELF for ARM的A.3 :
8320: e28fc600 add ip, pc, #0, 12
8324: e28cca08 add ip, ip, #8, 20 ; 0x8000
8328: e5bcf344 ldr pc, [ip, #836]! ; 0x344
其中的解释是:
ADD ip, pc, #-8:PC_OFFSET_27_20:__PLTGOT(X)
; R_ARM_ALU_PC_G0_NC(__PLTGOT(X))
ADD ip, ip, #-4:PC_OFFSET_19_12: __PLTGOT(X)
;R_ARM_ALU_PC_G1_NC(__PLTGOT(X))
LDR pc, [ip, #0:PC_OFFSET_11_0:__PLTGOT(X)]!
; R_ARM_LDR_PC_G2(__PLTGOT(X))
这些说明有两件事:
-
它们将GOT条目的地址计算为与PC的偏移量,并将其存储在IP寄存器中;
they compute the address of the GOT entry as an offset from PC and store it in the IP register;
他们跳到了这个GOT条目.
they jump to this GOT entry.
该规范指出:
回写"是对!"的使用.在最后一条指令中:这用于使用最终偏移量(#836)更新IP寄存器.这样,IP就会在PLT条目的末尾包含GOT条目的地址.
The "write-back" is the use of "!" in the last instruction: this is used to update IP register with the final offset (#836). This way IP contains the addess of the GOT entry at the end of the PLT entry.
动态链接程序在IP中具有GOT条目的地址:
The dynamic linker has the address of the GOT entry in IP:
-
它可以找到共享对象或可执行文件;
it can find the shared-object or executable;
它可以找到正确的重定位项.
it can find the correct relocation entry.
此重定位条目引用目标函数的符号(在您的情况下为printf
):
This relocation entry references the symbol of target function (printf
in your case):
Offset Info Type Sym. Value Sym. Name
0001066c 00000116 R_ARM_JUMP_SLOT 00000000 printf
从GOT查找重定位条目
现在不清楚从GOT地址中找到重定位条目的方式.可以使用二进制搜索,但并不方便. GNU ld.so就是这样(glibc/sysdeps/arm/dl-trampoline.S):
Finding the relocation entry from the GOT
Now the way the relocation entry is found from the GOT address is not clear. Binary search could be used but is would not be convenient. The GNU ld.so does it like this (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中.我想这是bybyt
.PLT0
:
00015b84 :
15b84: e52de004 push {lr} ; (str lr, [sp, #-4]!)
15b88: e59fe004 ldr lr, [pc, #4] ; 15b94
15b8c: e08fe00e add lr, pc, lr
15b90: e5bef008 ldr pc, [lr, #8]!
15b94: 0012f46c andseq pc, r2, ip, ror #8
动态链接器从这两个GOT地址中可以找到GOT偏移量和PLT重定位表中的偏移量.
From those two GOT addresses, the dynamic linker can find the GOT offset and the offset in the PLT relocation table.
在&GOT[2]
中,动态链接器可以找到PLTGOT的第二个条目(GOT[1]
),其中包含链接器结构的地址(动态链接器用来识别此共享库/可执行文件).
From &GOT[2]
, the dynamic linker can find the second entry of the PLTGOT (GOT[1]
) which contains the address of the linker struct (a reference used by the dynamic linker to recosgnise this shared-object/executable).
我没有在此指定位置:它似乎不属于基本的ARM ABI规范.
I don't where this is specified: it does not seem to be part of the base ARM ABI spec.
这篇关于动态链接器如何确定在Linux上调用哪个例程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!