【问题标题】:Location of global variables with DWARF (and relocation)使用 DWARF 定位全局变量(和重定位)
【发布时间】:2014-02-05 00:18:27
【问题描述】:

当动态链接二进制文件与库时,重定位信息用于绑定不同 ELF 对象的变量/函数。然而 DWARF 不受重定位的影响:调试器应该如何解析全局变量?

假设我有 liba.so (a.c) 定义一个全局变量(使用带有 GCC 或 Clang 的 GNU/Linux):

#include <stdio.h>

int foo = 10;

int test(void) {
  printf("&foo=%p\n", &foo);
}

和一个针对 liba.so (b.c) 链接的程序 b:

#include <stdio.h>

extern int foo;

int main(int argc, char** argv) {
  test();
  printf("&foo=%p\n", &foo);  
  return 0;
}

我希望 "foo" 将在 liba.so 中实例化 但实际上它在 liba.so 和 b 中都被实例化了:

$ ./b 
&foo=0x600c68 # <- b .bss
&foo=0x600c68 # <- b .bss

使用的 foo 变量(b 和 lib.so 都使用)在 b 的 .bss 中 而不是在 liba.so 中:

[...]
0x0000000000600c68 - 0x0000000000600c70 is .bss
[...]
0x00007ffff7dda9c8 - 0x00007ffff7dda9d4 is .data in /home/foo/bar/liba.so
0x00007ffff7dda9d4 - 0x00007ffff7dda9d8 is .bss in  /home/foo/bar/liba.so

foo 变量被实例化了两次:

  • 在 liba.so 中一次(与程序 b 链接时不使用此实例)

  • 曾经在 b 中(这个实例被用作 b 中另一个的实例)。

(我真的不明白为什么在可执行文件中实例化了变量。)

DWARF 信息中只有 b 中的声明(如预期):

$ readelf -wi b
[...]
<1><ca>: Abbrev Number: 9 (DW_TAG_variable)
  <cb>   DW_AT_name        : foo      
  <cf>   DW_AT_decl_file   : 1        
  <d0>   DW_AT_decl_line   : 3        
  <d1>   DW_AT_type        : <0x57>   
  <d5>   DW_AT_external    : 1        
  <d5>   DW_AT_declaration : 1
[...]

并且在 liba.so 中找到了一个位置:

$ readelf -wi liba.so
[...]
<1><90>: Abbrev Number: 5 (DW_TAG_variable)
  <91>   DW_AT_name        : foo      
  <95>   DW_AT_decl_file   : 1        
  <96>   DW_AT_decl_line   : 3        
  <97>   DW_AT_type        : <0x57>   
  <9b>   DW_AT_external    : 1        
  <9b>   DW_AT_location    : 9 bloc d'octets: 3 d0 9 20 0 0 0 0 0     (DW_OP_addr: 2009d0)
[...]

此地址是 liba.so (.data) 中 foo 的(未使用的)实例的位置。

  • 我最终得到了 foo 全局变量的 2 个实例(在 liba.so 中,一个在 b 中);
  • DWARF 只能看到第一个;
  • 只使用第二个。

调试器应该如何解析 foo 全局变量?

【问题讨论】:

    标签: c elf dwarf


    【解决方案1】:

    我真的不明白为什么在可执行文件中实例化了变量。

    你可以找到答案here

    调试器应该如何解析 foo 全局变量

    调试器读取符号表(除了调试信息),foo确实在主可执行文件b和@987654324中定义@:

    nm b | grep foo
    0000000000600c68 B foo
    

    【讨论】:

      【解决方案2】:

      (我阅读了@Employed Russian 提供的Oracle 文档。)

      全局变量重新实例化是针对非 PIC 代码进行的,以便在不修补非 PIC 代码的情况下以非 PIC 方式取消引用变量:

      • 已为非 PIC 代码复制了变量;
      • 变量在可执行文件中实例化;
      • 复制重定位指令用于在动态链接时从源共享对象复制数据;
      • 共享对象中的实例未使用(完成重定位复制后)。

      复制搬迁说明:

      $readelf -r b
      
      Relocation section '.rela.dyn' at offset 0x638 contains 2 entries:
        Offset          Info           Type           Sym. Value    Sym. Name + Addend
      000000600c58  000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
      000000600ca8  001200000005 R_X86_64_COPY     0000000000600ca8 foo + 0
      

      对于函数,GOT+PLT 技术的使用方式与它们在 PIC 代码中的使用方式相同。

      【讨论】:

        猜你喜欢
        • 2018-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多