000084d8 <.plt>:
84d8: e52de004 push {lr} ; (str lr, [sp, #-4]!)
84dc: e59fe004 ldr lr, [pc, #4] ; 84e8 <_start-0x58> //lr = 0x9790
84e0: e08fe00e add lr, pc, lr //lr = 0x9790+0x84e8
84e4: e5bef008 ldr pc, [lr, #8]!
//pc = [ 0x9790+0x84e8+8] = [0x11C80]
84e8: 00009790 muleq r0, r0, r7
84ec: e28fc600 add ip, pc, #0
84f0: e28cca09 add ip, ip, #36864 ; 0x9000
84f4: e5bcf790 ldr pc, [ip, #1936]! ; 0x790
84f8: e28fc600 add ip, pc, #0
84fc: e28cca09 add ip, ip, #36864 ; 0x9000
8500: e5bcf788 ldr pc, [ip, #1928]! ; 0x788
8504: e28fc600 add ip, pc, #0
8508: e28cca09 add ip, ip, #36864 ; 0x9000
850c: e5bcf780 ldr pc, [ip, #1920]! ; 0x780
8510: e28fc600 add ip, pc, #0
8514: e28cca09 add ip, ip, #36864 ; 0x9000
8518: e5bcf778 ldr pc, [ip, #1912]! ; 0x778
851c: e28fc600 add ip, pc, #0
//注意:pc总是指向当前地址+8
8520: e28cca09 add ip, ip, #36864 ; 0x9000
8524: e5bcf770 ldr pc, [ip, #1904]! ; 0x770
//pc=[0x8524+0x9000+0x770]=[0x11c94]
8528: e28fc600 add ip, pc, #0
852c: e28cca09 add ip, ip, #36864 ; 0x9000
8530: e5bcf768 ldr pc, [ip, #1896]! ; 0x768
8534: e28fc600 add ip, pc, #0
8538: e28cca09 add ip, ip, #36864 ; 0x9000
853c: e5bcf760 ldr pc, [ip, #1888]! ; 0x760
Disassembly of section .got:
00011c78 <_GLOBAL_OFFSET_TABLE_>:
11c78: 00011b90 muleq r1, r0, fp
11c7c
11c80
...
11c84: 000084d8 ldrdeq r8, [r0], -r8
11c88: 000084d8 ldrdeq r8, [r0], -r8
11c8c: 000084d8 ldrdeq r8, [r0], -r8
11c90: 000084d8 ldrdeq r8, [r0], -r8
11c94: 000084d8 ldrdeq r8, [r0], -r8
11c98: 000084d8 ldrdeq r8, [r0], -r8
11c9c: 000084d8 ldrdeq r8, [r0], -r8
...
从上面的分析得到一个疑惑,无论调用哪个外部函数都会去调用plt0,可plt0怎么知道我们到底在调用哪个外部函数? x86平台下是有传参数(got中的地址,和函数对应的符号表项)。在arm下我是没看到什么参数,只有ip比较可疑(见
绿色行)。
不过Android下现在是不支持lazy binding的,所以就算上面的plt0只是个摆设也没关系。可执行文件加载时其调用的外部函数对应的.got项就被修改了。这只是猜测,为了验证现在去看看linker的实现。