如何使用 dladdr 获取 gnu 间接函数的名称?
How to get name of gnu indirect function using dladdr?
我无法获得带有间接函数的 elf 的 gnu 扩展以与 dladdr
一起工作。
下面的例子中fabs
和sin
是libm
中的两个动态函数,其中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 地址传递给 name
和 dladdr
,然后愉快地在可执行文件的符号表中定位 sin
。
编辑:
Glibc 人员确认here。
我无法获得带有间接函数的 elf 的 gnu 扩展以与 dladdr
一起工作。
下面的例子中fabs
和sin
是libm
中的两个动态函数,其中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 地址传递给 name
和 dladdr
,然后愉快地在可执行文件的符号表中定位 sin
。
编辑:
Glibc 人员确认here。