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段就是自定义段。自定义段很重要。

发布了72 篇原创文章 · 获赞 98 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_42826337/article/details/105025383