从elf中读取函数地址

先准备一份测试代码:

#include <stdio.h>

void funcUp(void)
{
    printf("Hello world 1!\n");
    return;
}

int main(int argc, char* argv[])
{
    funcUp();
    funcDown();
    return 0;
}

int funcDown(void)
{
    printf("Hello world 2!\n");
    return 0;
}

然后编译并反汇编:

gcc -g testElf.c -o test 
objdump -S test

得到以下信息(部分):


可以看出在funcUp中调用printf时,汇编中显示的是callq  4003f0 <puts@plt>,下面就来研究一下printf在进程空间中的地址。puts@plt相当于编译器设定的中间函数,只有printf函数第一次被用到时才进行绑定(地址修正)。puts@plt对应的代码:


用调试器进行分析:

gdb test

设置断点,运行程序地址才会绑定:

(gdb) break main

Breakpoint 1 at 0x400513: file testElf.c, line 12.

(gdb) run

Starting program: /home/administrator/develop/test/elf/test 
Breakpoint 1, main (argc=1, argv=0x7fffffffdae8) at testElf.c:12
12    funcUp();

分析puts@plt,先跳到0x601018看看:

(gdb) x 0x601018

0x601018 <puts@got.plt>: 0x00000000004003f6

发现函数跳到了第二行,接着执行下去,到了第三行,查看0x4003e0代码:


执行下去,来到GOT表偏移0x10(第5项)的位置:

(gdb) x 0x601010
0x601010: 0x00007ffff7def210

(gdb)disassemble 0x00007ffff7def210
Dump of assembler code for function _dl_runtime_resolve:
   0x00007ffff7def210 <+0>: sub    $0x38,%rsp
   0x00007ffff7def214 <+4>: mov    %rax,(%rsp)
   0x00007ffff7def218 <+8>: mov    %rcx,0x8(%rsp)
   0x00007ffff7def21d <+13>: mov    %rdx,0x10(%rsp)
   0x00007ffff7def222 <+18>: mov    %rsi,0x18(%rsp)
   0x00007ffff7def227 <+23>: mov    %rdi,0x20(%rsp)
   0x00007ffff7def22c <+28>: mov    %r8,0x28(%rsp)
   0x00007ffff7def231 <+33>: mov    %r9,0x30(%rsp)
   0x00007ffff7def236 <+38>: mov    0x40(%rsp),%rsi
   0x00007ffff7def23b <+43>: mov    0x38(%rsp),%rdi
   0x00007ffff7def240 <+48>: callq  0x7ffff7de8690 <_dl_fixup>
   0x00007ffff7def245 <+53>: mov    %rax,%r11
   0x00007ffff7def248 <+56>: mov    0x30(%rsp),%r9
   0x00007ffff7def24d <+61>: mov    0x28(%rsp),%r8
   0x00007ffff7def252 <+66>: mov    0x20(%rsp),%rdi
   0x00007ffff7def257 <+71>: mov    0x18(%rsp),%rsi
   0x00007ffff7def25c <+76>: mov    0x10(%rsp),%rdx
   0x00007ffff7def261 <+81>: mov    0x8(%rsp),%rcx
   0x00007ffff7def266 <+86>: mov    (%rsp),%rax
   0x00007ffff7def26a <+90>: add    $0x48,%rsp
   0x00007ffff7def26e <+94>: jmpq   *%r11
End of assembler dump.

disassemble命令反汇编指定函数得到上面的结果。可以看出程序最后跳转到 _dl_runtime_resolve这个函数,这个函数是用来完成函数绑定工作的。

这时再看看puts@plt的第一条指令,跳到0x601018查看:

(gdb) x 0x601018
0x601018 <puts@got.plt>: loopne 0x600fd6

对比之前的内容。得出结论是,第一次执行时,通过_dl_runtime_resolve解析到函数地址,并保存puts的地址到0x601018里,以后执行时就直接调用。


参考:http://www.cnblogs.com/xingyun/archive/2011/12/10/2283149.html








  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值