嵌入式系統移植
1. 常用二進位制相關工具
strip: 可以實現剔除可執行檔案的符號表 (減少二進位制檔案的空間體積)
objcopy : 將ELF檔案的相關段拷貝成一個檔案 (-d 反編譯 -R 顯示重定向的入口)
readelf : 讀取ELF格式的內容 (-h 顯示ELF資訊 -S 檢視ELF結構)
objdump :將ELF檔案格式進行反彙編 (生成純二進位制資料檔案)
size :列出目標檔案每一段的大小以及總體的大小
nm:檢視符號表
2. Makefile內建的變數
預定義變數
LDFLAGS: 連結選項
CFLAGS : 編譯選項 (C編譯器的選項,無預設值)
AR:庫檔案維護程式的名稱,預設值為ar
AS 彙編程式的名稱,預設值為as
CC C編譯器的名稱,預設值為cc
CPP C預編譯器的名稱,預設值為$(CC) –E
CXX C++編譯器的名稱,預設值為g++
FC FORTRAN編譯器的名稱,預設值為f77
RM 檔案刪除程式的名稱,預設值為rm -f
自動變數
$@ 目標檔案的完整名稱
$^ 所有不重複的目標依賴檔案,以空格分開
$< 第一個依賴檔案的名稱
$* 不包含副檔名的目標檔名稱
$+ 所有的依賴檔案,以空格分開,並以出現的先後為序,可能 包含重複的依賴檔案
$? 所有時間戳比目標檔案晚的依賴檔案,並以空格分開
$% 如果目標是歸檔成員,則該變量表示目標的歸檔成員名稱
變數定義方式:遞迴展開方式、簡單方式
遞迴展開eg.
bar=$(ugh)
檢視變數:
echo $(foo)
優點:它可以向後引用變數
缺點:不能對該變數進行任何擴充套件
eg.以下程式碼會造成死迴圈
CFLAGS=$(CFLAGS) -O
3. 配置linux核心時的變數
ARCH : 選擇CPU的體系結構
*在Linux核心編譯時,可以通過設定Makefile中ARCH變數的值來選擇ARM體系還是MIPS體系進行核心編譯
CROSS_COMPILE : 指定交叉編譯器的字首
4. Linux核心編譯的預設檔案
ARM體系:zImage
(image是核心映象檔案,zimage是壓縮之後的核心映象檔案,uimage是在zimage基礎之上加上頭部一些資訊,其實也是壓縮之後的核心映象,uImage映象檔案適合使用bootm命令啟動)
X86體系:bzImage
Linux核心映象檔案可以是壓縮格式也可以不壓縮
5. Linux核心原始碼目錄
net: 存放網路協議原始碼
drivers/net : 存放網路驅動原始碼
6. Kconfig的常用關鍵字
bool:配置原始碼編譯進核心或不編譯進核心
tristate: 配置原始碼編譯進核心、不編譯進核心或以模組方式編譯進核心
*tristate意思是三態(3種狀態,對應Y、N、M三種選擇方式),bool是要麼真要麼假(對應Y和N)。所以tristate的意思就是這個配置項可以被三種選擇,bool的意思是這個配置項只能被2種選擇
source表示包含下一級Kconfig
depends on表示該配置選項依賴於其他配置選項的關係
7. busybox建立檔案系統時,會建立的內容:init、ls、cd、ifconfig等命令 (常用的shell命令)
8. Linux中可以自動建立裝置節點的命令是:mdev (該工具由busybox自帶)
9. 在嵌入式開發中,函式程式碼連結到.text段 (.text 就是指程式碼段)
10. 配置核心
配置核心後,預設生成的檔名是.config
make menuconfig表示以選單形式配置Linux核心的命令
11. inittab中常見動作
inittab決定init程序如何工作,有以下2個動作:
sysinit : 系統第一個shell指令碼執行的路徑指定
askfirst: 實現使用者摁任意鍵進入控制檯
12. 常見的Makefile,生成裸機程式的方法 ★
(1).Makefile 概述:
本質上是一個“自動編譯管理器”
“自動”指它能夠根據檔案時間戳自動發現更新過的檔案而減少編譯的工作量
通過讀入Makefile檔案的內容來執行大量的編譯工作
(2).Makefile基本結構:
由make工具建立的目標體(target),通常是目標檔案或可執行檔案
要建立的目標體所依賴的檔案(dependency_file)
建立每個目標體時需要執行的命令 (command)
*命令列前面必須是一個“TAB鍵”,否則編譯錯誤為:*** missing separator. Stop.
格式如下:
target : dependency_files
<TAB> command
eg.
hello.o : hello.c hello.h gcc -c hello.c -o hello.o
(3).make使用
直接執行即可
make
-C dir 讀入指定目錄下的Makefile
-f file 讀入當前目錄下的file檔案作為Makefile
-i 忽略所有的命令執行錯誤
-I dir指定被包含的Makefile所在目錄
-n 只打印要執行的命令,但不執行這些命令
-p 顯示make變數資料庫和隱含規則
-s 在執行命令時不顯示命令
-w 如果make在執行過程中改變目錄,列印當前目錄名
Makefile 生成裸機程式的模板:
#前面是一堆變數的定義
OBJCOPY = arm-linux-objcopy CC = arm-linux-gcc #gcc是肯定要有的
#後面寫Makefile規則
#生成裸機,最終目的一定是生成bin檔案
xxx.bin:xxx #ELF檔案與bin檔案之間的關係 $(OBJCOPY) -O binary $^ $@ #objcopy是先有輸入,再寫輸出,小寫的o第一個一定是目標 xxx:xxx.o main.o #連結:由.o檔案打包生成ELF檔案 $(CC) $(LDFLAGS) -o $@ $^ #需要加編譯選項,LDFLAGS為預設值
#所有的linux專案都有的公共規則,不能寫反~ %.o:%.c $(CC) $(CFLAGS) -c -o $@ $^ %.o:%.S $(CC) $(CFLAGS) -c -o $@ $^
例項: 編寫Makefile,將start.S生成為二進位制檔案
思路:首先,我們可以使用”arm-none-linux-gnueabbihf-gcc -c -o start.o start.S” 命令來生成.o檔案。
之後,我們可以使用“arm-none-linux-gnueabihf-gcc -nostolib -o abc start.o”命令來生成可執行檔案,其中nostlib表示不需要連結庫檔案。
最後,使用“arm-linux-gnueabihf-objcopy -O binary abc abc.bin”生成最後的二進位制檔案。
將這3個步驟依次按照Makefile的語法格式進行編譯即可生成二進位制檔案。
CROSS_COMPILE = /opt/Sourcery_CodeBench_Lite_for_Xilinx_GNU_Linux/bin/arm-linux-CC = gcc OBJS += start.o CFLAGS += -nostdlib LDFLAGS += -Tmap.lds TARGET := build.bin all:$(TARGET) $(TARGET):build $(CROSS_COMPILE)objcopy -S --gap-fill 0xff -O binary $^ $@ build:$(OBJS) $(CROSS_COMPILE)ld $(LDFLAGS) -o $@ $^ %.o:%.c $(CROSS_COMPILE)$(CC) -c $(CFLAGS) -o $@ $< %.o:%.S $(CROSS_COMPILE)$(CC) -c $(CFLAGS) -o $@ $< .PYHON:clean clean: rm -f *.o build build.bin
13. bootloader的工作流程
①. bootloader一般分為boot階段和loader階段
②. boot階段採用體系結構相關的組合語言編寫,主要是初始化CPU和記憶體裝置
③. boot階段為第二階段初始化C語言執行前環境,設定SP暫存器
④. loader階段根據系統映象儲存位置,初始化對應裝置的驅動,拷貝系統映象檔案內容到記憶體載入地址
⑤. loader階段根據核心啟動要求,初始化R0,R1,R2暫存器的值,將PC指標指向核心映象載入地址處
14. ext4格式映象檔案的製作過程
1.分配空間
(1).製作64M的映象檔案,命名為:a9rootfs.ext3
sudo dd if=/dev/zero of=a9rootfs.ext3 bs=1M count=64
(2).用ext3格式化上一步的映象檔案
sudo mkfs.ext3 a9rootfs.ext3
2.填充空間
(1).掛載映象檔案到一個目錄,建議放在同級目錄下,假設目錄名為mnt_fs
sudo mount -t ext3 -o loop a9rootfs.ext3 mnt_fs/
(2).建立根檔案系統目錄
(3).利用busybox製作可執行檔案
(4).拷貝檔案到mnt_fs目錄下
(5).拷貝動態庫到根檔案系統裡
(6).編寫inittab、etc/rc.d/rcS、etc/fstab檔案
3.解除安裝空間
sudo umount mnt_fs
15. GNU格式的連結指令碼
連結指令碼:怎麼把目標檔案組合在一起
#SECTIONS: SECTION 表示段,S表示很多段
#4個段有先後關係,最好不要打亂它的順序
#.text程式碼段、.rodata只讀資料段、.data資料段、.bss全域性初始化位清零段。語法為:段名:{*(同名段)}
#.text程式碼段是第一個,需要指定地址:start.o(.text)
#ALIGN(4) 4位元組對齊
SECTIONS { . = 0x20000000; #要什麼地址給什麼地址 . = ALIGN(4); .text : { start.o(.text) *(.text) } . = ALIGN(4); .rodata : { *(.rodata) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); .bss : { *(.bss) } }
16. make執行
make執行時讀取當前目錄下的Makefile檔案或makefile進行執行
Makefile和makefile檔案在make執行時的優先順序是不一樣的
make中如果目標檔案比依賴檔案新,那麼make將不執行對應的命令
17. uboot編譯時,不僅僅會產生對應體系的檔案,還可能產生x86體系的可執行檔案
uboot可以支援ARM、MIPS、PowerPC等眾多CPU體系結構(uboot即是bootloader的一種,引導啟動核心的)
18. 使用QEMU載入檔案時,必須是ELF格式的檔案
19.NFS
網路啟動的根檔案系統稱之為NFS
使用NFS作為根檔案系統時,linux核心需要載入網絡卡驅動
20. linux程序
linux的proc目錄下可以檢視到程序資訊
linux的1號程序叫init程序
21. Linux核心編譯時,objs-y的目標才被編譯進核心映象中
22. busybox原始碼是沒有體系結構相關的配置的
==================分============割============線==================
23.燒寫到系統的bootloader映象檔案是binary格式的檔案
24.ramdisk根檔案系統不可以燒寫到flash上
25.Linux系統提供VFS(虛擬檔案系統)層,方便訪問其核心掛載的根檔案系統
26.在嵌入式開發中,使用交叉編譯器在主機上編譯,在目標機上執行程式
27.bootloader在載入核心啟動前,需要將核心映象和核心啟動引數搬移到系統記憶體中