目标:

通过分析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又被包含在其中,如下所示:

 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)

 --- 3.2 Built-in object goals - obj-y            

~ ....

 Example:

   #drivers/isdn/i4l/Makefile

   # Makefile for the kernel ISDN subsystem and device drivers.

   # Each configuration option enables a list of files.

   obj-$(CONFIG_ISDN)             += isdn.o

   obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

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

例如:     obj-y += isdn.o

obj-y+= isdn_bsdcomp.o

 --- 3.3 Loadable module goals - obj-m

~ ...

 Example:

  #drivers/isdn/i4l/Makefile

  obj-$(CONFIG_ISDN) += isdn.o

  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/Makefile(ARM架构makefile)

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

 zImage Image xipImage bootpImage uImage: vmlinux

       $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@

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

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

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

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

由于打上补丁后, SRCARCH=arm

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

3 分析顶层目录Makefile

3.1 顶层vmlinux生成过程

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

 all: vmlinux

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

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

 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行处定义:

 vmlinux-init := $(head-y) $(init-y)                        // head-y:头文件   init-y:初始化文件

vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y) // core-y:核心文件libs-y:库文件 drivers-y:驱动文件net-y:网络文件

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行处定义:

 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行中定义

 init-y    := init/

然后在532行中修改init-y

 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行处修改:

 core-y    := usr/

 core-y    += kernel/ mm/ fs/ ipc/ security/ crypto/ block/

 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行进行修改:

 libs-y    := lib/

 libs-y1    := $(patsubst %/, %/lib.a, $(libs-y))        // libs-y1:= lib/ lib.a

 libs-y2    := $(patsubst %/, %/built-in.o, $(libs-y))    // libs-y2:= lib/ built-in.o

 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行处修改:

 drivers-y    := drivers/ sound/

 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行处修改:

 net-y    := net/

 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)

第3阶段——内核启动分析之make uImage编译内核(3)的更多相关文章

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

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

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

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

  3. 第3阶段——内核启动分析之make menuconfig内核配置(2)

    目标: 分析make menuconfig内核配置过程 在上1小结中(内核编译试验)讲到了3种不同的配置: (1)通过make menuconfig 直接从头到尾配置.config文件 (2) 通过m ...

  4. 第3阶段——内核启动分析之prepare_namespace()如何挂载根文件系统和mtd分区介绍(6)

    内核启动并初始化后,最终目的是像Windows一样能启动应用程序,在windows中每个应用程序都存在C盘.D盘等,而linux中每个应用程序是存放在根文件系统里面,那么挂载根文件系统在哪里,怎么实现 ...

  5. 第3阶段——内核启动分析之创建si工程和分析stext启动内核函数(4)

    目标: (1)创建Source Insight 工程,方便后面分析如何启动内核的 (2)分析uboot传递参数,链接脚本如何进入stext的  (3) 分析stext函数如何启动内核:  (3.1) ...

  6. tms320dm6446内核启动分析

    关于达芬奇DM6446,里面内部有两个部分,一个是ARM926ejs的核,还有一个是C64+DSP的视频处理核,而我需要关心的重点是arm926ejs的核(bootload和linux内核) 从boo ...

  7. Linux内核及分析 第三周 Linux内核的启动过程

    实验过程: 打开shell终端,执行以下命令: cd LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage-initrd rootf ...

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

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

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

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

随机推荐

  1. git push解决办法: ! [remote rejected] master -> master (pre-receive hook declined)

    前天准备上传一个project到GitLab上,但是试了很多次都上传不上去,报错如下: ! [remote rejected] master -> master (pre-receive hoo ...

  2. 利用百度API(js),通过地址获取经纬度的注意事项

    网上给的很多答案都是这种: http://api.map.baidu.com/geocoder?address=地址&output=输出格式类型&key=用户密钥&city=城 ...

  3. Samba服务部署

    Samba,是种用来让UNIX系列的操作系统与微软Windows操作系统的SMB/CIFS(Server Message Block/Common Internet File System)网络协议做 ...

  4. kill 和killall----杀死进程

    1.根据进程ip查看进程名 Liunx中 通过进程名查找进程PID可以通过 pidof  [进程名] 来查找. 反过来 ,通过PID查找进程名则没有相关命令.但在linux根目录中,有一个/proc的 ...

  5. HTML+CSS+JS简介

    1.HTML与 CSS 1 1.1 HTML 1 1.2 HTML5 2 1.2.1 HTML5的特性 3 1.3  CSS 4 2.JavaScript 6 2.1特性 7 2.2编程 8 3.Sp ...

  6. pythonchallenge

    # _*_ coding:utf-8 _*_ translated = '' message = 'g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr ...

  7. Java框架概述

    一.框架的意义 1.什么是框架? 框架就是一些类和接口的集合,通过这些类和接口协调来完成一系列的程序实现.有了框架,我们就可以集中精力进行业务逻辑的开发而不用去关心它的技术实现以及一些辅助的业务逻辑. ...

  8. 读书笔记 之《Thinking in Java》(对象、集合)

    一.前言: 本来想看完书再整理下自己的笔记的,可是书才看了一半发现笔记有点多,有点乱,就先整理一份吧,顺便复习下前面的知识,之后的再补上. 真的感觉,看书是个好习惯啊,难怪人家说"书籍是人类 ...

  9. Git版本控制之多人协作

         上篇文章我们主要简单的介绍了有关git的一些基本常识和一些简单的命令.但那终究是皮毛,我们使用git最主要的目的还是管理我们的项目,多人协作.本篇文章主要涉及以下两个大模块: 分支的概念及原 ...

  10. 为什么重写 equals 方法 必须重写 hashCode

    自己学到这,就记录了下来,代码都是自己敲得,有不对的地方希望大神指点出来 为什么重写 equals 方法 必须重写 hashCode 如果你重写了equals,比如说是基于对象的内容实现的,而不重写 ...