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

问题描述 投票:0回答:1

我正在尝试尝试在汇编中写入控制台。我最终使用了 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] 似乎是唯一有效的。

windows assembly winapi x86-64 nasm
1个回答
1
投票

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

要修复此问题,请将

add rsp, 8
更改为
sub rsp, 32
。 (当然,删除更改 rbx 的指令。该函数不得在不保留其值的情况下更改 rbx。)

© www.soinside.com 2019 - 2024. All rights reserved.