简短版本: 可以浏览所有ELF"部分"运行时期间的标题,并获取每个"部分的重定位地址"每个加载的共享库的标题。
长版:
我尝试在内核(dyn_debug)中存在的用户空间中实现相同的动态调试机制。它的工作方式是每个LOG宏实例在特定的"部分"中创建静态变量。在该计划中
__attribute__((section("__verbose")))
这迫使编译器将变量放在" .data"部分,但在" __详细"部分。可以通过变量访问此部分的后期启动和停止地址
__start___verbose,__ stop___verbose。通过这种方式,一些中心例程可以覆盖所有注册的" log"条目和按需更改属性。
这可以找到静态链接的可执行文件,但是当使用共享库时,有几个" __ verbose"部分(每个共享库一个)和可执行文件本身。 (我当然使用-fPIC标志以便包含在库中)
此外,所有内容都与" -export-dynamic"相关联。为了确保导出所有符号。
每个共享库和主可执行文件都有 init的属性(构造函数)方法。
我在2例中观察到两种不同的行为。
case1:对于第一种情况,库没有加载ldopen,而是加载了" libc加载器"
引用__start___verbose总是返回相同的地址(主要可执行文件的地址),其中只有" main"存在可执行的日志条目。
dlsym(RTLD_NEXT,__ start___verbose),返回" next"的符号地址。可解析的库,所以实际上我得到了所有地址。
案例2:使用ldopen加载库
问题:使用ldopen打开的库有没有办法获得该符号,除了4,因为4需要来自" loader"
的显式调用代码:
/* Main" */
void func1()
{
static int attribute__((section("__verbose"))) var = 1;
}
/* Shared library */
void func2()
{
static int attribute__((section("__verbose"))) var = 2;
}
/* Both in main and shared library
* Prints same address !!! BAD !! */
void __attribute__((constructor)) initializer()
{
struct int *iter;
for (iter = __start___verbose; iter != __stop___verbose; ++iter) {
printf("Value is %d", *iter)
}
}
/* Works for libraries opened by libc runtime.
* Does not work for libraries opened with LDOPEN*/
void __attribute__((constructor)) initializer()
{
struct int *iter = ;
for (iter = dlsym(RTLD_NEXT, "__start___verbose"); iter != __stop___verbose; ++iter) {
printf("Value is %d", *iter)
}
}
/* Snippet for main doing dynamic loading */
handle = ldopen('path', RTLD_NOW)
iter = dlsym(handle, "__start___verbose")
for (; iter != __stop___verbose; ++iter) {
printf("Value is %d", *iter)
}
答案 0 :(得分:1)
您不应该在运行时访问部分信息。段不应该在运行时使用,并且可能会从可执行文件中删除(剥离)。
我可能会使用自定义链接描述文件:
.__verbose:
{
PROVIDE_HIDDEN (__verbose_start = .);
*(.__verbose)
PROVIDE_HIDDEN (__verbose_end = .);
}
这为该部分定义了HIDDEN符号,因此每个ELF文件都有自己的符号版本。
然后ELF文件中的构造函数(或其他代码)可以使用它们:
struct foo*;
extern struct foo* __verbose_start __attribute__((visibility("hidden")));
extern struct foo* __verbose_stop __attribute__((visibility("hidden")));
void __attribute__((constructor)) initializer()
{
initialize_logging(__verbose_start,__verbose_stop);
}