2010-02-22 7 views
8

Итак, я хотел бы иметь возможность вызывать функции из dll C++. По определенным причинам я хотел бы назвать их из блока __asm ​​в моем коде на C++. Мой вопрос заключается в следующем: я знаю, что, прежде чем я вызываю функцию, я должен выдвинуть свои аргументы в стек в порядке, определенном с помощью функции призвании convention.However, может я просто сделать что-то вроде этого:Как передать аргументы в функции C++, когда я их вызываю из встроенной сборки

int a=5; 
double b = 5.0; 
__asm{ 
     push b 
     push a 
     call functionAddress 
} 

Меня беспокоит тот факт, что я, кажется, помню, что стандартный размер слова в сборке составляет 2 байта, а размер int в C++ обычно составляет 4 байта и 8 байтов для double.So, в приведенном выше примере, я действительно толкает полное значение каждой переменной или только первые пару байтов? Если приведенный выше код неверен, каков был бы правильный способ сделать это? Кроме того, если функция, которую мы вызываем, возвращает double, где это значение сохраняется? Я предполагаю, что он не может быть в реестре, потому что он может хранить только 32 бита (4 байта). Любая помощь с этим беспорядком была бы очень признательна :)

+2

Что произошло, когда вы попробовали? – Seth

+0

У меня проблема с двойниками: я сделал себе тестовую функцию в dll, которая принимает двойной аргумент и возвращает 1, если вход больше 5.0. Дело в том, что я несколько раз пытался вызвать функцию из сборки с аргументом 7.45454, а возвращаемое значение не всегда одно и то же. –

ответ

13

Протолкнуть значения 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) 
    } 
1

Как правило, вы будете нажимать полный размер компьютера слово. Это зависит от чипа, но на 32-битной Intel будет 4 байта, а на 64-битной Intel - 8 (в зависимости от компилятора - Visual Studio по-прежнему поддерживает только сборку IA32 - так 4 байта).

Лучшим ответом является просмотр документации для вашего конкретного компилятора.

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 
} 
+2

Для дополнительного спокойствия, после того, как вы выяснили, что это значит *, сделайте эквивалентный вызов с C++, скомпилируйте с отключенными оптимизациями и посмотрите на вывод сборки. Он должен примерно соответствовать тому, что вы делаете. –

+1

Но тогда, как бы вы нажмете двойной? В C++ оно должно быть 8 байтов, правильно? –