2011-09-08 47 views
4

我想按名稱獲取函數的地址。如何按名稱獲取函數地址?

例如,目前我使用dlsym

unsigned long get_func_addr(const char *func_name) 
{ 
    return (unsigned long)dlsym(NULL, func_name); 
} 

然而,dlsym僅適用於外部函數。它不適用於靜態功能。我知道在不同的文件中可能會有多個具有相同名稱的靜態函數。但我需要至少得到一個靜態函數的地址和名稱。有時靜態函數將被調入。但是,如果C文件是使用調試編譯的,那麼也可以。我認爲與-g,靜態功能的符號表是存在的,但我怎麼可以訪問它?

我不想創建一個表來將字符串映射到函數地址。我需要找到一種動態的方法。

+1

使用'stdint.h'中的'uintptr_t'而不是'unsigned long'。 –

+0

你爲什麼想這樣做?如果你能夠保證帶有靜態模塊是以調試模式編譯的,你應該能夠使該函數成爲非靜態的,或者爲它添加一個簡單的非靜態包裝器。 –

+1

This SO question has some pointers to information on how to read debugging symbols:http://stackoverflow.com/q/5045430/12711 –

回答

3

如果不創建一些可用於查找的外部文件,這實在是不可能的......例如,正如您所提到的,靜態函數的符號表存在,但是這是在編譯時生成的/鏈接時間...它不是從非編譯代碼模塊訪問的東西。

因此,基本上你可以從編譯和鏈接的可執行文件中生成和導出符號表作爲外部文件,然後有一個函數在外部文件中動態地查找函數名,該函數名將提供獲取編譯器和鏈接器編譯/鏈接到的函數的地址。

+0

我想這可能是可能的。你知道,backtrace()可以從地址獲得函數的名字。擴展回溯以支持從名稱獲取地址不應太困難。 – limi

+0

是的,但'backtrace()'是'libc'實現的一個函數,因此它是運行您的可執行文件的操作系統運行時的一部分。如果您有另一個程序正在爲您的C可執行文件創建一個虛擬運行時,那麼您還可以創建可從您的可執行文件調用的函數,以便運行時可以檢查您的進程,然後將信息返回給您(即ptrace,調試程序等) 。但是,除非運行時已經在可執行文件和自身之間創建了一種通信方法,否則這在你自己的代碼中是不可能的。 – Jason

3

A static函數在二進制文件中甚至不需要存在,所以沒有辦法得到它的地址。即使它確實存在,它可能已被編譯器根據某些參數只能採用特定值的知識進行了修改,或者它可能調用了調用約定,使其不能被外部調用等。唯一的辦法就是可以確保存在一個靜態函數的「真實」版本,如果它的地址通過函數指針對其他模塊可見的話。

0

如果您要查找的功能位於DLL中,您可以使用Windows API getprocaddress(),它將函數的名稱和DLL的名稱作爲參數。

如果你想找到用戶定義的函數,我會建議使用查找表作爲這些函數的名稱不存儲。

對於用戶定義的函數,可以強制每個函數在其起始處將其名稱導出到另一個函數。即:

void my_func() 
{ 
    register(my_func,"my_func");// the address and the name 
    // ... 
} 

因此,你可以稍後按名稱查找函數。