3

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

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

一切都很好,直到我切换回 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 中调用。

有可能做我想做的事吗?

4

1 回答 1

1

所以,问题已经解决了。这是我想要的一些解释的最小示例:

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

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

主文件

#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中。

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

于 2015-03-25T23:42:16.900 回答