GetStdHandle获取的标准输出句柄二次调用WriteFile时无效
问题分析:二次调用WriteFile返回ERROR_INVALID_HANDLE的原因及修复
你的问题核心在于违反了Windows x64调用约定的栈平衡规则:
Windows x64平台下,当函数参数超过4个时,多余参数需通过栈传递,且调用者必须在函数返回后手动清理栈上的参数。你的代码中调用WriteFile时,通过push 0传递了第五个参数(LPOVERLAPPED),但调用完成后未执行add rsp, 8恢复栈指针,导致后续栈操作的位置全部错位,最终引发第二次WriteFile调用时的无效句柄错误。
同时,Windows x64要求调用任何函数前栈指针必须是16字节对齐,栈未平衡会导致后续调用(如GetLastError、第二次WriteFile)的栈对齐违反约定,加剧未定义行为——第一次调用WriteFile正常只是偶然情况,栈错位后的操作必然引发错误。
修复后的代码
在每次WriteFile调用后添加栈平衡指令,恢复栈指针位置:
.intel_syntax noprefix .section .data msg: .ascii "Hello, World" msg1: .ascii "Hello, World\n" .section .text .global _start _start: call _main mov rcx, 0 call ExitProcess _main: push rbp mov rbp, rsp sub rsp, 32 mov rcx, -11 call GetStdHandle mov rbx, rax ; 第一次调用WriteFile,调用后平衡栈 mov rcx, rbx lea rdx, [rip + msg1] mov r8, 13 lea r9, [rbp - 4] push 0 call WriteFile add rsp, 8 ; 清理栈上的第五个参数 call GetLastError ; 第二次调用WriteFile,调用后平衡栈 mov rcx, rbx lea rdx, [rip + msg] mov r8, 12 lea r9, [rbp - 4] push 0 call WriteFile add rsp, 8 ; 清理栈上的第五个参数 call GetLastError mov rsp, rbp pop rbp ret
修复说明
- 每次调用WriteFile后执行
add rsp, 8,将栈指针恢复到push参数前的位置,保证后续操作的栈对齐和参数传递正确。 - 栈平衡后,栈指针始终符合Windows x64调用约定,第二次WriteFile调用时,rbx中存储的标准输出句柄能被正确传递,不会出现无效句柄错误。
内容的提问来源于stack exchange,提问作者Apple Pie
相关产品推荐
相关产品推荐

