摘自http://www.tuicool.com/articles/EvIzUn
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