看了一个很牛B的帖子,关于动态链接的: 804838c: e8 47 ff ff ff call 80482d8 其中,0x80482d8是printf在plt中的地址(逻辑地址)。plt是结构这样的: Disassembly of section .plt: 080482a8 <__gmon_start__@plt-0x10>: 80482a8: ff 35 60 95 04 08 pushl 0x8049560 80482ae: ff 25 64 95 04 08 jmp *0x8049564 80482b4: 00 00 add %al,(%eax) 080482b8 <__gmon_start__@plt>: 80482b8: ff 25 68 95 04 08 jmp *0x8049568 80482be: 68 00 00 00 00 push $0x0 80482c3: e9 e0 ff ff ff jmp 80482a8 <_init+0x30> 080482c8 <__libc_start_main@plt>: 80482c8: ff 25 6c 95 04 08 jmp *0x804956c 80482ce: 68 08 00 00 00 push $0x8 80482d3: e9 d0 ff ff ff jmp 80482a8 <_init+0x30> 080482d8 < printf @ plt>: 80482d8: ff 25 70 95 04 08 jmp *0x8049570 80482de: 68 10 00 00 00 push $0x10 80482e3: e9 c0 ff ff ff jmp 80482a8 <_init+0x30> 在call指令执行后执行
程序跳转到地址(addr1)0x8049570存储的地址(addr2)处,即*addr1 == addr2,若包含printf的库libc.so尚未加载,这时addr2的值就是0x080482de,即指令push $0x10。将0x10压入堆栈,用来定位printf在libc.so的位置。接下来的jmp指令将程序定位在0x80482a8,即<__gmon_start__@plt-0x10>处,将0x8049560压入堆栈。jmp *0x8049564指令是程序跳转到一个固定的加载程序处,即原帖中的function _dl_runtime_resolve: Dump of assembler code for function _dl_runtime_resolve: 0x4000a960 <_dl_runtime_resolve>: pushl %eax 0x4000a961 <_dl_runtime_resolve+1>: pushl %ecx 0x4000a962 <_dl_runtime_resolve+2>: pushl %edx 0x4000a963 <_dl_runtime_resolve+3>: movl 0x10(%esp,1),%edx 0x4000a967 <_dl_runtime_resolve+7>: movl 0xc(%esp,1),%eax 0x4000a96b <_dl_runtime_resolve+11>: call 0x4000a740 此时的堆栈情况见原帖。以下三条指令,将0x10和0x8049560作为参数放入寄存器edx、eax并调用 0x4000a963 <_dl_runtime_resolve+3>: movl 0x10(%esp,1),%edx 0x4000a967 <_dl_runtime_resolve+7>: movl 0xc(%esp,1),%eax 0x4000a96b <_dl_runtime_resolve+11>: call 0x4000a740 指令xchgl %eax,(%esp,1)将printf的地址放入栈顶。最精彩的一条指令当属ret $0x8,它将栈顶元素即printf的地址弹出至程序计数器PC,作为下一条将执行的指令地址,同时,清除堆栈中的0x10和0x8049560。此时堆栈中的情形,就如同直接调用了printf函数,似乎什么都没发生过。 此外 不知道我说清楚了没有,感觉说的很乱,文字也很乱。:-) |
|
来自: astrotycoon > 《链接加载》