首先簡要闡述關於gcc、glibc和 binutils模組之間的關係
一、關於gcc、glibc和binutils模組之間的關係
1、gcc(gnu collect compiler)是一組編譯工具的總稱。它主要完成的工作任務是“預先處理”和“編譯”,以及提供了與編譯器緊密相關的運行庫的支援,如 libgcc_s.so、libstdc++.so等。
2、binutils提供了一系列用來建立、管理和維護二進位目標檔案的工具程式,如彙編(as)、串連(ld)、靜態庫歸檔(ar)、反組譯碼 (objdump)、elf結構分析工具(readelf)、無效調試資訊和符號的工具(strip)等。通常,binutils與gcc是緊密相整合
的,沒有binutils的話,gcc是不能正常工作的。
3、glibc是gnu發布的libc庫,也即c運行庫。glibc是linux系統中最底層的api(應用程式開發介面),幾乎其它任何的運行庫 都會倚賴於glibc。glibc除了封裝linux作業系統所提供的系統服務外,它本身也提供了許多其它一些必要功能服務的實現,主要的如下:
(1)string,字串處理
(2)signal,訊號處理
(3)dlfcn,管理共用庫的動態載入
(4)direct,檔案目錄操作
(5)elf,共用庫的動態載入器,也即interpreter
(6)iconv,不同字元集的編碼轉換
(7)inet,socket介面的實現
(8)intl,國際化,也即gettext的實現
(9)io
(10)linuxthreads
(11)locale,本地化
(12)login,虛擬終端裝置的管理,及系統的安全訪問
(13)malloc,動態記憶體的分配與管理
(14)nis
(15)stdlib,其它準系統
二、redhat9上升級gcc
1、升級這些庫時,最好不要覆蓋系統中預設的;因為這些庫,尤其是glibc庫,是系統中最核心的共用庫和工具,如果盲目覆蓋,很可能導致整個系統 癱瘓,因為一般更新glibc庫時,其它所有以來libc庫的共用庫都需要重新被編譯一遍。因此,為了調試某個程式進入glibc時,最好把glibc安 裝到/usr/local/lib下。
2、首先編譯glibc庫。注意最好令建立一個glibc-build的目錄,configure時加上--enable-add- ons=linuxthreads選項。make install安裝到/usr/local下。
3、修改gcc的spec檔案(/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/specs),更改ld- linux.so.2為/usr/local/lib下的新的共用庫裝載器。
4、編譯binutils庫,此時被編譯出的程式會串連到/usr/local/lib下的新的libc庫。注意,在configure前,需要設 置ld預設串連的路徑(LIBRARY_PATH=/usr/local/lib:/lib:/usr/lib),否則binutils會 configure出錯,找不到libc中的一些符號。具體步驟如下:
(1)export LIBRARY_PATH=/usr/local/lib:/lib:/usr/lib
(2)mkdir binutils-build && cd binutils-build
(3)../binutils-2.13.90.0.18/configure
(4)make
(5)make -C ld clean
(6)make -C ld LIB_PATH=/usr/lib:/lib:/usr/local/bin(設定編譯後的ld的預設庫搜尋路徑,後面的比前面的優先順序高)
(7)make install
三、總結
1、運行時,動態庫的裝載依賴於ld-linux.so.6的實現,它尋找共用庫的順序如下:
(1)ld-linux.so.6在可執行檔目標檔案中被指定,可用readelf命令查看
(2)ld-linux.so.6預設在/usr/lib和lib中搜尋;當glibc安裝到/usr/local下時,它尋找/usr/local /lib
(3)LD_LIBRARY_PATH環境變數中所設定的路徑
(4)/etc/ld.so.conf(或/usr/local/etc/ld.so.conf)中所指定的路徑,由ldconfig產生二進位的 ld.so.cache中
2、編譯時間,搜尋庫的路徑順序如下:
(1)ld-linux.so.6由gcc的spec檔案中所設定
(2)gcc --print-search-dirs所列印出的路徑,主要是libgcc_s.so等庫。可以通過GCC_EXEC_PREFIX來設定
(3)LIBRARY_PATH環境變數中所設定的路徑,或編譯的命令列中指定的-L/usr/local/lib
(2)binutils中的ld所設定的預設搜尋路徑順序,編譯binutils時指定。
(可以通過“ld --verbose | grep SEARCH”來查看)
3、二進位程式的搜尋路徑順序為PATH環境變數中所設定。一般/usr/local/bin高於/usr/bin
4、編譯時間的標頭檔的搜尋路徑順序,與library的尋找順序類似。一般/usr/local/include高於/usr/include
————————————————————————————————————
前言
如果普通編程不需要瞭解這些東西,如果想精確控制你的對象檔案的格式或者你想查看一下檔案對象裡的內容以便作出某種判斷,剛你可以看一下下面的工 具:objdump, nm, ar。當然,本文不可能非常詳細的說明它們的使用方法和功能。如果你覺得本文不夠清楚,你可以使用:man. 我的計劃只是想讓更多的人瞭解這些工具,以後在今後 的編程過程中能有所協助。
作業系統: Linux
開始
- 庫檔案操作命令:ar ----非常好的東東。。讓你能查看函數庫裡的詳細情況和用多個對象檔案產生一個庫檔案。
- nm --列出目標檔案(.o)的符號清單。。NND,太激動了。剛知道此命令時讓我三天沒睡好覺。我就使勁用了一把。
- 常用法:
- nm -s filename.a/filename.o/a.out 裡邊所有的符號列表一清二楚。例:
# nm -s a.out
080495b8 A __bss_start
08048334 t call_gmon_start
080495b8 b completed.5751
080494b8 d __CTOR_END__
080494b4 d __CTOR_LIST__
080495ac D __data_start
080495ac W data_start
08048450 t __do_global_ctors_aux
08048360 t __do_global_dtors_aux
080495b0 D __dso_handle
080494c0 d __DTOR_END__
080494bc d __DTOR_LIST__
080494c8 d _DYNAMIC
080495b8 A _edata
080495bc A _end
0804847c T _fini
08048498 R _fp_hw
08048390 t frame_dummy
080484b0 r __FRAME_END__
08049594 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0804844c T __i686.get_pc_thunk.bx
080482b8 T _init
080494b4 a __init_array_end
080494b4 a __init_array_start
0804849c R _IO_stdin_used
080494c4 d __JCR_END__
080494c4 d __JCR_LIST__
w _Jv_RegisterClasses
080483e0 T __libc_csu_fini
080483f0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
080483b4 T main
080495b4 d p.5749
U puts@@GLIBC_2.0
08048310 T _start
- 選項/屬性:
-a或--debug-syms:顯示偵錯符號。
-B:等同於--format=bsd,用來相容MIPS的nm。
-C或--demangle:將低級符號名解碼(demangle)成使用者級名字。這樣可以使得C++函數名具有可讀性。
-D或--dynamic:顯示動態符號。該任選項僅對於動態目標(例如特定類型的共用庫)有意義。
-f format:使用format格式輸出。format可以選取bsd、sysv或posix,該選項在GNU的nm中有用。預設為bsd。
-g或--extern-only:僅顯示外部符號。
-n、-v或--numeric-sort:按符號對應地址的順序排序,而非按符號名的字元順序。
-p或--no-sort:按目標檔案中遇到的符號順序顯示,不排序。
-P或--portability:使用POSIX.2標準輸出格式代替預設的輸出格式。等同於使用任選項-f posix。
-s或--print-armap:當列出庫中成員的符號時,包含索引。索引的內容包含:哪些模組包含哪些名字的映射。
-r或--reverse-sort:反轉排序的順序(例如,升序變為降序)。
--size-sort:按大小排列符號順序。該大小是按照一個符號的值與它下一個符號的值進行計算的。
-t radix或--radix=radix:使用radix進位顯示符號值。radix只能為"d"表示十進位、"o"表示八進位或"x"表示十六進位。
--target=bfdname:指定一個目標代碼的格式,而非使用系統的預設格式。
-u或--undefined-only:僅顯示沒有定義的符號(那些外部符號)。
-l或--line-numbers:對每個符號,使用調試資訊來試圖找到檔案名稱和行號。對於已定義的符號,尋找符號地址的行號。對於未定義符號,尋找指 向符號重定位入口的行號。如果可以找到行號資訊,顯示在符號資訊之後。
-V或--version:顯示nm的版本號碼。
--help:顯示nm的任選項。
- objdump 檔案命令功能強的驚人。能實現上述兩個命令(ar,nm)的 很多功能。它主要是查看對象檔案的內容資訊。
- 常用法:
- objdump -h file<.o,.a,.out>//查看對象檔案所有的節sections.例如:
# objdump -h libtest1.o
libtest1.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000014 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 00000000 00000000 00000048 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000048 2**2
ALLOC
3 .rodata 0000000e 00000000 00000000 00000048 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .comment 0000001f 00000000 00000000 00000056 2**0
CONTENTS, READONLY
5 .note.GNU-stack 00000000 00000000 00000000 00000075 2**0
CONTENTS, READONLY
- objdump -t 查看對象檔案所有的符號列表,相當於 nm -s objfilename,如:
# objdump -t libtest1.olibtest1.o: file format elf32-i386
SYMBOL TABLE:
00000000 l df *ABS* 00000000 libtest1.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .rodata 00000000 .rodata
00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
00000000 l d .comment 00000000 .comment
00000000 g F .text 00000014 print_test1
00000000 *UND* 00000000 puts
- 更多資訊請查看選項:
--archive-headers
-a 顯示檔案庫的成員資訊,與 ar tv 類似 objdump -a libpcap.a
和 ar -tv libpcap.a 顯示結果比較比較
顯然這個選項沒有什麼意思。
--adjust-vma=offset
When dumping information, first add offset to all
the section addresses. This is useful if the sec-
tion addresses do not correspond to the symbol
table, which can happen when putting sections at
particular addresses when using a format which can
not represent section addresses, such as a.out.
-b bfdname
--target=bfdname
指定目標碼格式。這不是必須的,objdump能自動識別許多格式,
比如:objdump -b oasys -m vax -h fu.o
顯示fu.o的頭部摘要資訊,明確指出該檔案是Vax系統下用Oasys
編譯器產生的目標檔案。objdump -i將給出這裡可以指定的
目標碼格式列表
--demangle
-C 將底層的符號名解碼成使用者級名字,除了去掉所有開頭
的底線之外,還使得C++函數名以可理解的方式顯示出來。
--debugging
顯示調試資訊。企圖解析儲存在檔案中的調試資訊並以C語言
的文法顯示出來。僅僅支援某些類型的調試資訊。
--disassemble
-d 反組譯碼那些應該還有指令機器碼的section
--disassemble-all
-D 與 -d 類似,但反組譯碼所有section
--prefix-addresses
反組譯碼的時候,顯示每一行的完整地址。這是一種比較老的反組譯碼格式。
顯示效果並不理想,但可能會用到其中的某些顯示,自己可以對比。
--disassemble-zeroes
一般反組譯碼輸出將省略大塊的零,該選項使得這些零塊也被反組譯碼。
-EB
-EL
--endian={big|little}
這個選項將影響反組譯碼出來的指令。
little-endian就是我們當年在dos下玩彙編的時候常說的高位在高地址,
x86都是這種。
--file-headers
-f 顯示objfile中每個檔案的整體頭部摘要資訊。
--section-headers
--headers
-h 顯示目標檔案各個section的頭部摘要資訊。
--help 簡短的協助資訊。
--info
-i 顯示對於 -b 或者 -m 選項可用的架構和目標格式列表。
--section=name
-j name 僅僅顯示指定section的資訊
--line-numbers
-l 用檔案名稱和行號標註相應的目標代碼,僅僅和-d、-D或者-r一起使用
使用-ld和使用-d的區別不是很大,在源碼級調試的時候有用,要求
編譯時間使用了-g之類的調試編譯選項。
--architecture=machine
-m machine
指定反組譯碼目標檔案時使用的架構,當待反組譯碼檔案本身沒有描述
架構資訊的時候(比如S-records),這個選項很有用。可以用-i選項
列出這裡能夠指定的架構
--reloc
-r 顯示檔案的重定位入口。如果和-d或者-D一起使用,重定位部分以反匯
編後的格式顯示出來。
--dynamic-reloc
-R 顯示檔案的動態重定位入口,僅僅對於動態目標檔案有意義,比如某些
共用庫。
--full-contents
-s 顯示指定section的完整內容。
objdump --section=.text -s inet.o | more
--source
-S 儘可能反組譯碼出原始碼,尤其當編譯的時候指定了-g這種調試參數時,
效果比較明顯。隱含了-d參數。
--show-raw-insn
反組譯碼的時候,顯示每條彙編指令對應的機器碼,除非指定了
--prefix-addresses,這將是預設選項。
--no-show-raw-insn
反組譯碼時,不顯示彙編指令的機器碼,這是指定 --prefix-addresses
選項時的預設設定。
--stabs
Display the contents of the .stab, .stab.index, and
.stab.excl sections from an ELF file. This is only
useful on systems (such as Solaris 2.0) in which
.stab debugging symbol-table entries are carried in
an ELF section. In most other file formats, debug-
ging symbol-table entries are interleaved with
linkage symbols, and are visible in the --syms output.
--start-address=address
從指定地址開始顯示資料,該選項影響-d、-r和-s選項的輸出。
--stop-address=address
顯示資料直到指定地址為止,該選項影響-d、-r和-s選項的輸出。
--syms
-t 顯示檔案的符號表入口。類似於nm -s提供的資訊
--dynamic-syms
-T 顯示檔案的動態符號表入口,僅僅對動態目標檔案有意義,比如某些
共用庫。它顯示的資訊類似於 nm -D|--dynamic 顯示的資訊。
--version 版本資訊
objdump --version
--all-headers
-x 顯示所有可用的頭資訊,包括符號表、重定位入口。-x 等價於
-a -f -h -r -t 同時指定。
objdump -x inet.o