转自:http://www.tuicool.com/articles/EvIzUn

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

gcc选项-g与-rdynamic的异同_转的更多相关文章

  1. gcc选项-g与-rdynamic的异同

    摘自http://www.tuicool.com/articles/EvIzUn gcc选项-g与-rdynamic的异同 gcc 的 -g ,应该没有人不知道它是一个调试选项,因此在一般需要进行程序 ...

  2. gcc和g++

    一.GCC GNU编译器套件(GNU Compiler Collection)包括C.C++.Objective-C.Fortran.Java.Ada和Go语言的前端,也包括了这些语言的库(如libs ...

  3. gcc、g++

    http://hi.baidu.com/zhangcunli8499/item/257e187360b48b2bd6a89cc6 g++ src/*.cpp -I include/ -I includ ...

  4. -g vs -rdynamic

    [-g vs -rdynamic] -g选项与-rdynamic选项的差别:1,-g选项新添加的是调试信息(一系列.debug_xxx段),被相关调试工具,比如gdb使用,可以被strip掉. 2,- ...

  5. gcc与g++的区别

    一:gcc与g++比较 编译c/c++代码的时候,有人用gcc,有人用g++,于是各种说法都来了,譬如c代码用gcc,而 c++代码用g++,或者说编译用gcc,链接用g++,一时也不知哪个说法正确, ...

  6. gcc和g++编译c或者c++文件碰到的问题

    gcc和g++都是GNU(组织)的一个编译器.        误区一:gcc只能编译c代码,g++只能编译c++代码      两者都可以,但是请注意:      1.后缀为.c的,gcc把它当作是C ...

  7. gcc与g++的编译链接的示例详解

    一.编译方式的示例详解 1. 编译C代码 代码如下:main.c /*!  ************************************************************** ...

  8. GCC的gcc和g++区别

    看的Linux公社的一篇文章,觉得不错,内容复制过来了. 其实在这之前,我一直以为gcc和g++是一个东西,只是有两个不同的名字而已,今天在linux下编译一个c代码时出现了错误才找了一下gcc和g+ ...

  9. gcc 和g++区别

    gcc和g++都是GNU的一个编译器;这两者的区别:1.从源文件上看,对于文件后缀(扩展名)为.c的test.c文件,gcc会把它看成是C程序,而g++则会把它看成是C++程序;而对于文件后缀(扩展名 ...

随机推荐

  1. jQuery-template.js学习

    花了点时间,看了下jQuery-template.js,不多废话,先上结构 jQuery.each({..},function(){}) jQuery.fn.extend({..}) jQuery.e ...

  2. Andriod Studio adb.exe,start-server&#39; failed -- run manually if necessary 解决

    首先查看了我的任务管理器,共有三个adb的程序在运行: 错误提示的是 Andriod Studio 中的adb.exe启动失败,于是,去关掉另外两个adb.exe,两分钟左右后,又出现了三个adb. ...

  3. 邮件开发——base64账号密码转换

    package com.hq.base64; import java.io.BufferedReader; import java.io.FileInputStream; import java.io ...

  4. Java7并发编程实战(一) 守护线程的创建和运行

    Java里有一种特殊的线程叫做守护(Daemon)线程,这种线程的优先级很低,通常来说,当一个应用程序里面没有其他线程运行的时候,守护线程才运行,当线程是程序中唯一运行的线程时,守护线程执行结束后,J ...

  5. RBL开发笔记二

     17:13:55 2014-08-25 有以下几个点:  第一 :怎么在预处理阶段能够做到识别某个宏是否给定义了  这里就定义了一个SystemConfig.h 专门做这个事情  当然是需要make ...

  6. MySQL大数据分页的优化思路和索引延迟关联

    之前上次在部门的分享会上,听了关于MySQL大数据的分页,即怎样使用limit offset,N来进行大数据的分页,现在做一个记录: 首先我们知道,limit offset,N的时候,MySQL的查询 ...

  7. [转]AS3复制可视对象

    一,复制舞台上的影片剪 方法1——反射方法: var ClassRef:Class = getDefinitionByName(getQualifiedClassName(t_mc)) as Clas ...

  8. 20135202闫佳歆--week 8 实验:理解进程调度时机跟踪分析进程调度与进程切换的过程--实验及总结

    week 8 实验:理解进程调度时机跟踪分析进程调度与进程切换的过程 1.环境搭建: rm menu -rf git clone https://github.com/megnning/menu.gi ...

  9. C# WinForm程序添加引用后调用静态方法时报“Interfaces_Helper.Global”的类型初始值设定项引发异常。---&gt; System.NullReferenceException: 未将对象引用设置到对象的实例。

    出现原因: 因为Global类初始化某个静态变量时没有成功则会抛 System.NullReferenceException 异常,具体代码: public static string connstr ...

  10. Android调用Sqlite数据库时自动生成db-journal文件的原因

    数据库为了更好实现数据的安全性,一半都会有一个Log文件方便数据库出现意外时进行恢复操作等.Sqlite虽然是一个单文件数据库,但麻雀虽小五脏俱全,它也会有相应的安全机制存在 这个journal文件便 ...