從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 <[email protected]>: 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 <[email protected]>: loopne 0x600fd6

對比之前的內容。得出結論是,第一次執行時,通過_dl_runtime_resolve解析到函數地址,並保存puts的地址到0x601018裏,以後執行時就直接調用。


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








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章