У меня есть функция с подписью:
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
Есть ли другой способ?
Документация все объясняет … В Windows первые четыре целочисленных параметра передаются в регистрах RCX
, RDX
, R8
, R9
и с плавающей точкой в XMM0
, XMM1
, XMM2
, XMM3
все, что больше четырех параметров, передается в стек над теневым пространством. Для ОС типа Unix это немного отличается.
Итак, ваш пример верен — mov ebx, DWORD PTR[rbp + 48] ; e
Теневое пространство = 32 + сохраненный руб = 40 + 5-й параметр = 48
дано
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]