Как правильно вызывать 64-битный Windows API в сборке

Используя 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

person Erik Zimmerman    schedule 23.07.2014    source источник
comment
Вы пытались написать небольшую программу на C, которая вызывает WriteFile, и увидеть ее дизассемблирование в 64-битной сборке?   -  person Alex F    schedule 23.07.2014
comment
Да, но это еще больше сбивает меня с толку, потому что я не привык просматривать код, оптимизированный компилятором. Я склонен просто доверять тому, что выдает компилятор при написании программы на C.   -  person Erik Zimmerman    schedule 24.07.2014


Ответы (1)


[rsp-04h] обращается ниже указателя стека, это плохая идея. Все, что вы там напишете, все равно будет перезаписано call. Похоже, вам нужно освежить свои знания о соглашении о вызовах. Необходимо выделить теневое пространство для 4 аргументов в регистрах, а дополнительные аргументы должны быть размещены поверх них.

Кроме того, количество записываемых байтов должно быть фактическим числом, а не указателем.

global main
extern GetStdHandle
extern WriteFile

section .text
main:
    mov     rcx, 0fffffff5h
    call    GetStdHandle

    mov     rcx, rax
    mov     rdx, NtlpBuffer
    mov     r8, [NtnNBytesToWrite]
    mov     r9, NtlpNBytesWritten
    sub     rsp, 40
    mov     dword [rsp + 32], 00h
    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
person Jester    schedule 23.07.2014
comment
Теперь все это имеет смысл, мне действительно нужно еще немного заняться книгами. Так много ошибок, которые я сделал, было довольно легко сделать для новичка, но я чувствую, что теперь у меня есть немного лучшее понимание. Спасибо. - person Erik Zimmerman; 24.07.2014
comment
Когда я запускаю исполняемый файл, созданный с помощью этого кода, часть ExitProcess работает точно, однако я не вижу никаких строк, выводимых на консоль. - person mcandre; 18.06.2018