如何使用 dladdr 获取 gnu 间接函数的名称?

How to get name of gnu indirect function using dladdr?

我无法获得带有间接函数的 elf 的 gnu 扩展以与 dladdr 一起工作。

下面的例子中fabssinlibm中的两个动态函数,其中sin也是一个间接函数。从其指针查找 fabs 效果很好,但未找到 sin。我尝试了 dlopen-rdynamic 的各种标志,但都没有成功。

调试器显示了如何从 gnu-indirect-function variable 计算 sin__sin_avx

我是不是遗漏了什么或者 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
}

Am I missing something here or are indirect functions not supported by dladdr?

好的,这个很有趣。

因此 ifuncs 通过将原始函数地址(在本例中为 sin)替换为当前平台上动态链接器解析的地址来工作。 sin 可以根据 CPU 功能解析为 4 种实现之一:

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...

manages to work if you remove -fPIC

发生这种情况是因为无论何时编译 w/o -fPIC 编译器都知道当前源文件将转到主可执行文件,因此保证运行时函数地址解析为可执行文件的 PLT 条目。因此,它不是从 GOT 加载它,而是简单地将 PLT 地址传递给 namedladdr,然后愉快地在可执行文件的符号表中定位 sin

编辑:

Glibc 人员确认here