2.6 Linux内核makefile解析
来源:互联网 发布:微信网页授权 多域名 编辑:程序博客网 时间:2024/06/06 00:56
Linux内核的整个makefile编译系统称为kbuild系统,负责linux内核源码文件架构的编译和链接工作。2.4内核和2.6内核的kbuild实现上有非常大的差异,但是实现的功能基本是一样的,从顶层makefile目标到一个个子文件夹的递归调用,最终又合成一个顶层目标。2.4内核的makefile比较直观比较容易理解些,2.6的makefile文件比较难看懂,所以本文重点解析2.4内核的makefile架构,功能上其实大致相同。
可以参考附件中注释版的实际makefile进行学习。主要还只是记录我理解了的部分还有很多细节需要自己去学习分析。
1、2.4内核Makefile解析
以i386架构为例,2.4内核的makefile重点需要关注以下文件:
- $(TOPDIR) = lniux源码根目录
- $(TOPDIR)\makefile
- $(TOPDIR)\rules.makefile
- $(TOPDIR)\arch\i386\makefile
- $(TOPDIR)\arch\i386\boot\makefile
- $(TOPDIR)\arch\i386\boot\compressed\makefile
1.1、编译目标
内核编译需要用到的目标大概有以下几个:
- Make menuconfig (config、xconfig…):
读取各个子文件夹下面的config.in文件生成config菜单,根据用户在菜单下的选择结果最终在源码根目录下生成一个.config文件。这个.config文件包含用户的所有配置。
- Make dep:
在编译前,生成文件之间的依赖关系。
- Make vmlinux:
生成内核的elf格式文件。Vmlinux是最纯粹的内核文件,没有进过压缩,也不带boot启动代码。
- Make bzImage、zImage:
bzImage、zImage即vmlinuz文件。i386的vmlinuz文件生成方式是先将elf格式的vmlinux文件使用objcopy工具转换成bin格式文件,再将bin文件压缩并加上自解压的头,最终使用build工具将压缩内核和启动扇区文件接在一起生成bzImage文件。
bzImage和zImage的区别就是,zImage就是老版习惯使用低端640k的物理内存,bzImage使用1M以上的物理内存,现在基本都使用bzImage。
- Make install:
安装编译出来的内核,实际动作就是拷贝bzImage和System.map文件到/boot路径下。
- Make modules、modules_install:
Make modules编译在make menuconfig时,选择为M的模块。modules_install是安装模块,即拷贝编译出来的模块到相应目录。
- Make clean、mrproper、distclean:
由小到大范围的clean动作。
1.2、$(TOPDIR)\makefile解析
Vmlniux目标的生成规则:
vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o init/do_mounts.o linuxsubdirs $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \ --start-group \ $(CORE_FILES) \ $(DRIVERS) \ $(NETWORKS) \ $(LIBS) \ --end-group \ -o vmlinux $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
Vmlinux需要的各个子文件夹目标的编译目标:
SUBDIRS =kernel drivers mm fs net ipc lib crypto$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h include/config/MARKER $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@) // _dir_前缀的子目录目标,生成方法为直接进入子目录make,make -C $(SUBDIRS)
Clean相关目标的生成规则:
Menuconfig等配置目标:
symlinks: rm -f include/asm ( cd include ; ln -sf asm-$(ARCH) asm)// 创建符号链接include/asm指向架构目录include/asm-$(ARCH) @if [ ! -d include/linux/modules ]; then \ mkdir include/linux/modules; \ // 创建文件夹include/linux/modules Q:(编译模块的时候自动拷贝头文件进来??) fioldconfig: symlinks // 各种make config方式,生成根目录下的 $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.inxconfig: symlinks $(MAKE) -C scripts kconfig.tk wish -f scripts/kconfig.tkmenuconfig: include/linux/version.h symlinks $(MAKE) -C scripts/lxdialog all $(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.inconfig: symlinks $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
1.3、$(TOPDIR)\rules.makefile解析
编译vmlinux时,各个子文件夹的子目标的编译规则:
first_rule: sub_dirs // 编译vmlinux时,子目录每个makefile的默认目标就是first_rule,依赖于sub_dirs,对所有子目录进行make -C sub_dirs递归 $(MAKE) all_targetsall_targets: $(O_TARGET) $(L_TARGET) // all_targets目标,依赖于所有.o目标和所有.a目标## Rule to compile a set of .o files into one .o file // 将多个.o编译成一个.o的规则。#ifdef O_TARGET$(O_TARGET): $(obj-y) rm -f $@ ifneq "$(strip $(obj-y))" "" $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(obj-y), $^) else $(AR) rcs $@ endif @ ( \ echo 'ifeq ($(strip $(subst $(comma),:,$(LDFLAGS) $(EXTRA_LDFLAGS) $(obj-y))),$$(strip $$(subst $$(comma),:,$$(LDFLAGS) $$(EXTRA_LDFLAGS) $$(obj-y))))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ ) > $(dir $@)/.$(notdir $@).flagsendif # O_TARGET## Rule to compile a set of .o files into one .a file // 将多个.o编译成一个.a的规则。#ifdef L_TARGET$(L_TARGET): $(obj-y) rm -f $@ $(AR) $(EXTRA_ARFLAGS) rcs $@ $(obj-y) @ ( \ echo 'ifeq ($(strip $(subst $(comma),:,$(EXTRA_ARFLAGS) $(obj-y))),$$(strip $$(subst $$(comma),:,$$(EXTRA_ARFLAGS) $$(obj-y))))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ ) > $(dir $@)/.$(notdir $@).flagsendif
递归编译子文件夹目标的编译规则:
## A rule to make subdirectories#subdir-list = $(sort $(patsubst %,_subdir_%,$(SUB_DIRS)))sub_dirs: dummy $(subdir-list)// sub_dirs目标,依赖于$(subdir-list)ifdef SUB_DIRS$(subdir-list) : dummy// $(subdir-list)目标,依赖于对子目录的递归调用make -C subdir $(MAKE) -C $(patsubst _subdir_%,%,$@)endif
模块的编译规则:
## A rule to make modules // ---------- modules的生成规则 ----------#ALL_MOBJS = $(filter-out $(obj-y), $(obj-m)) // modules实际目标,取obj-m,那么obj-m module必须做到一个模块对应一个.o文件,而不能一个模块对应多个.cifneq "$(strip $(ALL_MOBJS))" "" MOD_DESTDIR := $(shell $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh) // MOD_DESTDIR目标,取主目录TOPDIR到当前目录的路径。endifunexport MOD_DIRSMOD_DIRS := $(MOD_SUB_DIRS) $(MOD_IN_SUB_DIRS) // MOD_DIRS, 包括MOD_SUB_DIRS、MOD_IN_SUB_DIRSifneq "$(strip $(MOD_DIRS))" "".PHONY: $(patsubst %,_modsubdir_%,$(MOD_DIRS)) // _modsubdir_$(MOD_DIRS)目标,进入子目录,继续递归make modules目标$(patsubst %,_modsubdir_%,$(MOD_DIRS)) : dummy $(MAKE) -C $(patsubst _modsubdir_%,%,$@) modules.PHONY: $(patsubst %,_modinst_%,$(MOD_DIRS)) // _modinst_$(MOD_DIRS)目标,进入子目录,继续递归make modules_install目标$(patsubst %,_modinst_%,$(MOD_DIRS)) : dummy $(MAKE) -C $(patsubst _modinst_%,%,$@) modules_installendif.PHONY: modulesmodules: $(ALL_MOBJS) dummy \// modules目标,依赖于_modsubdir_$(MOD_DIRS)、$(ALL_MOBJS)。$(ALL_MOBJS)生成真正的驱动文件编译 $(patsubst %,_modsubdir_%,$(MOD_DIRS)).PHONY: _modinst___modinst__: dummy // _modinst__目标,ifneq "$(strip $(ALL_MOBJS))" "" mkdir -p $(MODLIB)/kernel/$(MOD_DESTDIR) // 创建/lib/modules/$(KVER)/kernel/$(MOD_DESTDIR)文件夹 cp $(sort $(ALL_MOBJS)) $(MODLIB)/kernel/$(MOD_DESTDIR) // 拷贝$(ALL_MOBJS)到创建的文件夹中endif.PHONY: modules_installmodules_install: _modinst__ \ // modules_install目标,依赖于_modinst__、_modinst_$(MOD_DIRS)。 $(patsubst %,_modinst_%,$(MOD_DIRS))
1.4、$(TOPDIR)\arch\i386\makefile解析
定义编译vmlinux所需要的架构相关的部分:
LD=$(CROSS_COMPILE)ld -m elf_i386OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -SLDFLAGS=-e stextLINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS) // LINKFLAGS定义,调用link配置文件$(TOPDIR)/arch/i386/vmlinux.ldsHEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o // HEAD定义,在生成vmlinux的时候用到SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib // SUBDIRS定义,根据架构增加新的子目录。加进到SUBDIRS以后,会被子文件夹makefile的宏给自动调用。arch\i386下的 kernel mm lib文件夹是由这个包含来启动make编译的。CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) // CORE_FILES定义,在生成vmlinux的时候用到LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a // LIBS定义,在生成vmlinux的时候用到
1.5、$(TOPDIR)\arch\i386\boot\makefile解析
生成bzImage目标,使用build工具将boot扇区和压缩过的vmlinux文件构建在一起:
bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build // bzImage目标 $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out // 将bvmlinux装换成bvmlinux.out tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage // 使用tools/build将bbootsect bsetup compressed/bvmlinux.out生成bzImage
1.6、$(TOPDIR)\arch\i386\boot\compressed\makefile解析
生成bzImage所需要的压缩内核文件。将vmlniux文件,由elf格式转换成bin格式,并压缩,在文件头部再加上解压缩代码:
ZIMAGE_OFFSET = 0x1000BZIMAGE_OFFSET = 0x100000ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS)BZLINKFLAGS = -Ttext $(BZIMAGE_OFFSET) $(ZLDFLAGS)all: vmlinuxvmlinux: piggy.o $(OBJECTS) $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.obvmlinux: piggy.o $(OBJECTS) $(LD) $(BZLINKFLAGS) -o bvmlinux $(OBJECTS) piggy.ohead.o: head.S $(CC) $(AFLAGS) -traditional -c head.Scomma := ,misc.o: misc.c $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c misc.cpiggy.o: $(SYSTEM) tmppiggy=_tmp_$$$$piggy; \ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \$(OBJCOPY) $(SYSTEM) $$tmppiggy; \ gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \$(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
2、2.6内核Makefile解析
以i386架构为例,2.6内核的makefile重点需要关注以下文件:
- $(TOPDIR) = lniux源码根目录
- $(TOPDIR)\makefile
- $(TOPDIR) \scripts\Kbuild.include
- $(TOPDIR) \scripts\makefile.build
- $(TOPDIR) \scripts\makefile.lib
- $(TOPDIR) \scripts\kconfig\makefile
- $(TOPDIR)\arch\i386\makefile
- $(TOPDIR)\arch\i386\boot\makefile
- $(TOPDIR)\arch\i386\boot\compressed\makefile
2.6的kbuild系统更加复杂,这里只重点讲和2.4差异的地方。
2.1、编译目标
使用make help命令,可以查看所有可执行的make目标。
Make menuconfig (config、xconfig…):
2.6内核已经不是config.in文件,而改成了kconfig文件。
读取各个子文件夹下面的kconfig文件生成config菜单,根据用户在菜单下的选择结果最终在源码根目录下生成一个.config文件。这个.config文件包含用户的所有配置。
2.2、$(TOPDIR)\makefile解析
2.6的makefile复杂于2.4makefile,最大一部分就是定义了很多自定义make函数,然后再使用call来调用,例如:
$(call cmd,vmlinux__) = cmd_vmlinux__$(call if_changed_rule,vmlinux__) = rule_vmlinux__
有一个非常重要的自定义变量在编译目标的时候频繁用到:
#### Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=# Usage:# $(Q)$(MAKE) $(build)=dirbuild := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj // build目标。-f指定makefile文件,obj =
Vmlinux目标的生成规则:
# vmlinux image - including updated kernel symbols // 实际的vmlinux目标。vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE $(call if_changed_rule,vmlinux__) // 调用rule_vmlinux__ $(Q)rm -f .old_version
Vmlinux需要的各个子文件夹目标的编译目标:
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ // vmlinux需要的文件夹。去掉文件路径最后一个"/" $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ $(net-y) $(net-m) $(libs-y) $(libs-m))).PHONY: $(vmlinux-dirs)$(vmlinux-dirs): prepare scripts $(Q)$(MAKE) $(build)=$@ // 这里启动vmlinux各组成部分的编译
2.6内核会构建内置的符号表,即kallsyms组件。其编译规则如下:
ifdef CONFIG_KALLSYMS_EXTRA_PASSlast_kallsyms := 3elselast_kallsyms := 2endifkallsyms.o := .tmp_kallsyms$(last_kallsyms).odefine verify_kallsyms // 定义命令包:verify_kallsyms $(Q)$(if $($(quiet)cmd_sysmap), \ echo ' $($(quiet)cmd_sysmap) .tmp_System.map' &&) \ $(cmd_sysmap) .tmp_vmlinux$(last_kallsyms) .tmp_System.map $(Q)cmp -s System.map .tmp_System.map || \ (echo Inconsistent kallsyms data; \ echo Try setting CONFIG_KALLSYMS_EXTRA_PASS; \ rm .tmp_kallsyms* ; /bin/false )endef# Update vmlinux version before link# Use + in front of this rule to silent warning about make -j1# First command is ':' to allow us to use + in front of this rulecmd_ksym_ld = $(cmd_vmlinux__)define rule_ksym_ld // 定义命令包:rule_ksym_ld : +$(call cmd,vmlinux_version) $(call cmd,vmlinux__) $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmdendef# Generate .S file with all kernel symbolsquiet_cmd_kallsyms = KSYM $@ cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \ $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE $(call if_changed_dep,as_o_S).tmp_kallsyms%.S: .tmp_vmlinux% $(KALLSYMS) $(call cmd,kallsyms)# .tmp_vmlinux1 must be complete except kallsyms, so update vmlinux version.tmp_vmlinux1: $(vmlinux-lds) $(vmlinux-all) FORCE $(call if_changed_rule,ksym_ld).tmp_vmlinux2: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms1.o FORCE $(call if_changed,vmlinux__).tmp_vmlinux3: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms2.o FORCE $(call if_changed,vmlinux__)
2.3、$(TOPDIR) \scripts\Kbuild.include解析
定义了make中使用的通用自定义函数cmd、build、if_changed_rule等等:
#### Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=# Usage:# $(Q)$(MAKE) $(build)=dirbuild := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj // build目标。-f指定makefile文件,obj = # If quiet is set, only print short version of command // cmd表达式。如果quiet_格式命令被定义,,仅打印一个版本号,不打印命令的详细过程cmd = @$(if $($(quiet)cmd_$(1)),\ echo ' $(call escsq,$($(quiet)cmd_$(1)))' &&) $(cmd_$(1)) # Usage: $(call if_changed_rule,foo)# will check if $(cmd_foo) changed, or any of the prequisites changed,# and if so will execute $(rule_foo)if_changed_rule = $(if $(strip $? $(call arg-check, $(cmd_$(1)), $(cmd_$@)) ),\ // if_changed_rule表达式 @set -e; \ $(rule_$(1)))
2.4、$(TOPDIR) \scripts\makefile.build解析
解析了使用$(build)方法编译vmlniux文件夹各子目标的规则,vmlniux的子目标的编译和2.4内核不同,子文件夹下生成的子目标都是相同的built-in.o:
.PHONY: __build__build: // 默认目标ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)builtin-target := $(obj)/built-in.o // builtin-target变量等于文件夹下面的built-in.o endif# We keep a list of all modules in $(MODVERDIR)__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \// __build目标的依赖: $(builtin-target) $(lib-target) $(extra-y) $(obj-m) $(subdir-ym) $(always) $(if $(KBUILD_MODULES),$(obj-m)) \ $(subdir-ym) $(always) @: ## Rule to compile a set of .o files into one .o file // 规则:多个.o编译进一个.o#ifdef builtin-targetquiet_cmd_link_o_target = LD $@# If the list of objects to link is empty, just create an empty built-in.ocmd_link_o_target = $(if $(strip $(obj-y)),\ $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^),\ rm -f $@; $(AR) rcs $@)$(builtin-target): $(obj-y) FORCE // builtin-target目标的生成方法, $(call if_changed,link_o_target) // 调用表达式:if_changed -> cmd_link_o_targettargets += $(builtin-target)endif # builtin-target## Rule to compile a set of .o files into one .a file // 规则:多个.o编译进一个.a#ifdef lib-targetquiet_cmd_link_l_target = AR $@cmd_link_l_target = rm -f $@; $(AR) $(EXTRA_ARFLAGS) rcs $@ $(lib-y)$(lib-target): $(lib-y) FORCE $(call if_changed,link_l_target)targets += $(lib-target)endif
2.5、$(TOPDIR) \scripts\makefile.lib解析
提供子目录编译库时的编译规则。
2.6、$(TOPDIR) \scripts\kconfig\makefile解析
提供make menuconfig等config目标的编译规则。
3、内核编译相关问题
3.1、Q1:mips系统的vmlinuz格式?
Mips系统在生成内核的时候使用mkimage.exe工具将文件vmlinux转换成vmlinuz:“mkimage -A mips -O linux -T kernel -C none -a 0 -e 0 -n vmlinux -d vmlinux vmlinuz”。
经研究发现mips系统的vmlinuz依然是elf格式,mkimage.exe工具只是简单的给vmlinux文件加了一个0x40字节的文件头,对其内容原封没动。
这和386架构的vmlinuz生成大不相同,386架构得做法是使用objcopy命令将elf格式的vmlinux文件转换成bin格式的vmlinuz文件:
/* --------- linux-2.4.32\arch\i386\boot\Makefile --------- */bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build // bzImage目标 $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out // 将bvmlinux装换成bvmlinux.out tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage // 使用tools/build将bbootsect bsetup compressed/bvmlinux.out生成bzImage
3.2、Q2:/usr/src/linux-obj文件的来历?
Suse linux和编译内核相关,在/lib/modules/2.6.16.60-0.21-smp文件夹下面提供了build和source连个文件夹,可以看到其实是两个符号链接,build链接到/usr/src/linux-2.6.16.60-0.21-obj/i386/smp,source链接到/usr/src/linux-2.6.16.60-0.21。编译模块时,一般会将内核makefile指向/lib/modules/2.6.16.60-0.21-smp/build路径,而build实际上就是指向/usr/src/linux-2.6.16.60-0.21-obj/i386/smp目录,那/usr/src/linux-2.6.16.60-0.21-obj/i386/smp究竟是什么内容呢,我们继续往下追踪。
进入/usr/src/目录下查看/usr/src/linux-2.6.16.60-0.21和/usr/src/linux-2.6.16.60-0.21-obj/i386/smp目录下的实际内容:
可以看到linux和linux-2.6.16.60-0.21文件夹下是内核源文件目录,linux-2.6.16.60-0.21-obj和linux-obj是编译模块时指向的内核makefile目录。但是内核makefile目录不是应该指向内核源文件文件夹吗,为什么指向这个linux-obj文件夹,这个linux-obj文件夹到底是干什么的?
仔细研究以后,才发现其中的奥妙:编译模块时可以直接指向linux源代码目录,但是前提是这份源代码必须编译过,不然很多编译模块需要的组件都还没有产生,而且源代码文件夹只能保存一份当前配置,而linux-obj的子文件夹下面保存了很多种不同的配置,编译模块时可以根据自己需要的配置选取其中一种即可,而不用手工重新配置和编译内核。
所以linux-obj的作用是:1、保存了模块需要的组件,不用整个编译源码;2、保存了多种配置,可以灵活选择。应该是suse为了支持模块开发,特意封装的一系列文件夹。
3.3、Q3:内核编译头文件自解析?
由于内核需要自解析,所以它不能使用外部的库和头文件。其所有的头文件都包含在
3.4、Q4:内核的符号表自管理?
内核不同于用户态程序,用户态程序可以直接使用elf文件执行,有动态加载库来帮其解析加载elf文件格式和符号表。而内核不可能直接使用elf文件,也没有别人为其解析elf文件中的符号表。所以内核管理符号表,需要把elf文件中的符号表提取出来,当成数组编译到内核映像当中去,2.6内核的kallsyms组件就是干这个的。
其原理就是将整个elf格式的vmlinux文件,使用nm命令和scripts/kallsyms脚本将其符号表编译成kallsyms.o文件,再将kallsyms.o和vmlinux连接生成最终的vmlinux。
Vxworks映像也是这样干的:
3.5、Q5:elf格式文件和bin格式文件的不同加载方法?
Elf文件是不能自加载的,需要有额外的代码解析elf文件格式,将相应的段加载到对应位置,再根据解析的elf文件entry,跳转到对应地址执行。
但是很多时候没有解析elf的boot,需要文件一上去就能运行,这时就需要将elf转换成bin文件,并能满足自运行的需要。其中的原理是这样的:objcopy将elf转换成bin文件,它只会将所有要加载的段汇总,根据其加载到内存中的位置放到bin文件当中,最低加载地址作为bin文件的0偏移,段和段之间无效的空间全填0,所以bin文件有时候做出来很大。而boot代码只需要将bin文件整体copy到加载基地址上去即可,不需要解析elf文件格式了。这解决了elf文件解析问题,但是entry问题怎么解决呢?怎么能保证bin文件的第一句话就是elf的entry语句呢??这个使用链接手段来解决,使用ld的链接顺序,或者是链接脚本.lds文件来保证第一句话所在的模块被链接到文件的最开始,所以bin文件的最开始就是entry入口。
4、参考资料
- 2.6 Linux内核makefile解析
- Linux内核makefile解析
- Linux内核makefile解析
- Linux内核makefile解析
- linux内核makefile解析
- Linux内核makefile解析
- 【转】Linux内核makefile解析
- 关于linux内核模块Makefile的解析
- 关于linux内核模块Makefile的解析
- 关于linux内核模块Makefile的解析
- 关于linux内核模块Makefile的解析
- Linux 2.6内核Makefile浅析
- Linux 2.6内核Makefile浅析
- linux 2.6内核makefile分析
- Linux 2.6内核Makefile浅析
- Linux 2.6内核Makefile浅析
- Linux 2.6内核Makefile浅析
- Linux 2.6内核Makefile浅析
- loadrunner Lr_类函数之llr_debug_message()
- 数据挖掘学习入门建议
- 十月12号
- 拆箱与装箱
- 串口区分
- 2.6 Linux内核makefile解析
- 【bzoj2013】[Ceoi2010]A huge tower
- 关于Integer比较的问题
- Java添加事件监听的四种方法代码实例
- HDU
- loadrunner Lr_类函数之lr_decrypt()
- iterm2自动登陆,解决分栏后vi混乱
- 欧拉角和旋转矩阵相互转换
- 【SSH】Hibernate学习(一)