当动态链接二进制文件库时,重定位信息用于绑定不同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全局变量?
答案 0 :(得分:1)
我真的不明白为什么变量在可执行文件中实例化。
您可以找到答案here。
调试器应如何解析foo全局变量
调试器读取符号表(除了调试信息),foo
在主可执行文件b
中定义,并在liba.so
:
nm b | grep foo
0000000000600c68 B foo
答案 1 :(得分:0)
(我阅读了@Employed Russian提供的Oracle文档。)
对非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代码中使用的方法相同。