Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Location of global variables with DWARF (and relocation)

Tags:

c

elf

dwarf

When dynamically linking a binary with libraries, relocation information is used to bind the variables/functions of the different ELF objects. However DWARF is not affected by relocation: how is a debugger supposed to resolve global variables?

Let's say I have liba.so (a.c) defining a global variable (using GNU/Linux with GCC or Clang):

#include <stdio.h>

int foo = 10;

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

and an program b linked against liba.so (b.c):

#include <stdio.h>

extern int foo;

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

I expect that "foo" will be instanciated in liba.so but in fact it is instanciated in both liba.so and b:

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

The foo variable which is used (both by b and by lib.so) is in the .bss of b and not in 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

The foo variable is instanciated twice:

  • once in liba.so (this instance is not used when linked with program b)

  • once in b (this instance is used instance of the other in b).

(I don't really understand why the variable is instanciated in the executable.)

There is only a declaration in b (as expected) in the DWARF informations:

$ 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
[...]

and a location is found in 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)
[...]

This address is the location of the (unsued) instance of foo in liba.so (.data).

  • I end up with 2 instances of the foo global variable (on in liba.so and one in b);
  • only the first one can be seen with DWARF;
  • only the secone one is used.

How is the debugger supposed to resolve the foo global variable?

like image 739
ysdx Avatar asked Jan 24 '26 03:01

ysdx


1 Answers

I don't really understand why the variable is instanciated in the executable.

You can find the answer here.

How is the debugger supposed to resolve the foo global variable

The debugger reads symbol tables (in addition to debug info), and foo does get defined in both the main executable b, and in liba.so:

nm b | grep foo
0000000000600c68 B foo
like image 80
Employed Russian Avatar answered Jan 25 '26 18:01

Employed Russian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!