感谢支持
我们一直在努力

基于x86体系结构分析Linux-2.6.26内核编译过程

1.      Makefile的分析:


1)Linux内核编译简述:


Linux2.6内核引入了kbuild机制,通过makemenuconfig配置把配置信息保存到.config


文件中,当.config文件被改变之后,在重新编译,Kbuild能够保证只进行最小化的编译。


Linux内核的编译系统主要包括的文件:


交叉编译工具:是编译生成的可执行文件,负责提供内核编译过程中的交互,并把用户配置交互的结果保存到.config文件。


Kconfig文件:位于各个子目录下,其定义了交互配置时的菜单信息。


.config文件:内核配置文件,有配置工具生成.config文件。(即配置内核选项中出现的y,m,空)。


Scripts/Makefiel:接受make相关的命令,并根据命令中的参数进行相应的操作。最主要的操作时编译内核文件的vmlinux和相关的模块文件。


KbuildMakefies:分布在各个目录下,与Makefile不同。


*.cmd文件:.cmd文件用于保存的历史编译参数和依赖信息,为以后的是否需要重新编译相关文件提供依据和参考。


2)内核编译过程分析:


编译过程,是由make命令引发的一系列操作。我们敲入的make命令,会找到相应的makefile文件,去执行其中的命令规则的。因为我们会在内核源文件的根目录下执行make命令,所以首先会从顶层的makefile中开始执。只使用make命令,即没有任何参数的情况之下,make会执行的是Makefile文件中的默认规则,即all:vmlinux这个规则。


    vmlinux:$(vmlinux-lds)$(vminux-init)$(vmlinux-main)vmlinux.o$(kallsyms.o) F


这样可以看出vmlinux的依赖的几项内容了。


    对应这样的几个依赖文件,分别进行分析。


    vmlinux-lds := arch/$(SRCARCH)/kernel/vmlinux.lds


vmlinux-init:= $(head-y) $(init-y)


vmlinux-main:= $(core-y) $(libs-y) $(drivers-y) $(net-y)


这些就是以上三个依赖项的定义了。vmlinux-lds的定义已经很清楚了,就是对应目录arch/x86/kernel/下的vmlinux.lds了。至于vmlinux-init的定义,就得到arch/x86/makefile文件中去看了。因为顶层的Makefile文件把这个Makefile文件也include进去了。


其中head-y如下:


head-y:= arch/x86/kernel/head_$(BITS).o


head-y+= arch/x86/kernel/head$(BITS).o


head-y+= arch/x86/kernel/head.o


head-y+= arch/x86/kernel/init_task.o


至于BITS,按照要求之考虑32为的情况,即把BITS代换为32就可以了。所以,head-y有三个重要的文件组成,即head_32.S,head32.c,init_task.o文件。这也说明了其是与体系结构相关的。


其中那个init-y如下:


init-y      := init/


………


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


vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y)$(init-m) \


            $(core-y) $(core-m) $(drivers-y) $(drivers-m) \


            $(net-y) $(net-m) $(libs-y) $(libs-m)))


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


…………


这样可以看出,init-y是与体系结构无关的。一种涉及到了一个patsubs函数替换的工作。


其中还有core-y:


core-y      := usr/


……


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


……


vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m)\


            $(core-y) $(core-m) $(drivers-y) $(drivers-m) \


            $(net-y) $(net-m) $(libs-y) $(libs-m)))


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


vmlinux-main:= $(core-y) $(libs-y) $(drivers-y) $(net-y)


经过分析,分析core-y的定义,分析core-y中既包含体系结构相关的,又包含体系结构无关的内容。


当然,没有把每一个文件都分析的很透彻了。

至于$(vmlinux-lds)$(vminux-init)$(vmlinux-main)这三个,都是依赖于$(vmlinux-dirs)的。而vmlinux-dirs,又是依赖于上面说到的init-y,init-m,core-y,core-m,drivers-m,net-y,net-m,libs-y,libs-m等,并且定义时候要对这些文件进行排序和过滤,即使用了sort和filter函数。


通过这些就可以生成想要的一些文件见了。


接下来,就应该是编译过程中的链接操作了。即把生成的这些文件链接起来,生成最终的目标文件才行。在Makefile文件中,使用了如下的call操作,分别调用相关的链接规则。


$(callif_changed_rule,vmlinux__)


$(call cmd,vmlinux__)


其中又有quiet_cmd_vmlinux。


在确定了$(vmlinux-lds)$(vminux-init)$(vmlinux-main)都成功生成了之后,才可以执行该操作函数的。quiet_cmd_vmlinux这个主要是用来在编译时进行显示用的,可以看出显示结果为LD target列表,真正的命令为cmd_vmlinux__,通过这个命令将变量vmlinux-init和vmlinux-main指定的目标链接成vmlinux文件。链接脚本由vmlinux-lds指定,即 –T 后跟连接的脚本。


3)内核链接脚本简述


内核的链接脚本分析主要是针对arch/x86/kernel/vmlinux.lds进行的。


该链接脚本中,定义了链接输出文件的入口点,为phys_starup_32,其实就是0x100000,1M的地方;还设置了当前的起始地址;在SECTIONS中,定义了地址和相关的段内容等。


 


2.      bzImage的代码结构:


1)  bzImage生成过程:


在arch/x86/makefile文件中,可以看到


all: bzImage


 


# KBUILD_IMAGEspecify target image being built


                    KBUILD_IMAGE :=$(boot)/bzImage


zImage zlilozdisk: KBUILD_IMAGE := $(boot)/zImage


 


zImage bzImage:vmlinux


$(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)


$(Q)mkdir -p$(objtree)/arch/$(UTS_MACHINE)/boot


$(Q)ln -fsn ../../x86/boot/bzImage$(objtree)/arch/$(UTS_MACHINE)/boot/$@


这个说明,bzImage是依赖于vmlinux的。其规则为make kbuild_image,kbuild_imag。


同时,又是arch/86/boot/bzImage。这样,在arch/86/boot/makefile文件中,可以分析到:


$(obj)/zImage$(obj)/bzImage: $(obj)/setup.bin \


$(obj)/vmlinux.bin$(obj)/tools/build FORCE


$(callif_changed,image)


@echo’Kernel: $@ is ready’ ‘ (#’`cat .version`’)’


……………..


OBJCOPYFLAGS_vmlinux.bin:= -O binary -R .note -R .comment -S


$(obj)/vmlinux.bin:$(obj)/compressed/vmlinux FORCE


$(callif_changed,objcopy)


……………….


OBJCOPYFLAGS_setup.bin       := -O binary


$(obj)/setup.bin:$(obj)/setup.elf FORCE


$(callif_changed,objcopy)


…………………..


         这样一来,就可以看出了bzIamge的组成为setup.bin 和vmlinux.bin两部分了。


而setup.bin又是由setup.elf经过objcopy之后转换而成的。而setup.elf又可以有以下代码分析:


LDFLAGS_setup.elf  := -T


$(obj)/setup.elf:$(src)/setup.ld $(SETUP_OBJS) FORCE


$(callif_changed,ld)


         即setup.elf又依赖于$(SETUP_OBJS)。


SETUP_OBJS= $(addprefix $(obj)/,$(setup-y))


// 这个是在变量$(setup-y)前面加上前缀$(obj)

至于setup-y就可以接着找到了,即:


targets             := vmlinux.bin setup.bin setup.elfzImage bzImage


subdir-             := compressed


 


setup-y           += a20.o cmdline.o copy.o cpu.ocpucheck.o edd.o


setup-y           += header.o main.o mca.o memory.opm.o pmjump.o


setup-y           += printf.o string.o tty.o video.ovideo-mode.o version.o


setup-$(CONFIG_X86_APM_BOOT)+= apm.o


setup-$(CONFIG_X86_VOYAGER)+= voyager.o


 


# The linkorder of the video-*.o modules can matter. In particular,


#video-vga.o *must* be listed first, followed by video-vesa.o.


#Hardware-specific drivers should follow in the order they should be


# probed,and video-bios.o should typically be last.


setup-y           += video-vga.o


setup-y           += video-vesa.o


setup-y           += video-bios.o     


现在我就可以看出来了,就是把a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o


 header.o main.o mca.omemory.o pm.o pmjump.o等这些项,链接到一起,先生成了setup.elf文件,在把生成的这个setup.elf文件转换成setup.bin文件了。


    这就分析完bzImage其中的一个部分setup.bin了。


第二个部分的vmlinux.bin,可以根据上面列出的定义,即


$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE


可以看出来,vmlinux.bin是经过compressed/vmlinux经过objcopy转换而来的。这样,我就必须去看看vmlinux的组成了。在arch/x86/boot/compressed的目录下,分析其中的Makefile文件了。其中:


$(obj)/vmlinux:$(src)/vmlinux_$(BITS).lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.oFORCE


则vmlinux又由head_32.o misc.o piggy.o经过vmlinux_32.lds链接组成的。


misc.o的作用就是一个解压缩的功能。而piggy.o是由vmlinux.scr和vmlinux.bin.gz经过ld链接生成。vmlinux.bin.gz是vmlinux.bin经过gzip压缩之后生成,而vmlinux.bin是由顶层vmlinux经过objcopy得到得。


之后,利用objcopy把arch/x86/boot/cmpressed目录下的vmlinux文件转换成二进制的vmlinux文件,保存在arch/x86/boot/目录下了。


接着,利用build工具把arch/x86/boot/cmpressed目录下的setup.bin和vmlinux.bin拼接成bzImage.


2)  bzImage的组成:


其实,经过上一个分析bzImage的生成过程,就可以看出来bzImage的组成了。其实就是由两个部分组成的,分别是vmlinux.bin和setup.bin。setup.bin的功能是在内核启动阶段对平台相关的硬件进行初始化的,并且利用BIOS获取必要的硬件信息,其是与平台有关的。而vmlinux.bin文件时平台无关的了。


附(我的一个师兄的内核编译总结图):



在红线上方的是在目录arch/x86/boot下的,红线下的(不包括顶层vmlinux)在arch/x86/boot/compressed目录下的,顶层vmlinux是在顶目录下的。

赞(0) 打赏
转载请注明出处:服务器评测 » 基于x86体系结构分析Linux-2.6.26内核编译过程
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏