Называя Longlong rtllargeintegerdivide (Longlong, Longlong, Longlong*) в NASM (STDCALL)
-
13-10-2019 - |
Вопрос
Я пытаюсь вызвать следующую функцию:
long long RtlLargeIntegerDivide(long long dividend, long long divisor, long long* pRemainder)
в коде сборки (NASM). Он использует Конвенцию о вызове STDCALL, и возвращает коэффициент. Это спецификации:
Ввод: [EDX, EAX] (дивиденд), [ECX, EBX] (Divisor)
Вывод: [edx, eax] (коэффициент), [ecx, ebx] (остаток)
Как мне это сделать? (Моя главная проблема - не совсем понимание EBP и ESP, и как они относятся к локальным переменным.)
(И нет, это не домашнее задание; я пытаюсь внедрить библиотеку времени выполнения обертки.)
Благодарю вас!
Решение
В 32 -битном режиме вам вообще не нужно использовать EBP для доступа к локальным переменным вообще, это всего лишь остаток конвенции из 16 -битного и в любом случае не беспокоит нас сейчас.
ESP - ваш указатель стека, я полагаю, вы это знаете. Вы можете «распределить» пространство для ваших местных переменных, уменьшая ESP.
STDCALL Вызововое соглашение использует стек для прохождения аргументов. Они находятся в обычном порядке, когда в стеке, но если вы используете PUSH
Это означает, что вы подталкиваете их. Интегральные возвращаемые значения находятся в EAX (и EDX, когда это при необходимости). Вызовая функция очищает аргументы из стека.
Таким образом, следующий код должен делать то, что вы хотите:
sub ESP, 8; make room for remainder
push ESP ; pass pointer to remainder as argument
push ECX
push EBX ; pass divisor argument
push EDX
push EAX ; pass dividend argument
call RtlLargeIntegerDivide
; quotient returned in EDX:EAX
; so just load remainder from stack
pop EBX
pop ECX
(Для скорости вы можете использовать MOV
вместо PUSH
/POP
)