我有一個程序,靜態與出口的一些功能幾個C++庫的鏈接被刪除:保持導出函數由鏈接器
extern "C"
{
KSrvRequestHandler* CreateRequestHandler(const char* name);
bool DestroyRequestHandler(KSrvRequestHandler* handler);
const char** ListRequestHandlerTypes();
}
主程序然後調用使用GetProcAddress的/ dlsym進行這些功能:
#ifdef WIN32
HINSTANCE hDll = GetModuleHandle(NULL);
mCreateHandler = GetProcAddress(hDll, createFuncName );
mDestroyHandler = GetProcAddress(hDll, destroyFuncName);
mGetHandlerTypes = GetProcAddress(hDll, listFuncName );
#else // POSIX
void* handle = dlopen(NULL, 0);
mCreateHandler = dlsym(handle, createFuncName );
mDestroyHandler = dlsym(handle, destroyFuncName);
mGetHandlerTypes = dlsym(handle, listFuncName );
dlclose(handle);
#endif // !POSIX
所以這裏的關鍵是我使用動態鏈接在我自己的主程序中調用一個函數。 (爲什麼我這樣做超出了問題的範圍,但簡短的回答:這是一個插件架構,但我有一些標準的插件直接鏈接到主要的二進制文件 - 但我仍然想通過它來加載它們同樣的插件加載界面。例如,對於內置插件,我通過傳入當前可執行文件作爲插件接口的源代碼來加載它們。)
這裏是問題:鏈接器不知道我要去需要這些功能,並且不會鏈接它們。
如何強制這些函數被鏈接?對於動態庫,導出它們就足夠了。但是對於一個exe文件,甚至dll導出的函數都會被鏈接器刪除。
我知道我可以強制鏈接,讓主要的二進制文件將這些函數地址分配給某些東西或其他類似的黑客。有沒有正確的方法來做到這一點?
@UPDATE:所以我有一個解決方案,但它確實是醜陋的內部。仍在尋找更好的方法。
所以我必須以某種方式在加載內置接口的對象中定義我需要的符號。我不認爲有強制鏈接器鏈接符號的方法。例如。我無法知道如何構建一個函數庫,該函數始終與其看起來需要或不需要的函數相關聯。這完全取決於可執行文件的鏈接步驟。
所以在可執行文件中,我有一個宏定義了我需要的內置接口。每個內置插件有一個前綴,其所有的接口函數,因此,在我做文件的頂部:
DEFINE_BUILT_IN_PLUGIN(PluginOne)
DEFINE_BUILT_IN_PLUGIN(PluginTwo)
這將迫使我所需要的功能的定義。但宏做,這是這麼醜,我充滿了憤怒和自我懷疑的感覺(我已經刪除了尾隨從宏觀的可讀性斜槓):
#define FORCE_UNDEFINED_SYMBOL(x)
void* _fp_ ## x ## _fp =(void*)&x;
if (((ptrv) _fp_ ## x ##_fp * (rand() | 1)) < 1)
exit(0);
#define DEFINE_BUILT_IN_PLUGIN(PREFIX)
extern "C"
{
KSrvRequestHandler* PREFIX ## CreateRequestHandler(const char* name);
bool PREFIX ## DestroyRequestHandler(KSrvRequestHandler* handler);
const char** PREFIX ## ListRequestHandlerTypes();
}
class PREFIX ## HandlerInterfaceMagic
{
public:
PREFIX ## HandlerInterfaceMagic()
{
FORCE_UNDEFINED_SYMBOL(PREFIX ## CreateRequestHandler);
FORCE_UNDEFINED_SYMBOL(PREFIX ## DestroyRequestHandler);
FORCE_UNDEFINED_SYMBOL(PREFIX ## ListRequestHandlerTypes);
}
};
PREFIX ## HandlerInterfaceMagic PREFIX ## HandlerInterfaceMagicInstance;
由於編譯器是一種優化的天才, ,在FORCE_UNDEFINED_SYMBOLS我會竭盡全力欺騙編譯器鏈接一個未引用的函數。該宏只適用於某個功能。所以我必須創造這個假魔術課。一定會有更好的辦法。
無論如何 - 它確實有效。
我可能會誤解你的情況,但是你可以將導出的函數移動到單獨編譯的庫中,然後在需要時將它們從庫中鏈接起來? –
如果我將內置的插件插入到它們自己的動態庫中,那麼這就行得通了 - 基本上只是將它們編寫爲常規插件,而且它們總是附帶可執行文件。但是這不是最理想的,因爲我希望他們都在同一個文件中。但更大的問題是,內置插件需要訪問主程序的內部。例如。其中一個是內部程序狀態報告的診斷插件。我必須創建一個完整的反向界面(例如exe->插件),以將diag插件作爲單獨的dyn來完成此操作。庫。 –
請不要使用符號名稱的前導雙下劃線,它們是爲編譯器保留的。如果您擔心名稱衝突,請將它們放在名稱空間中。 –