Linker 动态链接器如何确定在Linux上调用哪个例程?

Linker 动态链接器如何确定在Linux上调用哪个例程?,linker,elf,dynamic-linking,binaries,Linker,Elf,Dynamic Linking,Binaries,我有一个关于Linux上的动态链接的问题。考虑下面的ARM二进制拆分。< /P> 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>:

我有一个关于Linux上的动态链接的问题。考虑下面的ARM二进制拆分。< /P>
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>
Main函数在8424:bl 8320处调用printf。8320是上面显示的.plt中的地址。现在.plt中的代码调用动态链接器来调用printf例程。我的问题是动态链接器如何能够说这是对printf的调用?

.rela.plt包含printf的地址,以通知动态链接器从何处找到printf

查看此链接以了解非常容易消化的详细信息。本文还阐明了首先通过共享库访问变量,然后通过函数访问变量的过程

.rela.plt包含printf的地址,用于通知动态链接器从何处找到printf


查看此链接以了解非常容易消化的详细信息。本文还阐明了首先通过共享库访问变量,然后通过函数访问变量的过程

详细描述了动态链接的过程

TL;DR:在静态链接时,ld在特殊部分创建一组表,如.rel.dyn、.rel.plt等,这些部分告诉运行时加载程序在运行时要做什么


您可以使用nm-D、readelf-Wr、objdump-R等检查这些表。

动态链接的过程描述得非常详细

TL;DR:在静态链接时,ld在特殊部分创建一组表,如.rel.dyn、.rel.plt等,这些部分告诉运行时加载程序在运行时要做什么


您可以使用nm-D、readelf-Wr、objdump-R等检查这些表。

TLDR;PLT通过传递以下消息调用动态链接器:

IP和PLTGOT[n+3]中GOT条目的地址

&PLTGOT[2]位于LR中

此外,PLTGOT[1]标识共享对象/可执行文件

动态链接器使用它来查找重新定位条目plt_relocation_table[n],从而找到符号printf

PLT输入代码的说明 这在以下几方面得到了解释:

委员会注意到:

当平台像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:

从这两个GET地址中,动态链接器可以在PLT重定位表中找到GET偏移量和偏移量

从&GOT[2],动态链接器可以找到PLTGOT-GOT[1]的第二个条目,其中包含链接器结构的地址,动态链接器使用该引用来识别此共享对象/可执行文件


我不知道这是在哪里指定的:它似乎不是基本臂ABI规范的一部分。

TLDR;PLT通过传递以下消息调用动态链接器:

IP和PLTGOT[n+3]中GOT条目的地址

&PLTGOT[2]位于LR中

此外,PLTGOT[1]标识共享对象/可执行文件

动态链接器使用它来查找重新定位条目plt_relocation_table[n],从而找到符号printf

PLT输入代码的说明 这在以下几方面得到了解释:

委员会注意到:

当平台像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:

从这两个GET地址中,动态链接器可以在PLT重定位表中找到GET偏移量和偏移量

从&GOT[2],动态链接器可以找到PLTGOT-GOT[1]的第二个条目,其中包含链接器结构的地址,动态链接器使用该引用来识别此共享对象/可执行文件


我不知道这是在哪里指定的:它似乎不是基本ARM ABI规范的一部分。

但我认为.rel.dyn仅用于变量,而不用于函数。动态函数包含在.rel.pltb中,但我认为.rel.dyn仅用于变量,而不用于函数。动态函数位于.rel.plt中。这与您上一个问题非常相似。这与您上一个问题非常相似。 Offset Info Type Sym. Value Sym. Name 0001066c 00000116 R_ARM_JUMP_SLOT 00000000 printf

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
[...]
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