使用 NASM 和 Mingw-w64 我一直在尝试运行以下程序,该程序应该使用 Windows API 将消息打印到屏幕上。它运行,但控制台上没有任何显示,并且导致对内存位置的访问无效(错误代码 0x3e6h)。为什么会这样,怎样才能让程序正常运行?
global main
extern ExitProcess
extern GetStdHandle
extern WriteFile
section .text
main:
mov rcx, 0fffffff5h
call GetStdHandle
mov rcx, rax
mov rdx, NtlpBuffer
mov r8, NtnNBytesToWrite
mov r9, NtlpNBytesWritten
mov dword [rsp - 04h], 00h
call WriteFile
ExitProgram:
mov rcx, 00h
call ExitProcess
section .data
NtlpBuffer: db 'Hello, World!', 00h
NtnNBytesToWrite: dd 0eh
section .bss
NtlpNBytesWritten: resd 01h
编译者
nasm -f win64 test.asm
gcc -s -o test.exe test.obj
[rsp-04h]
是在堆栈指针下方寻址,这是一个坏主意。不管你在那里写什么,无论如何都会被 call
覆盖。
看来您需要温习一下调用约定的知识。必须为寄存器中的 4 个参数分配影子空间,并且必须将更多参数放置在它们之上。
另外,要写入的字节数应该是实际数字,而不是指针。
global main
extern GetStdHandle
extern WriteFile
section .text
main:
sub rsp, 40 ; need to reserve shadow space before the first call
mov ecx, -11 ; GetStdHandle takes a DWORD arg, write it as 32-bit. This is STD_OUTPUT_HANDLE
call GetStdHandle
mov rcx, rax
mov rdx, NtlpBuffer ; or better, lea rdx, [rel NtlpBuffer]
mov r8, [NtnNBytesToWrite] ; or better, make it an EQU constant for mov r8d, bytes_to_write
mov r9, NtlpNBytesWritten ; first 4 args in regs
mov dword [rsp + 32], 00h ; fifth arg on the stack above the shadow space
call WriteFile
add rsp, 40
ExitProgram:
xor eax, eax
ret
section .data
NtlpBuffer: db 'Hello, World!', 00h
NtnNBytesToWrite: dq 0eh
section .bss
NtlpNBytesWritten: resd 01h
参见如何将函数或标签的地址加载到寄存器中回复:使用RIP相关的LEA而不是
mov reg, imm64
将地址放入寄存器中。
字符串中尾随的
0
字节不是必需的; WriteFile
采用指针 + 长度,而不是隐式长度的 C 字符串。您可能需要使用 db 'Hello...', 13,10
来包含换行符。 (DOS CR LF。)