【问题标题】:How do I pass arguments to C++ functions when I call them from inline assembly当我从内联汇编中调用 C++ 函数时,如何将参数传递给它们
【发布时间】:2011-01-19 18:34:50
【问题描述】:

所以,我希望能够从 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 字节)。对于这个混乱的任何帮助将不胜感激:)

【问题讨论】:

  • 你尝试的时候发生了什么?
  • 我在使用双打时遇到了问题:我在 dll 中创建了一个测试函数,它接受一个双参数并在输入大于 5.0 时返回 1。问题是我尝试调用汇编中的函数几次,参数为 7.45454,返回值并不总是相同。

标签: x86 callstack argument-passing inline-assembly


【解决方案1】:

要推送 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)
  }

【讨论】:

    【解决方案2】:

    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
    }
    

    【讨论】:

    • 为了更加安心,在您弄清楚它应该是什么之后,从 C++ 进行等效调用,在禁用优化的情况下进行编译,然后查看程序集输出.它应该与您正在做的事情大致匹配。
    • 但是,你将如何推动双打?在 c++ 中它应该是 8 个字节,对吧?
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2016-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-12
      • 1970-01-01
      • 1970-01-01
      • 2022-06-30
      • 1970-01-01
      相关资源
      最近更新 更多