为什么 Windows API WriteFile 要求将 rbx 设置为 [rsp]?

0 windows assembly winapi x86-64 nasm

我正在尝试尝试在汇编中写入控制台。我最终使用了 Windows API WriteFile 函数。它运作良好,但我遇到了一个奇怪的怪癖。如果我没有将 rbx 寄存器设置为 [rsp],则 WriteFile 不会返回并给出错误代码 0xC0000005,这是访问冲突错误。它仍然可以正确写入控制台,我觉得这很奇怪。这不是问题,我可以包含一行,没问题。但这让我很困扰,因为我无法弄清楚为什么会出现这种行为。

如果它确实有帮助,我将使用 NASM 和 GCC 来编译我的程序。

这是上下文的完整代码:

bits 64
default rel

extern GetStdHandle
extern WriteFile
extern ExitProcess

section .data
buffer db 0

section .text

print:
    push    rbp
    mov     rbp, rsp
    add     rsp, 8

    mov     rcx, -11
    call    GetStdHandle
    mov     rcx, rax

    mov     rax, 0x61616161
    mov     [buffer], rax
    mov     rdx, buffer
    mov     r8, 4

    mov     rbx, [rsp]
    call    WriteFile

    mov     rsp, rbp
    pop     rbp

    ret


global main
main:
    call    print

    mov     rcx, 0
    call    ExitProcess
Run Code Online (Sandbox Code Playgroud)

我尝试移动函数的内容来替换call print,在这种情况下,即使没有mov rbx, [rsp]. 我还尝试将 rbx 寄存器设置为其他值,但 [rsp] 似乎是唯一有效的。

prl*_*prl 5

Windows 调用约定要求调用者在返回地址上方的堆栈上提供 32 字节的可用空间,以供被调用函数使用。由于未提供此空间,WriteFile 函数会覆盖调用方堆栈的部分内容。特别是,它用 rbx 中的值覆盖返回地址。使用返回地址加载 rbx 会掩盖此错误。

要修复它,请更改add rsp, 8sub rsp, 32. (当然,删除更改 rbx 的指令。该函数不得在不保留 rbx 值的情况下更改 rbx。)