01 dll basics
-
Upload
tsu-fen-han -
Category
Education
-
view
206 -
download
2
Transcript of 01 dll basics
![Page 1: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/1.jpg)
DLL BasicsDLL BasicsReference: Reference:
Programming Applications for Microsoft Programming Applications for Microsoft Windows Fourth Edition p.p. 675Windows Fourth Edition p.p. 675
![Page 2: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/2.jpg)
IntroductionIntroduction
All the functionsAll the functions in the Windows API are in the Windows API are contained contained in DLLsin DLLs
The three DLLsThe three DLLs Kernel32.dllKernel32.dll: managing memory, processes, : managing memory, processes,
threadsthreads User32.dllUser32.dll: user-interface tasks: user-interface tasks GDI32.dllGDI32.dll: drawing image, display text: drawing image, display text
AdvAPI32.dll object security, registry manipulationComDlg32.dll common dialog boxesComCtl32.dll all of the common window controls
other DLLs
你可以下 dumpbin /exports User32.dll 看看到底他提供了哪些 function?
![Page 3: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/3.jpg)
IntroductionIntroduction
DLL DLL 為一堆 為一堆 function function 的集合的集合 ,, 通常不包含通常不包含 message-loopmessage-loop 建立視窗建立視窗
DLL DLL 的 的 function function 可以被可以被其他執行檔其他執行檔或 或 DLLDLL 呼呼叫叫
DLL DLL 的執行的執行 使用使用呼叫者 呼叫者 thread thread 的 的 stackstack 儲存 儲存 local variablelocal variable 記憶體配置記憶體配置 , , 使用呼叫者 使用呼叫者 threadthread 的 的 virtual space virtual space 配配
置置 全區域全區域變數與變數與靜態靜態變數變數 ::
Win98 Win98 為每一個為每一個 process process 配置一份複製品配置一份複製品 Win2000Win2000 以後 以後 使用 使用 copy-on-write copy-on-write 策略策略
![Page 4: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/4.jpg)
要注意的事情要注意的事情
一個一個 Process address space Process address space 中中 ,, 可能包可能包含含 執行檔 執行檔 image + image + 數個 數個 DLL modulesDLL modules
可能使用 可能使用 DLL DLL 的 的 module :module : 有些 有些 modules modules 使用 使用 C++ C++ run-time libraryrun-time library 有些使用 有些使用 staticstatic 版本的 版本的 librarylibrary 有些 有些 modules modules 不使用 不使用 C++ libraryC++ library
VB 或 其他程式語言
![Page 5: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/5.jpg)
要注意的事情要注意的事情VOID EXEFunc() { PVOID pv = DLLFunc(); // Access the storage pointed to by pv... // Assumes that pv is in EXE's C/C++ run-time heap free(pv); }
PVOID DLLFunc() { // Allocate block from DLL's // C/C++ run-time heap return(malloc(100));}
使用你 DLL 的人可能使用的是 static 版本的 free
在你的 DLL 中 , 使用 run-time版本的 malloc
VOID EXEFunc() { PVOID pv = DLLFunc(); // Access the storage pointed to by pv... // Assumes that pv is in EXE's C/C++ run-time heap DLLFreeFunc(pv);}
PVOID DLLFunc() { // Allocate block from DLL's C/C++ run-time heap return(malloc(100));}BOOL DLLFreeFunc(PVOID pv) { // Free block from DLL's C/C++ run-time heap return(free(pv)); }
比較好的策略 在 DLL 配置記憶體 , 在 DLL 釋放他
全部放在 DLL 中處理
![Page 6: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/6.jpg)
The Overall PictureThe Overall Picture
名詞的定義名詞的定義 Executable moduleExecutable module 從 從 DLL importing DLL importing 函函
式或變數來使用的 式或變數來使用的 modulemodule DLL modulesDLL modules exporting function exporting function 或變數 給 或變數 給
executable moduleexecutable module 使用的 使用的 modulesmodules
DLL modules 也可以 importing 其他人的 function 與變數使用
使用 DLL 的 Module
![Page 7: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/7.jpg)
DLL DLL 是是如何被建立如何被建立的的 以及如何被應用程式 以及如何被應用程式 implicitly linkimplicitly link
export 函式原型 , 結構Symbol 的 header file
函式的實作
產生 obj 檔
組合成 DLL 檔並且產生 lib 檔
DLL export 的部分使用 DLL 的部分
Import 你要使用的函式原型
呼叫 DLL 函式
產生 obj
結合 lib 解析出呼叫的函式 symbol
執行的部分
Loader 建立 address space 給 .exe Loader 載入必要的 DLL 到 process的 address space
Lib 檔dll 檔
exe 檔
COFF 格式
COFF 格式 =Common Object File Format
![Page 8: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/8.jpg)
建立一個最簡單的 建立一個最簡單的 DLL ModuleDLL Module
DLL DLL 可以 可以 exportexport Function, variable Function, variable 或 或 C++ classC++ class
全區域變數 : 影響抽象性 , 且不易維護
必須使用相同的編譯器才能 reference class
選擇 DLL選擇 Empty Project
1
2
3 把後面的 MyDLL.h 與 MyDLL.cpp 加到 project 中
![Page 9: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/9.jpg)
Export Symbol Export Symbol
下面這個檔案下面這個檔案 ,, 必須被散佈 必須被散佈
#ifdef MYLIBExport #define MYLIBAPI extern "C" __declspec(dllexport)#else #define MYLIBAPI extern "C" __declspec(dllimport)#endif
MYLIBAPI int g_nResult;MYLIBAPI int Add(int nLeft, int nRight);
MyLib.h
定義 exported 函式及變數的地方
當你要 export symbol 時 , 使用這個
當你要 import symbol 時 , 使用這個
![Page 10: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/10.jpg)
實作 實作 export export 函式函式
#include <windows.h>#define MYLIBExport #include "..\\MyLib.h"
int g_nResult;int Add(int nLeft, int nRight) { g_nResult = nLeft + nRight; return(g_nResult);}
Include 標準的 windows 及 C++ run-timeLibrary 標頭檔
定義目前是 export
Function 的 prototype
實作函式及變數的地方
MyLibFile1.cpp
#ifdef MYLIBExport #define MYLIBAPI extern "C" __declspec(dllexport)#else #define MYLIBAPI extern "C" __declspec(dllimport)#endifMYLIBAPI int g_nResult;MYLIBAPI int Add(int nLeft, int nRight);
MyLib.h
![Page 11: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/11.jpg)
為甚麼要加 為甚麼要加 extern “C” ? extern “C” ?
因為 因為 C++ C++ 編譯器會在 編譯器會在 function function 前面加上一些修前面加上一些修飾飾 ((manglemangle), ), 這樣會造成 這樣會造成 C C 程式無法 程式無法 link link 到正到正確的 確的 functionfunction
加入 加入 extern “C” function(); extern “C” function(); 可以要求編譯器可以要求編譯器不要不要加入 加入 manglemangle
為何 C++ 會對 function name 做 name name decorationdecoration 呢呢 ?? Function overloading Function overloading 與 與 c++ type-safe linkagec++ type-safe linkage
extern "C" __declspec(dllimport) void myfunction() { … }
void foo(int ,double);Comeau C++ 會把 foo 改成 foo
例如 :
void foo(int ,double);Comeau C++ 會把 foo 改成 foo_Fid F function name I 第一個參數是 int; d 第二個參數是 double
各家編譯器有不同的作法
參考資料 : http://www.comeaucomputing.com/techtalk/#externc
![Page 12: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/12.jpg)
我們來看看差別在哪裡我們來看看差別在哪裡 !!
#ifdef MYLIBExport #define MYLIBAPI extern “C” __declspec(dllexport)#else #define MYLIBAPI extern "C" __declspec(dllimport)#endifMYLIBAPI int g_nResult;MYLIBAPI int Add(int nLeft, int nRight);
如果你的 MyLib.h 的內容如下使用 “ C” 的方式命名
利用 dumpbin /exports 察看 MyDll.lib 結果
看到了嗎Symbol 沒有加上 mangle
那請問一下 : 加上 extern “C” 後 , 你的 DLL 是否還支援 function overloading ?
![Page 13: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/13.jpg)
如果你的 MyLib.h 的內容如下
#ifdef MYLIBExport #define MYLIBAPI extern __declspec(dllexport)#else #define MYLIBAPI extern __declspec(dllimport)#endifMYLIBAPI int g_nResult;MYLIBAPI int Add(int nLeft, int nRight);
沒有使用 “ C”
利用 dumpbin 察看 MyDll.lib 結果
看到了嗎Symbol 後面加了一些料
![Page 14: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/14.jpg)
#include “MyLib.h”void main(){ int Sum=Add(1,2);}
好了 , 接下來 , 就是直接使用 function
若你是由 VC 幫你建立 DLL export symbol骨架 , 那麼預設值是不加上” C”
要注意 : 別弄錯了 ,否則會發生 link 錯誤
![Page 15: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/15.jpg)
使用 使用 MyDLL.dllMyDLL.dll
Copy MyDLL.lib Copy MyDLL.lib 與 與 MyDLL.dllMyDLL.dll 到可以搜尋到可以搜尋到的地方 到的地方
選擇 Linker Input
1
設定 MyDLL.lib
2
#include “MyLib.h”void main(){ int Sum=Add(1,2);}
呼叫 MyDLL.dll export 的 function
3
你也可以直接在 Source code 中加入這行 #pragma comment( lib, "c:\\kk\\MyDll.lib" )
![Page 16: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/16.jpg)
__declspec(dllexport) 的意義
..
當 當 linker linker 產生 產生 DLLDLL 檔時檔時 ,, 會會 合併上述資訊產生 合併上述資訊產生 .lib .lib 檔檔 並且 並且 embed embed 一個 一個 symbol table symbol table 到 到 DLLDLL 檔中檔中
extern "C" __declspec(dllexport) void myfunction() { … }
Microsoft VC 發現 __declspec(dllexport)會在 .obj 中加入額外的鏈結資訊
亦即 lib 檔中包含 DLL 所輸出的 symbol 以及相對的位址 (Relative Virtual Address)
![Page 17: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/17.jpg)
查閱查閱 DLL DLL 檔所 檔所 export export 的 的 symbolsymbol – – 使用 使用 DumpBinDumpBin 公用程式公用程式
使用前使用前 ,, 先加入先加入 Path,Path, 使得相關的使得相關的 DLLDLL 檔可檔可以找到以找到
F:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDEF:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE
執行 執行 DumpBin.exe /exports DumpBin.exe /exports MyDll.dllMyDll.dll
Export 的 symbol相對位址
![Page 18: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/18.jpg)
讓其他的讓其他的 IDE IDE 也能使用 也能使用 Visual C+Visual C+++ 的的 DLLDLL
問題是問題是 對於 對於 __stdcall__stdcall 修飾字的 修飾字的 function,function, 無論是 無論是 C/C/
C++, Visual C++ C++, Visual C++ 都會對 都會對 function name function name 加入加入修飾符號修飾符號 . .
__declspec(dllexport) LONG __stdcall MyFunc(int a, int b);
_MyFunc@8
後面有 8 個 bytes__stdcall: 1. 最右邊的參數先推入堆疊2. 函式返回前 , 自行移除堆疊中的參數*Win32 API 使用 __stdcall
因為 C/C++ 不定參數的關係所以必須要在 function 後面加上需要 pop 的數字
![Page 19: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/19.jpg)
讓其他的讓其他的 IDE IDE 也能使用 也能使用 Visual C+Visual C+++ 的的 DLLDLL
解決方案解決方案 : : 要求 要求 VCVC 不要加額外的資訊到不要加額外的資訊到DLLDLL 中中 方法一方法一 : : 編輯 編輯 .def .def 檔檔
方法二方法二 : : 在 在 DLLDLL 原始程式中加入原始程式中加入
EXPORTS MyFunc
#pragma comment(linker, "/export:MyFunc=_MyFunc@8")
![Page 20: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/20.jpg)
沒有加入 .DEF 檔
加入 .DEF 檔
LIBRARY MYDllEXPORTS Add
dumpbin /exports MyDLL.dll
dumpbin /exports MyDLL.dll
補充
![Page 21: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/21.jpg)
Import Import 的實際意義的實際意義
在使用 在使用 DLL import DLL import 的的 symbol symbol 時你可以用 時你可以用 externextern 代替 代替 __declspec(dllimport)__declspec(dllimport)
extern "C" __declspec(dllimport) void myfunction() { … }
extern "C“ extern void myfunction() { … }
但是 , 如果你想產生比較有效率的程式碼 . 請使用 __declspec(dllimport)
因為 __declspec(dllimport) 可以讓編譯器知道這個 symbol 確定是由 DLL export 出來的
![Page 22: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/22.jpg)
Import Import 的實際意義的實際意義
Linker Linker 發現 發現 __declspec(dllimport) __declspec(dllimport) 時時 , , 會在執行檔會在執行檔中的 中的 import sectionimport section 列出該檔所參考的 列出該檔所參考的 symbolsymbol
查閱執行檔所需的 查閱執行檔所需的 symbol symbol
使用 MyDLL.dll 的部分
使用 Kernel32.dll 的部分
DumpBin –imports UseDLL.exe
![Page 23: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/23.jpg)
執行 執行 Executable ModuleExecutable ModuleStep1: Loader 會為該 Process 建立 virtual address
Step2: 將 executable module map 到 virtual address
Step3: 檢查 import section 並且 map 需要的 DLL 到 virtual space 中
搜尋 DLL 的順序2. 目前執行檔的位置3. 該 process 的目前目錄4. Windows 的系統目錄5. Windows 目錄6. Path 環境變數
Step4: 檢查每個 DLL 的 import section 並且 map 需要的 DLL 系統會紀錄每個 DLL 載入的次數
使得 DLL 不會重複載入
![Page 24: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/24.jpg)
當系統找不到 DLL 時 ,所發出的錯誤訊息
Step5: 檢查所有模組的 import symbol 與 載入 DLL 的 export 是否一樣
Step6: 計算每個 symbol 的實際位址 將其放到 executable module 的 import section
DLL base addr + RVA
事實上 , 是 update import section 中的 Imported Address Table (ITA)
Reference: ms-help://MS.MSDNQTR.2004JAN.1033/dnmsj00/html/hood0200.htm
![Page 25: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/25.jpg)
產生你的執行程式產生你的執行程式
當你的程式碼 當你的程式碼 reference reference 一個 一個 import import symbolsymbol 可以由 可以由 import section import section 得到真實的位址得到真實的位址 , , 因此因此
可以成功的存取 可以成功的存取 DLL DLL 的變數的變數 ,function,function 和類別和類別
缺點缺點 Loader Loader 啟動你的程式前啟動你的程式前 ,, 需要需要
重新計算重新計算每個 每個 module module 呼叫位址以及呼叫位址以及載入載入 DLL DLL 都都需要時間需要時間
由於 DLL 的 base address 可能會改變 , 所以必須在 loading time 時 ,才能決定 import function 真實所在位址
![Page 26: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/26.jpg)
EndEnd
![Page 27: 01 dll basics](https://reader034.fdocuments.us/reader034/viewer/2022042508/55a786e21a28ab7c188b46f3/html5/thumbnails/27.jpg)
附錄附錄
使用 Borland’s IMPLIB.exe 可直接將 COFF 的 library format 轉成 OMF 格式 IMPLIB (destination lib name) (source dll) 例如 : IMPLIB mydll.lib mydll.dll
OMF: Object Module Format (BCB 使用 )COFF: Common Object File Format (VC 使用 )