Как да извикате правилно 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