gcc选项-g与-rdynamic的异同
2016-06-01 18:08
519 查看
摘自http://www.tuicool.com/articles/EvIzUn
相比-g选项, -rdynamic 却是一个 连接选项 ,它将指示连接器把所有符号(而不仅仅只是程序已使用到的外部符号)都添加到动态符号表(即.dynsym表)里,以便那些通过 dlopen() 或 backtrace() (这一系列函数使用.dynsym表内符号)这样的函数使用。
看示例:
对于上面的示例代码,普通和加-g编译:
加-g编译后,因为包含了debug信息,因此生成的可执行文件偏大(程序本身非常小,所以增加的调试信息不多)。
看-g编译的符号表:
注意.dynsym表,只有该程序用到的几个外部动态符号存在。
加-rdynamic选项编译,readelf查看:
可以看到添加-rdynamic选项后,.dynsym表就包含了所有的符号,不仅是已使用到的外部动态符号,还包括本程序内定义的符号,比如bar、foo、baz等。
.dynsym表里的数据并不能被strip掉:
简单总结一下-g选项与-rdynamic选项的差别:
1,-g选项新添加的是调试信息(一系列.debug_xxx段),被相关调试工具,比如gdb使用,可以被strip掉。
2,-rdynamic选项新添加的是动态连接符号信息,用于动态连接功能,比如dlopen()系列函数、backtrace()系列函数使用,不能被strip掉,即强制strip将导致程序无法执行:
3,.symtab表在程序加载时会被加载器 丢弃 ,gdb等调试工具由于可以直接访问到磁盘上的二进制程序文件:
因此可以使用所有的调试信息,这包括.symtab表;而backtrace()系列函数作为程序执行的逻辑功能,无法去读取磁盘上的二进制程序文件,因此只能使用.dynsym表。
其它几个工具可以动态指定查看,比如nm、objdump:
4,-rdynamic选项不产生任何调试信息,因此在一般情况下,新增的附加信息比-g选项要少得多。除非是完全的静态连接,否则即便是没有加-rdynamic选项,程序使用到的外部动态符号,比如前面示例里的printf,也会被自动加入到.dynsym表。
完全参考:
http://stackoverflow.com/questions/8623884/gcc-debug-symbols-g-flag-vs-linkers-rdynamic-option
gcc选项-g与-rdynamic的异同
gcc 的 -g ,应该没有人不知道它是一个调试选项,因此在一般需要进行程序调试的场景下,我们都会加上该选项,并且根据调试工具的不同,还能直接选择更有针对性的说明,比如 -ggdb 。-g是一个编译选项,即在源代码编译的过程中起作用,让gcc把更多调试信息(也就包括符号信息)收集起来并将存放到最终的可执行文件内。相比-g选项, -rdynamic 却是一个 连接选项 ,它将指示连接器把所有符号(而不仅仅只是程序已使用到的外部符号)都添加到动态符号表(即.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 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) Symbol table '.symtab' contains 67 entries: Num: Value Size Type Bind Vis Ndx Name ... 48: 00000000004003e0 0 FUNC GLOBAL DEFAULT 13 _start 49: 00000000004004c4 6 FUNC GLOBAL DEFAULT 13 bar ... 53: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putchar@@GLIBC_2.2.5 54: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ 55: 00000000004005e8 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 56: 00000000004004d0 6 FUNC GLOBAL DEFAULT 13 foo ... 64: 00000000004004d6 31 FUNC GLOBAL DEFAULT 13 main 65: 0000000000400390 0 FUNC GLOBAL DEFAULT 11 _init 66: 00000000004004ca 6 FUNC GLOBAL DEFAULT 13 baz
注意.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 Symbol table '.symtab' contains 67 entries: Num: Value Size Type Bind Vis Ndx Name ... 50: 0000000000400640 0 FUNC GLOBAL DEFAULT 13 _start 51: 0000000000400724 6 FUNC GLOBAL DEFAULT 13 bar ... 55: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putchar@@GLIBC_2.2.5 56: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ 57: 0000000000400848 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 58: 0000000000400730 6 FUNC GLOBAL DEFAULT 13 foo ... 64: 0000000000400736 31 FUNC GLOBAL DEFAULT 13 main 65: 00000000004005f0 0 FUNC GLOBAL DEFAULT 11 _init 66: 000000000040072a 6 FUNC GLOBAL DEFAULT 13 baz [root@www c]#
可以看到添加-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等调试工具由于可以直接访问到磁盘上的二进制程序文件:
[root@www c]# gdb t.g -q Reading symbols from /home/work/dladdr/c/t.g...done. (gdb)
因此可以使用所有的调试信息,这包括.symtab表;而backtrace()系列函数作为程序执行的逻辑功能,无法去读取磁盘上的二进制程序文件,因此只能使用.dynsym表。
其它几个工具可以动态指定查看,比如nm、objdump:
[root@www c]# nm t.rd nm: t.rd: no symbols [root@www c]# nm -D t.rd 0000000000400848 R _IO_stdin_used w _Jv_RegisterClasses 0000000000600b6c A __bss_start 0000000000600b68 D __data_start w __gmon_start__ 0000000000400760 T __libc_csu_fini 0000000000400770 T __libc_csu_init U __libc_start_main 0000000000600b6c A _edata 0000000000600b80 A _end 0000000000400838 T _fini 00000000004005f0 T _init 0000000000400640 T _start 0000000000400724 T bar 000000000040072a T baz 0000000000600b68 W data_start 0000000000400730 T foo 0000000000400736 T main U printf [root@www c]# [root@www c]# objdump -T t.rd t.rd: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 printf 0000000000000000 w D *UND* 0000000000000000 __gmon_start__ 0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_main 0000000000400724 g DF .text 0000000000000006 Base bar 0000000000400730 g DF .text 0000000000000006 Base foo 0000000000600b68 g D .data 0000000000000000 Base __data_start 0000000000600b80 g D *ABS* 0000000000000000 Base _end 0000000000600b6c g D *ABS* 0000000000000000 Base _edata 0000000000600b68 w D .data 0000000000000000 Base data_start 0000000000400640 g DF .text 0000000000000000 Base _start 0000000000400848 g DO .rodata 0000000000000004 Base _IO_stdin_used 0000000000400770 g DF .text 0000000000000089 Base __libc_csu_init 0000000000600b6c g D *ABS* 0000000000000000 Base __bss_start 0000000000400736 g DF .text 0000000000000027 Base main 00000000004005f0 g DF .init 0000000000000000 Base _init 0000000000400760 g DF .text 0000000000000002 Base __libc_csu_fini 0000000000400838 g DF .fini 0000000000000000 Base _fini 000000000040072a g DF .text 0000000000000006 Base baz
4,-rdynamic选项不产生任何调试信息,因此在一般情况下,新增的附加信息比-g选项要少得多。除非是完全的静态连接,否则即便是没有加-rdynamic选项,程序使用到的外部动态符号,比如前面示例里的printf,也会被自动加入到.dynsym表。
完全参考:
http://stackoverflow.com/questions/8623884/gcc-debug-symbols-g-flag-vs-linkers-rdynamic-option
相关文章推荐
- Java之面向对象的三大特性:封装,继承,多态讲解
- Longest Palindromic Substring --leetcode 数据结构第五题
- db2数据库的使用总结
- 得到 TextView 颜色
- lua 写的游戏log逻辑(基本支持lua所有格式)
- Openresty+YII2.0下开发RestfulAPI系列3:开发基于php的restfulAPI
- java-script简单语法练习-第三天
- BZOJ1113 海报PLA
- 汉诺塔递归实现
- Nginx+Tomcat+MemCached 集群配置手册
- java中关于SSL/TSL的介绍和如何实现SSL Socket双向认证
- 11_实用技巧1—多级页面的抓取技巧
- 第13周项目2:动物这样叫(1)
- Android studio调试
- Spring Boot: HttpMediaTypeNotAcceptableException: Could not find acceptable representation原因及解决方法
- Debian/Gnome环境安装AMD官方显卡驱动
- web HTML5 调用摄像头的代码
- ccah-500 第11题What does CDH packaging do on install to facilitate Kerberos security setup
- Work Notes
- WebStrom 编辑器修改文件默认编码