5

我需要编写调用外部函数的代码,该函数可以是 32 位 Windows 应用程序中的 stdcall 调用或 cdecl 。
我的代码,调用者,不能提前知道它会是哪一个。现在,如果我尝试从定义为 stdcall 的调用站点调用 cdecl 函数,我会得到一个 checkEsp 异常对话框,我猜这是有充分理由的。
有什么办法吗?

4

3 回答 3

4

可以通过以下方式完成:

          mov     esi, esp

          push    arg3
          push    arg2
          push    arg1
          call    [SomeExternalProc]

          mov     esp, esi   ; now the stack is always properly cleaned 

外部过程将保留 esi。或者,您可以使用由外部过程甚至内存变量保留的任何其他寄存器 - 本地或全局。

好的,CDECL 和 STDCALL 的参数顺序是相同的 - 顺序相反。(最左边的 arg 在最低地址。)所以它们是兼容的,除了 ESP 在返回时指向的位置。两种约定都同意哪些寄存器是调用保留的还是调用破坏的。

于 2013-07-13T06:29:47.000 回答
1

您还可以使用 alloca() 具有保存和恢复堆栈指针的副作用:

{
    alloca( (uintptr_t)callback & 2 );
    callback();
}
于 2014-05-09T21:25:17.963 回答
0

cdecl 和 stdcall 在定义上是不兼容的。在 cdecl 中,调用者清理堆栈,在 stdcall 中,被调用者清理堆栈。如果你假设stdcall,但实际上是cdecl,没有人清理堆栈。这意味着您的 ESP(堆栈指针)在调用后将被搞砸。也许如果您提供更多详细信息,可能会有一种解决方法,但是没有办法在不知道调用约定的情况下调用函数而不会弄乱您的堆栈。

有关差异的定义, 请参见:http ://en.wikipedia.org/wiki/X86_calling_conventions。

于 2013-07-13T00:31:38.123 回答