You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 00:01:31