必知必會(huì)基礎(chǔ)知識(shí)第 1 彈
時(shí)間:2021-08-19 15:56:36
手機(jī)看文章
掃描二維碼
隨時(shí)隨地手機(jī)看文章
[導(dǎo)讀]關(guān)注「Linux大陸」,選擇「星標(biāo)公眾號(hào)」一起進(jìn)步!大家好,我是ZhengN。Linux大陸是我的另一個(gè)公眾號(hào),主要分享一些Linux相關(guān)的知識(shí)。大家可以關(guān)注關(guān)注。為什么重新申請(qǐng)了一個(gè)公眾號(hào)?1、留言功能。大雜燴公眾號(hào)無(wú)留言功能,錯(cuò)失了很多與大家互動(dòng)的機(jī)會(huì)。Linux大陸具備留言...
關(guān)注「Linux大陸」,選擇「星標(biāo)公眾號(hào)」一起進(jìn)步!大家好,我是ZhengN。Linux大陸是我的另一個(gè)公眾號(hào),主要分享一些Linux相關(guān)的知識(shí)。大家可以關(guān)注關(guān)注。為什么重新申請(qǐng)了一個(gè)公眾號(hào)?
1、留言功能。大雜燴公眾號(hào)無(wú)留言功能,錯(cuò)失了很多與大家互動(dòng)的機(jī)會(huì)。Linux大陸具備留言功能,歡迎大家來(lái)踩。2、內(nèi)容劃分。嵌入式大雜燴主要以嵌入式為中心展開(kāi),Linux大陸以Linux為中心展開(kāi)。做一些區(qū)分,方便大家進(jìn)行選擇篩選。好了,廢話不多說(shuō)~必知必會(huì)系列分享一些基礎(chǔ)但有用的知識(shí),有些知識(shí)雖然不能馬上運(yùn)用起來(lái),但也是有必要了解了解。這是必知必會(huì)系列第一篇:GNU。本文的一部分內(nèi)容之前也有在大雜燴分享過(guò),也一并集合到這,方便大家查閱。
GNU組件及軟件非常豐富,如:1、GCC
GCC原名為
Linux下面的標(biāo)準(zhǔn)c庫(kù)不僅有這一個(gè),如uclibc、klibc,以及上面被提到的Linux libc,但是glibc無(wú)疑是用得最多的。glibc在/lib目錄下的.so文件為libc.so.6。libc 實(shí)際上是一個(gè)泛指。凡是符合實(shí)現(xiàn)了 C 標(biāo)準(zhǔn)規(guī)定的內(nèi)容,都是一種 libc 。glibc 是 GNU 組織對(duì) libc 的一種實(shí)現(xiàn)。它是 unix/linux 的根基之一。嵌入式行業(yè)里還常用 uClibc ,是一個(gè)迷你版的 libc 。4、GDB
GDB(GNU symbolic debugger)是 GNU Project 調(diào)試器。GDB 可以做四種主要的事情(以及支持這些事情的其他事情)來(lái)幫助你捕獲行為中的錯(cuò)誤:6、其它
GNU系統(tǒng)包括很多軟件包,還包括非GNU的自由軟件。具體的介紹可以上gnu官網(wǎng)(http://www.gnu.org/software/)上查看:以上是對(duì)GNU及其內(nèi)容做了一個(gè)簡(jiǎn)單的介紹,下面對(duì)GUN相關(guān)的內(nèi)容做一些實(shí)例分享:
接著調(diào)用編譯器gcc進(jìn)行編譯,輸入上一步的.i文件,輸出.s匯編文件。然后調(diào)用匯編器as將.s為后綴的匯編語(yǔ)言文件處理生成以.o為后綴的目標(biāo)文件。當(dāng)所有的目標(biāo)文件都生成之后,調(diào)用鏈接器ld來(lái)進(jìn)行鏈接生成可執(zhí)行文件或庫(kù)文件。這一節(jié)我們先看生成可執(zhí)行文件,下一節(jié)再看如何生成庫(kù)文件。其中上圖中表明的-E、-S、-c為gcc編譯參數(shù)。gcc的基本用法如下:(2)編譯過(guò)程
使用編譯器將預(yù)處理文件(3)匯編過(guò)程
使用匯編器將匯編文件(4)鏈接過(guò)程
鏈接過(guò)程使用鏈接器將該目標(biāo)文件與其他目標(biāo)文件、庫(kù)文件、啟動(dòng)文件等鏈接起來(lái)生成可執(zhí)行文件。命令為:2、動(dòng)態(tài)、靜態(tài)鏈接
上一節(jié)的第(4)步的鏈接過(guò)程分為兩種。一種是靜態(tài)鏈接,另外一種是動(dòng)態(tài)鏈接。它們的區(qū)別如:
下面一起來(lái)使用nm工具查看目標(biāo)目標(biāo)文件的標(biāo)號(hào)。實(shí)例代碼test.c:
示例代碼gdb_test.c:
1、留言功能。大雜燴公眾號(hào)無(wú)留言功能,錯(cuò)失了很多與大家互動(dòng)的機(jī)會(huì)。Linux大陸具備留言功能,歡迎大家來(lái)踩。2、內(nèi)容劃分。嵌入式大雜燴主要以嵌入式為中心展開(kāi),Linux大陸以Linux為中心展開(kāi)。做一些區(qū)分,方便大家進(jìn)行選擇篩選。好了,廢話不多說(shuō)~必知必會(huì)系列分享一些基礎(chǔ)但有用的知識(shí),有些知識(shí)雖然不能馬上運(yùn)用起來(lái),但也是有必要了解了解。這是必知必會(huì)系列第一篇:GNU。本文的一部分內(nèi)容之前也有在大雜燴分享過(guò),也一并集合到這,方便大家查閱。
GNU簡(jiǎn)介
GNU計(jì)劃,有譯為“革奴計(jì)劃”,它的目標(biāo)是創(chuàng)建一套完全自由的操作系統(tǒng)GNU,并且其內(nèi)容軟件完全以GPL方式發(fā)布。這個(gè)操作系統(tǒng)是GNU計(jì)劃的主要目標(biāo),名稱來(lái)自GNU's Not Unix!的遞歸縮寫,因?yàn)镚NU的設(shè)計(jì)類似Unix,但它不包含具著作權(quán)的Unix代碼。作為操作系統(tǒng),GNU的發(fā)展仍未完成,其中最大的問(wèn)題是具有完備功能的內(nèi)核尚未被開(kāi)發(fā)成功。GNU的內(nèi)核,稱為Hurd,是自由軟件基金會(huì)發(fā)展的重點(diǎn),但是其發(fā)展尚未成熟。在實(shí)際使用上,多半使用Linux內(nèi)核作為系統(tǒng)核心。Linux操作系統(tǒng)包涵了Linux內(nèi)核與其他自由軟件項(xiàng)目中的GNU組件和軟件,可以被稱為GNU/Linux。GNU組件及軟件非常豐富,如:
1、GCC
GCC原名為GNU C語(yǔ)言編譯器
(GNU C Compiler),只能處理C語(yǔ)言。但其很快擴(kuò)展,變得可處理C ,后來(lái)又?jǐn)U展為能夠支持更多編程語(yǔ)言,如Fortran、Pascal、Objective -C、Java、Ada、Go以及各類處理器架構(gòu)上的匯編語(yǔ)言等,所以改名GNU編譯器套件
(GNU Compiler Collection)。2、glibc
glibc是GNU發(fā)布的libc庫(kù),即c運(yùn)行庫(kù)。glibc是linux系統(tǒng)中最底層的api,幾乎其它任何運(yùn)行庫(kù)都會(huì)依賴于glibc。glibc除了封裝linux操作系統(tǒng)所提供的系統(tǒng)服務(wù)外,它本身也提供了許多其它一些必要功能服務(wù)的實(shí)現(xiàn)。「glibc與libc的關(guān)系:」glibc 和 libc 都是 Linux 下的 C 函數(shù)庫(kù)。libc 是 Linux 下的 ANSI C 函數(shù)庫(kù);glibc 是 Linux 下的 GUN C 函數(shù)庫(kù)。ANSI C 函數(shù)庫(kù)是基本的 C 語(yǔ)言函數(shù)庫(kù),包含了 C 語(yǔ)言最基本的庫(kù)函數(shù)。這個(gè)庫(kù)可以根據(jù)頭文件劃分為 15 個(gè)部分,其中包括:glibc是linux下面c標(biāo)準(zhǔn)庫(kù)的實(shí)現(xiàn),即GNU C Library。glibc本身是GNU旗下的C標(biāo)準(zhǔn)庫(kù),后來(lái)逐漸成為了Linux的標(biāo)準(zhǔn)c庫(kù),而Linux下原來(lái)的標(biāo)準(zhǔn)c庫(kù)Linux libc逐漸不再被維護(hù)。Linux下面的標(biāo)準(zhǔn)c庫(kù)不僅有這一個(gè),如uclibc、klibc,以及上面被提到的Linux libc,但是glibc無(wú)疑是用得最多的。glibc在/lib目錄下的.so文件為libc.so.6。libc 實(shí)際上是一個(gè)泛指。凡是符合實(shí)現(xiàn)了 C 標(biāo)準(zhǔn)規(guī)定的內(nèi)容,都是一種 libc 。glibc 是 GNU 組織對(duì) libc 的一種實(shí)現(xiàn)。它是 unix/linux 的根基之一。嵌入式行業(yè)里還常用 uClibc ,是一個(gè)迷你版的 libc 。
3、coreutils
coreutils 是GNU下的一個(gè)軟件包,這個(gè)軟件包中包含了很多程序,如ls、mv等程序。常用的如:4、GDB
GDB(GNU symbolic debugger)是 GNU Project 調(diào)試器。GDB 可以做四種主要的事情(以及支持這些事情的其他事情)來(lái)幫助你捕獲行為中的錯(cuò)誤:- 啟動(dòng)你的程序,并指定可能影響其行為的所有內(nèi)容。
- 使程序在指定條件下停止。
- 檢查程序停止時(shí)發(fā)生的情況。
- 更改程序中的內(nèi)容,以便你可以嘗試糾正一個(gè)錯(cuò)誤的影響,然后繼續(xù)學(xué)習(xí)另一個(gè)錯(cuò)誤。
5、binutils
GNU binutils是一組二進(jìn)制工具集。包含的工具有:6、其它
GNU系統(tǒng)包括很多軟件包,還包括非GNU的自由軟件。具體的介紹可以上gnu官網(wǎng)(http://www.gnu.org/software/)上查看:以上是對(duì)GNU及其內(nèi)容做了一個(gè)簡(jiǎn)單的介紹,下面對(duì)GUN相關(guān)的內(nèi)容做一些實(shí)例分享:GCC編譯、鏈接
1、基本編譯流程
使用gcc工具集將C語(yǔ)言源代碼生成可執(zhí)行程序需要經(jīng)過(guò)4個(gè)步驟:預(yù)處理、編譯、匯編、鏈接
。如:首先,調(diào)用預(yù)處理器cpp進(jìn)行預(yù)處理,對(duì)源代碼.c文件中的文件包含(include)、預(yù)編譯語(yǔ)句(如宏定義define等)進(jìn)行分析,生成.i文件。接著調(diào)用編譯器gcc進(jìn)行編譯,輸入上一步的.i文件,輸出.s匯編文件。然后調(diào)用匯編器as將.s為后綴的匯編語(yǔ)言文件處理生成以.o為后綴的目標(biāo)文件。當(dāng)所有的目標(biāo)文件都生成之后,調(diào)用鏈接器ld來(lái)進(jìn)行鏈接生成可執(zhí)行文件或庫(kù)文件。這一節(jié)我們先看生成可執(zhí)行文件,下一節(jié)再看如何生成庫(kù)文件。其中上圖中表明的-E、-S、-c為gcc編譯參數(shù)。gcc的基本用法如下:
gcc?[options]?[filenames]
下面以一個(gè)實(shí)例來(lái)演示將C語(yǔ)言源代碼生成可執(zhí)行程序的過(guò)程。示例代碼hello.c:#include?
int?main(void)
{
?printf("Hello?gcc\n");
?return?0;
}
(1)預(yù)處理過(guò)程
使用預(yù)處理器cpp把源文件hello.c
經(jīng)過(guò)預(yù)處理生成hello.i
文件,預(yù)處理用于將所有的#include頭文件以及宏定義替換成其真正的內(nèi)容。預(yù)處理的命令為:gcc?-E?hello.c?-o?hello.i
上述命令中-E
是讓編譯器在預(yù)處理之后就退出,不進(jìn)行后續(xù)編譯過(guò)程;-o
是指定輸出文件名。預(yù)處理之后得到的仍然是文本文件。hello.i文件部分內(nèi)容截圖如下:(2)編譯過(guò)程
使用編譯器將預(yù)處理文件hello.i
編譯成匯編文件hello.s
。編譯的命令為:gcc?-S?hello.i?-o?hello.s
上述命令中-S讓編譯器在編譯之后停止,不進(jìn)行后續(xù)過(guò)程;-o是指定輸出文件名。匯編文件hello.s是文本文件,部分內(nèi)容截圖如下:(3)匯編過(guò)程
使用匯編器將匯編文件hello.s
轉(zhuǎn)換成目標(biāo)文件hello.o
。匯編過(guò)程的命令為:gcc?-c?hello.s?-o?hello.o
上述命令中-c
、-o
讓匯編器把匯編文件hello.s
轉(zhuǎn)換成目標(biāo)文件hello.o
。目標(biāo)文件hello.o
是二進(jìn)制文件。這時(shí)候我們可以使用如下命令查看hello.o的格式:file?hello.o
顯示的內(nèi)容:hello.o:?ELF?64-bit?LSB?relocatable,?x86-64,?version?1?(SYSV),?not?stripped
可以看到,hello.o是個(gè)ELF(Executable and Linking Format,可執(zhí)行鏈接格式)格式文件。另外,hello.o是個(gè)二進(jìn)制文件,使用vscode打開(kāi)可能會(huì)出現(xiàn)亂碼,可以安裝一個(gè)Binary插件。部分內(nèi)容截圖如下:(4)鏈接過(guò)程
鏈接過(guò)程使用鏈接器將該目標(biāo)文件與其他目標(biāo)文件、庫(kù)文件、啟動(dòng)文件等鏈接起來(lái)生成可執(zhí)行文件。命令為:gcc?hello.o?-o?hello
綜上:2、動(dòng)態(tài)、靜態(tài)鏈接
上一節(jié)的第(4)步的鏈接過(guò)程分為兩種。一種是靜態(tài)鏈接,另外一種是動(dòng)態(tài)鏈接。它們的區(qū)別如:(1)靜態(tài)鏈接
優(yōu)點(diǎn):代碼裝載速度快,執(zhí)行速度略比動(dòng)態(tài)鏈接庫(kù)快。缺點(diǎn):使用靜態(tài)鏈接生成的可執(zhí)行文件體積較大,包含相同的公共代碼,造成浪費(fèi)。(2)動(dòng)態(tài)鏈接
優(yōu)點(diǎn):生成的可執(zhí)行文件較靜態(tài)鏈接生成的可執(zhí)行文件小。缺點(diǎn):速度比靜態(tài)鏈接慢;使用動(dòng)態(tài)鏈接庫(kù)的應(yīng)用程序不是自完備的,需要依賴相關(guān)庫(kù)。初學(xué),理解不了?沒(méi)關(guān)系,分享一個(gè)易懂的比喻:把鏈接過(guò)程看做我們平時(shí)學(xué)習(xí)時(shí)做筆記的過(guò)程。我們平時(shí)學(xué)習(xí)時(shí)準(zhǔn)備一本筆記本專門記錄我們的學(xué)習(xí)筆記,比如在某本書的某一頁(yè)上看到一個(gè)很好很有用的知識(shí),這時(shí)候我們有兩種方法記錄在我們的筆記本上,一種是直接把那一頁(yè)的內(nèi)容全部抄寫一遍到筆記本上(靜態(tài)鏈接);另一種是我們?cè)诠P記本上做個(gè)簡(jiǎn)單的記錄(動(dòng)態(tài)鏈接),比如寫上:xxx知識(shí)點(diǎn)在《xxx》的xxx頁(yè)。從這兩種方法中我們可以很清楚地知道兩種方式的特點(diǎn),第一種方式的優(yōu)點(diǎn)就是我們?cè)趶?fù)習(xí)的時(shí)候就很方便,不用翻閱其它書籍了,但是缺點(diǎn)也很明顯,就是占用筆記本的空間很多,這種方法很快就把我們的筆記本給寫滿了。第二種方式的優(yōu)點(diǎn)就是很省空間,缺點(diǎn)就是每當(dāng)我們復(fù)習(xí)的時(shí)候,手頭上必須備著相關(guān)的參考書籍,比如我們?nèi)ソ淌覐?fù)習(xí)的時(shí)候,就得背著一大摞書去復(fù)習(xí),這樣我們復(fù)習(xí)的效率可能就沒(méi)有那么高了。這對(duì)應(yīng)到我們的動(dòng)態(tài)鏈接與靜態(tài)鏈接上是不是就很好理解了。下面看看具體實(shí)例:「文件1(main.c):」#include?"hello.h"
int?main(void)
{
?print_hello();
?return?0;
}
「文件2(hello.c):」#include?"hello.h"
void?print_hello(void)
{
?printf("hello?world\n");
}
「文件3(hello.h):」#ifndef?__HELLO_H
#define?__HELLO_H
#include?
void?print_hello(void);
#endif
「① 演示動(dòng)態(tài)鏈接」首先,將源文件生成目標(biāo)文件(*.o),命令:gcc?-c?main.c?hello.c
在Linux中,動(dòng)態(tài)庫(kù)的擴(kuò)展名一般為.so
。我們把上面生成的hello.o
文件生成相應(yīng)的動(dòng)態(tài)庫(kù),命令:gcc?-shared?hello.o?-o?libhello.so
使用鏈接動(dòng)態(tài)庫(kù)的方式生成可執(zhí)行程序,命令:gcc?main.o?-L.?-lhello?-o?hello_d_lib_test
這里的-L.
的含義是在搜索庫(kù)文件時(shí)包含當(dāng)前目錄,-lhello
的含義是鏈接名稱為libhello.so
的動(dòng)態(tài)庫(kù)。此時(shí),運(yùn)行hello_d_lib_test程序,可能會(huì)出現(xiàn)如下錯(cuò)誤:./hello_d_lib_test:?error?while?loading?shared?libraries:?libhello.so:?cannot?open?shared?object?file:?No?such?file?or?directory
這是因?yàn)檎也坏焦蚕韼?kù)文件libhello.so
,加載失敗。因?yàn)橐话闱闆r下Linux會(huì)在/usr/lib
路徑中搜索需要用到的庫(kù),而libhello.so
庫(kù)并不在這個(gè)路徑下。解決方法有如下幾種:- 把這個(gè)文件拷貝至
/usr/lib
路徑下。 - .配置文件/etc/ld.so.conf中指定的動(dòng)態(tài)庫(kù)搜索路徑。
- 臨時(shí)生效,可以用 LD_LIBRARY_PATH 環(huán)境變量指定。
export?LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
這時(shí)候再次運(yùn)行程序就可以正常運(yùn)行了。「② 演示靜態(tài)鏈接」靜態(tài)庫(kù)用ar
工具來(lái)制作。ar
是一個(gè)歸檔工具,用于建立、修改、提取歸檔文件(archive)。一個(gè)歸檔文件可以包含多個(gè)目標(biāo)文件,也被稱為靜態(tài)庫(kù)。在Linux下,靜態(tài)庫(kù)的擴(kuò)展名一般為.a
。把目標(biāo)文件hello.o
做成靜態(tài)庫(kù),命令:ar?-rv?libhello.a?hello.o
其中rv
參數(shù)為組合參數(shù),其中r參數(shù)表示當(dāng)建立的模塊名已經(jīng)存在時(shí),則覆蓋同名模塊,v參數(shù)用來(lái)顯示附加信息,比如被處理的文件的名字。使用鏈接靜態(tài)庫(kù)的方法生成可執(zhí)行程序,命令:gcc?main.o?-L.?-lhello?-o?hello_s_lib_test
刪除靜態(tài)庫(kù)之后,可執(zhí)行程序也是能正常運(yùn)行的。事實(shí)上,使用鏈接靜態(tài)庫(kù)的方式生成的可執(zhí)行程序與直接使用目標(biāo)文件生成的可執(zhí)行程序沒(méi)有區(qū)別。只是經(jīng)過(guò)了靜態(tài)庫(kù)的鏈接,變?yōu)榱艘粋€(gè)文件,方便于調(diào)用、移植和保存。歸檔工具ar可以很方便地查看和刪除歸檔文件中的成員。查看靜態(tài)庫(kù)libhello.a
中的內(nèi)容,命令:關(guān)于ar工具更多的命令參數(shù)可輸入ar --help
進(jìn)行查看。GCC工具集的使用
1、ar工具的使用
基本使用如上面靜態(tài)鏈接中的用法。2、addr2line工具的使用
addr2line可以將地址信息轉(zhuǎn)化成函數(shù)名或行數(shù)。例如,如下代碼運(yùn)行會(huì)產(chǎn)生段錯(cuò)誤:「test.c:」#include?
?
int?main(void)
{
?char?*str?=?"hello";
?str[0]?=?'a';
?return?0;
}
首先,編譯時(shí)加上-g參數(shù),產(chǎn)生調(diào)試信息。gcc?test.c?-g?-o?test
運(yùn)行會(huì)產(chǎn)生段錯(cuò)誤Segmentation fault (core dumped)。此時(shí)會(huì)產(chǎn)生相關(guān)錯(cuò)誤系統(tǒng)存于系統(tǒng)日志中。我們可以使用如下命令查看我們當(dāng)前程序的錯(cuò)誤信息:dmesg?|?grep?test
此時(shí)會(huì)輸出類似如下信息:[?1081.831805]?test[2763]:?segfault?at?55f1d81186a4?ip?000055f1d811860d?sp?00007ffc6fc1d080?error?7?in?test_addr2line[55f1d8118000 1000]
此時(shí)借助addr2line工具可以查到產(chǎn)生錯(cuò)誤的行號(hào):addr2line?-e?test?55f1d81186a4
3、nm工具的使用
nm工具用于顯示文件中的符號(hào),可以用于各種ELF格式文件。ELF格式文件包括如下三種類型:nm工具的使用方式:nm?[option]?[file]
其中,可以使用nn --help
命令來(lái)查看支持的參數(shù)。其中,nm顯示的符號(hào)類型如:其中符號(hào)類型有大小寫之分,小寫字母表示這個(gè)符號(hào)是局部符號(hào),大寫字母表示這個(gè)符號(hào)是全局符號(hào)。下面一起來(lái)使用nm工具查看目標(biāo)目標(biāo)文件的標(biāo)號(hào)。實(shí)例代碼test.c:
#include?
static?int?a?=?1;
static?int?b;
void?print_hello(void)
{
????printf("hello\n");
}
int?main(void)
{
????print_hello();
}
編譯之后得到可執(zhí)行程序test。執(zhí)行如下命令查看test中的符號(hào):nm?test
輸出結(jié)果如:0000000000201010?d?a
0000000000201018?b?b
#?省略部分內(nèi)容......
000000000000064d?T?main
000000000000063a?T?print_hello
#?省略部分內(nèi)容......
從輸出結(jié)果可以知道,a是一個(gè)全局符號(hào),該符號(hào)位于已初始化數(shù)據(jù)(RW Data)部分。b也是一個(gè)全局符號(hào),該符號(hào)位于未初始化數(shù)據(jù)(BSS)部分。main符號(hào)與print_hello符號(hào)位于代碼部分。4、strip工具的使用
strip工具用于刪除文件中的符號(hào)。strip工具的使用方式:strip?[option]?[file]
其中,可以使用strip--help
命令來(lái)查看支持的參數(shù)。我們以nm工具的演示代碼來(lái)做演示。我們編譯得到的可執(zhí)行程序?yàn)閠est。沒(méi)有執(zhí)行strip之前,使用nm命令查看到的符號(hào)如:0000000000201010?d?a
0000000000201018?b?b
#?省略部分內(nèi)容......
000000000000064d?T?main
000000000000063a?T?print_hello
#?省略部分內(nèi)容......
使用ls -lh test
命令查看test程序的大小為:8.2k。這時(shí)候執(zhí)行如下命令刪除test的符號(hào)部分,輸出test_strip文件:strip?test?-o?test_strip
使用nm命令查看test_strip文件是否有符號(hào),顯示結(jié)果為:nm:?test_strip:?no?symbols
表示test_strip沒(méi)有符號(hào)。使用ls -lh test_strip
命令查看test_strip的大小為:6k??梢?jiàn)去掉符號(hào)表之后地程序變小了。在資源有限的系統(tǒng)中,可以使用這種方法為程序進(jìn)行瘦身。5、readelf工具的使用
readelf工具用于顯示ELF格式文件的信息。例如:readelf?-h?test
輸出結(jié)果如:ELF?Header:
??Magic:???7f?45?4c?46?02?01?01?00?00?00?00?00?00?00?00?00?
??Class:?????????????????????????????ELF64
??Data:??????????????????????????????2's?complement,?little?endian
??Version:???????????????????????????1?(current)
??OS/ABI:????????????????????????????UNIX?-?System?V
??ABI?Version:???????????????????????0
??Type:??????????????????????????????DYN?(Shared?object?file)
??Machine:???????????????????????????Advanced?Micro?Devices?X86-64
??Version:???????????????????????????0x1
??Entry?point?address:???????????????0x530
??Start?of?program?headers:??????????64?(bytes?into?file)
??Start?of?section?headers:??????????6528?(bytes?into?file)
??Flags:?????????????????????????????0x0
??Size?of?this?header:???????????????64?(bytes)
??Size?of?program?headers:???????????56?(bytes)
??Number?of?program?headers:?????????9
??Size?of?section?headers:???????????64?(bytes)
??Number?of?section?headers:?????????29
??Section?header?string?table?index:?28
通過(guò)輸出信息可以知道文件的類型、文件的格式等信息。6、objdump工具的使用
objdump工具用于顯示目標(biāo)文件的信息。objdump工具的使用方式:objdump?[option]?[file]
如:objdump?-h?hello.o
輸出結(jié)果如:hello.o:?????file?format?elf64-x86-64
Sections:
Idx?Name??????????Size??????VMA???????????????LMA???????????????File?off??Algn
??0?.text?????????00000013??0000000000000000??0000000000000000??00000040??2**0
??????????????????CONTENTS,?ALLOC,?LOAD,?RELOC,?READONLY,?CODE
??1?.data?????????00000000??0000000000000000??0000000000000000??00000053??2**0
??????????????????CONTENTS,?ALLOC,?LOAD,?DATA
??2?.bss??????????00000000??0000000000000000??0000000000000000??00000053??2**0
??????????????????ALLOC
??3?.rodata???????0000000c??0000000000000000??0000000000000000??00000053??2**0
??????????????????CONTENTS,?ALLOC,?LOAD,?READONLY,?DATA
??4?.comment??????0000002a??0000000000000000??0000000000000000??0000005f??2**0
??????????????????CONTENTS,?READONLY
??5?.note.GNU-stack?00000000??0000000000000000??0000000000000000??00000089??2**0
??????????????????CONTENTS,?READONLY
??6?.eh_frame?????00000038??0000000000000000??0000000000000000??00000090??2**3
??????????????????CONTENTS,?ALLOC,?LOAD,?RELOC,?READONLY,?DATA
顯示內(nèi)容包含目標(biāo)文件各個(gè)節(jié)的信息。7、strings工具的使用
strings工具用于查看文件中的字符串。strings工具的使用方式:strings?[option]?[file]
其中,可以使用strings--help
命令來(lái)查看支持的參數(shù)。實(shí)例代碼test.c:#include?
int?main(void)
{
????printf("11111\n");
????printf("22222\n");
????printf("33333\n");
????printf("44444\n");
????printf("55555\n");
}
編譯之后得到可執(zhí)行程序test。執(zhí)行如下命令查看test中的符號(hào):strings?test
輸出結(jié)果如:#?省略部分內(nèi)容......
11111
22222
33333
44444
55555
#?省略部分內(nèi)容......
8、objcopy工具的使用
objcopy工具用于對(duì)目標(biāo)文件的內(nèi)容進(jìn)行轉(zhuǎn)換。objcopy工具的使用方式:objcopy?[option]?[file]
如使用如下命令可以刪除可執(zhí)行程序test中的.data段輸出到test_rm:objcopy?test?-R?.data?test_rm
objcopy配合-R參數(shù)的使用可以達(dá)到類似strip工具的效果,給程序進(jìn)行瘦身。GDB的基本使用
GDB(GNU Debugger)是一個(gè)強(qiáng)大的命令行調(diào)試工具。在Linux下進(jìn)行開(kāi)發(fā),gdb工具是必知必會(huì)的工具之一。首先,看一下gdb常用的命令:下面以實(shí)例來(lái)進(jìn)行基本使用的演示:示例代碼gdb_test.c:
#include?
//?測(cè)試函數(shù)1
void?test0(void)
{
?int?i?=?-1;
?if?(i?=?0)
??printf("i?=?%d\n",?i);
?else?if?(i?=?1)
??printf("i?=?%d\n",?i);
?else
??printf("i?=?%d\n",?i);
}
//?測(cè)試函數(shù)2
void?test1(void)
{
?int?a[10]?=?{0,1,2,3,4,5,6,7,8,9};
?int?*p?=?