Как передать структуру по значению в сборке x86 - PullRequest
1 голос
/ 07 июня 2019

Я пытаюсь вызвать функцию из API Windows в MASM.

Это подпись:

BOOL WINAPI SetConsoleScreenBufferSize(
  _In_ HANDLE hConsoleOutput,
  _In_ COORD  dwSize
);

Структура COORD dwSize передается по значению, но когда я пытаюсь вызвать ее, функция завершается ошибкой.

выглядит так:

                .DATA
dwSize          COORD   <20, 20>
                .CODE
                INVOKE  SetConsoleScreenBufferSize,
                        hConsoleOutput,
                        dwSize

Это вызывает ошибку типа, и программа не собирается. Если я передаю ссылку на структуру, программа собирается, но функция не работает. Я пробовал с другими функциями, которые принимают структуры по значению, но безуспешно.

Ответы [ 2 ]

3 голосов
/ 07 июня 2019

Ганс правильный Invoke не понимает, как передать структуру по значению.COORD - это 2 16-битных значения, размер которых равен DWORD.В случае COORD вы можете преобразовать его в DWORD в качестве параметра Invoke.Это должно сработать:

                .DATA
dwSize          COORD   <20, 20>
                .CODE
                INVOKE  SetConsoleScreenBufferSize,
                        hConsoleOutput,
                        DWORD PTR [dwSize]

Примечание: Важно понимать, что, поскольку COORD оказалось размером с DWORD, мы могли бы с этим покончить.Для структур, размер которых не может быть помещен в стек напрямую, вам нужно построить структуру в стеке и использовать инструкцию CALL вместо Invoke.

2 голосов
/ 07 июня 2019

COORD - это просто два 16-разрядных числа, упакованных вместе и переданных как обычное 32-разрядное число.

MSVC (x86) превращает

COORD cord = { 0x666, 0x42 };
SetConsoleScreenBufferSize(0, cord);

в

33db            xor     ebx,ebx

66c745986606    mov     word ptr [ebp-68h],666h    ; store cord.x
66c7459a4200    mov     word ptr [ebp-66h],42h     ; store cord.y

ff7598          push    dword ptr [ebp-68h]        ; push the whole struct
53              push    ebx                        ; push 0
ff1540104000    call    dword ptr [image00400000+0x1040 (00401040)] ; SetConsoleScreenBufferSize

После push ', но перед call стек начинается с:

00000000 00420666 ...

или обнуление регистра с последующим нажатием, что является пропущенной оптимизацией по сравнению с push 0немедленный ноль.Хранение в стеке сначала также только потому, что источник был скомпилирован с отключенной оптимизацией.

...