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

为何无法直接从全局变量加载值到寄存器?链接错误解析

汇编访问C全局变量的链接错误问题

问题代码

main.c

int NUM;

extern void exitprocnow();

int main(void) {
    NUM = 10;
    exitprocnow();
    return 1;
}

exitprocnow.asm(出错版本)

[bits 64]
extern NUM
extern ExitProcess

section .text
    global exitprocnow

exitprocnow:
    mov rcx, [NUM]
    call ExitProcess

编译错误信息

$> nasm -f win64 .\exitproc.asm -o call.o
$> gcc .\main.c .\call.o -lkernel32
.\call.o:.\exitproc.asm:(.text+0x4): relocation truncated to fit: IMAGE_REL_AMD64_ADDR32 against symbol "NUM" defined in .bss section in C:\Users\YO\AppData\Local\Temp\cccoJTdm.o
collect2.exe: error: ld returned 1 exit status

可行的汇编代码

exitprocnow:
    mov rdx, NUM
    mov rcx, [rdx]
    call ExitProcess

疑问

  1. 为何无法直接将全局变量的值加载到寄存器?
  2. 上述链接错误的具体含义是什么?

问题解答

1. 直接加载全局变量值失败的原因

在Windows x64(AMD64)平台上,全局变量的地址是64位的,但mov rcx, [NUM]这种写法,NASM默认会生成使用32位绝对地址偏移的内存访问指令。如果全局变量NUM的实际地址超出了32位整数的表示范围(Windows x64进程地址空间本身是64位,变量可能被分配到高地址区域),32位的偏移量就无法容纳完整的64位地址,导致链接时无法完成地址重定位。

而先执行mov rdx, NUM再mov rcx, [rdx]的写法是正确的:mov rdx, NUM会生成适配x64的寻址方式(通常是RIP相对寻址或直接加载64位绝对地址),能正确获取NUM的64位地址,之后通过寄存器间接访问内存就能拿到变量的值。

2. 链接错误的具体含义

这条错误的核心是重定位类型不匹配导致地址截断:

  • 汇编器为mov rcx, [NUM]生成了IMAGE_REL_AMD64_ADDR32类型的重定位项,也就是指令里预留了32位空间来存放NUM的绝对地址。
  • 链接时发现NUM的实际地址是64位的,无法塞进32位的预留空间里,只能截断地址来适配,而这会导致地址无效,因此链接器抛出错误,提示“重定位截断以适配”。

简单来说:你试图用32位的地址空间去存放一个64位的全局变量地址,空间不够,链接器无法完成地址填充,所以报错。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 18:25:17