使用mingw-w64编译x86汇编时遇R_X86_64_32S重定位错误求解
解决MingW编译AT&T汇编的重定位错误与运行问题
错误原因解析
- 重定位错误:x64 Windows的PE可执行文件中,符号地址可能超出32位范围,直接用
mov $hello, %rdi这种32位立即数寻址会触发R_X86_64_32S截断错误。改用RIP相对寻址可以避免这个问题,无需使用movabs。 - 调用约定不匹配:你的代码使用的是Linux的SysV x64调用约定(参数存在RDI/RDX等),但Windows x64采用Microsoft调用约定,前4个参数需放在
RCX/RDX/R8/R9,且栈要保持16字节对齐。
修正后的代码
.text hello: .asciz "Hello World!\n" .global main main: push %rbp mov %rsp, %rbp sub $16, %rsp # 保证栈16字节对齐(Windows x64调用约定要求) mov $0, %rax # 无浮点参数,AL设为0 lea hello(%rip), %rcx # RIP相对寻址加载字符串地址到RCX(第一个参数寄存器) call printf mov $0, %rcx # exit函数的参数放在RCX call exit mov %rbp, %rsp pop %rbp ret
编译命令
保持你原来的命令即可:
x86_64-w64-mingw32-gcc -o test test.s
关键修改点
- RIP相对寻址:用
lea hello(%rip), %rcx替代mov $hello, %rdi,既解决了32位地址截断问题,又符合x64 PE的寻址规范。 - 调用约定适配:
- 将字符串地址从
RDI移到RCX(Windows x64第一个参数寄存器)。 exit函数的参数从RDI移到RCX。- 新增
sub $16, %rsp保证栈16字节对齐(调用函数前必须满足的要求)。
- 将字符串地址从
后续Windows API开发提示
如果要调用Windows原生API(比如创建窗口),需要注意:
- 所有API遵循Microsoft x64调用约定,参数按
RCX/RDX/R8/R9顺序传递。 - 需要链接对应系统库,比如
kernel32.dll(ExitProcess)、user32.dll(CreateWindowEx)等,MingW会自动处理大部分常用库的链接。 - 部分Windows API仅支持宽字符版本(如
CreateWindowExW),需注意字符串编码适配。
内容的提问来源于stack exchange,提问作者Floris van Onna
相关产品推荐
相关产品推荐

