是否可以用汇编语言编写 dllexport(然后是 dllimport)函数?

Is it possible to dllexport (and then dllimport) function written in assembly?

我有一个大型 C++ 项目,其中包含几个模块 - 所有模块都被编译为动态库。我针对多个平台,包括 Windows、Linux 和 MacOSX。

分析测试揭示了一些关键点,我在这些点上获得了巨大的性能提升,例如:哈希计算、一些向量运算等。我使用 SSE/MMX.[=15 在汇编中实现了这个功能=]

一切都很好,直到我在 Visual C++ 中切换回 x64 目标,其中不允许内联汇编。我卡住了。此外,这些功能也用于其他模块。

基本上,我想要实现的是实现一些函数,这些函数驻留在程序集中的 DLL 中。我试过这个:

Api.h

extern "C" void DLL_API __stdcall sample_fun(/*args*/);

Api.asm

sample_fun PROC public ;args
.....
sample_fun ENDP

这显然行不通,因为名称修改。

我也试过这个:

Api.h

void DLL_API sample_fun(/*args*/);

Api.cpp

extern "C" __stdcall sample_fun_impl(/*args*/).

void DLL_API sample_fun(/*args*/)
{
  return sample_fun_impl(/*args*/);
}

Api.asm

sample_fun_impl PROC public ;args
.....
sample_fun_impl ENDP

在这种情况下,我仍然收到有关未解析的外部符号 (sample_fun_impl) 的链接器错误,这很奇怪,因为它实际上是一个私有函数,只能从 DLL 中调用。

是否可以做我想做的事?

那么,问题就解决了。这是我想要的一些解释的最小示例:

Asx.h

namespace Asx
{
#if ASX_PLATFORM_IS64BIT //This is resolved using 'ifdef _M_X64'
    extern ASX_DLL_API ULONGLONG roundup_pow2_64(ULONGLONG value);
#else
    extern ASX_DLL_API DWORD roundup_pow2_32(DWORD value);
#endif
}

Asx.cpp

#include "Asx.h"

#if ASX_PLATFORM_IS64BIT
extern "C" ULONGLONG __cdecl roundup_pow2_64_impl(ULONGLONG value);
#else
extern "C" DWORD __cdecl roundup_pow2_32_impl(DWORD value);
#endif

namespace Asx
{

#if ASX_PLATFORM_IS64BIT
    ULONGLONG roundup_pow2_64(ULONGLONG value)
    {
        return roundup_pow2_64_impl(value);
    }
#else
    DWORD roundup_pow2_32(DWORD value)
    {
        return roundup_pow2_32_impl(value);
    }
#endif

}

Asx_asm_impl.asm

IFNDEF ASX_PLATFORM_IS64BIT
.686P
.MODEL FLAT, C
.XMM
ENDIF

.CODE

IFDEF ASX_PLATFORM_IS64BIT

roundup_pow2_64_impl PROC public, value:QWORD
//Implementation
roundup_pow2_64_impl ENDP

ELSE

roundup_pow2_32_impl PROC public, value:DWORD
//Implementation
roundup_pow2_32_impl ENDP

ENDIF

END

怎么了?

1) 我没有考虑到调用约定在 x64 中的处理方式不同,但是意外地这并没有造成任何问题。

2) 在某些时候,我注意到,标记为 __cdecl 的函数由链接器使用其名称前加下划线进行搜索。我制作了 dumpbin 个有问题的 DLL,它就在那里 - 但确实在开头有一个下划线!所以我保留了它的声明,并将其名称从 roundup_pow2_32_impl 更改为 _roundup_pow2_32_impl,同时我添加了 MODEL FLAT, C.

3) 我在 .asm 文件中使用了 IFDEF/IFNDEF。但我假设,所有对 cl 可见的定义对 ml/ml64 也是可见的。错误的。只有在手动添加所需常量后,一切才开始工作(.asm 文件属性 -> Microsoft 宏汇编器 -> 常规 -> 预处理器定义)。

我想在尝试了许多不同的解决方案之后,一切都变成了一个大混乱。清理设置完美运行:

Main.cpp

#include "../Asx/Header.h"

int main(int argc, char** argv)
{
#if ASX_PLATFORM_IS64BIT
    ULONGLONG v = Asx::roundup_pow2_64(4000);
#else
    DWORD v = Asx::roundup_pow2_32(4000);
#endif

    return 0;
}

在 Win32 和 x64 中的结果:4096

非常感谢 bogdan!没有他关于在 x64 上调用约定说明符的提示,我不会解决这个问题。