关键词:
目标:
通过分析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/Makefile(ARM架构makefile)
首先在./arch/arm/Makefile文件第227行得到:
227 zImage Image xipImage bootpImage uImage: vmlinux 228 $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
得出uImage等5个目标的生成都是依赖于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
3 分析顶层目录Makefile
3.1 顶层vmlinux生成过程
在顶层目录makefile中第484行得出:
484 all: vmlinux
其中,all就是直接 make 指令编译内核,显然make uImage和make都依赖于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)
第3阶段——内核启动分析之创建si工程和启动内核分析
目标:(1)创建SourceInsight工程,方便后面分析如何启动内核的(2)分析uboot传递参数,链接脚本如何进入stext的 (3) 分析stext函数如何启动内核 1创建内核sourcesight工程 1.1点击“addall”添加所有文件,后面再慢慢删去A... 查看详情
第3阶段——内核启动分析之start_kernel初始化函数
内核启动分析之start_kernel初始化函数(init/main.c)stext函数启动内核后,就开始进入start_kernel初始化各个函数,下面只是浅尝辄止的描述一下函数的功能,很多函数真正理解需要对linux相关体系有很深的了解后才能明白 代码如下:&nbs... 查看详情
第3阶段——内核启动分析之挂载根文件系统和mtd分区介绍
内核启动并初始化后,最终目的是像Windows一样能启动应用程序在windows中每个应用程序都存在C盘、D盘等而linux中每个应用程序是存放在根文件系统里面那么挂载根文件系统在哪里,怎么实现最终目的运行应用程序? 1.进入stext函... 查看详情
内核启动分析(代码片段)
...分析的准备工作2.16.2.head.S文件分析12.16.3.内核启动的汇编阶段2.16.4.内核启动的C语言阶段12.16.5.内核启动的C语言阶段22.16.6.内核启动的C 查看详情
内核启动12(代码片段)
...分析的准备工作2.16.2.head.S文件分析12.16.3.内核启动的汇编阶段2.16.4.内核启动的C语言阶段12.16.5.内核启动的C语言阶段22.16.6.内核启动的C 查看详情
第1阶段——uboot启动函数bootm命令分析
本节主要学习:详细分析UBOOT中"bootcmd=nandread.jffs20x30007FC0kernel;bootm0x30007FC0"中怎么实现bootm命令启动内核.其中bootm要做的事情:a读取头部,把内核拷贝到合适的地方(0X30008000)b在do_boom_linux()中把参数给内核准备好,并告诉内核参数的首地... 查看详情
内核配置裁剪及启动流程(代码片段)
文章目录一、内核分析之编译初体验二、内核分析之配置三、内核分析之Makefile四、内核分析之启动过程一、内核分析之编译初体验1.解压缩2.配置内核的配置有三种方法(1)直接执行makemenuconfig,从头到尾每一条都自... 查看详情
第4阶段——制作根文件系统之编译配置安装busybox
在上一节分析出制作一个最小的根文件系统至少需要:(1)/dev/console(终端控制台,提供标准输入、标准输出以及标准错误)/dev/null (为空的话就是/dev/null,所有写到这个文件中的数据都会被丢弃掉。)(2)init进程的程序(也就是busybox,因... 查看详情
androido:init进程启动流程分析(阶段二)
在前一篇博客AndroidO:init进程启动流程分析(阶段一)中,我们分析了init进程第一阶段(内核态)的流程。在本篇博客中,我们来看看init进程第二阶段(用户态)的工作。一、初始化属性域init进程的第二阶段仍然从main函数开始入... 查看详情
内核启动过程分析
...考博客:《如何快速确定程序的入口》。3、汇编代码阶段3.1、设置成SVC模式并禁止终端s 查看详情
android笔记-android启动之linux内核启动
...以分为三篇文章来介绍,其实也就是Android启动的三个阶段。第一个阶段是Lin 查看详情
bsp开发之kernellinux启动流程以及编译流程分析(代码片段)
...文件build-in.o过程分析vmlinux、Image,zImage、uImage的区别内核启动流程分析linux顶层Makefile分析MAKEFLAGS+=-rR#静默输出makeV=1静默输出ifeq("$(originV)",& 查看详情
《linux操作系统分析》之linux系统的理解及学习linux内核的心得
...行第二篇:《Linux操作系统分析》之分析精简的Linux的内核中断和时间片轮询第三篇:《Linux操作系统分析》之跟踪分析Linux内核的启动过程第四篇:《Linux操作系统分析》之使用库函数API和C代码中嵌入汇编代码两种方... 查看详情
uboot启动源码分析
开发板smdk2410的uboot为例。 第一阶段文件为cpu/arm920t/start.S和board/smdk2410/lowlevel_init.S。一、第一阶段 1、设置cpu为svc模式 2、关看门狗、关中断 3、cpu初始化 4、设置栈 5、时钟初始化 6、拷贝uboot到ram 7、清除bss段 8、setPreLoadedONRAM 9... 查看详情
第1阶段——uboot通过nand命令读内核分析
本节主要学习:详细分析UBOOT中"bootcmd=nandread.jffs20x30007FC0kernel;bootm0x30007FC0"怎么实现nand命令读内核.1.nandread.jffs20x30007FC0kernel步骤a:从NANDFILSHE中kernel分区读出步骤b:放到0x30007FC0去1.1 kernel分区:是flash中内核区其中在flash中定 查看详情
第十章-语义分析之类型检查
由于Java是静态类型的语言,所以在编译阶段,所有的变量都能得出确定的类型。 1、类型循环继承、循环引用Java是单继承的,也就是说Java只能继承一个实现类。但是在继承过程中可能会形成循环,接口也是。 2... 查看详情
u-boot.2012.10——mini2440(启动流程分析)
...:https://blog.csdn.net/suiyuan19840208/article/details/72399491、第一阶段功能 *硬件设备初始化 *加载u-boot第二段代码到RAM空间 *设置好栈 *跳转到第二段代码入口2、第二段代码的功能 *初始化本阶段使用的硬件设备 *检... 查看详情
uboot启动第一阶段分析(代码片段)
一.uboot第一阶段初识 1.1.什么是uboot第一阶段 1.1.1.启动os三个阶段 1.1.1.1.bl0阶段 a.这段代码是三星固化到iROM中,可以查看《S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf》 b.... 查看详情