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

Windows10 64位汇编中WriteConsoleA无法多次输出问题

问题原因分析

你代码里的核心错误是第二次调用WriteConsoleA时,把第一次调用的返回值当成了标准输出句柄传入,导致句柄无效,写入操作被系统拒绝。

具体来说:

  • 第一次调用GetStdHandle后,rax里是有效的标准输出句柄
  • 调用WriteConsoleA后,rax会被覆盖成该函数的返回值(BOOL类型,成功时为1,失败时为0)
  • 第二次调用WriteConsoleA时,你执行mov rcx, rax,此时rcx的值是1,不是真正的标准输出句柄,所以第二次写入完全无效。
修复方案

需要在首次获取句柄后,把它存到一个不会被后续函数调用覆盖的地方——要么用内存变量,要么用Windows x64调用约定里的非易失性寄存器(比如rbx,这类寄存器在函数调用后会保留原值)。

方案1:用内存变量保存句柄

修改后的完整代码:

section .data
    sum_msg db 'Sum: ', 0
    sum db '15', 0

section .bss
    num_bytes_written resq 1
    stdout_handle resq 1  ; 新增变量存标准输出句柄

section .text
    global _start

    extern GetStdHandle
    extern WriteConsoleA
    extern ExitProcess

_start:
    ; 获取标准输出句柄
    mov ecx, -11           ; STD_OUTPUT_HANDLE
    call GetStdHandle

    ; 检查句柄是否有效
    cmp rax, -1
    je .exit

    mov [stdout_handle], rax  ; 把有效句柄存到内存

    ; 输出"Sum: "
    mov rcx, [stdout_handle] ; 使用保存的句柄
    lea rdx, [rel sum_msg]
    mov r8d, 5             ; 消息长度("Sum: "共5个字节)
    lea r9, [rel num_bytes_written]
    call WriteConsoleA

    ; 输出"15"
    mov rcx, [stdout_handle] ; 再次用保存的句柄
    lea rdx, [rel sum]
    mov r8d, 2             ; "15"的字节数,不需要包含末尾的0
    lea r9, [rel num_bytes_written]
    call WriteConsoleA

    ; 循环防止程序直接退出
.loop:
    nop
    jmp .loop

.exit:
    ; 退出程序
    xor ecx, ecx           ; 退出码0
    call ExitProcess

方案2:用非易失性寄存器保存句柄

如果不想新增内存变量,可以用rbx(Windows x64调用约定中,rbx、rbp、r12-r15属于非易失性寄存器,函数调用不会修改它们的值):

; ... 其他部分不变 ...
_start:
    ; 获取标准输出句柄
    mov ecx, -11
    call GetStdHandle

    cmp rax, -1
    je .exit

    mov rbx, rax  ; 把句柄存到rbx

    ; 输出"Sum: "
    mov rcx, rbx ; 用rbx里的句柄
    ; ... 后续代码不变 ...

    ; 输出"15"
    mov rcx, rbx ; 再次用rbx里的句柄
    ; ... 后续代码不变 ...
额外注意事项
  1. Windows x64调用约定规则:
    • 函数前4个参数依次放在rcx、rdx、r8、r9中
    • 函数返回值存在rax里
    • 非易失性寄存器可以安全保存跨函数调用的数据,不用怕被覆盖
  2. WriteConsoleA的长度参数:这个函数不处理C风格的空终止字符串,直接按你指定的字节数输出,所以sum的长度写2就对了,不需要包含末尾的0。
验证修复

重新编译链接:

nasm -f win64 sum.asm -o sum.obj
gcc -nostdlib -o sum.exe sum.obj -lkernel32

运行后就能得到预期的Sum: 15输出。

内容的提问来源于stack exchange,提问作者kavi castelo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:33:22