常用交叉編譯工具整理(arm-linux-gcc)
一、arm-linux-gcc
1. 編譯部分:
-o : 後面接的是輸出檔名(arm-linux-gcc -o hello hello.c)
-v : 可以觀看編譯細節 (arm-linux-gcc -v -o hello hello.c)
-c : 預編譯,編譯和彙編原始檔,不做連線 [裸板程式一般先不做連線,最後一起做連結](arm-linux-gcc -o hello.o -c hello.c)
-S : 編譯後停止,不進行彙編(arm-linux-gcc -S -o hello.s hello.c)
-E : 預編譯後即頂著,不進行編譯(arm-linux-gcc -E hello.c)
-g : 產生除錯資訊
-Wall : 開啟所有需要注意的警告資訊
2. 優化部分
(注可以指定多個"-O"選項,不管帶不帶數字,生效的是最後一個)
-O or -O1 : 不使用-O/-O1時,可以減少編譯的開銷,使編譯結果能夠除錯,語句是獨立的,只有聲明瞭register的變數才分配使用暫存器;
使用-O/-O1時,編譯器試圖減少目標碼的大小和執行時間。
-O2 : 多優化一些,除了涉及空間和速度交換的優化選項,執行幾乎所有優化工作,例如不進行迴圈展開和函式內嵌;
-O3 : 優化的更多,除了-O2, 還開啟"-finline-functions"
-O0 : 不作優化
3. 連結部分
-llibrary_name : 連結名為library的庫檔案,真正的名字為liblibrary.a,如要連結libtest.a or libtest.so ,則寫成-ltest,如果有動態庫,則會優先連結動態庫。
-Llibpath : 指定連結庫搜尋路徑,如庫都放在/prj/libs/下面,則-L/prj/libs
-nostartfiles : 不連線系統標準啟動檔案,標準庫檔案仍然正常使用(編譯bootloader,kernel時用到)
-nostdlib : 不連線系統標準啟動檔案和標準庫檔案,只把指定的檔案傳遞給聯結器(編譯bootloader,kernel時用到)
[與-nostartfiles的區別是,-nostartfiles只是不包含啟動檔案]
-static : 在支援dynamic linking的系統上阻止連線共享庫[預設情況下會優先選擇連線動態庫,使用了static會直接連線靜態庫] (gcc-static -o main main.c func.c)
-shared :生成共享OBJ檔案 (gcc -shared -o libfunc.so -c func.c; gcc -o main main.c -lfunc -L.)
-fPIC :編譯成位置無關,當編譯多個檔案為動態庫是,必須使用這個選項
(gcc-shared -fPIC -o libfunc.so func1.c func2.c func3.c)
-Xlinkeroption : 把選項option傳遞給聯結器,如果要帶引數,必須使用兩次"-Xlinker" (-Xlinker -assert -Xliner definitions)
-Wl,option : 把選項option傳遞給聯結器,如果option有逗號,則傳遞多個選項。常見有(-Wl,--start-group ... -Wl, --end-group)
4. 目錄部分
-Iinclude_dir : 在標頭檔案中搜索路徑列表中新增include_dir
-Llibpath : 指定連結庫搜尋路徑,如庫都放在/prj/libs/下面,則-L/prj/libs
二、arm-linux-ld
-T : 用於指定程式碼段,資料段,bss段的起始地址 or 指定一個連線指令碼
1. 用於指定程式碼段,資料段,bss段的起始地址
-Ttext startaddr //text 指的是程式碼段, startaddr指的是起始地址
-Tdata startaddr //data指的是資料段
-Tbss startaddr //bss通常指全域性未初始化變數
如下:指定程式碼段的執行地址為0x00000000,沒有定義資料段,bss段的起始地址,被依次放在程式碼段後面
arm-linux-ld-Ttext 0x00000000 -g led_on.o -o led_on.elf
注:位置無關碼和位置相關碼 bootloader,kernel剛開始執行時所處的位置通常不等於執行地址, 在程式開頭使用b,bl,mov等"位置無關"指令
將程式碼從Flash中copy到sdram中,然後再用位置相關碼ldr pc, =addr跳轉到相應位置執行。
2. 指定一個連線指令碼
arm-linux-ld -Tlink.lds -o led_on.elf len_on.S
link.lds:
/*
*OUTPUT_FORMAT 指定輸出格式,elf32-littlearm的意思是指定輸出可執行檔案是elf格式,32位ARM指令,小端
*OUTPUI_ARCH 指定輸出可執行檔案的平臺為ARM
*ENTRY 指定程式入口地址
*_start 等於SECTIONS裡面.=0x30000000, 即目的碼的起始地址
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS{
.= 0x30000000;
.text: { *(.text) }
.rodata ALIGN(4) : { *(.rodata) }
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) *(COMMON) }
}
section格式為:
SECTIONS{
...
secname start ALIGN(align) (NOLOAD) : AT(ldadr)
{ contexts } > region : phdr = fill
}
secname : 用來命名這個段; 如 .bss
contexts : 用來確定什麼部分放在這個段;
start : 重定位地址,執行地址,如果程式碼中有位置無關指令,程式在執行時,這個段必須放在這個地址上
ALGIN(align) : 雖然start指定執行地址,但是仍然可以指定對齊要求,對齊後的才是真正執行地址
NOLOAD : 用來告訴載入器,在執行時不用載入這個段,只有在作業系統的情況下才有意義
AT(ldadr) : 編譯出來映像檔案中的地址-載入地址load address, 如果不使用這個選項,
載入地址等於執行地址。A段放在A處,B段放在B處,執行前再把A,B讀出來組裝成一個完整的執行程式
在程式碼中指定某個section:
格式:__attribute__((unused,section (".section-name")))
如:
C語言中:__attribute__((unused,section (".u_boot_cmd")))
link-ds中:
.= .;
__u_boot_cmd_start= .;
.u_boot_cmd: { *(.u_boot_cmd) }
__u_boot_cmd_end= .;
三、arm-linux-objcopy
1. input-file, out-file
: 表示輸入目標檔案(源目標檔案)和輸出目標檔案(目的目標檔案)
2. -I bfdname or --input-target=bfdname
: input-file檔案BFD庫中描述的標準格式名,如果不指定,則arm-linux-objcopy自己去分析原始檔的格式
3. -Obfdname or --output-target=bdfname
: 輸出格式
4. -F bfdname or --target=bfdname
: 源目標檔案是什麼格式,目標檔案就是什麼格式,只複製不做格式轉換
5.-R sectionname or--remove-section=sectionname
: 從輸出檔案中刪掉所有名為sectionname的段
6.-S or --strip-all
: 不從原始檔中複製重定位資訊和符號資訊到目標檔案中去(bootloader,kernel等裸板程式用到)
7.-g or --strip-debug
: 不從原始檔中複製除錯符號到目標檔案中去
在編譯bootloader, kernel時,常用arm-linux-objcopy將ELF格式生成結果轉化為二進位制檔案:
// binary表示輸出格式為二進位制檔案
// file.elf表示ELF格式檔名
// file.bin表示二進位制檔名
#arm-linux-objcopy -O binary -S file.elf file.bin
bfdname 有以下幾個格式:ELF檔案格式(elf32-littlearm, elf32-bigarm)、S-record檔案格式(srec)、HEX檔案格式(ihex)、bin檔案格式(binary)
BIN檔案格式(binary): 原始的二進位制格式,內部沒地址標記,直接照二進位制格式下載,並且照絕對地址燒寫到Flash中,
就可以啟動了,而如果下載執行,則下載到編譯時的地址即可。
ELF檔案格式 : 是Linux系統下的一種常用、可移植目標檔案(objectfile)格式
S-Record檔案格式
HEX檔案格式
四、 arm-linux-objdump (反彙編程式碼)
1. -b bfdname or --target=bfdname : 指定目標碼格式,
2. --infoor -i : 檢視目標碼格式列表
3. --disassemble or -d : 反彙編可執行段(executablesections)
4. -D or --disassemble-all : 反彙編所有段
5. --file-headers or -f : 顯示檔案的整體頭部摘要資訊
6. --section-headers, --headers or -h : 顯示目標檔案各個段頭部摘要資訊
7. --section=nameor -j name : 僅顯示指定section的資訊
//將ELF格式的檔案轉換成為反彙編檔案,arm-linux-objdump預設格式elf
#arm-linux-objdump -D file.elf > file.dis
//將二進位制檔案轉換成反彙編檔案
#arm-linux-objdump -D -b binary -m arm file.bin > file.bin
五、arm-linux-readelf (檢視當前檔案or庫是由什麼編譯器所編譯 )
#arm-linux-readelf–h libxxx.so
六、arm-linux-ar (生成.a or 把.a拆分成.o)
1. -x : 把.a拆分成.o
#arm-linux-ar -x libfunc.a
2.生成靜態庫.a檔案
-c : 建立一個文件
-s : 在文件中新增索引
-r : 插入檔案成員
/* libfunc.a一定在.o檔案前面 */
#arm-linux-ar -rcs libfun.a fun1.o fun2.o fun3.o
七、arm-linux-strip (去掉其中的除錯資訊,執行檔案大小or動態庫將小的多)
arm-linux-strip libfunc.so