是否可以用汇编语言编写 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 上调用约定说明符的提示,我不会解决这个问题。
我有一个大型 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 上调用约定说明符的提示,我不会解决这个问题。