strongdevil
strongdevil

Reputation: 83

GCC: why global variable missing in dynamic symbol table?

Code:

//test.c
#include <stdio.h>
int v_flag = 0xCACA;

void main(int argc, char* argv[]){
  printf("v_flag = %d, &v_flag=%p \n", v_flag, &v_flag);
  v_flag++;
  printf("v_flag = %d\n", v_flag);

}

Compile:

$ gcc -fPIC -o test test.c

Run: (not important)

$ ./test

v_flag = 51914, &v_flag=0x601034
v_flag = 51915

Read symbol tables:


$ gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-8)
...

$ ld --version
GNU ld version 2.23.52.0.1-16.el7 20130226
...

$ readelf -s test

Symbol table '.dynsym' contains 4 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
     3: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__

Symbol table '.symtab' contains 65 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
                            ...
    58: 0000000000601048     0 NOTYPE  GLOBAL DEFAULT   25 _end
    59: 0000000000400450     0 FUNC    GLOBAL DEFAULT   13 _start
    60: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start
    61: 0000000000400514    89 FUNC    GLOBAL DEFAULT   13 main
    62: 0000000000601034     4 OBJECT  GLOBAL DEFAULT   24 v_flag
                            ...

Question 1: Why the global variable v_flag appears in symtab, but not in dynsym? (note: disable optimizations "-O0" does not help)

Following up Question 1, adding "-rdynamic" flag will make v_flag (and also others) appear in dynsym:


$ gcc -rdynamic -o test test.c

$ readelf -s test

Symbol table '.dynsym' contains 18 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
     3: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
                            ...
    11: 0000000000400670     0 FUNC    GLOBAL DEFAULT   13 _start
    12: 0000000000601038     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start
    13: 0000000000400734    89 FUNC    GLOBAL DEFAULT   13 main
    14: 0000000000400600     0 FUNC    GLOBAL DEFAULT   11 _init
    15: 0000000000400800     2 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    16: 0000000000400848     0 FUNC    GLOBAL DEFAULT   14 _fini
    17: 0000000000601034     4 OBJECT  GLOBAL DEFAULT   24 v_flag

Symbol table '.symtab' contains 65 entries:
                            ...

However, according to the man page


-rdynamic
    Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table.

Hence, question 2, can we say that v_flag is unused (hence it does not appear in dynsym)? If so, why?

Update 1:

This issue does not show up in ld version 2.20.* (Thank Konstantin Vladimirov for pointing out this).

Upvotes: 2

Views: 4788

Answers (2)

Swapnil.Das
Swapnil.Das

Reputation: 25

Was not able to comment so had to write it here.

The same behavior(i.e doesn't show v_flag in dynsym table) happens in GNU ld version 2.20.51.0.2-5.36.el6 20100205.

So I guess edit out the Update in question as not all 2.20.* works.

So for now only way is to use -rdynamic, someone please add an answer if there is some other way, because -rdynamic feels like a hack.

Also I have seen cases where without rdynamic and also ld-version > 2.23 works, but I am not able to see the reason or reproduce it on why that works.

Upvotes: 0

Konstantin Vladimirov
Konstantin Vladimirov

Reputation: 7009

First you should realize, that even with rdynamic, you are doing here something really awkward -- exporting position-dependent v_flag to dynamic loader specific dynsym section.

Answering your questions -- it is dropped because it is unused. And it is unused because it can not be used in any sensible dynamic context.

I think what you do really want -- is to compile a code to be positional independent:

gcc -o test test.c -fPIC

Now without any rdynamic hacks, you do have:

 0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
 1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (2)
 2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
 3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
 4: 0000000000601020     4 OBJECT  GLOBAL DEFAULT   25 v_flag

I suggest you to read some docs on writing shared libraries. This one is my favorite.

In assembly:

  .globl  v_flag
  .data
  .align 4
  .type v_flag, @object
  .size v_flag, 4
v_flag:
  .long 51914

Tested: GCC 4.4.3, GCC 4.7.2, GCC 4.8.2, GCC 4.9.2, linker ld 2.20.1

Upvotes: 2

Related Questions