Называя тип longlong RtlLargeIntegerDivide(тип longlong, тип longlong, тип longlong*) в NASM (нарушением соглашения о стандартном)


Я пытаюсь вызвать следующую функцию:

long long RtlLargeIntegerDivide(long long dividend, long long divisor, long long* pRemainder)

В ассемблерном коде (NASM). Он использует соглашение о вызове stdcall и возвращает частное. Это спецификации:

Входные данные: [EDX, EAX] (дивиденд), [ECX, EBX] (делитель)

Выходные данные: [EDX, EAX] (частное), [ECX, EBX] (остаток)

Как мне это сделать? (Моя главная проблема заключается не в точном понимании EBP и ESP, а в том, как они соотносятся с локальными переменными.)

(и нет, это не домашнее задание; Я пытаюсь реализовать оболочку C библиотеки времени выполнения.)

Спасибо!

1 2

1 ответ:

В 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)