我有一个用 MSVC 构建的程序,它正在动态加载一个 dll。 dll 提供了一个从主程序调用的函数。如果两者都是使用 MSVC 或 gcc 构建的,一切都很好,但是当我编译时,例如MSVC 的 main 和 gcc 的 dll 出了点问题。
# ifdef __GNUC__
# define CDECL __attribute__ ((__cdecl__))
# else
# define CDECL __cdecl
# endif
struct EXP result {
uint32_t code;
};
#define SUCCESS result{0};
virtual result CDECL foo(char const* const*& target) const {
target = (char const* const*)0xAFFE;
return SUCCESS;
}
问题是,调用目标之后是零而不是0xAFFE。主程序是使用 __cdecl
作为调用约定编译的。该结构已打包(未对齐),但我也尝试对齐到不同的大小(1、2、4、8、16)。我还尝试使用 __declspec/__atribute__(dllexport)
和两种变体的不同组合。
如果我看一下汇编代码,有两个很大的不同:
; MSVC | gcc
;===============================|================================
; before calling |
;-------------------------------|--------------------------------
| sub dword ptr [esp+4],8
|
; foo(); |
;-------------------------------|--------------------------------
push ebp | push ebp
mov ebp,esp | mov ebp,esp
mov eax,dword ptr [target] |
mov dword ptr [eax],0AFFEh |
mov eax,dword ptr [ebp+0Ch] | mov eax,dword ptr [ebp+0Ch]
mov dword ptr [eax],0 | mov dword ptr [eax],0AFFEh
| mov eax,0
pop ebp | pop ebp
ret | ret
即使我在两个编译器上使用相同的调用约定,为什么会这样?我该如何解决?
最佳答案
在这种情况下,调用约定毫无意义。问题是 vtable 布局之类的东西。 MSVC ABI 和 Itanium 在很多事情上存在分歧。除非明确支持,否则您不能编译 C++ 接口(interface)并在编译器之间混合和匹配。如果设置正确,Clang 和 G++ 应该可以互操作,而 Clang 和 MSVC 可能可以互操作,具体取决于您使用的具体功能。
一般来说,不要为 C++ 接口(interface)混合搭配 C++ 编译器。这是行不通的。
关于c++ - MSVC 和 gcc 之间的调用约定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31950743/