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

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


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 в адрес вызова функции.
dll/dll.txt · Последнее изменение: 2024/01/23 16:27 — vasco