zoukankan      html  css  js  c++  java
  • linux-2.6.22.6内核启动分析之Makefile文件

    学习目标

    分析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的依赖关系,代码如下:

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

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

    413 include $(srctree)/arch/$(ARCH)/Makefile                                    #来源于顶层Makefile中文件
    414 export KBUILD_DEFCONFIG
    ........
    185 #ARCH        ?= $(SUBARCH)
    186 ARCH        ?= arm
    187 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的依赖关系如下代码:

    745 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)变量代表的内容,并对变量所代表内容进行一一展开。

    608 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文件
    443 init-y := init/ #来源于顶层Makefile文件
    573 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

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

    437 libs-y := lib/ #来源于顶层Makefile文件
    577 libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) #来源于顶层Makefile文件
    578 libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y)) #来源于顶层Makefile文件
    579 libs-y := $(libs-y1) $(libs-y2) #来源于顶层Makefile文件

    435 drivers-y := drivers/ sound/ #来源于顶层Makefile文件
    575 drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) #来源于顶层Makefile文件

    436 net-y := net/ #来源于顶层Makefile文件
    576 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

    610 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依赖文件下执行的命令

    745 vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE           #顶层Makefile文件
    746 ifdef CONFIG_HEADERS_CHECK
    747     $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
    748 endif
    749    $(call if_changed_rule,vmlinux__)
    759    $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
    751    $(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将是分析入手点。

  • 相关阅读:
    052 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 14 Eclipse下程序调试——debug2 多断点调试程序
    051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试——debug入门1
    050 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 12 continue语句
    049 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 11 break语句
    048 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 10 案例——阶乘的累加和
    047 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 09 嵌套while循环应用
    046 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 08 for循环的注意事项
    045 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 07 for循环应用及局部变量作用范围
    剑指OFFER----面试题04.二维数组中的查找
    剑指OFFER----面试题03. 数组中重复的数字
  • 原文地址:https://www.cnblogs.com/053179hu/p/9279445.html
Copyright © 2011-2022 走看看