GCC:为什么动态符号表中缺少全局变量?

时间:2015-03-27 08:03:44

标签: gcc symbols

代码:

//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);

}

编译:

$ gcc -fPIC -o test test.c

运行:(不重要)

$ ./test

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

读取符号表:


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

问题1 :为什么全局变量 v_flag 出现在 symtab 中,而不出现在 dynsym 中? (注意:禁用优化“-O0”没有帮助)

关注问题1,添加“ -rdynamic ”标志将使 v_flag (以及其他人)出现在 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:
                            ...

然而,根据手册页


-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.

因此,问题2 ,我们可以说 v_flag 未使用(因此它不会出现在 dynsym )?如果是这样,为什么?

更新1:

这个问题没有出现在ld版本2.20。*中(感谢Konstantin Vladimirov指出这一点)。

2 个答案:

答案 0 :(得分:1)

首先你应该意识到,即使使用rdynamic,你在这里做的事情也很尴尬 - 将依赖于位置的v_flag导出到动态加载器特定的dynsym部分。

回答你的问题 - 因为它未被使用而被删除。 它未被使用,因为它无法在任何合理的动态环境中使用。

我认为你真正想要的是编译一个与位置无关的代码:

gcc -o test test.c -fPIC

现在没有任何rdynamic黑客,你确实有:

 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

我建议你阅读一些关于编写共享库的文档。 This one is my favorite

汇编:

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

测试:GCC 4.4.3,GCC 4.7.2,GCC 4.8.2,GCC 4.9.2,链接器ld 2.20.1

答案 1 :(得分:0)

由于无法发表评论,因此不得不在此处写下。

GNU ld version 2.20.51.0.2-5.36.el6 20100205中发生了相同的行为(即,dynsym表中未显示v_flag)。

因此,我想编辑出有问题的更新,因为并非所有2.20。*都适用。

因此,目前唯一的方法是使用-rdynamic,如果还有其他方法,请有人提供答案,因为-rdynamic就像是黑客。

我也看到了没有rdynamic并且ld-version> 2.23有效的情况,但是我看不出原因或无法重现该原因。