Получить аргументы процедуры сборки x64 masm

У меня есть функция с подписью:

extern "C" int foo(int a, int b, int c, int d, int e);

что на самом деле написано в сборке.

С ml (32 бита), используя стандартное соглашение о вызовах, вы можете написать

.code
foo PROC a: DWORD, b: DWORD ,c: DWORD, d: DWORD, e: DWORD

mov eax, d
mov ebx, e

и начать использовать эти метки для доступа к вашим аргументам

С ml64 (64 бита) fastcall является единственным доступным соглашением. У меня нет проблем с доступом к первым аргументам, хранящимся в регистрах, но возникают проблемы с доступом к аргументам в стеке (e в этом примере): я пытался

.code
foo PROC a: DWORD, b: DWORD ,c: DWORD, d: DWORD, e: DWORD

а также

.code
foo PROC  e: DWORD

но ценность в e это мусор.

Я обнаружил, что если я использую адрес стека напрямую, я нахожу значение.

.code
foo PROC  e: DWORD

mov eax, r9                  ; d
mov ebx, DWORD PTR[rbp + 48] ; e

Есть ли другой способ?

6

Решение

Документация все объясняет … В Windows первые четыре целочисленных параметра передаются в регистрах RCX, RDX, R8, R9 и с плавающей точкой в XMM0, XMM1, XMM2, XMM3все, что больше четырех параметров, передается в стек над теневым пространством. Для ОС типа Unix это немного отличается.

Итак, ваш пример верен — mov ebx, DWORD PTR[rbp + 48] ; e

Теневое пространство = 32 + сохраненный руб = 40 + 5-й параметр = 48

4

Другие решения

дано

extern "C" int foo(int a, int b, int c, int d, int e);

Я обнаружил, что Visual Studio 2010 не сохраняет базовый указатель RBP если

.code
foo PROC

но сохраните базовый указатель, если

.code
foo PROC  e: DWORD

Более поздние версии (vs2015) не допускают второй код.

Существует дополнительная оптимизация в системах x64, где RBP не используется (выяснил трудный путь). Это говорит:

Традиционное использование% rbp в качестве указателя кадра для кадра стека
можно избежать, используя% rsp (указатель стека) для индексации в
кадр стека. Этот метод сохраняет две инструкции в прологе и
эпилог и делает один дополнительный регистр общего назначения (% rbp)
имеется в наличии.

Так что возможно, что либо foo PROC e: DWORD не компилируется (vs2015), или foo PROC падает, потому что RBP является нулевым.

Правильный способ получения аргументов стека заключается в использовании RSP указатель стека, учитывая, что

RBP = RSP + 8 * num_saved_reg

куда num_saved_reg это количество регистров, указанное в директиве PROC. Поэтому, когда rbp не сохраняется (в противном случае добавьте 8)

PROC -> DWORD PTR[rsp + 40]
PROC use RDI -> DWORD PTR[rsp + 40 + 8]
PROC use RDI RSI RBX -> DWORD PTR[rsp + 40 + 24]
0

По вопросам рекламы [email protected]