2

我想解析ARM elf中的动态链接函数。众所周知,当我们调用一个extern函数(fn1)时,它会跳转到相关的PLT位置,它的PLT代码会从相关的GOT位置获取地址。如果第一次调用fn1,GOT中这个地址就是PLT段的起始偏移,控制跳转到那里(每个PLT fn都会第一次跳转到这里),解析fn1的真实地址,把它到 GOT,然后调用它。而之后我们再次调用fn1的时候,它会跳转到PLT,而fn1的地址已经在GOT中了,所以我们可以直接调用它。

这是我的理解,我使用gdb在x86中验证成功。但是,当我切换到 ARM 时,事情似乎很奇怪。我发现PLT fn不是跳转到PLT section的起始偏移来解析地址,GOT数据不是PLT section的起始偏移,也不是程序运行后extern fn的地址。(但它包含运行前 PLT 部分的起始偏移量)

这是我在 GDB 中的调试设置:
1. 程序的反汇编视图

.PLT
===========================================================================
.plt:000083D0                 AREA .plt, CODE
.plt:000083D0                 STR             LR, [SP,#var_4]!
.plt:000083D4                 LDR             LR, =(_GLOBAL_OFFSET_TABLE_ - 0x83E0)
.plt:000083D8                 ADD             LR, PC, LR
.plt:000083DC                 LDR             PC, [LR,#8]!
.plt:000083DC ; ---------------------------------------------------------------------------
.plt:000083E0 off_83E0        DCD _GLOBAL_OFFSET_TABLE_ - 0x83E0 ;
.plt:000083E4 ; =============== S U B R O U T I N E =======================================
.plt:000083E4 sub_83E4
.plt:000083E4                 ADRL            R12, 0x83EC
.plt:000083EC                 LDR             PC, [R12,#(off_90D4 - 0x83EC)]! ; sub_83D0
.plt:000083F0 ; =============== S U B R O U T I N E =======================================
.plt:000083F0 sub_83F0
.plt:000083F0                 ADRL            R12, 0x83F8
.plt:000083F8                 LDR             PC, [R12,#(off_90D8 - 0x83F8)]! ; sub_83D0

.GOT
===========================================================================
.got:000090C8                 AREA .got, DATA
.got:000090C8 _GLOBAL_OFFSET_TABLE_ DCD 0             ; DATA XREF: sub_83D0+8
.got:000090CC                 DCD 0
.got:000090D0                 DCD 0
.got:000090D4 off_90D4        DCD sub_83D0            ; DATA XREF: sub_83E4+8
.got:000090D8 off_90D8        DCD sub_83D0            ; DATA XREF: sub_83F0+8
.got:000090D8 ; .got          ends

.TEXT
===========================================================================
.text:00008434                 ADD             R0, PC  ; "okkkkkkk..."
.text:00008436                 BLX             sub_83F0
.text:0000843A                 POP             {R4,PC}

2. 运行 arm-eabi-gdb

// start gdb
(gdb) target remote :5039

// before running, GOT's data is ok
(gdb) x/2x 0x90d4  
0x90d4: 0x000083d0      0x000083d0

// PLT
(gdb) x/11i 0x83d0 
   0x83d0:      push    {lr}            ; (str lr, [sp, #-4]!)
   0x83d4:      ldr     lr, [pc, #4]    ; 0x83e0
   0x83d8:      add     lr, pc, lr
   0x83dc:      ldr     pc, [lr, #8]!
   0x83e0:      andeq   r0, r0, r8, ror #25
   0x83e4:      add     r12, pc, #0
   0x83e8:      add     r12, r12, #0
   0x83ec:      ldr     pc, [r12, #3304]!       ; 0xce8
   0x83f0:      add     r12, pc, #0
   0x83f4:      add     r12, r12, #0
   0x83f8:      ldr     pc, [r12, #3296]!       ; 0xce0

// set a breakpoint at the fn(printf)'s plt
(gdb) b *0x83f0
Breakpoint 1 at 0x83f0

// running, before call printf at first time, the GOT's data is?
(gdb) c
Continuing.
Breakpoint 1, 0x000083f0 in ?? ()

// strange...
(gdb) x/2x 0x90d4
0x90d4: 0xafd14ff9      0xafd19b81

(gdb) ni
0x000083f4 in ?? ()

(gdb) ni
0x000083f8 in ?? ()

(gdb) i r
...
r12            0x83f8   33784
sp             0xbe9b2c38       0xbe9b2c38
lr             0x843b   33851
pc             0x83f8   0x83f8

// after 'ni', printf is called and output a string...
// will return to 0x843a
(gdb) ni
0x0000843a in ?? ()

就这样。即使我在 0x83d0 处设置断点并运行,也没有完全中断!!!请帮我...

4

0 回答 0