x86 中的下划线前缀问题:从 C++ 函数调用 NASM 函数在 x64 中有效,但在 x86 中失败

b0c*_*zz3 3 c++ windows assembly nasm visual-studio-2019

我在 Windows 10 中使用 Visual studio 2019,我想使用 MSVC(平台工具集 142)和 NASM(版本 2.14.02)在 x86 中编译以下代码:

foo.asm

section .text

global foo
foo:
    mov eax, 123
    ret
Run Code Online (Sandbox Code Playgroud)

主程序

extern "C" int foo(void);

int main()
{
    int x = foo();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但我得到了错误:

在此输入图像描述

在 x64 中运行良好,在 x86 中生成的文件 main.obj 向函数名 foo 添加前导下划线,从而生成 _foo。这在 x64 中不会发生,但将符号保留为 foo,而不是 _foo。

那么,是否有任何适用于 x86 和 x64 平台的解决方案(最好不修改源代码,也许是 MSVS 编译器的一些编译器/链接器标志)?

我真的很感谢任何帮助。

rus*_*tyx 8

前缀_是名称修改的结果,这取决于目标平台 ABI(操作系统、位数、调用约定)。

\n

根据 Microsoft 的说法,该_前缀用于 32 位 Windowscdecl调用约定,但不用于 64 位(来源):

\n
\n

C 修饰名称的格式

\n

C 函数的修饰形式取决于其声明中使用的调用约定,如下表所示。这也是在 C++ 代码声明为具有 extern“C”链接时使用的装饰格式。默认调用约定是 __cdecl。请注意,在 64 位环境中,函数不会被修饰

\n

调用约定 \xe2\x80\x83\xe2\x80\x94\xe2\x80\x83 修饰
\n __cdecl\xe2\x80\x83 前导下划线 ( _)
\n __stdcall\xe2\x80\x83 前导下划线 ( _) 和尾随 at 符号( @) 后跟参数列表中十进制字节数
\n __fastcall\xe2\x80\x83 前导和尾随符号 ( @) 后跟表示参数列表中字节数的十进制数
\n __vectorcall\xe2\x80\ x83 参数列表中两个尾随符号 ( @@) 后跟十进制字节数

\n
\n

背后的原因可能是 32/64 位 Windows 调用约定并不真正兼容。例如,64 位模式下的函数参数以不同的方式传递,并且必须在调用之间保留不同的寄存器。

\n

无论如何,为了回答这个问题,我可以想出几个解决方案:

\n

解决方案1

\n

生成 的代码.asm应该仅在 32 位模式下添加前导_(生成的程序集可能也必须在其他方面有所不同,特别是在涉及指针的情况下)。

\n

解决方案2

\n

_使用预处理器在 64 位模式下添加前导:

\n
#ifdef _WIN64\n#  define foo _foo\n#endif\n\nextern "C" int foo(void);\n\nint main()\n{\n    int x = foo();\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n