Инструменты пользователя

Инструменты сайта


dll:dll

DLL

Как посмотреть содержимое DLL

В VS есть утилита dumpbin.exe, а в Delphi утилита TDump.exe.

> TDump.exe SM_Dll.dll > dump.txt

Фролов: Анализ DLL-библиотек при помощи утилиты tdump.exe

Экспорт - импорт функций

В заголовочном файле лежат объявления функций.

  • При сборке DLL те функции, которые должны экспортироваться из DLL необходимо пометить как __declspec(dllexport). Если ни одна функция не будет помечена, то будут экспортированы вообще все функции которые есть внутри всех модулей DLL, что есть не хорошо.
  • При сборке проекта, использующего dll, эти-же функции должны быть помечены как __declspec(dllimport)
  • Если исходники dll просто подключены к проекту, то никаких модификаторов к функциям не требуется.
#if defined(SM_DLL_LIBRARY)
  #define DLL_EXP __declspec(dllexport)
  #define ADDCALL __stdcall
#else
# if defined(BUILD_APP)
  #define DLL_EXP __declspec(dllimport)
  #define ADDCALL __stdcall
# else
  #define DLL_EXP
  #define ADDCALL
# endif
#endif

DLL_EXP ret_status_t ADDCALL init(const char * fileCfg, const char * fileValues, const char * fileAppCfg,
                  EventCallBack notifyFunc,
                  LogCallBack logFunc, uint8_t logEna);
DLL_EXP ret_status_t ADDCALL initGetCompleted(uint8_t *completed);
DLL_EXP ret_status_t ADDCALL setLogEnable(uint8_t logEna);
DLL_EXP ret_status_t ADDCALL deinit();

Если DLL собирается в QtCreator, то define можно объявить в *.pro файле:

DEFINES += SM_DLL_LIBRARY 

Name Mangling

В компилируемом файле *.с могут быть функции с одинаковым именем, но с разным набором входных параметров. Линкеру, собирающему несколько объектных файлов (*.о) необходимо понимать, какому вызову следует подставить ту или иную реализацию функции. Поэтому компилятор, формируя объектные файлы, "шифрует" в названии функции параметры ее вызова. Это называется - манглирование.

DLL файл, это тоже своего рода объектный файл. Поэтому внутри DLL названия функций представлены в манглированном виде.

При этом манглирование у разных компиляторов может быть различным. Если использующее DLL приложение собирается компилятором, манглирование которого отличается от манглирования компилятора, которым собиралась DLL, то импорт функции по имени не получится. Деманглирование даст не то исходное имя, которое ожидает импортировать из библиотеки программист. Но можно с помощью утилит dumpbin.exe / TDump.exe узнать как в DLL называется функция и загрузить ее по прямо по манглированному имени. Пример для Delphi:

Содержимое dll, полученное TDump.exe:

...
Exports from libNT_Spectrm.dll
  5 exported name(s), 5 export addresse(s).  Ordinal base is 1.
  Sorted by Name:
    RVA      Ord. Hint Name
    -------- ---- ---- ----
    0001683B    1 0000 _ZN9NT_SM_DLL10boardCountEPh
    ... прочие функции
...

Загрузка манглированной функции _ZN9NT_SM_DLL10boardCountEPh:

  • _Z : используется манглирование имен
  • N : содержит имя класса/пространство имен и т.п.
  • 9 NT_SM_DLL : 9 букв в NT_SM_DLL
  • 10 boardCount : 10 букв в boardCount
  • E : конец имени
var
  SMDLL_GetBoardCount  : function(var brdCount: Byte) : Integer; stdcall;

function SMDLL_LoadDll(dllFileName: string): THandle;
var
  lFuncNotFoundMsg : string;
begin
  result := 0;
  if (dllFileName = '') or (not FileExists(dllFileName)) then
  begin
    OutputDebugString(PChar('SMDLL: Dll File not found: ' + dllFileName));
    exit;
  end;

  result := LoadLibrary(PChar(dllFileName));
  if result < HINSTANCE_ERROR then
  begin
    OutputDebugString(PChar('SMDLL: Can"t load Library: ' + dllFileName));
    exit;
  end;

  lFuncNotFoundMsg := '';

  @SMDLL_GetBoardCount := LoadDllFunc(result, '_ZN9NT_SM_DLL10boardCountEPh', lFuncNotFoundMsg);
  ...
end  

Подробнее "Using Existing DLLs"

Посмотреть название функции в неманглированном виде можно командой:

$> c++filt -n _ZN9NT_SM_DLL23appSingleLaserGetStatusEPj

NT_SM_DLL::appSingleLaserGetStatus(unsigned int*)

NOTE: При использовании stdcall в манглировании используются символы @:

  • _ZN9NT_SM_DLL23appSingleLaserGetStatusEPj@4 - stdcall
  • _ZN9NT_SM_DLL23appSingleLaserGetStatusEPj - соглашение по умолчанию (скорее всего cdecl)

stdcall vs cdecl

Обсуждение на stackoverflow

// 1. Вызов функции
i = Func(x, y, z);

// 2. Исполнение функции
int Func(int a, int b, int c) 
{ 
  return a + b + c; 
}

CDECL

  1. Вызов функции
    • PUSH в стек значений x, y, z
    • CALL Func
    • значение из регистра А сохраняется в переменную i
    • POP (удаление) из стека x, y, z
  2. Исполнение функции
    • Чтение регистров из стека в регистры и вычисление.
    • Сохранение результата в регистр А.
    • RET в адрес вызова функции. (Переменные x, y, z по прежнему в стеке.)

STDCALL

  1. Вызов функции
    • PUSH в стек значений x, y, z
    • CALL Func
    • значение из регистра А сохраняется в переменную i
  2. Исполнение функции
    • Чтение регистров из стека в регистры и вычисление.
    • Сохранение результата в регистр А.
    • POP (удаление) из стека x, y, z
    • RET в адрес вызова функции.

Metadata from AI

Для изменения метаданных DLL в Qt с использованием qmake, вам нужно использовать макросы VERSION, VERSION_INFO и RC_FILE. В файле .pro вы можете установить версию DLL через макрос VERSION, например: VERSION = 1.2.3. Для добавления более детальной информации, такой как имя продукта, описание, и т.д., используйте макрос VERSION_INFO и создайте файл ресурсов .rc (для Windows). В файле .rc вы определяете необходимые ресурсы, включая информацию о версии, используя структуру VS_VERSION_INFO. Затем, в вашем файле .pro укажите этот файл через макрос RC_FILE.

  • Создайте файл version.rc:
VS_VERSION_INFO VERSIONINFO
 FILEVERSION     1,2,3,4
 PRODUCTVERSION  1,2,3,4
 FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
 FILEFLAGS     0x1L
#else
 FILEFLAGS     0x0L
#endif
 FILEOS        0x40004L
 FILETYPE      0x2L
 FILESUBTYPE   0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "CompanyName",      "MyCompany"
            VALUE "FileDescription",  "My Awesome DLL"
            VALUE "FileVersion",      "1.2.3.4"
            VALUE "InternalName",     "my_awesome_dll"
            VALUE "LegalCopyright",   "Copyright (C) 2024 MyCompany"
            VALUE "OriginalFilename", "my_awesome_dll.dll"
            VALUE "ProductName",      "MyAwesomeLibrary"
            VALUE "ProductVersion",   "1.2.3.4"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END

* Добавьте в *.pro файл:

VERSION = 1.2.3.4
VERSION_INFO_RC = version.rc
RC_FILE = $$VERSION_INFO_RC

Пояснения:

  • VERSION = 1.2.3.4: Устанавливает версию DLL.
  • VERSION_INFO_RC = version.rc: Указывает имя файла ресурсов.
  • RC_FILE = $$VERSION_INFO_RC: Включает файл ресурсов в процесс сборки.

В файле version.rc:

  • FILEVERSION и PRODUCTVERSION должны соответствовать версии, указанной в VERSION.
  • CompanyName, FileDescription, FileVersion, InternalName, LegalCopyright, OriginalFilename, ProductName, ProductVersion - поля, которые будут отображаться в свойствах файла DLL.
  • FILEFLAGS может быть использован для указания отладочной или релизной версии.
  • Translation указывает используемую кодировку.
dll/dll.txt · Последнее изменение: 2025/10/22 15:33 — vasco