2017-01-08 96 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