ARM ELF函数重定位

Posted gm-201705

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ARM ELF函数重定位相关的知识,希望对你有一定的参考价值。

ARM ELF的函数重定位与x86是一致的,但由于汇编指令不同,再鼓捣一遍。

示例代码:

#include <stdio.h>
#include <stdlib.h>

int main () {
        puts ("Hello world");
        sleep (1);
        FILE *fp = fopen ("1.c", "r");
        fclose (fp);
        exit (0);
}

通过 readelf -r 可以查看ELF中所有需要重定位的函数,我们以fopen()函数为例,分析其重定位过程。

$ arm-linux-androideabi-readelf -r elf_2

Relocation section ‘.rel.plt‘ at offset 0x278 contains 7 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00009ff4  00000516 R_ARM_JUMP_SLOT   00000000   fopen

首先main()函数中,通过 bl 82f4调用fopen(),82f4是一个16进制表示的地址,位于.plt节。

$ arm-linux-androideabi-objdump -d elf_2
000083c8 <main>:
...
    8404:       ebffffba        bl      82f4 <[email protected]>
 Disassembly of section .plt:
 
 000082f4 <[email protected]>:
    82f4:       e28fc600        add     ip, pc, #0, 12 @由于ARM三级流水,PC = 0x82f4 + 0x8
    82f8:       e28cca01        add     ip, ip, #4096
    82fc:       e5bcfcf8        ldr     pc, [ip, #3320]! @ip + 0xcf8 = 0x9ff4

以上三条指令执行完,从0x9ff4位置取值给pc,完成间接寻址的跳转。看一下0x9ff4处内容:

(gdb) p/x *0x9ff4
$1 = 0x82b0

程序跳转到0x82b0位置:

Disassembly of section .plt:

000082b0 <[email protected]>:
    82b0:       e52de004        push    {lr}            ; (str lr, [sp, #-4]!)
    82b4:       e59fe004        ldr     lr, [pc, #4]    ; 82c0 <[email protected]>
    82b8:       e08fe00e        add     lr, pc, lr
    82bc:       e5bef008        ldr     pc, [lr, #8]!
    82c0:       00001d18        andeq   r1, r0, r8, lsl sp

可以看到,这是.plt节的开始位置,IDA帮助我们做了一些显示的优化,所以其汇编结果与objdump看到的不同,它假装替我们完成了GOT的重定位过程,实际并非如此:

@ida的显示结果
.got:00009FF4 fopen_ptr       DCD __imp_fopen

下面解析一下.plt节开头的这几条指令:

@ 1. stack <- lr

@ 2. lr <- 0x1d18

@ 3. lr <- 0x82c0 + 0x1d18 = 0x9fd8

@ 4. pc <- [0x9fd8 + 0x8], lr <- 0x9fd8 + 0x8 = 0x9fe0

发现程序最终从0x9fe0地址处取值,并间接寻址将其作为地址跳转过去执行。使用gdb发现,此处静态值为0x0。显然这块地址内容,要由程序运行时动态补充的,否则这条指令将产生0地址访问异常。

(gdb) p/x *0x82c0
$1 = 0x1d18
(gdb) p/x *0x9fe0
$2 = 0x0
(gdb) 

技术分享图片

原来GOT的前3项,是为系统预留的(GOT[0][1][2]),其中GOT[1]中是ELF中所有动态库构成的链表的指针,GOT[2]是_dl_runtime_resolve函数指针。这个函数将具体完成函数的重定向过程,并将结果反馈到GOT表中。

因此上面静态分析时,GOT这3个表项是没有值的,它们由加载器动态填充。

以前画的x86的图,同样适应 ARM:

 技术分享图片

 

以上是关于ARM ELF函数重定位的主要内容,如果未能解决你的问题,请参考以下文章

ELF重定位

ELF文件格式分析

ELF 动态链接 - so 的 重定位表

ELF文件认知(二)可重定位目标文件

ELF重定位:Relocation Sections

ELF重定位:Relocation Sections