学习目标

分析Makefile文件,了解内核中的哪些文件被编译,如何被编译,连接时顺序如何确定!


Linux内核源码中包含很多的Makefile文件,这些Makefile文件又包含其它的一些文件,比如配置信息、通用规则等等。我们可以把内核中的Makefile文件分为5类,如下表所示:

顶层Makefile 所有Makefile文件的核心,从总体控制内核的编译、连接
.config

配置文件,在执行配置命令时生成。所有Makefile文件都根据.config来决定如何使用哪些文件

arch/$(ARCH)/Makefile 对应CPU体系结构的Makefile文件,用来决定那些体系结构相关的文件参与内核的生成,并提供一些规则来生成特定格式内核映象
kbuild Makefile 各级子目录下的Makefile,相对比较简单,被上一级Makefile调用来编译当前目录下的文件
script/Makefile.* Makefile共用规则和脚本

执行make uImage命令时内核最终被编译,所以要分析内核Makefile文件关系,把目标uImage作为分析的入手点最为合适。打开顶层Makefile文件,在顶层Makefile文件中查找目标uImage的依赖关系,结果发现在顶层Makefile文件中不能直接找到目标uImage的依赖。虽然在顶层Makefile文件中没有直接找到目标uImage的依赖关系,但我们执行make uImage命令时内核被编译,所以我们可以推测目标uImage肯定是在其它目录下的Makefile中定义,并且这个目录下的Makefile文件被顶层的Makefile文件所包含。查找其它目录下的Makefile文件,最终在arch/arm目录下Makefile文件中找到目标uImage的依赖关系,代码如下:

 zImage Image xipImage bootpImage uImage: vmlinux                            #来源于arch/arm目录下的Makefile文件
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

为了验证上面推测是否正确,我们在顶层Makefile中搜索"include"字符,找到顶层Makefile中所有包含文件。通过筛选后找到下面所示代码:

 include $(srctree)/arch/$(ARCH)/Makefile                                    #来源于顶层Makefile中文件
export KBUILD_DEFCONFIG
........
#ARCH ?= $(SUBARCH)
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-

上述代码$(srctree)=源码根目录、$(ARCH)=arminclude $(srctree)/arch/$(ARCH)/Makefile就表示顶层Makefile包含arch/arm目录下Makefile,由此可见前面我们的推测是正确的。


从上面227行代码中可以发现,目标uImage依赖于vmlinux。uImage文件有两部分组成,头部和真正内核部分,要获得uImage文件必须先编译出内核,也就是先生成vmlinux文件,最后根据vmlinux文件生成uImage文件。下面我们还要找出vmlinux的依赖关系,在顶层Makefile中找到vmlinux的依赖关系如下代码:

 vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE                             #来源于顶层的Makefile

可以看出vmlinux生成依赖于$(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o),因此为了进一步分析,我们要分别找出$(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o)变量代表的内容,并对变量所代表内容进行一一展开。

 vmlinux-init := $(head-y) $(init-y)                                           #来源于顶层Makefile文件
94 head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o #来源于arch/arm目录下的Makefile文件
init-y := init/ #来源于顶层Makefile文件
init-y := $(patsubst %/, %/built-in.o, $(init-y)) #来源于顶层Makefile文件

第94行$(MMUEXT)内容为空,head$(MMUEXT).o就是head.o, head-y := arch/arm/kernel/head.o arch/arm/kernel/init_task.o

第573行$(patsubst <pattern>,<replacement>,<text> ) 是一个Makefile函数,查找<text>中的单词是否符合模式<pattern>,如果匹配的话,则以<replacement>替换。这里,<pattern>可以包括通配符“%”,表示任意长度的字串。如果<replacement>中也包含“%”,那么,<replacement>中的这个“%”将是<pattern>中的那个“%”所代表的字串。init-y :=init/built-in.o

第608行将$(head-y) $(init-y)用94行和573行分析结果替换,可以得到vmlinux-init :=arch/arm/kernel/head.o arch/arm/kernel/init_task.o init/built-in.o

 vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)                     #来源于顶层Makefile文件
core-y := usr/ #来源于顶层Makefile文件
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ #来源于顶层Makefile文件
core-y := $(patsubst %/, %/built-in.o, $(core-y)) #来源于顶层Makefile文件 libs-y := lib/ #来源于顶层Makefile文件
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) #来源于顶层Makefile文件
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y)) #来源于顶层Makefile文件
libs-y := $(libs-y1) $(libs-y2) #来源于顶层Makefile文件 drivers-y := drivers/ sound/ #来源于顶层Makefile文件
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) #来源于顶层Makefile文件 net-y := net/ #来源于顶层Makefile文件
net-y := $(patsubst %/, %/built-in.o, $(net-y)) #来源于顶层Makefile文件

结合438行和562行,574行,第574行core-y := kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o

结合437行、577行和578行,第579行libs-y := lib/lib.a lib/built-in.o

结合435行,第575行drivers-y := drivers/built-in.o sound/built-in.o

结合436行,第576行net-y :=net/built-in.o

第609行将$(core-y) $(libs-y) $(drivers-y) $(net-y)用574行、579行、575行和576分析结果替换,可以得到vmlinux-main :=kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o lib/lib.a lib/built-in.o drivers/built-in.o sound/built-in.o net/built-in.o

 vmlinux-all  := $(vmlinux-init) $(vmlinux-main)

结合608行和609行分析结果,将610行$(vmlinux-init) $(vmlinux-main)替换,可以得到vmlinux-all :=arch/arm/kernel/head.o arch/arm/kernel/init_task.o init/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o lib/lib.a lib/built-in.o drivers/built-in.o sound/built-in.o net/built-in.o


以上介绍了构成内核的原材料,但它们怎样组合编译、连接成为内核,我们还要去看vmlinux依赖文件下执行的命令

 vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE           #顶层Makefile文件
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

我们可以通过分析上面命令得到编译过程以及生成的一些文件,但上面命令涉及很多函数、脚本,实在太过庞大,没有那么多精力去这样做。这时可以通过另一种方法直接编译内核,先通过rm vmlinux命令删去之前执行make uImage生成的vmlinux,再执行make uImage V=1查看更加详细编译过程,连接命令如下图所示:

图中vmlinux为连接输出结果,arch/arm/kernel/vmlinux.lds为连接脚本,后面的一些内容为连接的原材料,这些原材料和我们上面分析的原材料也基本一一对应。

总结:

1、顶层Makefile和arch/$(ARCH)/Makefile决定根目录下哪些子目录、arch/$(ARCH)目录下哪些文件和目录被编进内核,最后,各级子目录下的Makefile决定所在目录下哪些文件将被编进内核,哪些文件被编成模块,进入哪些子目录继续调用它们的Makefile。

2、通过分析得到了编译内核的连接脚本是arch/arm/kernel/vmlinux.lds,第一个文件是arch/arm/kernel/head.S,后续分析内核启动时,第一个文件arch/arm/kernel/head.S将是分析入手点。

linux-2.6.22.6内核启动分析之Makefile文件的更多相关文章

  1. linux-2.6.22.6内核启动分析之head.S引导段代码

    学习目标: 了解arch/arm/kernel/head.S作为内核启动的第一个文件所实现的功能! 前面通过对内核Makefile的分析,可以知道arch/arm/kernel/head.S是内核启动 ...

  2. linux-2.6.22.6内核启动分析之配置

    配置过程最终结果是生成.config文件,我们想要对配置的目的有很清楚的了解,必须先对.config文件进行分析.通过cd命令切换到linux-2.6.22.6内核目录,输入vi .config 可以 ...

  3. linux-2.6.22.6内核启动分析之编译体验

    1 解压缩.打补丁操作 1.1 打开ubuntu,通过FTP将windows相应文件夹下的linux-2.6.22.6.tar.bz2和补丁文件linux-2.6.22.6-jz2440.patch上 ...

  4. 第3阶段——内核启动分析之start_kernel初始化函数(5)

    内核启动分析之start_kernel初始化函数(init/main.c) stext函数启动内核后,就开始进入start_kernel初始化各个函数, 下面只是浅尝辄止的描述一下函数的功能,很多函数 ...

  5. mkimage工具 加载地址和入口地址 内核启动分析

    第三章第二节 mkimage工具制作Linux内核的压缩镜像文件,需要使用到mkimage工具.mkimage这个工具位于u-boot-2013. 04中的tools目录下,它可以用来制作不压缩或者压 ...

  6. Linux内核启动分析过程-《Linux内核分析》week3作业

    环境搭建 环境的搭建参考课件,主要就是编译内核源码和生成镜像 start_kernel 从start_kernel开始,才真正进入了Linux内核的启动过程.我们可以把start_kernel看做平时 ...

  7. Linux内核启动分析

    张超<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 我的代码可见https://www.shiyanlo ...

  8. linux内核启动分析(2)

    -----以下内容为从网络上整理所得------ 主要介绍kernel_init线程(函数),这个线程在rest_init函数中被创建,kernel_init函数将完成设备驱动程序的初始化,并调用in ...

  9. Linux内核启动分析笔记

    一.驱动加载 1.驱动加载调用关系 start_kernel //init/main.c rest_init //最后执行它 kernel_init //使用kernel_thread创建一个进程执行 ...

随机推荐

  1. linux 命令行模式下,浏览网页方法

    Ubuntu自带最新版的Gnome桌面,拥有大量的服务和桌面应用程序,让您仅通过一张安装光盘就可以体验到无比舒适的操作环境.下文介绍的在ubuntu下使用终端命令行上网的方法. 第一步,需要安装一个名 ...

  2. hibernate对象的三种状态及转换

    一.hibernate对象三种状态 Transient(瞬时状态):没有session管理,同时数据库没有对应记录 举例:new 出来的对象还没有被session管理,此时该对象处于Transient ...

  3. 排查在 Azure 中新建 Windows 虚拟机时遇到的经典部署问题

    尝试创建新的 Azure 虚拟机 (VM) 时,遇到的常见错误是预配失败或分配失败. 当由于准备步骤不当,或者在从门户捕获映像期间选择了错误的设置而导致 OS 映像无法加载时,将发生预配失败. 当群集 ...

  4. 自动化测试基础篇--Selenium unittest生成测试报告(HTMLTestRunner)

    如何生成HTMLTestRunner测试报告.接上篇文章,对于unittest框架,运行后,测试结果不便于查看,同时多个case存在的时候,可能会导致case result记录不正确的情况. 为此,引 ...

  5. Java学习---传输安全设计

    1.计算机安全的概念 用于保护数据和阻止Hacker的工具统称为计算机安全(Computer Security).信息安全最基本的方法就是利用加密信息防止未授权的人窃听,加密是以某种特殊的算法改变原有 ...

  6. cheerio数据抓取

    很多语言都能写个爬虫抓取数据,js自然也可以,使用cheerio可以支持css检索,较快捷的获取需要的数据.首先,先把node.js给安装了.可到官网下载.安装好node.js后,使用npm安装che ...

  7. MAC软件工具下载

    CRThttps://www.cnblogs.com/codegeekgao/p/8277015.html navicathttp://xclient.info/search/s/navicat/?t ...

  8. SQL进价2:三值逻辑和null

    1.SQL中的bool类型的值有三种 普通编程语言里的布尔型只有 true 和 false 两个值,这种逻辑体系被称为二值逻辑.而 SQL 语言里,除此之外还有第三个值 unknown,因此这种逻辑体 ...

  9. [19/04/13-星期六] 网络编程_基本概念(关注传输层、数据传输,TCP和UDP)

    一.概念 ▪ 什么是计算机网络? 计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统, 网络管理软件及网络通信协议的管理和协调下,实现资源共享和信 ...

  10. 8、Web Service-IDEA-jaxws规范下的 spring整合CXF

    前提:开发和之前eclipse的开发有很大的不同! 1.服务端的实现 1.新建项目 此时创建的是web项目 2.此时创建的项目是不完整的需要开发人员手动补充完整 3.对文件夹的设置(满满的软件使用方法 ...