好记性不如铅笔头

C && C++, 编程

【转】gcc选项-g与-rdynamic的异同

本部分转自【 http://blog.csdn.net/runboying/article/details/7006224 】,有删改。

-rdynamic
用来通知链接器将所有符号添加到动态符号表中(目的是能够通过使用 dlopen 来实现向后跟踪)
-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. This option is needed for some uses of dlopen or to
allow obtaining backtraces from within a program.

本部分转自【 http://www.lenky.info/archives/2013/01/2190 】,有精简。

cc的-g,应该没有人不知道它是一个调试选项,因此在一般需要进行程序调试的场景下,我们都会加上该选项,并且根据调试工具的不同,还能直接选择更有针对性的说明,比如-ggdb。-g是一个编译选项,即在源代码编译的过程中起作用,让gcc把更多调试信息(也就包括符号信息)收集起来并将存放到最终的可执行文件内。
相比-g选项,-rdynamic却是一个连接选项,它将指示连接器把所有符号(而不仅仅只是程序已使用到的外部符号,但不包括静态符号,比如被static修饰的函数)都添加到动态符号表(即.dynsym表)里,以便那些通过dlopen()或backtrace()(这一系列函数使用.dynsym表内符号)这样的函数使用。

看示例:

[root@www c]# cat t.c 
#include <stdio.h>
void bar() {}
void baz() {}
void foo() {}
int main() { foo(); printf("test"); return 0; }

对于上面的示例代码,普通和加-g编译:

[root@www c]# uname -a
Linux www.t1.com 2.6.38.8 #2 SMP Wed Nov 2 07:52:53 CST 2011 x86_64 x86_64 x86_64 GNU/Linux
[root@www c]# gcc -O0 -o t t.c 
[root@www c]# gcc -O0 -g -o t.g t.c 
[root@www c]# readelf -a t > t.elf
[root@www c]# readelf -a t.g > t.g.elf
[root@www c]# ls -lh *.elf t t.g
-rwxr-xr-x. 1 root root 6.6K Jul 24 06:50 t
-rw-r--r--. 1 root root  15K Jul 24 06:51 t.elf
-rwxr-xr-x. 1 root root 7.9K Jul 24 06:50 t.g
-rw-r--r--. 1 root root  16K Jul 24 06:51 t.g.elf

加-g编译后,因为包含了debug信息,因此生成的可执行文件偏大(程序本身非常小,所以增加的调试信息不多)。
看-g编译的符号表:

[root@www c]# readelf -s t.g
 
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 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
。。。

 注意.dynsym表,只有该程序用到的几个外部动态符号存在。
加-rdynamic选项编译,readelf查看:

[root@www c]# gcc -O0 -rdynamic -o t.rd t.c 
[root@www c]# readelf -s t.rd 
 
Symbol table '.dynsym' contains 20 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 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     3: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
     5: 0000000000400724     6 FUNC    GLOBAL DEFAULT   13 bar
     6: 0000000000400730     6 FUNC    GLOBAL DEFAULT   13 foo
     7: 0000000000600b68     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
     8: 0000000000600b80     0 NOTYPE  GLOBAL DEFAULT  ABS _end
     9: 0000000000600b6c     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    10: 0000000000600b68     0 NOTYPE  WEAK   DEFAULT   24 data_start
    11: 0000000000400640     0 FUNC    GLOBAL DEFAULT   13 _start
    12: 0000000000400848     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    13: 0000000000400770   137 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    14: 0000000000600b6c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    15: 0000000000400736    39 FUNC    GLOBAL DEFAULT   13 main
    16: 00000000004005f0     0 FUNC    GLOBAL DEFAULT   11 _init
    17: 0000000000400760     2 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    18: 0000000000400838     0 FUNC    GLOBAL DEFAULT   14 _fini
    19: 000000000040072a     6 FUNC    GLOBAL DEFAULT   13 baz
。。。

可以看到添加-rdynamic选项后,.dynsym表就包含了所有的符号,不仅是已使用到的外部动态符号,还包括本程序内定义的符号,比如bar、foo、baz等。
.dynsym表里的数据并不能被strip掉:

[root@www c]# strip t.rd 
[root@www c]# readelf -s t.rd
 
Symbol table '.dynsym' contains 20 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 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     3: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.2.5 (2)
     5: 0000000000400724     6 FUNC    GLOBAL DEFAULT   13 bar
     6: 0000000000400730     6 FUNC    GLOBAL DEFAULT   13 foo
     7: 0000000000600b68     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
     8: 0000000000600b80     0 NOTYPE  GLOBAL DEFAULT  ABS _end
     9: 0000000000600b6c     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    10: 0000000000600b68     0 NOTYPE  WEAK   DEFAULT   24 data_start
    11: 0000000000400640     0 FUNC    GLOBAL DEFAULT   13 _start
    12: 0000000000400848     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used
    13: 0000000000400770   137 FUNC    GLOBAL DEFAULT   13 __libc_csu_init
    14: 0000000000600b6c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    15: 0000000000400736    39 FUNC    GLOBAL DEFAULT   13 main
    16: 00000000004005f0     0 FUNC    GLOBAL DEFAULT   11 _init
    17: 0000000000400760     2 FUNC    GLOBAL DEFAULT   13 __libc_csu_fini
    18: 0000000000400838     0 FUNC    GLOBAL DEFAULT   14 _fini
    19: 000000000040072a     6 FUNC    GLOBAL DEFAULT   13 baz
。。。

简单总结一下-g选项与-rdynamic选项的差别:
1,-g选项新添加的是调试信息(一系列.debug_xxx段),被相关调试工具,比如gdb使用,可以被strip掉。
2,-rdynamic选项新添加的是动态连接符号信息,用于动态连接功能,比如dlopen()系列函数、backtrace()系列函数使用,不能被strip掉,即强制strip将导致程序无法执行:

[root@www c]# ./t.rd 
test[root@www c]# strip -R .dynsym t.rd
[root@www c]# ./t.rd 
./t.rd: relocation error: ./t.rd: symbol , version GLIBC_2.2.5 not defined in file libc.so.6 with link time reference
[root@www c]# 

 3,.symtab表在程序加载时会被加载器丢弃,gdb等调试工具由于可以直接访问到磁盘上的二进制程序文件,因此可以使用所有的调试信息,这包括.symtab表;而backtrace()系列函数作为程序执行的逻辑功能,无法去读取磁盘上的二进制程序文件,因此只能使用.dynsym表。

[root@www c]# gdb t.g -q
Reading symbols from /home/work/dladdr/c/t.g...done.
(gdb) 

其它几个工具可以动态指定查看,比如nm、objdump。

4,-rdynamic选项不产生任何调试信息,因此在一般情况下,新增的附加信息比-g选项要少得多。除非是完全的静态连接,否则即便是没有加-rdynamic选项,程序使用到的外部动态符号,比如前面示例里的printf,也会被自动加入到.dynsym表。

完全参考:
http://stackoverflow.com/questions/8623884/gcc-debug-symbols-g-flag-vs-linkers-rdynamic-option

转载请保留地址:http://www.lenky.info/archives/2013/01/2190 或 http://lenky.info/?p=2190

备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来信讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

发表评论

18 + 14 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据