8

所以,我希望能够从 c++ dll 调用函数。出于某些原因,我想从我的 C++ 代码中的 __asm 块中调用它们。我的问题是:我知道在调用函数之前,我必须按照函数调用约定指定的顺序将其参数推送到堆栈上。但是,我可以简单地做这样的事情吗:

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

让我担心的是,我似乎记得汇编中的标准字大小是 2 字节,而 C++ 中 int 的大小通常是 4 字节,而双精度则为 8 字节。所以,在上面的例子中,我真的是推送每个变量的完整值,还是仅推送前几个字节?如果上面的代码不正确,那么正确的方法是什么?另外,如果我们调用的函数返回一个双精度值,这个值存储在哪里?我假设它不能在寄存器中,因为它只能存储 32 位(4 字节)。对于这个混乱的任何帮助将不胜感激:)

4

3 回答 3

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)
  }
于 2010-02-23T17:42:44.723 回答
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
}
于 2010-02-22T18:58:46.847 回答
1

通常,您将推动计算机字的完整大小。这因芯片而异,但在 32 位 Intel 上为 4 字节,在 64 位 Intel 上为 8(取决于编译器——Visual Studio 仍仅支持 IA32 汇编——因此为 4 字节)。

最好的答案是查看特定编译器的文档。

于 2010-02-22T18:57:59.097 回答