1. 程式人生 > >嵌入式Linux應用開發完全手冊(一)嵌入式Linux基礎知識

嵌入式Linux應用開發完全手冊(一)嵌入式Linux基礎知識

嵌入式Linux應用開發完全手冊

3 嵌入式Linux基礎知識

3.1 交叉編譯工具

  • 編譯工具鏈,編譯工作由幾個步驟完成,分別用到了不同的工具
    • PC端應用
      • gcc
      • ld
      • objcopy
      • objdump
    • 交叉編譯(編譯和執行在不同的環境下),arm平臺工具鏈
      • arm-linux-gcc
      • arm-linux-ld

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執行的當前路徑對比一下。