![](/img/trans.png)
[英]undefined reference to `_GLOBAL_OFFSET_TABLE_' in gcc 32-bit code for a trivial function, freestanding OS
[英]Why can nasm assembly with unqualified references to _GLOBAL_OFFSET_TABLE_ apparently be assembled and linked as PIC?
當get_got.asm
包含對其GOT絕對地址的引用時,為什么我可以將get_got.asm
作為位置無關的代碼進行匯編和鏈接?
get_got.asm
extern _GLOBAL_OFFSET_TABLE_
section .text
global get_got
get_got:
mov rax, _GLOBAL_OFFSET_TABLE_
ret
main.c中
#include <stdio.h>
void* get_got(void);
int main(int argc, char* argv[]) {
printf("%p\n", get_got());
}
組裝,編譯,鏈接,運行:
nasm -felf64 -o get_got.o get_got.asm
gcc -fPIC -shared -o get_got.so get_got.o
gcc -Wl,-rpath=\$ORIGIN -o main main.c get_got.so
./main
0x148ba1cba000
這里發生了什么? 在我看來,它就像get_got.so一樣,以某種方式為GOT提供了一個固定的絕對地址,直到運行時它才知道地址。 反匯編get_got.so表明mov實際上包含立即數(0x201000)。 顯然我對某件事有重大誤解。 我希望這會導致nasm生成鏈接器阻塞的重定位。
我使用lea rax, [rel _GLOBAL_OFFSET_TABLE_]
構建了您的代碼和修改后的版本。
我readelf -a
了readelf -a
輸出。 但是,來自不同地址的噪音很多。
readelf -a get_got.so | diff -u - <(readelf -a get_got_rel.so) | less
最有趣的區別是:
--- readelf -a get_got.so
+++ readelf -a get_got_rel.so
....
-Dynamic section at offset 0xe40 contains 22 entries:
+Dynamic section at offset 0xe50 contains 21 entries:
...
- 0x0000000000000016 (TEXTREL) 0x0
0x000000006ffffffe (VERNEED) 0x3b0
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0x398
- 0x000000006ffffff9 (RELACOUNT) 4
+ 0x000000006ffffff9 (RELACOUNT) 3
因此,絕對版本具有文本重定位 。 我不知道Linux / ELF動態鏈接可以在映射共享庫后應用修正。 但顯然可以。 (最好不要這樣做,因為它會使內存頁面變臟,因此它不再只是由磁盤上的文件支持。)
但是我檢查了GDB,這就是正在發生的事情:在get_got
設置一個斷點並運行它:
(gdb) disas
Dump of assembler code for function get_got:
=> 0x00007f9e77b235b0 <+0>: movabs rax,0x7f9e77d24000
0x00007f9e77b235ba <+10>: ret
objdump -dRC -Mintel get_got.so
:(注意不帶-w
換行):
00000000000005b0 <get_got>:
5b0: 48 b8 00 10 20 00 00 movabs rax,0x201000
5b7: 00 00 00
5b2: R_X86_64_RELATIVE *ABS*+0x201000
5ba: c3 ret
感謝@Jester提供-R
技巧; 我通常使用objdump -dr ...
,而不是-R
,小寫的r不會為.so
打印任何重定位。
在get_got.o
, -r
顯示movabs rax,0x0 2: R_X86_64_64 _GLOBAL_OFFSET_TABLE_
。
gcc -nostdlib -pie
也將64位絕對重定位鏈接到PIE可執行文件中。 (PIE可執行文件是 ELF共享對象)。
PIC / PIE中不允許的是32位絕對重定位: x86-64 Linux中不再允許32位絕對地址? 。 您收到一個鏈接器錯誤。 諸如array[rcx*4]
類的尋址模式在PIC / PIE代碼中不可用,您需要單獨的指令才能將地址放入寄存器。
lea rdi, [rel array]
比64位立即絕對一個更好的選擇,因為它的體積更小,更友好的微指令緩存中,並加載時不需要修正。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.