为什么具有对_GLOBAL_OFFSET_TABLE_的非限定引用的nasm程序集显然可以组装并链接为PIC?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么具有对_GLOBAL_OFFSET_TABLE_的非限定引用的nasm程序集显然可以组装并链接为PIC?相关的知识,希望对你有一定的参考价值。
为什么我可以组合和链接get_got.asm
作为位置无关代码,当它包含对其GOT的绝对地址的引用时?
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
", 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 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动态链接可以在映射共享库之后应用fixup。但显然它可以。 (最好不要这样做,因为它会弄脏内存页面,因此它不再仅仅受磁盘上文件的支持。)
但我检查了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位绝对重定位:32-bit absolute addresses no longer allowed in x86-64 Linux?。您收到链接器错误。像array[rcx*4]
这样的寻址模式在PIC / PIE代码中不可用,需要单独的指令将地址输入寄存器。
lea rdi, [rel array]
是一个比64位立即绝对更好的选择,因为它对uop缓存更小,更友好,并且在加载时不需要修复。
以上是关于为什么具有对_GLOBAL_OFFSET_TABLE_的非限定引用的nasm程序集显然可以组装并链接为PIC?的主要内容,如果未能解决你的问题,请参考以下文章