我正在尝试尝试在汇编中写入控制台。我最终使用了 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 调用约定要求调用者在返回地址上方的堆栈上提供 32 字节的可用空间,以供被调用函数使用。由于未提供此空间,WriteFile 函数会覆盖调用方堆栈的部分内容。特别是,它用 rbx 中的值覆盖返回地址。使用返回地址加载 rbx 会掩盖此错误。
要修复此问题,请将
add rsp, 8
更改为 sub rsp, 32
。 (当然,删除更改 rbx 的指令。该函数不得在不保留其值的情况下更改 rbx。)