Возможно ли dllexport (а затем и dllimport) функция, написанная на ассемблере?

У меня большой проект C++, содержащий несколько модулей - все они скомпилированы в динамические библиотеки. Я нацеливаюсь на несколько платформ, включая Windows, Linux и MacOSX.

Тесты профилирования выявили некоторые критические моменты, в которых мне удалось получить огромный выигрыш в производительности, например: хэш-вычисления, некоторые векторные операции и т. Д. Я реализовал эту функциональность в сборке с использованием SSE/MMX.

Все было хорошо, пока я не переключился обратно на цель x64 в Visual C++, где встроенная сборка не разрешена. И я застрял. Также эти функции используются и в других модулях.

По сути, я пытаюсь реализовать некоторые функции, которые находятся внутри библиотеки 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.

Можно ли сделать то, что я пытаюсь сделать?

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 будет также виден ml/ml64, Неправильно. Только после ручного добавления необходимых констант все стало работать (.asm Свойства файла -> Microsoft Macro Assembler -> Общие -> Определения препроцессора).

Я думаю, после того, как попробовал и попробовал много разных решений, все превратилось в один большой беспорядок. Чистая настройка работала отлично:

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,

И большое спасибо за Богдана! Без его намека на вызов спецификаторов соглашения на x64 я бы не решил это.

Другие вопросы по тегам