简版: 在运行时可以遍历所有ELF“节”标题,并为每个加载的共享库获取每个“节”标题的重定位地址。Linux在运行时迭代ELF“节”标题
长版本: 我试图在内核(dyn_debug)中实现用于用户空间中的动态调试的相同机制。它的工作方式是每个LOG宏实例在程序中的特定“部分”中创建静态变量 __attribute__((section("__verbose")))
这会强制编译器将该变量放在“.data”部分而不是“__verbose”部分。本节后面的开始和结束地址可以通过变量 __start___verbose,__stop___verbose来访问。通过这种方式,一些中央例程可以遍历所有已注册的“日志”条目并根据需要更改属性。 这适用于静态链接的可执行文件,但是在使用共享库时,有几个“__verbose”节(每个共享库一个节)和一个可执行文件本身。 (我使用-fPIC标志当然是为了包含在库中) 为了确保所有的符号都被导出,所有与“-export-dynamic”链接的所有内容。
对于init,每个共享库和主可执行文件都有 属性(构造函数)方法。
我曾在2例中观察到两种不同的行为。
情形1:对于第一壳体库不装载ldopen而是由“libc的加载器”
引用__start___verbose总是返回相同的地址(即主可执行文件的),其中,仅“main”的可执行记录条目存在。
dlsym(RTLD_NEXT,__start___verbose)返回“下一个”可解析库的符号地址,所以实际上我得到所有地址。
的情况下2:加载库ldopen
- 引用__start___verbose总是返回相同的地址(主可执行的)
- 的dlsym(RTLD_NEXT,__start___verbose)返回NULL。
- dlsym(RTLD_DEFAULT,__start___verbose)返回“主”进程表。
- 的dlsym(手柄,__start___verbose) - 返回正确的区段地址
问:有没有办法为库ldopen打开,以获得该符号,除了4,如4需要显式调用从“装载机”
代码:
/* 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)
}
你做什么特别的有'__start ___ verbose'和'__stop ___ verbose'变量,因为我没有他们。 – ysdx
难道你不想在ELF文件的(高优先级)构造函数中初始化你的变量吗?否则,在执行构造函数的代码时,它们不会被初始化。 – ysdx