【问题标题】:GCC: why global variable missing in dynamic symbol table?GCC:为什么动态符号表中缺少全局变量?
【发布时间】:2015-05-31 11:56:10
【问题描述】:

代码:

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

运行:(不重要)

$ ./测试 v_flag = 51914, &v_flag=0x601034 v_flag = 51915

读取符号表:

$ gcc --版本 gcc (GCC) 4.4.7 20120313 (红帽 4.4.7-8) ... $ ld --版本 GNU ld 版本 2.23.52.0.1-16.el7 20130226 ... $ readelf -s 测试 符号表“.dynsym”包含 4 个条目: Num:值大小类型绑定 Vis Ndx 名称 0: 0000000000000000 0 NOTYPE 本地默认值 1: 0000000000000000 0 FUNC 全局默认值和 printf@GLIBC_2.2.5 (2) 2:0000000000000000 0 FUNC 全局默认值和 __libc_start_main@GLIBC_2.2.5 (2) 3:0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 符号表 '.symtab' 包含 65 个条目: Num:值大小类型绑定 Vis Ndx 名称 ... 58: 0000000000601048 0 NOTYPE 全球默认值 25 _end 59: 0000000000400450 0 FUNC 全局默认值 13 _start 60: 0000000000601038 0 NOTYPE 全局默认值 25 __bss_start 61: 0000000000400514 89 FUNC 全局默认值 13 主要 62: 0000000000601034 4 对象全局默认值 24 v_flag ...

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

跟进问题1,添加“-rdynamic”标志将使v_flag(以及其他)出现在dynsym中:

$ gcc -rdynamic -o 测试 test.c $ readelf -s 测试 符号表 '.dynsym' 包含 18 个条目: Num:值大小类型绑定 Vis Ndx 名称 0: 0000000000000000 0 NOTYPE 本地默认值 1: 0000000000000000 0 FUNC 全局默认值和 printf@GLIBC_2.2.5 (2) 2:0000000000000000 0 FUNC 全局默认值和 __libc_start_main@GLIBC_2.2.5 (2) 3:0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ ... 11:0000000000400670 0 FUNC 全局默认值 13 _start 12:0000000000601038 0 NOTYPE 全局默认值 25 __bss_start 13:0000000000400734 89 FUNC 全局默认值 13 主要 14:0000000000400600 0 FUNC 全局默认值 11 _init 15:0000000000400800 2 FUNC 全局默认值 13 __libc_csu_fini 16:0000000000400848 0 FUNC 全局默认值 14 _fini 17:0000000000601034 4 对象全局默认值 24 v_flag 符号表 '.symtab' 包含 65 个条目: ...

但是,根据手册页

-r动态 在支持它的目标上将标志 -export-dynamic 传递给 ELF 链接器。这指示链接器将所有符号(不仅是使用的符号)添加到动态符号表中。

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

更新 1:

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

【问题讨论】:

    标签: gcc symbols


    【解决方案1】:

    无法评论,所以不得不在这里写。

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

    所以我猜想编辑有问题的更新,因为并非所有 2.20.* 都有效。

    所以目前唯一的方法是使用 -rdynamic,如果有其他方法,请有人添加答案,因为 -rdynamic 感觉就像一个 hack。

    我还看到了没有 rdynamic 和 ld-version > 2.23 的情况,但我无法看到原因或重现它为什么有效。

    【讨论】:

      【解决方案2】:

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

      回答您的问题 - 因为它未使用而被丢弃。 并且它没有被使用,因为它不能用于任何合理的动态上下文中。

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

      gcc -o test test.c -fPIC
      

      现在没有任何 rdynamic hack,您确实有:

       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

      【讨论】:

      • 感谢您提供非常有帮助的答案。我忘记了 -fPIC 标志是我的严重错误。然而,即使使用 -fPICv_flag 仍然不在 dynsym 中。这对我来说很奇怪,因为我在 dynsym 中期待 v_flag。我用 gcc 4.8.2 测试了“-fPIC”(还没有用 gcc 4.4.7)。你试过的 gcc 版本是什么?
      • 我用 gcc 4.4.7 测试过。 v_flag 不会出现在 dynsym 中,即使使用“-fPIC”也是如此。
      • 这真的很奇怪,因为今天我测试了 4.7.2、4.8.2、4.9.2 和 4.4.3——在所有情况下 v_flag 都在正确的部分(在 fPIC 编译的情况下) .我的拱门是 x86_64,链接器是 2.20.1
      • 很高兴收到您的来信。我用 GNU ld 版本 2.20.51.0.2-20.fc13 20091009 进行了测试,它工作正常。所以,我猜链接器在以后的版本中改变了行为。问题是我目前的工具链使用的是 GNU ld 版本 2.23.52.0.1-16.el7 20130226。真想明白为什么会有这样的变化?
      猜你喜欢
      • 1970-01-01
      • 2017-09-20
      • 1970-01-01
      • 2011-08-21
      • 2021-12-10
      • 2020-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多