2015-10-13 57 views
0

最近我看了一下plt和如何實現,並編寫了一段如下所示的用於跟蹤的示例代碼。而且我看到了一些讓我困惑的事情。共享圖庫中的全局變量在32位和64位二進制中以及它的位置有不同的訪問方式?

got.c

#include <stdio.h> 
static int static_data; 
int global_data; 
extern int count; 

int 
main(void) 
{ 
    static_data = 12; 
    global_data = 32; 

    add_count(); 
    count += static_data; 
    count += global_data; 

    printf("error, %p\n", &count); 

    return count; 
} 

extern.c

#include <errno.h> 
#include <stdio.h> 

int count = 0x1; 

void 
add_count(void) 
{ 
    errno = 0xdead; 
    count += errno; 
    fprintf(stdout, "%p\n", &count); 
    fprintf(stdout, "%p\n", &count); 
    fprintf(stdout, "%p\n", &count); 
} 

並編譯如下:

gcc -shared -fpic extern.c -o extern.so 
sudo cp extern.so /lib/libextern.so 
gcc -g got.c -o got.bin -lextern 

問題1:在libextern計數 爲什麼全局變量的地址。那麼是0x601048?

問題2: 用於外部符號,使用.plt和.got.plt進行延遲綁定,但對於像count這樣的全局變量,爲什麼32位使用get_pc_thunk來引用.got,而64位只是0xXXX(% rip)來處理.got?或者32位可以使用這種rip + offset方式來處理libextern.so的.got?

在此先感謝!

當-m32編譯函數ADD_COUNT:

550 5bf: 83 ec 14    sub $0x14,%esp 
551 5c2: e8 c9 fe ff ff   call 490 <__x86.get_pc_thunk.bx> 
552 5c7: 81 c3 39 1a 00 00  add $0x1a39,%ebx 
553 5cd: e8 ae fe ff ff   call 480 <[email protected]> 
554 5d2: c7 00 ad de 00 00  movl $0xdead,(%eax) 
555 5d8: e8 a3 fe ff ff   call 480 <[email protected]> 
556 5dd: 8b 10     mov (%eax),%edx 
557 5df: 8b 83 e4 ff ff ff  mov -0x1c(%ebx),%eax 
558 5e5: 8b 00     mov (%eax),%eax 
559 5e7: 01 c2     add %eax,%edx 

當功能ADD_COUNT編譯爲X86_64 64位:

567 789: e8 d2 fe ff ff   callq 660 <[email protected]> 
568 78e: c7 00 ad de 00 00  movl $0xdead,(%rax) 
569 794: e8 c7 fe ff ff   callq 660 <[email protected]> 
570 799: 8b 10     mov (%rax),%edx 
571 79b: 48 8b 05 26 08 20 00 mov 0x200826(%rip),%rax  # 200fc8 <_DYNAMIC+0x1c0> 
572 7a2: 8b 00     mov (%rax),%eax 
573 7a4: 01 c2     add %eax,%edx 

MMAP FYI

00400000-00401000 r-xp 00000000 08:01 1975032       /home/pli/validation/got.bin 
00600000-00601000 r--p 00000000 08:01 1975032       /home/pli/validation/got.bin 
00601000-00602000 rw-p 00001000 08:01 1975032       /home/pli/validation/got.bin 
7ffff7813000-7ffff79ce000 r-xp 00000000 08:01 5771356     /lib/x86_64-linux-gnu/libc-2.19.so 
7ffff79ce000-7ffff7bcd000 ---p 001bb000 08:01 5771356     /lib/x86_64-linux-gnu/libc-2.19.so 
7ffff7bcd000-7ffff7bd1000 r--p 001ba000 08:01 5771356     /lib/x86_64-linux-gnu/libc-2.19.so 
7ffff7bd1000-7ffff7bd3000 rw-p 001be000 08:01 5771356     /lib/x86_64-linux-gnu/libc-2.19.so 
7ffff7bd3000-7ffff7bd8000 rw-p 00000000 00:00 0 
7ffff7bd8000-7ffff7bd9000 r-xp 00000000 08:01 5767525     /lib/libextern.so 
7ffff7bd9000-7ffff7dd8000 ---p 00001000 08:01 5767525     /lib/libextern.so 
7ffff7dd8000-7ffff7dd9000 r--p 00000000 08:01 5767525     /lib/libextern.so 
7ffff7dd9000-7ffff7dda000 rw-p 00001000 08:01 5767525     /lib/libextern.so 
7ffff7dda000-7ffff7dfd000 r-xp 00000000 08:01 5771353     /lib/x86_64-linux-gnu/ld-2.19.so 
7ffff7fed000-7ffff7ff0000 rw-p 00000000 00:00 0 
7ffff7ff8000-7ffff7ffa000 rw-p 00000000 00:00 0 
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0       [vdso] 
7ffff7ffc000-7ffff7ffd000 r--p 00022000 08:01 5771353     /lib/x86_64-linux-gnu/ld-2.19.so 
7ffff7ffd000-7ffff7ffe000 rw-p 00023000 08:01 5771353     /lib/x86_64-linux-gnu/ld-2.19.so 
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0       [stack] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0     [vsyscall] 

回答

0

這是正常的,當您切換架構...只需檢查鏈接腳本即可查看內存映射的不同。

+0

謝謝,這意味着我可以使用64位二進制鏈接腳本的方式在32位二進制,對不對? –

+0

可能不是......這就像是說:那麼我可以在我的IPv4平臺中使用IPv6地址的整個空間。只是他們不適合。 64允許64位內存(超過32位的crunchillon字節允許)認爲虛擬地址的空間是64位可尋址的,而舊的只有32位。對於你現在32位的每個地址,現在你有32位地址的全部範圍來傳播一個進程的虛擬內存。 –

+0

得到了,它幾乎取決於,謝謝,:-) –

0

最後,我找到了這個問題的答案,並放在這裏爲某人可能需要這個。 1.對於fPIC構建庫,每個全局變量將被視爲定義的外部變量,並且在主可執行文件.bss節中有一個此變量的副本。 2.看來,在IA 32位彙編中,我們無法獲得%eip寄存器作爲基址寄存器。