Windows 64位NASM代码使用变量时无输出,求原因及解决方法
Windows 64位NASM代码变量参数传递的重定位错误解决
问题代码
extern GetStdHandle, WriteConsoleA, ExitProcess section .text _main: mov rcx, STD_OUTPUT_HANDLE call GetStdHandle mov rcx, rax ; hConsoleOutput mov rdx, msg ; *lpBuffer mov r8, len ; nNumberOfCharsToWrite ;mov r9, 0 ; lpNumberOfCharsWritten ;push 0 ; lpReserved call WriteConsoleA mov rcx, 0 call ExitProcess section .data STD_OUTPUT_HANDLE: dq -11 msg: db "Hello World!", 0x0A len equ $-msg
问题现象
- 代码编译链接正常,但运行无输出
- 替换
mov rcx, STD_OUTPUT_HANDLE为mov rcx, -11可正常输出,但希望使用变量形式 - 修改为
mov rcx, [STD_OUTPUT_HANDLE]时出现重定位错误:main.obj:main.asm:(.text+0x4): relocation truncated to fit: IMAGE_REL_AMD64_ADDR32 against '.data' - 编译链接命令:
nasm -fwin64 main.asm && ld -LC:/Windows/System32 -lkernel32 -o main.exe main.obj
问题分析
- 原代码
mov rcx, STD_OUTPUT_HANDLE传递的是变量的内存地址,而非变量存储的-11值,导致GetStdHandle收到非法参数,调用失败无输出。 - 使用
mov rcx, [STD_OUTPUT_HANDLE]时,NASM默认生成32位绝对地址重定位,但64位Windows程序的.data段地址是64位的,超出32位范围,因此触发截断错误。
解决方法
在64位NASM代码中,需使用RIP相对寻址来访问数据段变量,明确生成符合64位PE规范的重定位。将mov rcx, STD_OUTPUT_HANDLE修改为:
mov rcx, [rel STD_OUTPUT_HANDLE]
修改后的完整代码
extern GetStdHandle, WriteConsoleA, ExitProcess section .text _main: mov rcx, [rel STD_OUTPUT_HANDLE] call GetStdHandle mov rcx, rax ; hConsoleOutput mov rdx, [rel msg] ; 可选:同样用RIP相对寻址访问msg mov r8, len ; len是汇编时计算的常量,无需修改 ;mov r9, 0 ; lpNumberOfCharsWritten push 0 ; lpReserved(注:原代码注释掉了,这里建议保留以符合Win64调用约定) call WriteConsoleA mov rcx, 0 call ExitProcess section .data STD_OUTPUT_HANDLE: dq -11 msg: db "Hello World!", 0x0A len equ $-msg
注:Win64调用约定中,WriteConsoleA的第五个参数需要通过栈传递,原代码注释掉了push 0,建议保留以保证参数完整。
内容的提问来源于stack exchange,提问作者user2868758
相关产品推荐
相关产品推荐

