2.交叉工具链
2.交叉工具鏈
一、交叉工具鏈:
交叉工具鏈,其實(shí)他有兩個(gè)含義,一個(gè)就是交叉工具,所謂的交叉工具就是運(yùn)行的環(huán)境和編譯的環(huán)境不是在一體的。就像我們現(xiàn)在,編譯裸機(jī)程序是在pc機(jī)上面執(zhí)行的。可我們運(yùn)行程序是在開(kāi)發(fā)板。鏈,就是很多的意思,就是一個(gè)工具的集合。在我們前面配置arm-linux-gcc的工具中。在/usr/local/arm/4.3.2/bin的目錄下有很多編譯工具。例如圖1-1:
圖1.-1 交叉工具鏈
下面我們來(lái)寫(xiě)一個(gè)簡(jiǎn)單的程序,用這些工具編譯。
Hello.c:
#include <stdio.h>
void main(){
????printf("hello fish!\n");
}
這是一個(gè)簡(jiǎn)單的hello程序。首先我們先用我們熟悉的gcc編譯并執(zhí)行。圖1-2:
圖1-2
我們看到程序正常運(yùn)行。輸出了內(nèi)容。
接下來(lái)我們用剛安裝的交叉工具來(lái)編譯運(yùn)行。圖1-3:
圖1-3
我們看見(jiàn)程序出錯(cuò)了。提示的信息是不能運(yùn)行的二進(jìn)制文件。這就奇怪了。這是為啥呢?其實(shí)呢。我在前面已經(jīng)提過(guò)了,arm-linux-*工具,編譯的程序是在開(kāi)發(fā)板運(yùn)行的。其實(shí)我們可以通過(guò):file 文件名.來(lái)查看該應(yīng)用程序運(yùn)行的平臺(tái)。圖1-4:
圖1-4
可以看到信息,hello是gcc編譯生成的是運(yùn)行在x86架構(gòu)的,hello1是arm-linux-gcc編譯生成的是運(yùn)行在ARM架構(gòu)的。
接下來(lái)我們把hello1拷貝到開(kāi)發(fā)板運(yùn)行看看。
我已在開(kāi)發(fā)板燒寫(xiě)好了linux系統(tǒng),通過(guò)u盤(pán),把hello1拷貝到開(kāi)發(fā)板。然后插入開(kāi)發(fā)板的usb口。在終端可以看見(jiàn)提示信息,這是因?yàn)槲覀兊膌inux帶有usb驅(qū)動(dòng),當(dāng)我們的usb插進(jìn)去的時(shí)候,它檢測(cè)到了usb,加載好了驅(qū)動(dòng)。現(xiàn)在我們進(jìn)入u盤(pán),運(yùn)行hello1程序。圖1-5.這時(shí)仍然提示錯(cuò)誤。如下:
?
?
這是為啥呢?這是我們的開(kāi)發(fā)板缺少程序運(yùn)行時(shí)需要的動(dòng)態(tài)庫(kù),因?yàn)槲覄偛啪幾g的時(shí)候沒(méi)有加-static屬性。加上-static屬性重新編譯。圖1-6:
圖1-6
可以看到,這次加入了-static條件,編譯生成的hello2程序比hello1大了許多,就是因?yàn)榘堰\(yùn)行需要的庫(kù)文件都靜態(tài)鏈接進(jìn)來(lái)了。同樣拷貝到u盤(pán),可以看到順利運(yùn)行。圖1-7:
圖1-7
二、交叉工具鏈的詳述:
1.arm-linux-gcc編譯器:
前面,可以看到gcc和arm-linux-gcc工具的編譯條件都是一樣的。可為什么編譯出來(lái)的應(yīng)用程序會(huì)運(yùn)行在不同的平臺(tái)呢?這是因?yàn)?#xff0c;他們兩個(gè)在編譯的時(shí)候引用的頭文件不同。傳統(tǒng)的gcc是默認(rèn)去/usr/include尋找它需要的頭文件。圖1-8:
圖1-8頭文件
而arm-linux-gcc尋找的頭文件的目錄不同。首先使用arm-linux-gcc –help查看它的使用:圖1-9:
圖1-9
注意到參數(shù)-print-search-dirs就是顯示尋找頭文件的參數(shù)目錄。加上該參數(shù)得到一下信息圖1-10:
圖1-10
從上面的顯示看到arm-linux-gcc默認(rèn)是到我們安裝arm-linux-gcc的目錄去找頭文件的。
?
?
2.arm-linux-ld:
arm-linux-ld是鏈接器,下面介紹它的使用。
首先先用arm-linux-gcc生成中間文件.o文件。圖2-1:
arm-linux-gcc -g -c led.S
圖2-1
在上面的參數(shù)中-g表示可以用gdb來(lái)調(diào)試信息,-c是只編譯不鏈接。最后生成led.o中間文件。接下來(lái)就是使用arm-linux-ld把該文件鏈接成elf文件:圖2-2:
arm-linux-ld -Tled.lds -o led.elf led.o
圖2-2
上面語(yǔ)句的意思是利用arm-linux-ld鏈接器,按照-T指定的鏈接器腳本,把生成的led.o(如果有多個(gè).o文件,在后面繼續(xù)加上),鏈接成led.elf文件。
?
3.arm-linux-readelf:
利用該工具可以查看生成的.elf文件的內(nèi)容:
執(zhí)行:arm-linux-readelf -a led.elf。-a參數(shù)是all的意思,表示查看所有信息:圖2-3:
圖2-3
從上面看到elf文件有一個(gè)固定的頭:ELF Header:然后:
Data: 2's complement, little endian
是表示他是運(yùn)行在小端處理器的。
Machine: ARM
是表示他是運(yùn)行在ARM平臺(tái)的。
所以當(dāng)運(yùn)行一個(gè)程序出錯(cuò)的時(shí)候,當(dāng)檢查完語(yǔ)法沒(méi)問(wèn)題,仍然不能運(yùn)行的時(shí)候,就應(yīng)該用readelf查看一下這些信息是否符合。如果上面的兩種檢查完了之后還是不能運(yùn)行。接下來(lái)就是查看需要的庫(kù)是否存在。使用的命令:
arm-linux-readelf -d hello
運(yùn)行結(jié)果:圖2-4:
圖2-4
上面顯示了該hello應(yīng)用程序需要的庫(kù)是libc.so.6.如果沒(méi)有該庫(kù),該程序運(yùn)行不了。
?
?
?
?
4.arm-linux-objdump:
ARM反匯編器。
上面已經(jīng)使用arm-linux-gcc編譯產(chǎn)生了可執(zhí)行文件hello2.現(xiàn)在對(duì)它進(jìn)行反匯編。命令:
arm-linux-objdump -D -S hello2 >mydump
該命令的意思是將hello2可執(zhí)行程序反匯編,輸出到mydump文件。執(zhí)行之后會(huì)在該目錄下產(chǎn)生一個(gè)mydump文件:圖2-5:
打開(kāi)可以看到對(duì)應(yīng)的匯編代碼:
但是,都是匯編代碼,看起來(lái)還是非常困難。可以在編譯的時(shí)候加上-g調(diào)試信息的參數(shù),這樣反匯編之后會(huì)有部分的c代碼存在。這樣可以讓我們更加容易看懂程序。
圖2-5
可以看到加上-g編譯,反匯編后,在匯編代碼里居然有c代碼出現(xiàn)。在上面的代碼中printf("hello fish!\n");的匯編實(shí)現(xiàn)就是它下面兩行。源代碼:
5.最后一個(gè)是文件格式轉(zhuǎn)換工具:arm-linux-objcopy:
從上面的操作知道,匯編代碼通過(guò)arm-linux-gcc -g -c led.S,把一個(gè)匯編文件轉(zhuǎn)化為一個(gè)led.o文件,接著使用:arm-linux-ld -Tled.lds -o led.elf led.o,把led.o利用led.lds腳本,鏈接成一個(gè)led.elf文件。但是elf文件無(wú)法在板子運(yùn)行,必須轉(zhuǎn)化為.bin格式的二進(jìn)制文件。這就是arm-linux-objcopy的功能:
arm-linux-objcopy -O binary led.elf led.bin
圖2-6:
圖2-6
?
轉(zhuǎn)載于:https://www.cnblogs.com/FORFISH/p/5188679.html
總結(jié)
- 上一篇: 【PL/SQL】--导出oracle单表
- 下一篇: 我的新设计