DWARF(和重定位)的全局变量的位置

时间:2014-02-05 00:18:28

标签: c elf dwarf

当动态链接二进制文件库时,重定位信息用于绑定不同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中为on,在b中为1);
  • 只有第一个可以看到DWARF;
  • 仅使用了第二个。

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

2 个答案:

答案 0 :(得分:1)

  

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

您可以找到答案here

  

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

调试器读取符号表(除了调试信息),foo 在主可执行文件b中定义,并在liba.so

nm b | grep foo
0000000000600c68 B foo

答案 1 :(得分:0)

(我阅读了@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代码中使用的方法相同。