使用NASM与WinAPI编写Hello World无输出,请求排查问题
排查Win64 NASM程序无输出问题
我用Netwide Assembler(NASM)编写输出Hello World的Win64汇编程序,编译运行后无任何输出,但退出状态为0(成功)。程序遵循x64调用约定传递参数:首参数入RCX,次参数入RDX,第三入R8,第四入R9,第五放在[RSP + 32]。
程序代码
section .data phrase db 'Hello World' ; 定义字符串字节变量 charsWritten dd 0 ; 存储实际写入字符数的变量 section .text global _start extern ExitProcess ; 导入退出程序函数 extern WriteConsoleA ; 导入控制台输出函数 extern GetStdHandle ; 导入标准句柄获取函数 _start: mov rcx, -10 ; 传入STD_OUTPUT_HANDLE常量值-10 call GetStdHandle ; 调用后句柄保存在rax中 mov r8, rax ; 保存标准输出句柄到r8 mov rcx, r8 ; 第一个参数:标准输出句柄 mov rdx, phrase ; 第二个参数:字符串指针 mov r8, 11 ; 第三个参数:字符串长度11 mov r9, charsWritten ; 第四个参数:charsWritten的指针 mov qword [rsp + 32], 0 ; 第五个参数:保留参数设为0 call WriteConsoleA ; 调用输出函数 mov rcx, 0 ; ExitProcess参数:退出码0 call ExitProcess ; 退出程序
编译运行步骤
C:\Users\Мила ПК\Desktop>nasm -f win64 test.asm -o test.o C:\Users\Мила ПК\Desktop>ld -o test.exe test.o -lkernel32 C:\Users\Мила ПК\Desktop>test.exe C:\Users\Мила ПК\Desktop>echo %ERRORLEVEL% 0
环境信息
| 参数 | 值 |
|---|---|
| 操作系统 | Windows 11 Pro |
| 系统架构 | 64位 |
| 处理器 | Intel i7 |
问题原因分析
程序无输出的核心问题是栈对齐不符合Win64调用约定:
Win64调用约定明确要求,执行call指令调用函数前,栈指针RSP必须保持16字节对齐。_start入口点处栈是16字节对齐状态,但调用GetStdHandle时,call指令会将8字节的返回地址压入栈,导致RSP偏移8字节,不再满足对齐要求。后续调用WriteConsoleA时,栈未恢复对齐状态,触发函数调用行为异常,最终没有执行输出操作。
另外代码中存在一个参数保存的风险:调用GetStdHandle后将句柄存入r8,但后续又用r8传递WriteConsoleA的第三个参数,会覆盖之前保存的句柄值——好在代码中紧接着将r8赋值给rcx,刚好在覆盖前完成了句柄传递,未直接引发错误,但写法不严谨。
修正后的代码
section .data phrase db 'Hello World' charsWritten dd 0 section .text global _start extern ExitProcess extern WriteConsoleA extern GetStdHandle _start: ; 入口处预留32字节影子空间,同时保持栈16字节对齐(32是16的倍数) sub rsp, 32 mov rcx, -10 call GetStdHandle ; 调用GetStdHandle后栈偏移8字节,调整回16对齐 sub rsp, 8 mov rcx, rax ; 1st参数:标准输出句柄 mov rdx, phrase ; 2nd参数:字符串指针 mov r8, 11 ; 3rd参数:字符串长度 mov r9, charsWritten ; 4th参数:charsWritten指针 mov qword [rsp + 32], 0 ; 5th参数:保留参数 call WriteConsoleA ; 恢复栈空间后调用ExitProcess add rsp, 40 mov rcx, 0 call ExitProcess
内容的提问来源于stack exchange,提问作者Nair
相关产品推荐
相关产品推荐

