2015-05-31 42 views
1

我在寫一個C++內存分析器。在任何全局對象之前初始化

衆所周知,一個可執行程序可能包含許多全局對象,其DLL模塊可能包含全局對象,如 。這些全局對象將初始化爲CRT 初始化 - 在入口點之後和WinMain之前;對於DLL, 的入口點是_DllMainCRTStartup,在進入DllMain之前, 將初始化該DLL的所有全局對象。

全局對象可能會分配內存。因此內存分析器 必須在任何全局對象初始化之前初始化。在 做了大量的研究後,我發現這不是一件容易的事。

一個想法是使用CreateProcess和CREATE_SUSPENDED標誌 - 嘗試 以獲得第一次機會。之後,使用CreateRemoteThread在目標進程中調用 LoadLibrary來加載注入DLL,並且 初始化該DLL。但它不起作用because this will load all the implicit-linking DLLs of the executable program first.也許CreateRemoteThread觸發這種行爲?

那麼,我們如何獲得第一次機會呢?

回答

0

可能有辦法做到這一點,否則使用非常特定於平臺的方式,但解決該問題的一種方法是將延遲初始化與dylib加載相結合。

例如,假設你的內存分配函數遠銷這樣的:

API void* exported_alloc(); 
API void exported_free(void* mem); 

...裏面dylib稱爲mem.dll

在這種情況下,爲了確保所有其他dylibs可以得到它被加載時,我們可以創建一箇中央靜態鏈接庫(例如:sdk.lib),您的所有dylibs的鏈接針對與像這樣的標題:

#ifndef MEMORY_H 
#define MEMORY_H 

// Memory.h 
void* my_alloc(); 
void my_free(void* mem); 

#endif 

...我們可以實現像這樣:

static void* (exported_alloc)() = 0; 
static void (exported_free)(void* mem) = 0; 

static void initialize() 
{ 
    if (!exported_alloc) 
    { 
     // Load 'mem.dll' (ex: 'LoadLibrary') and look up 
     // symbols for `exported_alloc` and `exported_free` 
     // (ex: GetProcAddress). 
    } 
} 

void* my_alloc() 
{  
    initialize(); 
    return exported_alloc(); 
} 

void my_free(void* mem) 
{ 
    initialize(); 
    exported_free(mem); 
} 

。然後,當你用DLL完成在適當的時候調用FreeLibrary。這會產生一些運行時間的開銷(類似於訪問單例的開銷),但它是一個跨平臺的解決方案(假設您有跨平臺的方式在運行時加載/卸載dylibs /共享庫)。

使用此解決方案,在全局範圍內分配內存的所有DLL將在以緩存初始化方式執行任何內存分配之前加載mem.dll,確保它們都可以在適當的位置訪問您的內存函數時間。

+0

我會繼續思考這個想法。也許initialize()加載mem.dll是不安全的,因爲my_alloc()將在初始化全局對象時被調用,它從入口點開始,是的 - 加載器鎖定可能導致死鎖。 – amanjiang