2017-01-08 48 views
4

我無法通過間接函數獲得gnu擴展到elf,與dladdr一起使用。如何使用dladdr獲取gnu間接函數的名稱?

在下面的例子中,fabssinlibm中的兩個動態函數,其中sin也是一個間接函數。從它的指針查找fabs效果不錯,但找不到sin。我已嘗試各種標誌dlopen-rdynamic沒有成功。

調試器顯示如何從gnu-indirect-function variable__sin_avx評估sin

我在這裏丟失了些什麼或者是間接功能dladdr不支持?

/* 
    compiled with g++-5 -fPIC -ldl 
*/ 

#include <cmath> 
#include <dlfcn.h> 
#include <iostream> 

char const * name (void * arg) 
{ 
    void * h = dlopen (NULL, RTLD_LAZY); 

    if (h) 
    { 
     Dl_info res; 
     int status = dladdr (arg, & res); 
     dlclose (h); 

     if (status && res.dli_sname && arg == res.dli_saddr) 
      return res.dli_sname; 
    } 

    return ""; 
} 

int main() 
{ 
    std::cout << fabs (0.0) << " " << name ((void *) fabs) << std::endl; // found 
    std::cout << sin (0.0) << " " << name ((void *) sin) << std::endl; // not found 
} 
+0

有趣的,如果你刪除'-fPIC',管理工作。 – yugr

回答

3

我失去了一些東西在這裏或者間接的功能不提供dladdr支持?

好的,這一個很有趣。

因此,ifuncs通過用當前平臺上的動態鏈接程序替換原來的函數地址(在本例中爲sin)來工作。 sin可以解決1-4之一的實現依賴於CPU的能力:

libm_ifunc (__sin, (HAS_ARCH_FEATURE (FMA4_Usable) ? __sin_fma4 : 
        HAS_ARCH_FEATURE (AVX_Usable) 
        ? __sin_avx : __sin_sse2)); 
weak_alias (__sin, sin) 

現在每個__sin_XXX是一個內部的Glibc功能是libm.so出口,這就是爲什麼dladdr沒有找到它。

因此,答案是基本沒有,dladdr不能很好地ifuncs工作...

管理,如果你刪除-fPIC

這是因爲每當你編譯W/O工作-fPIC編譯器知道當前源文件將轉到主可執行文件,因此運行時函數地址保證解析爲可執行文件的PLT條目。因此,不是從GOT加載,而是簡單地將PLT地址傳遞給namedladdr,然後在可執行文件的symtab中快速找到sin

編輯:

被Glibc鄉親here證實。

+0

非常感謝。我確實找到了關於ifunc和可見性的一些[posts](https://gcc.gnu.org/ml/gcc/2016-08/msg00138.html),但是這個主題對我來說很新。作爲解決方法,是否有任何方法可以引用原始間接函數,即具有'__attribute__ ifunc'的函數? – listcrawler

+0

我個人並不知道比手動解析GOT表格更簡單的方法(例如[這裏描述](http://vxheaven.org/lib/vrn00.html#c6)),但這是一件很有意義的事情。您可以嘗試在[libc-help]中提問(https://sourceware.org/ml/libc-help/)。 – yugr

+0

而[這裏](https://sourceware.org/ml/libc-help/2017-01/msg00010.html)是我對libc-help問題的回答。簡而言之,原始ifunc符號名稱的信息在解析執行時會丟失。 關於解析GOT - 赦免我的程序集 - 但從我可以從生成的代碼中讀取的內容,我不確定ifuncs是否在程序啓動時已經解決,而不是在第一次調用時解決。如果是這樣,那麼就沒有機會解析GOT原來的ifunc地址了,對吧? – listcrawler

相關問題