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

如何让GCC恢复函数中使用的$rdx寄存器?汇编与C混合编译的寄存器未恢复问题问询

解答你的汇编与C代码编译问题

先帮你理清两个核心疑问,再处理链接警告的问题:

疑问1:为什么stringEqual中使用了rdx却未恢复?

这是对x86-64 System V调用约定的误解。在这个约定里,寄存器被明确分成两类:

  • 被调用者保存寄存器(Callee-saved):rbp、rbx、r12-r15,被调用函数必须保证这些寄存器的值在返回时和进入时一致(你看到stringEqual开头push %rbp、结尾leave恢复rbp,这完全符合规范)。
  • 调用者保存寄存器(Caller-saved):rax、rdi、rsi、rdx、rcx、r8、r9,这类寄存器被调用函数可以随意修改,不需要恢复。如果调用者需要保留这些寄存器的值,必须在调用函数前自行保存(比如push到栈上)。

你的stringEqual里rdx属于调用者保存寄存器,所以它完全不需要恢复rdx的值。真正的问题出在你的汇编代码prog.asm里:调用stringEqual前,你把checked_malloc的返回值存在了rdx里,但调用stringEqual后,rdx的值被破坏了(因为stringEqual内部调用的strcmp也会修改rdx),导致后续代码使用rdx时拿到错误值。

疑问2:如何设置GCC让它恢复函数内部使用的寄存器?

其实不需要额外设置GCC——GCC生成的代码已经严格遵循x86-64调用约定了。你需要修正的是汇编代码里的调用者逻辑:在调用stringEqual前,把需要保留的rdx寄存器值保存到栈上,调用完成后再恢复。比如修改prog.asm:

; 在调用stringEqual前保存rdx
push rdx
mov rsi, [rdx + 0]
call stringEqual
; 调用完成后恢复rdx
pop rdx

处理链接警告

你遇到的两个链接警告和寄存器问题无关,是PIE(位置无关可执行文件)相关的:

  1. relocation in read-only section '.text' 和 creating DT_TEXTREL in a PIE:你的汇编代码里使用了绝对地址寻址(比如mov rdi, L11),而GCC默认生成PIE,这类绝对寻址会导致只读的.text段需要重定位,从而触发警告。

解决方法有两种:

方法1:禁用PIE编译

修改编译命令,添加-no-pie参数:

gcc prog.o runtime.c -g -no-pie -o run.out

生成非位置无关的可执行文件后,绝对地址寻址就不会触发警告了。

方法2:修改汇编代码使用RIP相对寻址

把汇编里的绝对地址引用改成RIP相对的形式,比如:

; 把 mov rdi, L11 改成
lea rdi, [rip + L11]
; 同理,mov rdi, L12 改成
lea rdi, [rip + L12]
; mov rdi, L13 改成
lea rdi, [rip + L13]

这种方式符合PIE的要求,不会产生重定位警告。


内容的提问来源于stack exchange,提问作者Shore

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 18:42:42