使用@GOT而非@GOTPCREL(%rip)引发段错误的原因咨询
GNU汇编中@GOT与@GOTPCREL(%rip)的差异导致段错误的原因
我在调试GNU汇编和重定位类型时发现,只用@GOT替代@GOTPCREL(%rip)会导致程序段错误,不清楚问题出在哪。
出错的汇编代码
.text .global main main: sub $8, %rsp leaq hello(%rip), %rdi call *printf@GOT movq $60, %rax syscall .data hello: .string "Hello, World!\n"
编译命令:gcc test.S -o test
正常运行的汇编代码
.text .global main main: sub $8, %rsp leaq hello(%rip), %rdi call *printf@GOTPCREL(%rip) movq $60, %rax syscall .data hello: .string "Hello, World!\n"
编译命令:gcc test.S -o test
原因解析
1. @GOT的问题所在
@GOT对应的是R_X86_64_GOT重定位类型,它会生成一个指向GOT(全局偏移表)条目的绝对虚拟地址。但现在gcc默认编译生成PIE(位置无关可执行文件),程序运行时的加载地址是随机分配的,编译时的绝对虚拟地址和运行时的实际地址不匹配,直接调用这个错误的地址就会触发段错误。
2. @GOTPCREL(%rip)的工作原理
@GOTPCREL(%rip)对应的是R_X86_64_GOTPCREL重定位类型,这是x86_64平台位置无关代码的标准实现方式:
%rip寄存器保存的是当前指令的下一条指令地址- 通过计算当前
%rip到GOT条目的偏移量来获取实际地址,这个偏移量在编译时就确定了,不受程序加载地址的影响 - 最终能正确找到GOT中保存的printf函数的实际运行地址,所以调用不会出错
额外说明
如果非要让@GOT版本的代码运行,可以用gcc -no-pie test.S -o test编译,关闭PIE模式后程序会以绝对地址加载,@GOT生成的绝对地址就能匹配运行时地址,但这种方式会丧失地址随机化的安全特性,不推荐在实际场景中使用。
内容的提问来源于stack exchange,提问作者user108813
相关产品推荐
相关产品推荐

