Linux-uboot-學習筆記(5):uboot的配置和編譯過程代碼分析

Linux-uboot-學習筆記(5):uboot的配置和編譯過程代碼分析

Linux-基礎入門-學習筆記(3):uboot常用命令與環境變量一文中,已經對uboot的基本認識有了一個簡單的介紹,也知道了uboot是引到操作系統啓動和部署整個計算機系統的最重要的一部分,下面對uboot的配置和編譯過程代碼進行詳細分析。

首先說明該uboot程序針對samsung的s5pv210板卡:

一、Makefile編譯代碼分析

uboot版本確定代碼段(24-29)
VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 4
EXTRAVERSION =	
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
VERSION_FILE = $(obj)include/version_autogenerated.h

此段代碼主要是通過uboot版本號的3個級別,VERSION(主板本號),
PATCHLEVEL(次版本號),SUBLEVEL(再次版本號)以及
EXTRAVERSION(另外附加的版本信息)。最終生成了一個變量U_BOOT_VERSION,這個變量記錄了Makefile中配置的版本號
在這裏插入圖片描述
include/version_autogenerated.h文件是編譯過程中自動生成的一個文件,所以源目錄中沒有,但是編譯過後的uboot中就有了。它裏面的內容是一個宏定義,宏定義的值內容就是我們在Makefile中配置的uboot的版本號

修改主機和虛擬機名段(31-43)
HOSTARCH := $(shell uname -m | \
	sed -e s/i.86/i386/ \
	    -e s/sun4u/sparc64/ \
	    -e s/arm.*/arm/ \
	    -e s/sa110/arm/ \
	    -e s/powerpc/ppc/ \
	    -e s/ppc64/ppc/ \
	    -e s/macppc/ppc/)
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
	    sed -e 's/\(cygwin\).*/cygwin/')
export	HOSTARCH HOSTOS

在這裏插入圖片描述
這兩個環境變量是主機的操作系統和主機的CPU架構,得出後保存備用,後面自然會用到。

靜默編譯(50-54)
ifeq (,$(findstring s,$(MAKEFLAGS)))
XECHO = echo
else
XECHO = :
endif

使用方法就是編譯時make -s-s會作爲MAKEFLAGS傳給Makefile,在這段代碼作用下XECHO變量就會被變成空(默認等於echo),於是實現了靜默編譯(無echo)。

確定編譯方式(78-123)
ifdef O
ifeq ("$(origin O)", "command line")
BUILD_DIR := $(O)
endif
endif

ifneq ($(BUILD_DIR),)
saved-output := $(BUILD_DIR)

# Attempt to create a output directory.
$(shell [ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR})

# Verify if it was successful.
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)
$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
endif # ifneq ($(BUILD_DIR),)

編譯複雜項目,Makefile提供2種編譯管理方法。
(1)原地編譯: 默認情況下是當前文件夾中的.c文件,編譯出來的.o文件會放在同一文件夾下。好處是管理方便,壞處是容易污染源文件目錄,而且無法同時維護2個或2個以上的配置編譯方式。
(2)單獨輸出文件夾的編譯方式: 在編譯時另外指定一個輸出目錄,將來所有的編譯生成的.o文件或生成的其他文件全部丟到那個輸出目錄下去。源代碼目錄不做任何污染,這樣輸出目錄就承載了本次配置編譯的所有結果。

由代碼可以看出,當編譯時用-o指定編譯目錄時,參數會傳遞到BUILD_DIR中,並進行一系列創建目錄的過程。
在這裏插入圖片描述
OBJTREE: 編譯出的 .o文件存放的目錄的根目錄。在默認編譯下,OBJTREE等於當前目錄;在O=xx編譯下,OBJTREE就等於我們設置的那個輸出目錄。
SRCTREE: 源碼目錄,其實就是源代碼的根目錄,也就是當前目錄。

總結:在默認編譯下,OBJTREE和SRCTREE相等;在O=xx這種編譯下OBJTREE和SRCTREE不相等。Makefile中定義這兩個變量,其實就是爲了記錄編譯後的.o文件往哪裏放,就是爲了實現O=xx的這種編譯方式的。

給config.mk傳參(130-133)

在這裏插入圖片描述
include/config.mk不是源碼自帶的(你在沒有編譯過的源碼目錄下是找不到這個文件的),要在配置過程(make x210_sd_config)中才會生成這個文件。因此這個文件的值和我們配置過程有關,是由配置過程根據我們的配置自動生成的。

通過linux進入到config.mk文件中:
在這裏插入圖片描述
通過134行導出了這5個變量作爲環境變量,這裏的配置值來自於2589行那裏的配置項。如果我們要更改這裏的某個配置值要到2589行那裏調用MKCONFIG腳本傳參時的參數。

交叉編譯工具鏈(136-182)

在這裏插入圖片描述
ARCH環境變量是定義當前編譯的目標CPU的架構。
CROSS_COMPILE是定義交叉編譯工具鏈的前綴的。定義這些前綴是爲了在後面用(用前綴加上後綴來定義編譯過程中用到的各種工具鏈中的工具)。我們把前綴和後綴分開還有一個原因就是:在不同CPU架構上的交叉編譯工具鏈,只是前綴不一樣,後綴都是一樣的。實現可移植性

實際運用時,我們可以在Makefile中去更改設置CROSS_COMPILE的值,也可以在編譯時用make CROSS_COMPILE=xxxx來設置,而且編譯時傳參的方法可以覆蓋Makefile裏面的設置。

config.mk文件解析(185)

(1)首先該文件完成了對交叉編譯工具鏈的補全(94-107)
在這裏插入圖片描述
(2)生成開發板配置項autoconfig.mk (112)
在這裏插入圖片描述
autoconfig.mk文件不是源碼提供的,是配置過程自動生成的。
這個文件的作用就是用來指導整個uboot的編譯過程。這個文件的內容其實就是很多CONFIG_開頭的宏(可以理解爲變量),這些宏/變量會影響我們uboot編譯過程的走向(原理就是條件編譯)。在uboot代碼中有很多地方使用條件編譯進行編寫,這個條件編譯是用來實現可移植性的。(可以說uboot的源代碼在很大程度來說是拼湊起來的,同一個代碼包含了各種不同開發板的適用代碼,用條件編譯進行區別。)
在這裏插入圖片描述
這個文件不是憑空產生的,配置過程也是需要原材料來產生這個文件的。原材料在源碼目錄的inlcude/configs/xxx.h頭文件。(X210開發板中爲include/configs/x210_sd.h)。這個h頭文件裏面全都是宏定義,這些宏定義就是我們對當前開發板的移植每一個開發板的移植都對應這個目錄下的一個頭文件,這個頭文件裏每一個宏定義都很重要,這些配置的宏定義就是我們移植uboot的關鍵所在。

(3)包含各種配置文件,在對應的路徑下查找。(114-130)
在這裏插入圖片描述
例如此時ARCH=arm,所以要去根目錄下找arm_config.mk。其他同理。

(4)添加鏈接腳本文件(142-149)
在這裏插入圖片描述
(5)指定鏈接地址TEXT_BASE(156-158)
在這裏插入圖片描述
Makefile中在配置X210開發板時,在board/samsung/x210目錄下生成了一個文件config.mk,其中的內容就是:TEXT_BASE = 0xc3e00000相當於定義了一個變量。
TEXT_BASE是將來我們整個uboot鏈接時指定的鏈接地址。因爲uboot中啓用了虛擬地址映射,因此這個C3E00000地址就等於0x23E00000(也可能是33E00000具體地址要取決於uboot中做的虛擬地址映射關係)。

(6)自動推導規則(239-256)
在這裏插入圖片描述

添加編譯的目標文件和各種庫(190-289)

所有的編譯目標文件都被+=添加到obj中,所有的庫文件都被+=添加到lib中。

Makefile中第一個目標all(291)

在這裏插入圖片描述
291行出現了整個主Makefile中第一個目標all(也就是默認目標,我們直接在uboot根目錄下make其實就等於make all,就等於make這個目標)。

各種目標和依賴(291-最後)

其中有幾個是比較重要的:
u-boot是最終編譯鏈接生成的elf格式的可執行文件。
在這裏插入圖片描述
unconfig字面意思來理解就是未配置。這個符號用來做爲我們各個開發板配置目標的依賴。目標是當我們已經配置過一個開發板後再次去配置時還可以配置。
在這裏插入圖片描述
我們配置開發板時使用:make x210_sd_config,因此分析x210_sd_config肯定是主Makefile中的一個目標。
在這裏插入圖片描述
這裏的MKCONFIG變量其實就是根目錄下的mkconfig腳本,然後後面是將5個參數傳進去。

二、mkconfig配置代碼分析

第一章講到了Makefile的編譯過程以及一些重要內容的分析。在Makefile最後有一個目標名爲x210_sd_config,當我們在執行make x210_sd_config時完成了對uboot的配置,因此我們詳細分析其中對應的mkconfig腳本的配置過程。
在這裏插入圖片描述

傳參

$(@:_config=):x210_sd_config裏的_config部分用空替換,得到:x210_sd,這就是第一個參數。
所以在給mkconfig進行傳參時的參數分配爲:
$1: x210_sd
$2: arm
$3: s5pc11x
$4: x210
$5: samsumg
$6: s5pc110

所以,$# = 6

賦值BORAD_NAME(23-28)

在這裏插入圖片描述
25行和26行的意思是,mkconfig腳本傳參只能是4、5、6,如果大於6或者小於4都不行。
通過28行可以打印出我們在進行配置時的那句話:Configuring for x210_sd board…

創建符號鏈接(33-118)

這些符號鏈接文件的存在就是整個配置過程的核心,這些符號鏈接文件(文件夾)的主要作用是給頭文件包含等過程提供指向性連接。根本目的是讓uboot具有可移植性。
uboot可移植性的實現原理: 在uboot中有很多彼此平行的代碼,各自屬於各自不同的架構/CPU/開發板,我們在具體到一個開發板的編譯時用符號連接的方式提供一個具體的名字的文件夾供編譯時使用。這樣就可以在配置的過程中通過不同的配置使用不同的文件,就可以正確的包含正確的文件。
(1)在include目錄下創建asm文件,指向asm-arm。
在這裏插入圖片描述
(2)在inlcude/asm-arm下創建一個arch文件,指向include/asm-arm/arch-s5pc110
在這裏插入圖片描述

(3)在include目錄下創建regs.h文件,指向include/s5pc110.h
在inlcude/asm-arm下創建一個arch文件,指向include/asm-arm/arch-s5pc11x在這裏插入圖片描述
(4)在include/asm-arm下創建一個proc文件,指向include/asm-arm/proc-armv
在這裏插入圖片描述

創建config.mk文件(123-129)

這裏創建的config.mk文件對應Makeflie中的第133行的config.mk文件。
在這裏插入圖片描述

追加頭文件(134-141)

在這裏插入圖片描述
這個文件裏面的內容就一行==#include <configs/x210_sd.h>==,這個頭文件是我們移植x210開發板時,對開發板的宏定義配置文件。這個文件是我們移植x210時最主要的文件。
x210_sd.h文件會被用來生成一個autoconfig.mk文件,這個文件會被主Makefile引入,指導整個編譯過程。這裏面的這些宏定義會影響我們對uboot中大部分.c文件中一些條件編譯的選擇。從而實現最終的可移植性。

三、鏈接腳本代碼分析

在config.mk中的第142-149行添加了鏈接腳本文件,下面對該u-boot.lds文件進行分析:
在這裏插入圖片描述
ENTRY(_start) 用來指定整個程序的入口地址。所謂入口地址就是整個程序的開頭地址,可以認爲就是整個程序的第一句指令。有點像C語言中的main。
. = ALIGN(4): 四字節對齊。

在這裏插入圖片描述
鏈接腳本中除了.text .data .rodata .bss段等編譯工具自帶的段之外,編譯工具還允許我們自定義段。譬如uboot總的.u_boot_cmd段就是自定義段。自定義段很重要。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章