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

cotxawn7  于 2023-10-19  发布在  Windows
关注(0)|答案(1)|浏览(98)

我正在尝试用汇编语言写控制台。我最终使用了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

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

ki0zmccv

ki0zmccv1#

Windows调用约定要求调用方在返回地址上方的堆栈上提供32字节的可用空间,以供调用的函数使用。由于未提供此空间,因此WriteFile函数将覆盖调用方堆栈的部分。特别是,它使用rbx中的值来替换返回地址。使用返回地址加载rbx可以掩盖这个错误。
要修复它,请将add rsp, 8更改为sub rsp, 32。(当然,删除更改rbx的指令。函数不能改变rbx而不保留其值。)

相关问题