交叉編譯之必知必會

 做嵌入式Linux開發(fā),最熟悉的莫過于交叉編譯了。
image.png

1. 編譯器

??嵌入式開發(fā)和桌面應(yīng)用的一個很大不同就是:我們必須自己準備配置所需的工具環(huán)境。并不像Windows開發(fā)那樣裝一個VS就一切OK了,這其中最重要的就是編譯器的準備。

  • 在Ubuntu上我一般是使用sudo apt-get install arm-linux-gnu命令進行交叉編譯工具的安裝。但大多數(shù)時候這是行不通的。因為arm架構(gòu)或者特定ARM芯片的特性(如是否支持浮點運算),導(dǎo)致后期使用時故障頻出。
  • 使用開發(fā)板提供商或芯片提供商提供的開發(fā)套件,這些往往對某些特性做了優(yōu)化,是最能契合我們的芯片開發(fā)的一種方式。
  • Linaro下載對應(yīng)架構(gòu)的編譯程序,這些開發(fā)環(huán)境適用性很好,在沒能找到官方提供的套件的時候,這是一個很好的選擇。

??當(dāng)然,下載安裝完成后需要將可執(zhí)行文件的路徑加到系統(tǒng)的 PATH路徑中

2.交叉編譯器選項

??編譯程序分為4個步驟:

  • 1.預(yù)處理,生成預(yù)編譯文件(.文件):

      Gcc –E hello.c –o hello.i
    
  • 2.編譯,生成匯編代碼(.s文件):

      Gcc –S hello.i –o hello.s
    
  • 3.匯編,生成目標(biāo)文件(.o文件):

      Gcc –c hello.s –o hello.o
    
  • 4.鏈接,生成可執(zhí)行文件:

      Gcc hello.o –o hello
    

2.2 警告選項

??在默認情況下,警告選項是默認不打開的,后來Dock在開發(fā)的實踐過程中,返現(xiàn)使用-Wall選項可以事先發(fā)現(xiàn)很多簡單錯誤,為后期免去很多麻煩:

  • 判斷語句 if(a = b)
  • 缺少 default分支
  • 類型不匹配對比int a = 0; long b = 2; if(a == b)
  • 其他Dock還未遇到的

??就是這三個簡單的錯誤,曾經(jīng)讓Dock花費很多時間去調(diào)試。錯誤應(yīng)該消滅在萌芽。

2.3 包含鏈接選項

??Gcc編譯器默認是會自動尋找包含編譯環(huán)境中的頭文件和鏈接庫,但是在使用自己的頭文件和鏈接庫時,需要自己手動指定。

  • -I[path-to-include_file] 使用 -I 指定頭文件的路徑
  • -L[path-to-lib] 使用-L 指定庫文件的路徑
  • -lxx.so 使用-l 選項指定要鏈接的庫文件,默認 l代替lib文件,如鏈接libmath.so要使用 -lmath
  • -nostartfiles 不鏈接啟動文件,即暫時不鏈接main函數(shù)
  • -nostdlib 不鏈接標(biāo)準庫文件,在裸機程序中比較常用,如uboot中就會使用到這個選項,因為鏈接標(biāo)準庫的話,程序就會變得很大。
  • -static 靜態(tài)鏈接,這樣就不會使用動態(tài)庫,但后邊有時需要制定 libxx.a靜態(tài)庫文件,同時文件體積會變得很大

2.4 objcpy objdump

??雖然說能夠編譯出程序并且能夠運行就已經(jīng)夠了,但是這兩個程序使我們做嵌入式程序所不能忽視的。

2.4.1 ELF格式

ELF(Executable and Linking Format)是unix-like系統(tǒng)下的一種文件格式,它是一種對象文件的格式,用于定義不同類型的對象文件(Object files)中都放了什么東西、以及都以什么樣的格式去放這些東西。即是在程序的頭部加上了一段信息:

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:                              EXEC (Executable file)
 Machine:                           Advanced Micro Devices X86-64
 Version:                           0x1
 Entry point address:               0x42dfe0
 Start of program headers:          64 (bytes into file)
 Start of section headers:          67460488 (bytes into file)
 Flags:                             0x0
 Size of this header:               64 (bytes)
 Size of program headers:           56 (bytes)
 Number of program headers:         8
 Size of section headers:           64 (bytes)
 Number of section headers:         40
 Section header string table index: 37

對應(yīng)的結(jié)構(gòu)體為:

typedef struct
{
        unsigned char e_ident[EI_NIDENT];     /* 魔數(shù)和相關(guān)信息 */
        Elf32_Half    e_type;                 /* 目標(biāo)文件類型 */
        Elf32_Half    e_machine;              /* 硬件體系 */
        Elf32_Word    e_version;              /* 目標(biāo)文件版本 */
        Elf32_Addr    e_entry;                /* 程序進入點 */
        Elf32_Off     e_phoff;                /* 程序頭部偏移量 */
        Elf32_Off     e_shoff;                /* 節(jié)頭部偏移量 */
        Elf32_Word    e_flags;                /* 處理器特定標(biāo)志 */
        Elf32_Half    e_ehsize;               /* ELF頭部長度 */
        Elf32_Half    e_phentsize;            /* 程序頭部中一個條目的長度 */
        Elf32_Half    e_phnum;                /* 程序頭部條目個數(shù)  */
        Elf32_Half    e_shentsize;            /* 節(jié)頭部中一個條目的長度 */
        Elf32_Half    e_shnum;                /* 節(jié)頭部條目個數(shù) */
        Elf32_Half    e_shstrndx;

??但是在uboot等環(huán)境中,是無法識別這些信息的。裸機程序總是從頭一條一條指令的進行執(zhí)行。所以在有些情況下我們需要去掉這些信息。那就用到了objcopy命令:

objcopy用于將object的部分獲全部內(nèi)容拷貝到另一個object,從而可以實現(xiàn)格式的變換。

arm-linux-gnu-objcopy -O binary boot.elf boot.bin就常用來將elf轉(zhuǎn)換為RAW格式,從而在裸機上運行。

2.4.2 objdump

??objdumpb即是常用的反匯編程序,Dock常用的兩條命令為:

  • arm--linux-objdump -d boot.elf將 elf反匯編
  • arm--linux-objdump -d -b binary -m arm boot.bin 將 bin反匯編
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容