Возможно ли 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 я бы не решил это.