Linux迭代ELF" section"运行时期间的标头

时间:2016-03-29 21:36:08

标签: c linux elf

简短版本: 可以浏览所有ELF"部分"运行时期间的标题,并获取每个"部分的重定位地址"每个加载的共享库的标题。

长版: 我尝试在内核(dyn_debug)中存在的用户空间中实现相同的动态调试机制。它的工作方式是每个LOG宏实例在特定的"部分"中创建静态变量。在该计划中 __attribute__((section("__verbose"))) 这迫使编译器将变量放在" .data"部分,但在" __详细"部分。可以通过变量访问此部分的后期启动和停止地址  __start___verbose,__ stop___verbose。通过这种方式,一些中心例程可以覆盖所有注册的" log"条目和按需更改属性。 这可以找到静态链接的可执行文件,但是当使用共享库时,有几个" __ verbose"部分(每个共享库一个)和可执行文件本身。 (我当然使用-fPIC标志以便包含在库中) 此外,所有内容都与" -export-dynamic"相关联。为了确保导出所有符号。

每个共享库和主可执行文件都有 init的属性(构造函数)方法。

我在2例中观察到两种不同的行为。

case1:对于第一种情况,库没有加载ldopen,而是加载了" libc加载器"

  1. 引用__start___verbose总是返回相同的地址(主要可执行文件的地址),其中只有" main"存在可执行的日志条目。

  2. dlsym(RTLD_NEXT,__ start___verbose),返回" next"的符号地址。可解析的库,所以实际上我得到了所有地址。

  3. 案例2:使用ldopen加载库

    1. 引用__start___verbose始终返回相同的地址(主要可执行文件的地址)
    2. dlsym(RTLD_NEXT,__ start___verbose)返回NULL。
    3. dlsym(RTLD_DEFAULT,__ start___verbose)返回" main"流程表。
    4. dlsym(handle,__ start___verbose) - 返回正确的部分地址
    5. 问题:使用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)
      }
      

1 个答案:

答案 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);  
}