嵌入式Linux應用開發完全手冊(一)嵌入式Linux基礎知識
阿新 • • 發佈:2018-11-12
嵌入式Linux應用開發完全手冊
3 嵌入式Linux基礎知識
3.1 交叉編譯工具
- 編譯工具鏈,編譯工作由幾個步驟完成,分別用到了不同的工具
- PC端應用
- gcc
- ld
- objcopy
- objdump
- 交叉編譯(編譯和執行在不同的環境下),arm平臺工具鏈
- arm-linux-gcc
- arm-linux-ld
- PC端應用
3.1.1 arm-linux-gcc
- C/C++檔案的編譯步驟
- 預處理 preprocessing
- 編譯 compilation
- 彙編 assembly
- 連線 linking
預處理
根據預處理命令(#開頭的命令)修改原始檔,形成.i檔案
用到額工具是arm-linux-cpp
編譯
將經過預處理的.i檔案,翻譯成彙編程式碼,.s檔案
用到的工具是ccl
彙編
將彙編程式碼檔案.s翻譯成目標檔案 .o檔案
用到的工具是arm-linux-as
連線
將彙編生成的目標檔案和庫檔案連線起來,最終生成特定平臺的可執行檔案
用到的工具是arm-linux-ld
聯結器處理的檔案一般包括
- .o 目標檔案
- .a 庫檔案
arm-linux-gcc的重要選項
- -E 預處理 :預處理結果通過stdout顯示出來
- -S 預處理、編譯 :可以生成.s檔案
- -c 預處理、編譯、彙編 :可以生成.o檔案
- -o 指定輸出檔名 :如果不指定名成,按照一般規則生成
- -v 顯示製作gcc命令時的配置 :顯示更詳細的編譯資訊
- -Wall 顯示所有警告資訊 :Warning ALL
- -g 產生除錯資訊,以便GDB使用 : 要使用gdb除錯,必須有這個選項
- -O 優化選項 :O0,O1,O2,O3 4級優化,一般應用選O2
- [object-file-name] :連線的時候,目標檔案和庫檔名稱
- -l[library] :連線名為l[library]的庫檔案,庫檔名稱規則lib[libraay].so
- -nostartfiles :不連線系統標準啟動檔案,編譯bootloader, 核心的時候會用到
- -nostdlib :不連線系統標準啟動檔案和標準庫檔案,編譯bootloader和核心會用到
- -static :組織連線共享庫,開啟這個選線櫃讓編譯出來的結果很大,不動態連線一些庫,那麼就都包含在編譯結果裡邊了
- -shared :生成庫檔案
- -I[dir] :標頭檔案搜尋路徑中新增 dir
- -L[dir] :-l指定某個庫需要連線的時候,這個引數增加搜尋路徑,比如-L. 當前目錄作為搜尋目錄新增進來
/ * 舉例 */
[main.c] - include [sub.h]
[sub.h]
[sub.c] - include [sub.h]
--------
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o
--------
gcc -S -o main.s main.c
gcc -E main.c | less
--------
gcc -shared -o sub.a sub.o sub2.o sub3.o
arm-linux-ld選項
- -T :指定程式碼段、資料段、bss段的起始位置,或者指定一個連線指令碼
:-T引數只用於連線bootloader,核心等“沒有底層軟體支援”的軟體
:連線運行於作業系統之上的軟體時,不需要-T,使用預設連線即可
-Ttext startaddr
-Tdata startaddr
-Tbss startaddr
/* 程式碼段執行地址0x00000000,沒有定義資料段,bss段,它們依次放在程式碼段後面 */
arm-linux-ld -Ttext 0x00000000 -g ledon.o -o ledon_elf
/* 使用連線指令碼設定地址 */
arm-linux-ld -Ttimer.lds -o timer_elf head.o init.o interrupt.o main.o
[timer.lds]
--------
SECTIONs {
. = 0x30000000;
.text : {*(.text)}
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : {*(.data)}
.bss ALIGN(4) : {*(.bss) *(COMMON)}
}
--------
arm-linux-objcopy選項
- arm-linux-objcopy用來賦值一個目標檔案到另一個檔案中,可以使用不同於原始檔的格式來輸出目的檔案,也就是可以用來進行格式轉換
- 可以用它來將elf檔案轉換位二進位制可執行檔案
/* 編譯bootloader和核心的時候,用此命令將elf檔案轉換為二進位制檔案 */
arm-linux-objcopy -O binary -S elf_file bin_file
arm-linux-objdump選項
- 用於顯示二進位制檔案資訊,常用來檢視反彙編程式碼
/* 將elf格式檔案反彙編 */
arm-linux_objdump -D elffile > dis_file
/* 將二進位制檔案反彙編 */
arm-linux-objdump -D binary -m arm bin_file > dis_file
3.2 Makefile
Makefile就是一個名字是Makefile的檔案。內部縮排必須使用Tab,不能轉換為空格。
這裡介紹Makefile的最基本的規則。
格式
[Makefile]
--------
target : prerequiries
<Tab>command
--------
- 目標 通常是要生成的檔名稱,可以是可執行檔案或者obj檔案。也可以是一個需要執行的動作名稱,比如“clean”
- 依賴 用來產生目標的原料(比如原始檔),一個目標通常有幾個依賴。
- 命令 生成目標時進行的動作。可以有若干命令,一個命令一行
- 依賴發生改變,目標就需要通過命令重新生成。如果依賴沒有改變,目標不需要重新生成。
/* 一個最簡單的例子 */
hello: hello.c
gcc -o hello hello.c
clean:
rm -f hello
變數及賦值
- 延時變數
- =
- ?=
- 立即變數
- :=
- 擴充套件變數
- +=
src := $(shel ls *.c) /* 立即變數的賦值 */
obj := $(patsubst %.c, %.o, $(src))
obj += temp.o /* 擴充套件變數 */
test: $(obj) /* 變數使用 */
gcc ...
Makefile函式
Makefile裡邊可以使用一些函式,格式如下
$(function arguments)
字串替換和分析函式
- $(subst from, to, text)
- $(patsubst pattern, replacement, text)
- $(strip string)
- $(findstring find, in)
- $(filter pattern…, text)
- $(filterout pattern…, text)
- $(sort list)
$(subst ee, EE, feet on the street)
fEEt on the strEEt
$(patsubst %.c, %.o, x.c.c bar.c)
x.c.o ar.o
$(strip a b c
a b c
$(findstring a, a b c)
a
$(findstring a, b c)
$(filter %.c %.s, foo.c bar.c baz.s ugh.h)
foo.c bar.c baz.s
$(filterout %.c %.s, foo.c bar.c baz.s ugh.h)
ugh.h
$(sort foo bar lose)
bar foo lose
檔名函式
- $(dir names)
- $(notdir names)
- $(suffix names)
- $(basename names)
- $(addsuffix suffix, names)
- $(addprefix prefix, names)
- $(wildcard pattern)
$(dir src/foo.c hacks)
src/ ./
$(notdir src/foo.c hacks)
foo.c hacks
$(suffix src/foo.c src-1.0/bar.c hacks)
.c .c
$(basename src/foo.c src-1.0/bar.c hacks)
src/foo src-1.0/bar hacks
$(addsuffix .c, foo bar)
foo.c bar.c
$(addprefix src/, foo bar)
src/foo, src/bar
$(wildcard *.c) /* 等於 $(shell ls *.c)*/
1.c 2.c
其他
- $(foreach var, list, text)
- $(if condition, then-part, else-part)
- $(origin var)
- $(shell cmd)
dirs := a b c d
files := $(foreach dir, $(dir), $(wildcard $(dir)/*))
/* files 變數賦值為 a/ b/ c/ d/ 下邊的所有檔案*/
自動變數
- [email protected] 規則的目標檔案
- $^ 所有依賴名字,名字之間空格分開
- $< 第一個依賴的名字
一個稍微複雜點的例子
src := $(shell *.c)
objs := $(patsbust %.c, %.o, $(src))
test: $(objs)
gcc -o [email protected] $^
%.o: %.c
gcc -c -o [email protected] $<
clean:
rm -f test *.o
3.3 常用ARM彙編指令和ATPCS規則
ARM彙編指令
- 相對跳轉b, bl
- 資料傳送指令mov
- 地址讀取偽指令ldr
- 記憶體訪問指令 ldr str ldm stm
- 加減 add sub
- 程式轉檯暫存器訪問指令 msr mrs
- 其他 .extern .text .global
ATPCS
ARM程式和Thumb程式中子程式呼叫規則。
- 暫存器
- r0 - r3 傳遞引數
- r4 - r11 儲存區域性變數
- r12 子程式間scratch暫存器,別名ip
- r13 資料棧指標,別名sp
- r14 連線暫存器,別名lr
- r15 程式計數器,別名pc
- 堆疊
- FD 滿減堆疊
- 8位元組對齊
- stmdb ldmia 指令訪問,db: Decending before, ia:increase after
- 引數傳遞規則
- 引數不超過4個,用r0 - r3,超過4個用堆疊
- 返回結果用r0 - r3
4 Windows,Linux環境下的工具、命令介紹
4.1 windows
Source insight
Cuteftp, SecureCRT, tftp
- 這幾個工具用Xshell就全搞定了,不用書上介紹的這幾個 *
4.2 Linux
KScope
CKermit
Vi
- 這幾個工具暫時用不到,就用windows環境 Samba連線Linux即可,Vi可以通過Vimtutor熟悉下 *
grep find 命令
grep
- grep [operation] PATTERN [FILE…]
grep "request_irq" * -R // *表示當前目錄下所有檔案,-R 表示遞迴查詢所有子目錄
grep "request_irq" kernel -R // 在當前目錄的kernel目錄下查詢,包含所有子目錄
find -name "*.[ch]" | xargs grep "request_irq" // 在當前目錄下所有的.c .h 檔案中查詢關鍵字
find
- find [-H] [-L] [-P] [path…] [expression]
find -name "*fb*"
find drivers/net -name "*fb*"
man
- man [section] name
- 需要注意的是[section] 部分,因為同一個關鍵字,可以出現在不同的地方,比如uname 可以是shell命令,也可以是系統格呼叫,單純根據關鍵字是無法定位的。*
- section的定義
- 1 命令,比如ls grep find
- 2 系統呼叫,比如open read socket
- 3 庫呼叫,比如fopen, fread
- 4 特殊檔案 比如 /dev 目錄下的檔案
- 5 檔案格式和慣例,比如/etc/passwd
- 6 遊戲
- 7 其他
- 8 系統管理命令,如mount
- 9 核心例程
man uname
man 2 uname
tar
- tar有打包、解包、壓縮、解壓縮 4種功能
- 壓縮格式
- gzip .gz .z
- bzip2 .bz2
- tar命令常用選項
- c 建立
- x 提取
- z 使用gzip方式處理
- j 使用bzip2方式處理
- f 檔案,接檔名
- 最常用的選項組合套路
- czf, cjf 建立壓縮包
- xzf, xjf 解壓縮
tar czf dirA.tar.gz dirA
tar cjf dirA.tar.bz2 dirA
tar xzf dirA.tar.gz
tar xjf dirA.tar.bz2
diff patch
- diff是UNIX標準的檔案差異對比工具和格式
- diff常用選項
- -u 顯示上下文中一些相同的行
- -r 遞迴比較各目錄下的檔案
- -N 不存在的檔案當做空檔案
- -w 忽略空格
- -B 忽略空行
- 用diff命令製作補丁檔案
diff -urNwB linux-2.6.22.6 linux-2.6.22.6_ok > linux-2.6.22.6_ok.diff
- patch的用法,patch用來把一個補丁檔案(.diff)合併到工程中
cd linux-2.6.22.6
patch -p1 < ../linux-2.6.22.6_ok.diff
其中引數-p1 中是數字1,不是子母l。含義是忽略補丁檔案中所有路徑相關欄位的的第一級目錄,具體應該忽略幾級,需要開啟diff檔案檢視一下,跟patch執行的當前路徑對比一下。