You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 15:32:15