• 第3阶段——内核启动分析之make uImage编译内核(3)


    目标:

    通过分析makefile,明白make uImage如何编译内核

    把整个内核的makefile分成三类(makefile资料文档在linux-2.6.22.6/Documentation/build/makefiles.txt)

    <1>各级子目录makefile(每个子目录都有makefile)
    <2>/arch/arm/Makefile(架构相关的makefile)
    <3>顶层目录makefile

    在顶层目录makefile中auto.conf和/arch/arm/Makefile又被包含在其中,如下所示:

    413 include $(srctree)/arch/$(SRCARCH)/Makefile 

    443
    include include/config/auto.conf

    1.分析子目录makefile, 随便打开一个子目录makefile,可以看到类似的内容:

    obj-y  += mem.o random.o tty_io.o n_tty.o tty_ioctl.o
    
    obj-m    += s3c24xx_leds.o
    
    obj-m    += s3c24xx_buttons.o
    
    obj-m    += ker_rw.o
    
    obj-$(CONFIG_LEGACY_PTYS) += pty.o
    
    obj-$(CONFIG_UNIX98_PTYS) += pty.o

    makefile资料文档中得到(linux-2.6.22.6/Documentation/build/makefiles.txt)

    40 --- 3.2 Built-in object goals - obj-y            
    
    41~59 ....
    
    60 Example:
    
    61   #drivers/isdn/i4l/Makefile
    
    62   # Makefile for the kernel ISDN subsystem and device drivers.
    
    63   # Each configuration option enables a list of files.
    
    64   obj-$(CONFIG_ISDN)             += isdn.o
    
    65   obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

    从上面第40行得出要追加built-in.o文件(编译进内核)时,使用obj-y

    例如:     obj-y += isdn.o   

                 obj-y+= isdn_bsdcomp.o

    167 --- 3.3 Loadable module goals - obj-m
    
    168~188 ...
    
    189 Example:
    
    190  #drivers/isdn/i4l/Makefile
    
    191  obj-$(CONFIG_ISDN) += isdn.o
    
    192  isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o

    从上面第167行得出加载模块.ok文件时,使用obj-m

    例如: obj-m += isdn.o

             isdn-objs: = isdn_net_lib.o isdn_v110.o isdn_common.o

    最后编译成isdn.ko模块文件

    所以

    在配置文件auto.conf中CONFIG_XXX=y, 那么编译时,源码.o文件会被Makefile追加到built-in.o文件,供给顶层Makefile生成内核
    在配置文件auto.conf中CONFIG_XXX=m,那么编译时, 源码.o文件会被Makefile编译成模块XXX.ko文件;
    在配置文件auto.conf中CONFIG_XXX=n, 那么编译时,对应的源码文件不会被makefile编译;

    2分析./arch/arm/MakefileARM架构makefile)

    首先在./arch/arm/Makefile文件第227行得到:

    227 zImage Image xipImage bootpImage uImage: vmlinux
    
    228       $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

     得出uImage5个目标的生成都是依赖于vmlinux(vmlinux位于顶层makefile,其中vmlinux 指未压缩的内核,不能直接加载)

    由于,我们在顶层目录下执行make uImage,但是uImage在./arch/arm/Makefile,

    在顶层makefile中第413行可以看到:

    413 include $(srctree)/arch/$(SRCARCH)/Makefile 

    由于打上补丁后, SRCARCH=arm

    所以这个./arch/arm/Makefile被顶层makefile包含,然后调用了./arch/arm/Makefile中的uImage

    分析顶层目录Makefile

    3.1 顶层vmlinux生成过程

    在顶层目录makefile中第484行得出:

    484 all: vmlinux

    其中,all就是直接 make 指令编译内核,显然make uImagemake都依赖于vmlinux(内核)

    然后在746得到出vmlinux生成步骤:

    746 vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE

    3.1.1 接下来分析顶层vmlinux依赖文件

    可以看出vmlinux依赖于:


    vmlinux-lds: 链接脚本
    vmlinux-init: 初始化相关的代码
    vmlinux-main:核心代码

    kallsyms.o  变量


    这些依赖在顶层Makefile中608行处定义:

    608 vmlinux-init := $(head-y) $(init-y)                        // head-y:头文件   init-y:初始化文件 
    
    609 vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y) // core-y:核心文件libs-y:库文件 drivers-y:驱动文件net-y:网络文件
    611 vmlinux-lds := arch/$(SRCARCH)/kernel/vmlinux.lds // arch/arm/kernel/vmlinux.lds链接脚本

    逐个分析:

    (1) vmlinux-lds  

    因为我们是使用的arm架构,$(SRCARCH) = arm

    因此   vmlinux-lds  :=arch/arm/kernel/vmlinux.lds

    首先查看arch/arm/kernel/vmlinux.lds文件

    如下所示,在288行处设置了内核运行在虚拟地址0Xc0008000处,接下来按顺序存放vmlinux的依赖文件

    SECTIONS
    
    {
    
    . = (0xc0000000) + 0x00008000;          //设置内核运行地址
    
     .text.head : {                           
    
      _stext = .;
    
      _sinittext = .;
    
    *(.text.head)                     //存放.text.head段
    
    }
    
    .init : {
    *(.init.text)                    //存放.init.text段   
    
    ...   ...

    (2)  vmlinux-init
    head-y/arch/arm/makefile中94行处定义:

    94 head-y := arch/arm/kernel/head$(MMUEXT).o  arch/arm/kernel/init_task.o

    由于MMUEXT没有定义 ,所以变量head-y 应为  

    head-y := arch/arm/kernel/head.o     arch/arm/kernel/init_task.o

    init-y在顶层makefile中427行中定义

    427 init-y    := init/

    然后在532行中修改init-y

    532 init-y    := $(patsubst %/, %/built-in.o, $(init-y))

    这里的patsubst 是实现匹配替换的,在这里将$(init-y)  中的  / 替换为'/built-in.o' 。

    所以变量init-y 应为  

    init-y          := init/built-in.o

    因此  vmlinux-init := arch/arm/kernel/head.o   arch/arm/kernel/init_task.o    init/built-in.o

    (3) vmlinux-main

    core-y 在顶层Makefile中438行定义,在562行处追加,在574行处修改:

    438 core-y    := usr/
    
    562 core-y    += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
    
    574 core-y    := $(patsubst %/, %/built-in.o, $(core-y))   //将$(core-y)中的  的/ 替换为'/built-in.o' 。

    所以变量core-y 应为  

    core-y := usr/ built-in.o  kernel/ built-in.o  mm/ fs/ built-in.o  ipc/ built-in.o  security/ built-in.o  crypto/ built-in.o  block/ built-in.o

    libs-y 在顶层Makefile中437行定义,然后后面577行进行修改:

    437 libs-y    := lib/
    
    577 libs-y1    := $(patsubst %/, %/lib.a, $(libs-y))        // libs-y1:= lib/ lib.a
    
    578 libs-y2    := $(patsubst %/, %/built-in.o, $(libs-y))    // libs-y2:= lib/ built-in.o
    
    579 libs-y    := $(libs-y1) $(libs-y2)                  // libs-y:= lib/ lib.a   lib/ built-in.o

    所以变量libs-y 应为

    libs-y:= lib/ lib.a   lib/ built-in.o

    core-y 在顶层Makefile中435行定义,在574行处修改:

    435 drivers-y    := drivers/ sound/
    
    475 drivers-y    := $(patsubst %/, %/built-in.o, $(drivers-y)

    所以变量drivers-y 应为

    drivers-y  := drivers/ built-in.o   sound/ built-in.o     

    net-y 在顶层Makefile中436行定义,在575行处修改:

    436 net-y    := net/
    
    576 net-y    := $(patsubst %/, %/built-in.o, $(net-y))   

    所以变量net-y 应为

    net-y  := net/ built-in.o   

    因此   vmlinux-main := usr/ built-in.o  kernel/ built-in.o  mm/ 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的依赖文件分析完毕

    3.1.2 顶层vmlinux生成规则分析

    直接make uImage ,然后ctrl+z 暂停编译,从串口上分析

    (1)首先rm vmlinux 删除目标文件,再make uImage v=1   (V=1表示显示详细编译过程 ) 

    如上图主要通过arm-linux-ld连接选项,通过vmlinux.lds链接脚本对内存的地址设置,然后将 顶层vmlinux依赖文件分析出来的所有文件按一定顺序布局并输出vmlinux文件  arm-linux-ld使用参考:http://www.cnblogs.com/lifexy/p/7065175.html)

  • 相关阅读:
    RabbitMQ安装与配置
    在Web项目中使用shiro
    solr整合spring
    mycat
    SpringSession管理
    Nginx安装与配置(Nginx服务器和Tomcat服务器是不同的服务器)
    dubbo负载均衡与服务降级以及Zookeeper认证
    小笔记
    SpringMVC路径转发与重定向
    java-同步控制及不可变设置(只读访问)
  • 原文地址:https://www.cnblogs.com/lifexy/p/7348534.html
Copyright © 2020-2023  润新知