uboot移植之前期准备篇1
uboot移植之init_sequence_f函数数组分析(番外篇)
uboot移植之源码流程分析篇3(超详细!)
uboot移植之修改支持SDRAM篇4
uboot移植之修改支持NorFlash篇5
uboot移植之修改支持NandFlash识别篇6(超详细)
分析uboot,先要分析顶层Makefile,熟悉整体的编译流程。
smdk2410_config是Makefile文件中定义的目标之一。当执行make smdk2410_config,会按顺序读取匹配Makefile中的规则,并找到对应的目标,根据其依赖关系,决定哪些目标需要更新,根据规则链不断地重复这个过程,直到找到最原始的依赖关系,并最终生成.config配置文件,供顶层Makefile读取。
定位目标:
% 符号为通配符,%config表明所有以 config 结尾的目标,其依赖于scripts_basic outputmakefile FORCE三者。但是,该规则置于ifeq中,需分析config-targets变量,发现于
make 的环境变量叫“MAKECMDGOALS”,这个变量中会存放你所指定的终极目标的列表,如果在命令行上,你没有指定目标,那么,这个变量是空值。比如make smdk2410_config,那个MAKECMDGOALS的值等于smdk2410_config。
$(filter $(no-dot-config-targets), $(MAKECMDGOALS))表示调用Makefile的filter函数,过滤掉 $(MAKECMDGOALS)中所有不符合$(no-dot-config-targets)模式的单词。比如 $(filter %.c %.s, foo.c bar.c bax.s uar.h),结果为 bax.s uar.h。而filter-out函数的作用则刚好相反,去除所有符合的单词。
执行ifneq后,过滤后为空,空==空,所以ifneq分支不执行。dot-config还等于1,查找 KBUILD_EXTMOD 变量定义位置
由注释可知,由于我们make时并没有传入参数指定路径,所以,SUBDIRS变量为空;$(origin M):origin 函数通过返回一个字符串来告诉你 M 变量的定义情况。(file:在Makefile中定义;command line:在命令行中定义;undefined:从来没有定义....)不过,我们并没有以 make M=dir 的方式编译,所以此处ifeq也不执行。KBUILD_EXTMOD变量为空。
所以440行的条件判断成立,$(filter config %config,$(MAKECMDGOALS))结果还是smdk2410_config,不为空,config-targets := 1,至此,已经确定466行分支条件成立。(words函数返回值是$(MAKECMDGOALS)变量的单词数目,所以,不执行ifneq)
在478行,Q = @ MAKE=make 。@就是控制命令的输出流信息,比如:
A:=abc @echo $(A) 输出结果:abc
A:=abc echo $(A) 输出结果:echo abc abc
编译的时候可以通过输入参数V=1决定,详情:https://blog.csdn.net/qwaszx523/article/details/53218014
编译的时候定义了很多默认变量,MAKE变量的定义可以通过命令查看:
至于build变量,在当前Makefile中并没有找到其定义,何不妨搜索一下,看看是否包含在其他头文件中?
后面的不用看,撑死了最大范围也就当前行(478),到include scripts/Kbuild.include找,果真发现
build := -f $(srctree)/scripts/Makefile.build obj
所以make smdk2410_config最终要478行,即:
make -f ./scripts/Makefile.build obj=scripts/kconfig smdk2410_config
但是该目标依赖于scripts_basic outputmakefile FORCE三者,后两者为空,scripts_basic目标依赖于:
将其展开即为:
make -f ./scripts/Makefile.build obj=scripts/basic
rm -f .tmp_quiet_recordmcount
在bash中输入编译命令,校验分析结果:
当我们make但并没有指定生成目标的时候,那么默认是生成_all,从头往下找,发现_all被定义为伪目标:
129 # That's our default target when none is given on the command line
130 PHONY := _all
131 _all:
伪目标又称为假象目标,仅仅是一个标签,并不会在编译的过程中产生目标文件,而且伪目标一般没有依赖文件,所以目标被认为是最新的。但是,也可以为伪目标指定所依赖的对象。比如:
all: first second third
.PHONY: all
first: XXX
second: XXX
third: XXX
上述的all目标依赖于first second third,由于伪目标的特性是总会被执行的,所以其依赖的三个目标就总是不如all这个目标新,每次都会检查依赖的目标是否最新。
195 # If building an external module we do not care about the all: rule
196 # but instead _all depend on modules
197 PHONY += all
198 ifeq ($(KBUILD_EXTMOD),)
199 _all: all
200 else
201 _all: modules
202 endif
由1分析我们已经可以知道,$(KBUILD_EXTMOD)为空,所以伪目标 _all 依赖于 all ,而all又依赖于$(ALL-y)。
804 all: $(ALL-y)
所以,最终统揽全文件的重任就落到$(ALL-y)手上了,根据ALL-$(valiable)决定对应的文件是否编译进终极文件。
还有把各种库文件打包,比如驱动,设备树,net等等
最后,把所有生成的目标文件链接在一起,连接过程如下:
直接执行make V=1命令,在最后的输出信息很容易找到其详细链接过程:
两个横框之间的就是组成输出-o uboot 的原材料,也就是各种的obj文件。通过链接脚本u-boot.lds和链接地址 -Ttext 0x0 可以知道u-boot代码的组织排放,也就是各种段,还有文件先后的排放次序。
也就是说,后面的text段,data段等等,都放在(当前地址 .=0x0 + 链接地址-Ttext 0x0的位置) 0x0 ,因为 . =0x0这只是个代码地址偏移值,真正的起始地址是由编译时指定的。
最开始排放的是代码段中的*(.__image_copy_start) ,*(.vectors)以及arch/arm/cpu/arm920t/start.o (.text*)。
通常,在调用代码重定位的时候,就是要把__image_copy_start到__image_copy_end之间的数据进行拷贝,放到链接地址,关于链接地址本篇暂不讨论。而*(.vectors)存放的是中断向量表。
很明显,要想分析启动流程,应从arch/arm/cpu/arm920t/start.o入手,也就是该目录下的start.s汇编源码。
请戳链接:uboot移植之源码流程分析篇3
水平有限,草草分析,很多地方都没有深入去探究,有什么分析的不恰当,还望告知。
关于make过程更详尽的分析请看:https://blog.csdn.net/q_z_r_s/article/details/80719298
参考资料:
《ARM9嵌入式系统设计与应用开发》 熊茂华 杨震伦 主编
《嵌入式Linux应用开发完全手册》 韦东山著