簡體   English   中英

為什么帶有_GLOBAL_OFFSET_TABLE_的不合格引用的nasm組裝顯然可以作為PIC進行組裝和鏈接?

[英]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 -areadelf -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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM