首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Windows 核心編程:DLL 進階技術——顯式連結、基址重定位與模組繫結

     編輯:關於C語言

兩種 DLL 載入方式

隱式連結顯式連結
編譯期連結 .lib,啟動時自動載入執行期呼叫 LoadLibrary 手動載入
EXE 含導入表EXE 無導入表,不需 .lib
缺 DLL 無法啟動可延遲載入、優雅降級

顯式連結完整流程

// 1. 載入 DLL
HMODULE hDll = LoadLibraryEx(L"mydll.dll", NULL, 0);
if (!hDll) return ERROR_MOD_NOT_FOUND;

// 2. 取得函式位址
typedef void (CALLBACK *PFN_DUMP)(HMODULE);
PFN_DUMP pfn = (PFN_DUMP)GetProcAddress(hDll, "DumpModule");
if (!pfn) { FreeLibrary(hDll); return ERROR_PROC_NOT_FOUND; }

// 3. 呼叫函式
pfn(hDll);

// 4. 卸載
FreeLibrary(hDll);

DLL 參考計數機制

  • LoadLibrary:計數 +1,首次載入才映射映像
  • FreeLibrary:計數 -1,歸零時卸載映像
  • 計數各行程獨立

FreeLibraryAndExitThread 解決「自刪」難題

VOID FreeLibraryAndExitThread(HMODULE hDll, DWORD exitCode) {
    FreeLibrary(hDll);      // 可能卸載含本執行緒代碼的 DLL
    ExitThread(exitCode);   // 但 Kernel32.dll 仍在,安全返回
}

適用於 DLL 內建立的背景執行緒結束時自我清理。

DllMain 入口點與四大通知

BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, PVOID reserved) {
    switch (reason) {
        case DLL_PROCESS_ATTACH:  // 進程載入(首次)
            DisableThreadLibraryCalls(hInst); // 優化:不需要 THREAD 通知
            break;
        case DLL_THREAD_ATTACH:   // 執行緒建立
            break;
        case DLL_THREAD_DETACH:   // 執行緒結束
            break;
        case DLL_PROCESS_DETACH:  // 進程卸載/結束
            break;
    }
    return TRUE;
}
  • DLL_PROCESS_ATTACH 返回 FALSE 會導致載入失敗、進程終止
  • 禁忌:DllMain 內不要呼叫其他 DLL 的匯出函式(可能未初始化)

模組基址重定位

  • DLL 有偏好基址,衝突時系統重定位(修正絕對位址)
  • 重定位會複製頁面,破壞頁面共享,增加記憶體壓力
  • 解決:/BASE 指定不衝突基址,或使用模組繫結

模組繫結

  • 預先計算匯入函式真實位址寫入 IAT,啟動時跳過解析
  • 需目標 DLL 基址不變,否則失效回退重定位
  • 工具:bind.exe、VS 連結器 /BIND

參考:《Windows 核心編程》第 5 版第 4 部分

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved