Так, я хотел бы смочь вызвать функции от C++ dll. По определенным причинам я хотел бы назвать их от __ asm блок в моем коде C++. Мой вопрос - это: Я знаю, что, прежде чем я вызову функцию, я должен продвинуть ее аргументы на стеке в порядке, указанном соглашением о вызовах функции. Однако могу я просто делать что-то вроде этого:
int a=5;
double b = 5.0;
__asm{
push b
push a
call functionAddress
}
То, что волнует меня, является тем, что я, кажется, помню, что стандартный размер слова в блоке составляет 2 байта, в то время как размер интервала в C++ обычно - 4 байта и 8 байтов для двойного. Так, в примере выше, я действительно продвигаю полную стоимость каждой переменной, или просто первые два байта? Если бы код выше не является правильным, каков был бы правильный способ сделать это? Кроме того, если функция, мы называем возвраты двойным, где это значение хранится? Я предполагаю, что это не может быть в регистре, потому что это может только сохранить 32 бита (4 байта).Any, справка с этой путаницей значительно ценилась бы :)
Для передачи 8-байтовых значений, таких как двойные, вы не сможете использовать обычную инструкцию PUSH
. И вы также не помещаете параметры с плавающей запятой (или двойные) в стек с плавающей запятой. Вам нужно «вручную» положить эти параметры жира в стек. Например, чтобы передать π в качестве параметра функции f:
__asm {
FLDPI // load pi onto FP stack
SUB ESP,8 // make room for double on processor stack
FSTP QWORD PTR [ESP] // store pi in proc stack slot (and pop from FP stack)
CALL f
ADD ESP,8 // clean up stack (assuming f is _cdecl)
}
В общем, вы будете использовать полный размер компьютерного слова. Это зависит от чипа, но на 32-битном Intel это будет 4 байта, а на 64-битном Intel - 8 (в зависимости от компилятора - Visual Studio все еще поддерживает только сборку IA32 - так что 4 байта).
Лучший ответ - посмотреть документацию для вашего конкретного компилятора.
32-битная архитектура x86 автоматически дополняет значения, помещаемые в стек, до 32 бит.
Есть кое-что, о чем нужно помнить. Если функция, которую вы вызываете, использует соглашение о вызовах __cdecl, вы должны «вытолкнуть» то, что вы отправили позже. Однако для функций __stdcall этого делать нельзя.
extern "C" int __cdecl function1(int, double);
extern "C" double __stdcall function2(char, char*);
int a = 5;
double b = 5.0;
int retval1;
char c = '5';
char *d = "Hello";
double retval2;
__asm {
push b
push a
call function1
add esp, 4*2 // "pop" what we pushed
mov retval1, eax
push d
push c
call function2
mov retval2, eax
}