Win64环境下NASM汇编程序无法向控制台输出的问题排查
问题根因
你把Linux系统的中断调用逻辑和Windows x64平台的API调用规则完全混淆了,代码存在多个根本性错误,编译链接没报错不代表逻辑正确,程序实际没有执行到有效输出逻辑,也没有正确触发进程退出。
具体错误点
- 错误使用
int指令调用Win32 API:你链接的WriteFile、ExitProcess是kernel32.dll导出的用户态函数,需要用call指令直接调用,不存在“给寄存器传系统调用号、触发软中断调API”的用法——int后面跟的是中断号,不是函数地址,你写的int WriteFile属于未定义行为,只是刚好没有触发崩溃,程序直接跳过了函数调用逻辑往下执行。 - 调用约定、参数完全不匹配:
- Windows x64的用户态函数调用,前四个参数按顺序放在
RCX/RDX/R8/R9寄存器,调用前需要给被调函数预留32字节的影子空间,且栈要16字节对齐,你完全没有遵守这个约定。 - 你代码里写的
rbx=1(stdout文件描述符)、rdx=4(sys_write系统调用号)是Linux平台的规则,Windows上完全不生效:Windows的控制台标准输出句柄不是硬编码的1,需要调用GetStdHandle传入参数-11(即STD_OUTPUT_HANDLE)才能拿到。 WriteFile的参数顺序你完全传错了,它需要5个参数:控制台句柄、缓冲区指针、写入长度、实际写入长度的输出指针、重叠结构指针,你之前的寄存器赋值完全不符合要求。
- Windows x64的用户态函数调用,前四个参数按顺序放在
- 换行符不符合Windows控制台规范:你用的单独
0xa(即\n)在部分Windows控制台环境下不会触发行缓冲刷新,应该用Windows标准的CRLF换行(0xd,0xa即\r\n)。
修正后的可运行代码
extern GetStdHandle extern WriteFile extern ExitProcess section .text global Start Start: sub rsp, 28h ; 预留32字节影子空间 + 调整栈到16字节对齐,共40字节(0x28) ; 获取标准输出句柄 mov rcx, 0FFFFFFFFFFFFFFF5h ; STD_OUTPUT_HANDLE 常量值为-11 call GetStdHandle ; 调用WriteFile输出字符串 mov rcx, rax ; 参数1:刚拿到的stdout句柄 mov rdx, msg ; 参数2:字符串起始地址 mov r8, len ; 参数3:字符串长度 mov r9, bytes_written ; 参数4:接收实际写入字节数的变量指针 mov qword [rsp + 20h], 0 ; 参数5:lpOverlapped传NULL,放在栈上影子空间之后 call WriteFile ; 退出进程,返回码0 mov rcx, 0 call ExitProcess section .data msg db 'Hello, world!', 0dh, 0ah ; 字符串+CRLF换行 len equ $ - msg section .bss bytes_written resq 1 ; 预留8字节存储实际写入长度
编译运行命令
和你之前用的命令一致,直接执行即可正常输出:
nasm -f win64 -o hello_world.obj hello_world.asm golink hello_world.obj kernel32.dll hello_world.exe
内容的提问来源于stack exchange,提问作者JNichols
相关产品推荐
相关产品推荐

