linux - 为什么派二进制文件不允许使用 "symbol@GOT"?

标签 linux assembly x86 position-independent-code got

这是示例程序集文件,test.s

.global main  
main:  
 mov __progname@GOT, %eax         // failed to compile
 mov __progname@GOT(%ebx), %eax   //succeed to compile

我尝试用 -pie 标志编译它,但失败了。

$ gcc -pie -o test test.s
osboxes@osboxes:/mnt/hgfs/VM_Shared/Reassemblabla/src$ gcc -pie -o test test.s
/usr/bin/ld: /tmp/ccPGMLlH.o: direct GOT relocation R_386_GOT32X against `__progname' without base register can not be used when making a shared object
/usr/bin/ld: failed to set dynamic section sizes: File format not recognized
collect2: error: ld returned 1 exit status

错误说,在 pie 二进制文件中,访问 GOT 条目只能使用基址寄存器。

问题。
我不知道为什么编译器会像上面那样提示。
更具体地说,为什么 pie 二进制文件不允许 __progname@GOT 寻址?



我的意见。
Loader 在加载 pie 二进制文件时知道 __progname@GOT 的地址。

因此,加载器可以在加载时简单地将此地址写入__progname@GOT 的位置。
这就是 loader 可以做的。

所以我不明白为什么编译器坚持像这样的寄存器相关访问
mov __progname@GOT(%ebx), %eax.

最佳答案

PIE 应该使用 pc 相对寻址; ia32 在这方面很糟糕,所以你需要做类似的事情:

    call thunk
    add  $_GLOBAL_OFFSET_TABLE__, %eax
    mov  __progname@GOT(%eax), %eax
    ret
thunk:
    mov (%esp), %eax
    ret

注意计算从这个程序地址到 _GLOBAL_OFFSET_TABLE__ 的偏移量以引用 GOT。因此,程序可以在任何地址加载(而不是链接或定位),并且会找到 GOT 和所有变量,因为相对偏移量是相同的。 作为引用,上面的 amd64 版本类似于:

mov    __progname(%rip), %rax
ret

请注意,这两者都使文本保持“纯”....

关于linux - 为什么派二进制文件不允许使用 "symbol@GOT"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53394184/

相关文章:

assembly - x86_64 程序集 : effects of the interrupt flag and TPR register

linux - 格式字符串错误 - 利用

c++ - 检查输入和 sleep boost 线程

assembly - 二进制到BCD转换

assembly - 想要在程序集中以空终止字符串,但出现段错误

c - 生成简单的 shell 二进制代码并复制到堆栈以防止堆栈溢出

assembly - 以下汇编代码行的含义是什么?

java - 在 Java 中使用 smartcardio 在 Raspberry Pi 上使用多个 NFC ACR122U 设备

linux - 如何更改几个子目录中多个文件中的一个字符串?

assembly - Intel 64/IA32 封装水平 ADD 用于四字?