为什么馅饼二进制不允许"symbol@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

错误表示,在饼图二进制中,只能使用基址寄存器访问GOT条目

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



我的看法
Loader在pie二进制文件的加载时间中知道__progname@GOT的地址。

所以,加载程序只需在加载时将该地址写入__progname@GOT的位置即可
这就是加载器所能做的。

所以我不明白为什么编译器坚持像
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

请注意,这两者都保持了文本的"纯净"。。。。

最新更新