Linux-Android启动之zImage生成过程详解
可以看到,在顶层makefile的第278行,包含了scripts/Kbuild.include文件,在这里定义了大量的函数和变量,供顶层makefile和其他makefile文件使用。
在顶层makefile文件的第412行,包含了arch/arm/Makefile。这个是体系结构相关makefile文件。它定义了体系结构相关的一些变量及规则。
当执行”make”时,arch/arm/Makefile中的185行的规则将是make遇到的第一个规则:
all: $(KBUILD_IMAGE)
KBUILD_IMAGE这个变量是arch/arm/Makefile的第182行定义。
KBUILD_IMAGE := zImage
然后看zImage的构建规则,在arch/arm/Makefile的第212行开始定义
zImage Image xipImage bootpImage uImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
build变量在scripts/Kbuild.include文件中第114行定义:
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
boot变量在arch/arm/Makefile的187行定义:
boot := arch/arm/boot
MACHINE变量的值在arch/arm/Makefile的147行开始定义
ifneq ($(machine-y),)
MACHINE := arch/arm/mach-$(machine-y)/
else
MACHINE :=
endif
这里machine-y := s3c2410,所以变量MACHINE的值为
MACHINE := arch/arm/mach-s3c2410
所以上面的规则可写为如下形势
zImage: vmlinux
$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj= /
arch/arm/boot MACHINE= arch/arm/mach-s3c2410 arch/arm/boot/ zImage
这个规则的依赖是vmlinux,下面先看看这个依赖目标的创建规则。
vmlinux目标的规则在顶层Makefile的第738行定义。
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
$(call if_changed_rule,vmlinux__)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
$(Q)rm -f .old_version
这里涉及到几个变量,先看看这几个变量的定义,前三个变量分别在605、602、603行定义。
vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
其中head-y在arch/arm/Makefile中第89行定义,
head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
init-y在顶层makefile的433行定义
init-y := init/
后又在第567行进行处理
init-y := $(patsubst %/, %/built-in.o, $(init-y))
所以变量init-y应为
init-y := init/built-in.o
因此
vmlinux-init := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o init/built-in.o
同理,其他几个变量也可通过类似方法进行分析,这里不一一分析了。vmlinux-init这个变量的构建规则在748行定义:
$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
这里是一个空命令的规则。空命令行可以防止make在执行时试图为重建这个目标去查找隐含命令。其依赖为vmlinux-dirs,这个变量在顶层Makefile第558行定义:
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) /
$(core-y) $(core-m) $(drivers-y) $(drivers-m) /
$(net-y) $(net-m) $(libs-y) $(libs-m)))
这个变量指定了一系列要进入的下层目录。他的规则在顶层Makefile第757行定义
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
这里的两个依赖就不分析了,主要看一下这个规则的命令,build和$@变量展开后如下
$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build /
obj =$(vmlinux-dirs)
这里会再一次进入scripts/Makefile.build执行83行规则
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) /
$(if $(KBUILD_MODULES),$(obj-m)) /
$(subdir-ym) $(always)
@:
因为KBUILD_BUILTIN在顶层Makefile中被初始化为1,所以这个规则的依赖有一个builtin-target变量。这个变量在scripts/Makefile.build的78行定义
ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
变量obj就是vmlinux-dirs变量指定的目录。所以这里会构建$(vmlinux-dirs)/built-in.o目标,在scripts/Makefile.build文件的261行开始,有这个目标的规则及命令的定义
ifdef builtin-target
quiet_cmd_link_o_target = LD $@
# If the list of objects to link is empty, just create an empty built-in.o
cmd_link_o_target = $(if $(strip $(obj-y)),/
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^),/
rm -f $@; $(AR) rcs $@)
$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target),
scripts/Makefile.build在第16行开始包含了vmlinux-dirs变量指定目录中的Makefile文件,在这些makefile文件中会指定obj-y变量,它指定的都是一些*.o目标文件,
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
这些*.o文件的生成方法由scripts/Makefile.build文件202行的模式规则指定
%.o: %.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
通过上面这一系列的步骤,就编译链接出由变量vmlinux-init指定的目标,vmlinux-main变量指定的目标的构建与此类似。再看看vmlinux的构建规则
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
$(call if_changed_rule,vmlinux__)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
$(Q)rm -f .old_version
现在vmlinux的依赖都处理好了,开始执行这个规则的命令,命令
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
是进行头文件的相关检测,这里不作详细分析。看第二条命令
$(call if_changed_rule,vmlinux__)
这里通过函数调用,执行rule_vmlinux__,在顶层Makefile第636行开始定义
define rule_vmlinux__
:
$(if $(CONFIG_KALLSYMS),,+$(call cmd,vmlinux_version))
$(call cmd,vmlinux__)
$(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
$(Q)$(if $($(quiet)cmd_sysmap), /
echo ' $($(quiet)cmd_sysmap) System.map' &&) /
$(cmd_sysmap) $@ System.map; /
if [ $$? -ne 0 ]; then /
rm -f $@; /
/bin/false; /
fi;
$(verify_kallsyms)
endef
这里主要还是调用cmd_vmlinux__,定义在顶层Makefile的610行
cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ /
-T $(vmlinux-lds) $(vmlinux-init) /
--start-group $(vmlinux-main) --end-group /
$(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
通过这个命令将变量vmlinux-init和vmlinux-main指定的目标链接成vmlinux文件。链接脚本由vmlinux-lds指定。在顶层 Makefile 605行定义:
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
现在再看一下zImage的构建规则
zImage: vmlinux
$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj= /
arch/arm/boot MACHINE= arch/arm/mach-s3c2410 arch/arm/boot/ zImage
其依赖vmlinux已经构建完成,它的命令同样是执行scripts/Makefile.build文件,它的开头包含了arch/arm/boot/Makefile文件,在这个文件的第56行开始就是arch/arm/boot/zImage的构建规则:
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
变量obj的值就是arch/arm/boot,前面已经分析过。其依赖 $(obj)/compressed/vmlinux的构建规则在arch/arm/boot/Makefile的53行开始定义的
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
这个规则的依赖$(obj)/Image的构建规则在arch/arm/boot/Makefile的49行开始定义:
$(obj)/Image: vmlinux FORCE
$(call if_changed, objcopy)
@echo ' Kernel: $@ is ready'
在这个规则中,将前面创建的vmlinux文件通过二进制工具objcopy进行处理,在scripts/Makefile.build的第19行包含了scripts/Makefile.lib
include scripts/Makefile.lib
在这个makefile文件中,有cmd_objcopy的定义,在156行开始定义
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
变量OBJCOPY在顶层Makefile中289行定义:
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPYFLAGS变量在arch/arm/Makefile中第15行定义
OBJCOPYFLAGS :=-O binary -R .note -R .comment –S
所以命令cmd_objcopy可扩展为
cmd_objcopy = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment –S $< $@
这就是处理vmlinux的命令。然后看看规则
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
的命令行,变量扩展后为:
$(Q)$(MAKE) -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj= /
$(obj)/compressed $(obj)/compressed/vmlinux
于是在scripts/Makefile的开头会包含arch/arm/boot/compressed/Makefile文件,并执行其中的$(obj) /vmlinux目标所在的规则,在这个Makefile文件的第98行开始定义:
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o /
$(addprefix $(obj)/, $(OBJS)) FORCE
$(call if_changed,ld)
@:
这里先看$(obj)/piggy.o,在arch/arm/boot/compreseed/Makefile的103行开始
$(obj)/piggy.gz: $(obj)/../Image FORCE
$(call if_changed,gzip)
$(obj)/piggy.o: $(obj)/piggy.gz FORCE
这两个规则的第一个就是把由vmlinux生成的Image进行压缩生成piggy.gz,然后生成piggy.o
cmd_ld命令在scripts/Makefile.lib文件149行定义:
quiet_cmd_ld = LD $@
cmd_ld = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$(@F)) /
$(filter-out FORCE,$^) -o $@
这里根据链接脚本arch/arm/boot/compressed/vmlinux.lds链接生成了arch/arm/boot/compressed/vmlinux文件。然后在arch/arm/boot/Makefile的第56行的规则中
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
经过objcopy处理后便生成的最终的zImage 。
下面看一下顶层Makefile生成的vmlinux以及arch/arm/boot/compressed/makefile生成的vmlinux的起始地址。
通过顶层Makefile中的规则生成vmlinux是根据arch/arm/kernel/vmlinux.lds这个脚本链接生成的。arch/arm/kernel/vmlinux.lds是由arch/arm/kernel/vmlinux.lds.S生成的,其生成规则在scripts/Makefile.build的第246行开始定义
quiet_cmd_cpp_lds_S = LDS $@
cmd_cpp_lds_S = $(CPP) $(cpp_flags) -D__ASSEMBLY__ -o $@ $<
%.lds: %.lds.S FORCE
$(call if_changed_dep,cpp_lds_S)
在arch/arm/kernel/vmlinux.lds.S的开始处有
#ifdef CONFIG_XIP_KERNEL
. = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
#else
. = PAGE_OFFSET + TEXT_OFFSET;
#endif
我们这里的起始地址就是PAGE_OFFSET + TEXT_OFFSET。
在include/asm-arm/memory.h的49行开始有
#ifndef PAGE_OFFSET
#define PAGE_OFFSET UL(0xc0000000)
#endif
而arch/arm/kernel/vmlinux.lds.S的开头有
#include <asm/memory.h>
asm是一个符号,链接到asm-arm上的
在arch/arm/Makefile第140行,有
TEXT_OFFSET := $(textofs-y)
第90行有
textofs-y := 0x00008000
所以TEXT_OFFSET := 0x00008000
在153行有export TEXT_OFFSET将此变量输出。这样arch/arm/kernel/vmlinux.lds.S也就获得了PAGE_OFFSET + TEXT_OFFSET的值。
现在看看arch/arm/boot/compressed/makeflie生成的vmlinux。它是根据arch/arm/boot/compressed/vmlinux.lds链接脚本生成的。这个脚本由arch/arm/boot/compressed/vmlinux.lds.in生成,在这个文件的开始处有
. = TEXT_START;
现在看arch/arm/boot/compressed/Makefile,在110行有
$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config
@sed "$(SEDFLAGS)" < $ $@
这就是由vmlinux.lds.in生成vmlinux.lds的规则,在它的命令中有个变量SEDFLAGS,在74行定义
SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
这里就把TEXT_START换成了ZTEXTADDR。再往上看从66行起
ifeq ($(CONFIG_ZBOOT_ROM),y)
ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT)
ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS)
else
ZTEXTADDR := 0
ZBSSADDR := ALIGN(4)
endif
如果zImage是从ram中启动ZTEXTADDR := 0,否则从rom或flash启动时ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT),这里要在配置时设定CONFIG_ZBOOT_ROM_TEXT的值。
到这里,关于zImage的生成过程算是可以结束了。
Linux-Android启动之zImage生成过程详解相关推荐
- Linux_arm_启动_c语言部分详解,[原创]Linux arm 启动 c语言部分详解第四讲
Linux arm启动c语言部分详解第四讲(from setup_per_cpu_areas();) Written by leeming 上面的setup_arch花了我们大量的篇幅,现在我们要继续 ...
- [PXE] Linux(centos6)中PXE 服务器搭建,PXE安装、启动及PXE理论详解
本篇blog主要讲述了[PXE] linux(centos)PXE无盘服务器搭建,安装,启动及pxe协议详解 , Kickstart (PXE+DHCP+TFTP+HTTP). PXE环境概述 作为中 ...
- centos终止linux程序,CentOS启动和停止服务详解
CAMS 在安装过程中, 1. 添加服务 添加服务的步骤为: (1) 将该服务的脚本文件拷入/etc/rc.d/init.d 文件夹下,例如: service camsd stop 停止 camsd ...
- 《Android Studio应用开发实战详解》——第1章,第1.4节Android和Linux的关系
本节书摘来自异步社区<Android Studio应用开发实战详解>一书中的第1章,第1.4节Android和Linux的关系,作者 王翠萍,更多章节内容可以访问云栖社区"异步社 ...
- python调用adb shell命令_Python之使用adb shell命令启动应用的方法详解
Python之使用adb shell命令启动应用的方法详解 一直有一个心愿希望可以用Python做安卓自动化功能测试,在一步步摸索中,之前是用monkeyrunner,但是发现对于控件ID的使用非常具 ...
- Android签名与校验过程详解
原文:https://blog.csdn.net/gulinxieying/article/details/78677487 目 录 一.签名与校验原理概要 2 1.数字签名简介 2 2. ...
- Android网络开发技术实战详解
<Android网络开发技术实战详解> 基本信息 作者: 朱桂英 丛书名: Android移动开发技术丛书 出版社:电子工业出版社 ISBN:9787121173493 上架时间:2012 ...
- libraries 和android runtime之间的关系,《Android Studio应用开发实战详解》——第1章,第1.3节Android系统架构...
本节书摘来自异步社区<Android Studio应用开发实战详解>一书中的第1章,第1.3节Android系统架构,作者 王翠萍,更多章节内容可以访问云栖社区"异步社区&quo ...
- 《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——1.3节搭建Android应用开发环境...
本节书摘来自异步社区<Android多媒体应用开发实战详解:图像.音频.视频.2D和3D>一书中的第1章,第1.3节搭建Android应用开发环境,作者 王石磊 , 吴峥,更多章节内容可以 ...
最新文章
- arrays must all be same length
- 添加类iOS cocos2d 2游戏开发实战(第3版)
- js中三元运算符的两种情况
- final阶段团队贡献分分配
- 百度提前批-百度智能小程序(面经详解)
- 如何判断 .NET Core 应用程序是以管理员身份运行
- socket 端口和地址复用
- 从键盘中读取字符流 自定义异常
- 数据库SQL Server2012笔记(八)——Statement与PreparedStatement的区别,JDBC方式操作数据库...
- tcp服务端无故死掉了linux,TCP服务端socket会丢连接的诡异问题及思考
- TinyWeb--C++构建高性能Web服务器
- delphi2007、2010无法二次启动,报错 EditorLineEnds.ttr 另一个程序正在使用此文件
- 2022年电子商务概论(农)之形考作业二
- Netty4 学习笔记之三:粘包和拆包
- linux 系统挂载ISO 文件
- navicat连接阿里云数据库
- 计算机是如何存储矩阵,如何存储稀疏邻接矩阵(How to store sparse adjacency matrix)
- js 校验手机号码格式
- Android 简单直接--无需jar包zing实现生成、扫描二维码
- c语言程序设计创新大作业,C语言程序设计大作业报告.pdf
热门文章
- Linux 下搭建 php 开发环境完整教程
- 浏览器兼容性问题解决方案· 总结
- 小知识:常用开源协议详细解析
- c语言删除一行程序代码,删除C语言程序中所有的注释语句的实现代码
- H - 拦截导弹 OpenJ_Bailian - 2945(dp动态规划)
- c# 线向量生成多边形_python脚本实现abaqus前处理2D多晶粒建模(附完整源码)-Voronoi多边形的生成...
- java socket编写服务器_Java网络学习笔记1:用(Server)Socket编写简单的客户/服务器程序...
- 几个简单的排序方式1
- PAT_B_1017_Java(20分)
- csrf攻击 java_java使用jsp servlet来防止csrf 攻击的实现方法