gcc选项-g与-rdynamic的异同

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

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

 

 

编译链接实战(15)-rdynamic选项导出所有符号到动态符号表 而使用 -rdynamic 选项重新编译程序时,会将所有符号导出到动态符号表中,backtrace_symbols 函数可以从动态符号表中查询到相应的符号信息,从而得到更详细的调用链信息,例如函数名、参数和行号等。默认链接器在产生可执行文件时,只会将那些链接时被其他共享模块引用到的符号放到动态符号表中,这样可以减少动态符号表的大小,也就是说,在共享模块中反向引用主模块中的符号时,只有那些在链接时被共享模块引用到的符号才会被导出。这样,在运行时,可执行文件将包含完整的符号信息,包括函数名、全局变量等。 阅读详情

相关推荐

gcc: 选项 -rdynamic;cmake错误一例

这个选项的意义是,向ELF链接器发送一个标记:‘-export-dynamic’,当然发送的前提是链接器支持这个标记。具体的规则在文件:“/usr/share/cmake/Modules/Platform/Linux-GNU.cmake”导致的问题是cmake的默认规则里又有这么个test 编译器的步骤就会导致cmake执行错误。因为这个选项受某些gcc本身编译时的配置控制,所以有些gcc版本不支持这个选项。如果不支持,可能需要别的方式将这个-export-dynamic 传递过去。

mzhan017的博客 1570

gcc-g,-o,-c,-D,-w,-W,-Wall,-O3等参数的意义

一、-g -g可执行程序包含调试信息 -g为了调试用的 加个-g 是为了gdb 用,不然gdb用不到 二、-o -o指定输出文件名 -o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项gcc就给出预设的可执行文件a.out。 一般语法: gcc filename.c -o filename 上面的意思是如果你不...

幽冥之花的博客 2万+

编译,连接 -- 笔记

1linux 程序库的符号,Linux动态库(.so)符号表 linux 程序库的符号,Linux动态库(.so)符号表_weixin_39528029的博客-CSDN博客 1.1.动态链接库的符号表 动态链接库(shared object library)在linux里以.so结尾,是elf(Executable and Linkable Format)文件的一种,有两个符号表:“.symtab”和“.dynsym”。 .symtab: 包含大量的信息(包括全局符号global symbo.

tianyu的专栏 - Linux site:blog.csdn.net/wishfly 1189

GCC/G++调试添加编译选项-g作用用法

reference: https://blog.csdn.net/tanrui519521/article/details/79867221 http://c.biancheng.net/view/8153.html 1.问题 为什么调试的时候需要编译选项中添加 -g 默认编译生成的可执行文件是无法使用 gdb 来跟踪或调试的,因为可执行程序中没有可供 gdb 调试使用的特殊信息,为了将必要的调试信息整合到可执行文件中,我们便需要用到 -g 选项,这样生成的可执行程序,倘若出现问题,便可以使用 gdb 找出

limanjihe的专栏 3万+

【2017-12-02】【转】gcc选项-g-rdynamic异同

转载介绍GCC编译选项-g(调试信息)和-rdynamic(导出所有符号)的作用和区别,通过readelf、strip和gdb命令对比两个选项对符号表的影响。适合需要动态加载和backtrace功能的C程序开发。

cstriker1407的专栏 180

gcc选项-g-rdynamic异同_转

转自:http://www.tuicool.com/articles/EvIzUn gcc 的 -g ,应该没有人不知道它是一个调试选项,因此在一般需要进行程序调试的场景下,我们都会加上该选项,并且根据调试工具的不同,还能直接选择更有针对性的说明,比如 -ggdb 。-g是一个编译选项,即在源代码编译的过程中起作用,让gcc把更多调试信息(也就包括符号信息)收集起来并将存放到最终的可执行文件内。 ...

weixin_33836223的博客 152

gcc或g++的编译选项 -shared -fPIC -g -rdynamic 部分转载

动态库 Linux下动态链接库(shared object file,共享对象文件)的文件后缀为.so,它是一种特殊的目标文件(object file),可以在程序运行时被加载(链接)进来。使用动态链接库的优点是:程序的可执行文件更小,便于程序的模块化以及更新,同时,有效内存的使用效率更高。 创建一个动态链接库,可使用 GCC-shared选项。输入文件可以是源文件、汇编文件或者目标文件。另外还得结合-fPIC选项-fPIC 选项作用于编译阶段,告诉编译器产生位置无关代码(Position-I.

fengdijiang的专栏 7606

调试--收藏01

1. 段错误如何解决段错误

吃不饱、力不足的博客 103

昨日学习笔记

gcc选项-g-rdynamic异同gcc 的 -g ,应该没有人不知道它是一个调试选项,因此在一般需要进行程序调试的场景下,我们都会加上该选项,并且根据调试工具的不同,还能直接选择更有针对性的说明,比如 gdb 。-g是一个编译选项,即在源代码编译的过程中起作用,让gcc把更多调试信息(也就包括符号信息)收集起来并将存放到最终的可执行文件内。 相比-g选项, -rdynamic 却是一个 连...

wykkunkun的博客 196

链接选项 -rdynamic动态符号表

注意,这是链接选项,而不是编译选项。在将c文件编译成.o的过程中,使用rdynamic是没有任何效果的。只有将.o链接成elf时,才有效果。这主要是对可执行程序而言的,而编译动态库时,即使没有rdynamic选项,默认也会将非静态函数放入动态符号表中(刻意隐藏的函数除外)。一个验证方法显示可执行程序文件内的动态符号(注意,仅仅是动态符号):readelf -Ds a.out默认情况下,可执行程序(...

bobbypollo的专栏 1万+

gcc-rdynamic参数的作用

【代码】gcc-rdynamic参数的作用。

最后一个bug的博客 840

gcc -rdynamic参数解释

选项 -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,

工作记录--创造或收集原创 3万+

【GNU】gcc -g编译选项 -g0 -g1 -g2 -g3 -gdwarf

GCC-g 选项用于在编译时生成,这些信息会嵌入到生成的目标文件或可执行文件中,主要目的是为了支持调试器(如 gdb)对程序的调试工作。当你在编译代码时使用-g选项GCC 会将额外的调试信息嵌入到生成的可执行文件或目标文件中。调试信息存储在符号表中,不会影响程序的实际执行逻辑。生成的调试信息可以被调试器(例如gdb使用-g选项时,GCC 不会对程序进行优化,确保调试时的代码行为和源代码的逻辑一致。如果需要同时优化代码并生成调试信息,可以结合使用-O选项(例如-g -O2。

W__winter的博客 2909
上一篇: linux c获得时间和设置时间
下一篇: 如何用#define宏定义多行函数
whatday
博客等级 码龄20年 3703粉丝 96原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值