【发布时间】:2018-11-20 13:33:51
【问题描述】:
这里是示例汇编文件,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 的位置。
这就是装载机可以做的。
所以我不明白为什么编译器坚持像 mov __progname@GOT(%ebx), %eax 这样的寄存器相对访问。
【问题讨论】:
-
Loader 通常不会写入代码部分,因为这会破坏跨进程的共享,这对库很重要。它对可执行文件不是特别有用,但由于 PIE 是建立在相同功能之上的,因此不允许这样做。
-
@Jester 但是......当我们使用直接内存访问时,加载程序会写入代码部分。例如,当我们使用
mov MY_SYMBOL, %eax之类的指令并将其编译为饼图二进制文件时,MY_SYMBOL的地址直到加载时才固定。在这种情况下,加载程序在加载时将MY_SYMBOL的地址写入<.text>部分。 -
是的,从技术上讲这是可能的,但 GOT 的全部意义在于避免代码中的重定位。如果您可以接受搬迁,则不需要 GOT,只需使用您展示的简单搬迁即可。
-
@Jester 哦,这很有意义。是的,你是对的。我们使用 GOT 来避免代码中的重定位,而使用 relocaion 访问 GOT 部分很奇怪……就像自相矛盾。感谢您的评论!
-
有趣的问题。这个source 有一条关于 GOT 地址对于 PIC 未知的评论。我不知道为什么共享库会出现这种情况,本地 GOT 是已知的。也许他们在谈论另一个模块的 GOT?还允许使用
lea(记录在 ABI 中)。最后,似乎算法的描述是骗人的,.got部分的 end 被减去。我现在想不出任何原因。
标签: linux assembly x86 position-independent-code got