记在前面的杂七杂八
- 内核的生成,实际上最终的目的是生成一个binary文件zImage,大小2-5MB的数量级。
- 用户可以从kernel.org得到的tar.gz格式的内核源代码,此代码解压后,就会生成初始状态的内核源代码树,这种状态称为内核的初始状态。
- 通过make mrproper/make distclean等指令,可以使内核恢复到刚解压的状态。其中make mrproper只清除包括.config文件在内的,为内核编译及连接而生成的诸多配置文件。distclean对象执行mrproper命令,清除内核编译后生成的所有对象文件,备份文件等。
- 如果将初始化状态的内核直接编译,虽然能生成vmlinux,但大多数情况下会引起内核严重错误(kernel panic)。构建内核前,需要执行的最重要,最需谨慎处理的部分是内核配置(kernel configureation)过程。内核配置过程也是适当选择与自身相吻合的各种内核要素的过程。
- 内核的配置可以用xconfig,menuconfig,gconfig等,最终都是会执行一个二进制文件,如menuconfig最终执行的是mconf,这个程序在./script/kconfig/目录下。
- 在构建内核时,各个*.o的目录下都有一个.*.cmd,这个文件是记录这个.o最终执行的编译命令的,如vmlinux.cmd和.vmlinux.o.cmd。
- 一句make一般来说,默认的目标有两个,一个是vmlinux,一个是zImage
- 通过emulator启动goldfish的时候,实际上启动的是zImage,这货才2.5MB左右,启动命令如下: - emulator -show-kernel -kernel /mnt/VMDisk1/kernel/goldfish/arch/arm/boot/zImage -avd test -qemu -s
 
- 在图形化界面下,内核的配置也会有很多很多问题,一般每个系统均提供自定义配置文件,这些配置文件都是与具体芯片相关的(Soc, System on Chip),如下: 
tigger@ubuntu:/mnt/VMDisk1/kernel/goldfish$ cd arch/
alpha/      blackfin/   frv/        ia64/       microblaze/ openrisc/   s390/       sparc/      unicore32/  
arm/        c6x/        h8300/      m32r/       mips/       parisc/     score/      tile/       x86/        
avr32/      cris/       hexagon/    m68k/       mn10300/    powerpc/    sh/         um/         xtensa/ 
tigger@ubuntu:/mnt/VMDisk1/kernel/goldfish/arch/arm/configs$ ll
total 632
drwxr-xr-x  2 tigger tigger  4096 2014-10-14 20:09 ./
drwxr-xr-x 88 tigger tigger  4096 2014-11-01 02:28 ../
-rw-r--r--  1 tigger tigger  1998 2014-10-11 02:28 acs5k_defconfig
-rw-r--r--  1 tigger tigger  2011 2014-10-11 02:28 acs5k_tiny_defconfig
-rw-r--r--  1 tigger tigger  2509 2014-10-14 20:09 afeb9260_defconfig
-rw-r--r--  1 tigger tigger  2241 2014-10-11 02:28 ag5evm_defconfig
-rw-r--r--  1 tigger tigger  2617 2014-10-11 02:28 am200epdkit_defconfig
......
内核的构建
    
    make goldfish_armv7_defconfig
    
    make menuconfig
    
    make
- .config文件是构建内核所需的内核配置目录,它是在CONFIG_XXX变量中用y,n,m三个状态进行配置的目录,这种形态的内核配置系统叫做kconfig。根据kconfig提供的三个状态(y,n,m)决定是否构建内核相应的模块(Kconfig系统中y,n,m只是bool类型的配置选项,实际上.config中可能有hex/int/bool/tristate/string这多种类型的选项)。 - 状态为y时:相应的二进制文件,与vmlinux链接。
- 状态为m时:不会和vmlinux链接,但作为模块执行编译。
- 状态为n时:不编译。
 
- mconf通过.config配置文件,生成autoconf.h头文件 
tigger@ubuntu:/mnt/VMDisk1/kernel/goldfish$ find ./ -name autoconf.h
./include/linux/autoconf.h
./include/generated/autoconf.h
这两个文件是一样的,也不知道谁复制的谁,大体看一下文件内容:
#define CONFIG_RING_BUFFER 1
#define CONFIG_NF_CONNTRACK_H323 1
#define CONFIG_KERNEL_GZIP 1
#define CONFIG_INPUT_KEYBOARD 1
#define CONFIG_IP_NF_TARGET_REDIRECT 1
#define CONFIG_CRC32 1
#define CONFIG_NF_NAT_PROTO_SCTP 1
#define CONFIG_HAVE_AOUT 1
#define CONFIG_VFP 1
#define CONFIG_AEABI 1
#define CONFIG_FB_TILEBLITTING 1
#define CONFIG_HIGH_RES_TIMERS 1
#define CONFIG_BLK_DEV_DM 1
#define CONFIG_VLAN_8021Q 1
可以发现,在.config中定义的的宏,在预处理阶段被处理成了各种#define语句。
linux内核Makefile分类: 
* Kernel Makefile: 位于内核源代码的顶层目录,也叫Top Makefile。主要用于指定编译内核的目标文件(vmlinux)和模块。在编译内核或模块时,这个文件会被首先读取,并根据内容设置环境变量。 
* kbuild Makefile: kbuild系统使用kbuild Makefile来编译内核或模块,Kbuild Makefile指定哪些编译近内核,哪些编译为模块。 
* arch Makefile: 位于./arch/$(ARCH)/Makefile,是系统对应平台的Makefile。top makefile会包含这个文件来指定平台相关信息,只有平台开发人员需要关心这个文件。
vmlinux的生成
编译后,vmlinux是在内核目录树的根目录下生成的一个ELF文件,这里以goldfish下执行make为例,查看vmlinux的生成。 当执行make命令的时候,会先扫描内核的根目录的Makefile:
PHONY := _all
_all:
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif
all: vmlinux
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
    
    $(call vmlinux-modpost)
    
    $(call if_changed_rule,vmlinux__)
    
    $(Q)rm -f .old_version
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
后续会分析其中的各个目标
目标文件 vmlinux.o
vmlinux.o是没有去除符号表的可执行文件,最终生成的vmlinux为真正的内核镜像
-rwxr-xr-x   1 tigger tigger  61M 2014-12-22 01:21 vmlinux*
-rw-r--r--   1 tigger tigger 109M 2014-12-22 01:21 vmlinux.o
目标文件 vmlinux.lds
vmlinux.lds是一个链接脚本,是给ld链接器使用的。一般来说,普通程序是不需要指定linker script的,也不需要关心各个section的具体位置。当程序执行时,kernel中的ELF Loader会根据ELF文件头解析可执行文件的各个section,并把他们映射到虚拟地址空间。然而,内核启动时,必须首先确定各个section的具体位置,这就是vmlinux.lds的作用。这个文件必然是体系结构相关的,在arm中有两个连接脚本分别位于: 
./arch/arm/kernel/vmlinux.lds(这个是给vmlinux编译用的连接脚本,就是这里面的vmlinux.lds) 
./arch/arm/boot/compressed/vmlinux.lds(这个是给zImage编译时候用的连接脚本)
目标文件 kallsyms.o
在2.6内核中,为了更好的调试内核,引入了kallsyms机制。kallsyms把内核中用到的所有函数地址和名称链接到内核文件,当内核启动后,同时加载到内存中。当发生oops时候,内核就会 
解析eip位于哪个函数中,然后打印出backtrace信息。内核编译的最后,make会执行:nm -n vmlinux|scripts/kallsyms,其中: 
1. nm -n vmlinux负责生成所有的内核符号并按地址排序 
2. scripts/kallsyms负责处理这个列表,并生成需要的链接文件tmp_kallsyms%.s 
也就是说kallsyms实际上是内核编译完了之后,vmlinux中通过nm命令生成的,所以所有符号地址都包括了,实际上是和System.map是一样的。 
而且kallsyms中所有函数的地址,是放在一个全局数组kallsyms_addresses[]中的,如下:
kallsyms_addresses:
        PTR     _text + 0x180
        PTR     _text + 0x180
        PTR     _text + 0x180
        PTR     _text + 0x194
        PTR     _text + 0x360
        PTR     _text + 0x374
        PTR     _text + 0x484
        PTR     _text + 0x594
        PTR     _text + 0x5f4
        PTR     _text + 0x5f8
        PTR     _text + 0x60c
        PTR     _text + 0x624
kallsyms_addresses中的每一个表项,都在重定位表中有记录,如果内核发生了重定位,那么kallsyms中的内容也会跟着修改,所以cat /proc/kallsyms的时候总是看到的是真正的函数地址。
kallsyms的整个符号表,最终都会放在kallsyms.o文件中。
kallsyms.o := .tmp_kallsyms$(last_kallsyms).o          
目标 vmlinux-init
vmlinux-init := $(head-y) $(init-y)
include $(srctree)/arch/$(SRCARCH)/Makefile
head-y := arch/arm/kernel/head$(MMUEXT).o \
        arch/arm/kernel/init_task.o
init-y  := init/
init-y          := $(patsubst %/, %/built-in.o, $(init-y))
所以最终vmlinux-init 实际上是: 
1. arch/arm/kernel/head.o(这是Image/vmlinux的入口代码)。 
2. arch/arm/kernel/init_task.o 
3. init/built-in.o 
三者链接而来的。
目标 vmlinux-main
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
core-y := usr/
ifeq ($(KBUILD_EXTMOD),)
core-y  += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
core-y := $(patsubst %/, %/built-in.o, $(core-y))
machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))
platdirs := $(patsubst %,arch/arm/plat-%/,$(plat-y))
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y += arch/arm/net/
core-y += $(machdirs) $(platdirs)
libs-y  := lib/
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y  := $(libs-y1) $(libs-y2)
libs-y := arch/arm/lib/ $(libs-y)
drivers-y  := drivers/ sound/ firmware/
drivers-y  := $(patsubst %/, %/built-in.o, $(drivers-y))
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
net-y := net/
net-y := $(patsubst %/, %/built-in.o, $(net-y))
总结一下,vmlinux-main是由以下四个目标组成的:
- core-y: 
 - 包含体系结构无关的usr/ kernel/ mm/ fs/ ipc/ security/ crypto/ block/ 目录下的built-in.o文件(如果是编译module,则只包含usr/built-in.o)。
- 包含体系结构相关的文件,在arm下为arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ arch/arm/net/下的built-in.o。
- 包含具体芯片相关的文件,如arch/arm/plat-%/ arch/arm/mach-%/下的built-in.o。
 
- libs-y: 包含arch/arm/lib/和 lib/目录下的built-in.o和lib.a文件。
- drivers-y: 包含drivers/ sound/ firmware/以及arch/arm/oprofile/(可选)目录下的built-in.o文件。
- net-y: 包含net/built-in.o文件。
vmlinux的生成过程规则: rule_vmlinux__
define rule_vmlinux__
    :
    
    
    $(if $(CONFIG_KALLSYMS),,+$(call cmd,vmlinux_version))
    
    $(call cmd,vmlinux__)
    
    
    $(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
    
    
    
    
    $(Q)$(if $($(quiet)cmd_sysmap),                                      \
        
      echo '  $($(quiet)cmd_sysmap)  System.map' &&)                     \
    $(cmd_sysmap) $@ System.map;                                         \
    if [ $$? -ne 0 ]; then                                               \
        rm -f $@;                                                    \
        /bin/false;                                                  \
    fi;
    
    $(verify_kallsyms)
endef
define 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 This is a bug - please report about it;                \
         echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround;      \
         rm .tmp_kallsyms* ; /bin/false )
endef
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
rule_vmlinux__ -> cmd_vmlinux__
      
      
      
      cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \
      
      -T $(vmlinux-lds) $(vmlinux-init)                          \
      
      --start-group $(vmlinux-main) --end-group                  \
      
      $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE ,$^)
rule_vmlinux生成的vmlinux.cmd:
      
      cmd_vmlinux := 
      arm-linux-androideabi-ld.bfd \ 
      -EL  -p --no-undefined -X --emit-relocs --build-id \ 
      -o vmlinux \ 
      -T arch/arm/kernel/vmlinux.lds \ 
      arch/arm/kernel/head.o arch/arm/kernel/init_task.o  init/built-in.o \ 
      --start-group  \
      usr/built-in.o  arch/arm/vfp/built-in.o  arch/arm/kernel/built-in.o  arch/arm/mm/built-in.o  arch/arm/common/built-in.o  arch/arm/net/built-in.o  mediatek/platform/mt6582/kernel/core/built-in.o  kernel/built-in.o  mm/built-in.o  fs/built-in.o  ipc/built-in.o  security/built-in.o  crypto/built-in.o  block/built-in.o  arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o  drivers/built-in.o  sound/built-in.o  firmware/built-in.o  mediatek/kernel/built-in.o  mediatek/custom/out/kernel/built-in.o  mediatek/platform/mt6582/kernel/drivers/built-in.o  aliyun/security/built-in.o  net/built-in.o \ 
      --end-group \
      .tmp_kallsyms2.o 
也就是说vmlinux实际上是由vmlinux.lds 连接vmlinux-init, vmlinux-main和.tmp_kallsyms2.o而成的,与vmlinx.o没有链接的关系!!!
vmlinux.o的生成
vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE
    $(call if_changed_rule,vmlinux-modpost)
define rule_vmlinux-modpost
    :
    
    +$(call cmd,vmlinux-modpost)
    
    $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
    
    
    $(Q)echo 'cmd_$@ := $(cmd_vmlinux-modpost)' > $(dot-target).cmd
endif
     
     
     
     cmd_vmlinux-modpost = $(LD) $(LDFLAGS) -r -o $@                          \
     $(vmlinux-init) --start-group $(vmlinux-main) --end-group             \
     $(filter-out $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
vmlinux.o的生成命令(.vmlinux.o.cmd)
        cmd_vmlinux.o := 
        arm-linux-androideabi-ld.bfd \ 
        -EL   \
        -r -o vmlinux.o \
        arch/arm/kernel/head.o arch/arm/kernel/init_task.o  init/built-in.o  \
        --start-group  \
        usr/built-in.o  arch/arm/vfp/built-in.o  arch/arm/kernel/built-in.o  arch/arm/mm/built-in.o  arch/arm/common/built-in.o  arch/arm/net/built-in.o  mediatek/platform/mt6582/kernel/core/built-in.o  kernel/built-in.o  mm/built-in.o  fs/built-in.o  ipc/built-in.o  security/built-in.o  crypto/built-in.o  block/built-in.o  arch/arm/lib/lib.a  lib/lib.a  arch/arm/lib/built-in.o  lib/built-in.o  drivers/built-in.o  sound/built-in.o  firmware/built-in.o  mediatek/kernel/built-in.o  mediatek/custom/out/kernel/built-in.o  mediatek/platform/mt6582/kernel/drivers/built-in.o  aliyun/security/built-in.o  net/built-in.o \
        --end-group
        
make -f $(srctree)/scripts/Makefile.modpost vmlinux.o
rule_vmlinux-modpost生成vmlinux.o后会调用
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@,解析后就是
解析后就是:
make -f $(srctree)/scripts/Makefile.modpost vmlinux.o
modpost = scripts/mod/modpost                   \
 $(if $(CONFIG_MODVERSIONS),-m)                  \
 $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,)       \
 $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
 $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
 $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(KBUILD_EXTRA_SYMBOLS))) \
 $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
 $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S)      \
 $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \
 $(if $(cross_build),-c)
vmlinux.o: FORCE
    $(call cmd,kernel-mod)
cmd_kernel-mod = $(modpost) $@
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
Module.symvers文件只有在开启CONFIG_MODVERSIONS才生效的,否则里面的crc全是0,我这里没有开,内容如下:
<CRC>           <Symbol>                <module> <type>
0x00000000      cfg80211_send_rx_assoc  vmlinux EXPORT_SYMBOL
0x00000000      generic_file_splice_write       vmlinux EXPORT_SYMBOL
0x00000000      set_anon_super  vmlinux EXPORT_SYMBOL
0x00000000      kmem_cache_alloc        vmlinux EXPORT_SYMBOL
0x00000000      replace_page_cache_page vmlinux EXPORT_SYMBOL_GPL
0x00000000      __cond_resched_softirq  vmlinux EXPORT_SYMBOL
0x00000000      mt_fh_popod_restore     vmlinux EXPORT_SYMBOL
0x00000000      i2c_put_adapter vmlinux EXPORT_SYMBOL
0x00000000      rtc_class_open  vmlinux EXPORT_SYMBOL_GPL
0x00000000      scsi_sense_key_string   vmlinux EXPORT_SYMBOL
......
总结一下:
- vmlinux依赖于目标文件vmlinux.o,但是二者的生成没有直接关系,即vmlinux并不链接vmlinux.o文件
- vmlinux和vmlinux.o的区别主要在于: 
 - vmlinux指定了–no-undefined编译选项,不可以有未决符号,而vmlinux.o可以有。
- vmlinux指定了链接脚本vmlinux.lds,vmlinux.o没有连接脚本。
- vmlinux连接了符号表*kallsyms*.o文件,vmlinux.o没有连接符号表。
- vmlinux没指定-r选项,vmlinux.o指定了-r选项,-r是用来生成可重定位的目标文件用的,这个选项导致了vmlinux.o虽然链接的较vmlinux少,但实际体积比vmlinux要大(在我编译出的镜像中,vmlinux大小61MB,包含56个段; vmlinx.o大小109MB,包含12119个段,其中有6061个段为重定位段,另外有5981个段为各种ksy*段,如__ksymtab_strings。
 
zImage的生成
all:    $(KBUILD_IMAGE)
KBUILD_IMAGE := zImage
zImage Image xipImage bootpImage uImage: vmlinux
    
    
    
    
    $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
obj-y :=
obj-m :=
lib-y :=
lib-m :=
-include include/config/auto.conf
include scripts/Kbuild.include
src := $(obj)
kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
include $(kbuild-file)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
ifneq ($(MACHINE),)
include $(srctree)/$(MACHINE)/Makefile.boot
endif
ZRELADDR    := $(zreladdr-y)
PARAMS_PHYS := $(params_phys-y)
INITRD_PHYS := $(initrd_phys-y)
$(obj)/zImage:	$(obj)/compressed/vmlinux FORCE
    
    
    $(call if_changed,objcopy)
    @echo '  Kernel: $@ is ready'
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
所以zImage实际上是依赖于$(obj)/compressed/vmlinux的,是后者执行了一个objcopy -binary过来的($(obj)/compressed/vmlinux并不是vmlinux,前者是内核Image压缩为piggy.gz后再次生成的一个压缩后的elf镜像,而后者是内核的镜像,$(obj)/compressed/vmlinux大小约为2.XMB,后面也称其为vmlinux(小),而另一个称为vmlinux(大))其命令行如下:
cmd_arch/arm/boot/zImage := arm-linux-androideabi-objcopy -O binary -R .comment -S  arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage
目标 $(obj)/compressed/vmlinux
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
    
    
    
    $(Q)$(MAKE) $(build)=$(obj)/compressed $@ 
$(obj)/Image: vmlinux FORCE
    
    
    
    $(call if_changed,objcopy)
    @echo '  Kernel: $@ is ready'
HEAD    = head.o
OBJS        =
OBJS        += string.o 
lib1funcs = $(obj)/lib1funcs.o
ashldi3 = $(obj)/ashldi3.o
$(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE
    $(call if_changed,$(suffix_y))
$(obj)/piggy.$(suffix_y).o:  $(obj)/piggy.$(suffix_y) FORCE
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
        $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) FORCE
    @$(check_for_multiple_zreladdr)
    $(call if_changed,ld)
    @$(check_for_bad_syms)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
文件piggy.gzip.s
        #此文件直接将piggy.zip包含进来了
        .section .piggydata,#alloc
        .globl  input_data
input_data:
        .incbin "arch/arm/boot/compressed/piggy.gzip"
        .globl  input_data_end
input_data_end:
zImage的生成流程图
从vmlinux到zImage的步骤如图: 
![]()
*.cmd
- 在构建内核时,各个*.o的目录下都有一个.*.cmd,这个文件是记录这个.o最终执行的编译命令的,如vmlinux.cmd和.vmlinux.o.cmd,从vmlinux到zImage的步骤总结如下:
cmd_arch/arm/boot/Image := arm-eabi-objcopy \
     -O binary -R .comment -S  vmlinux arch/arm/boot/Image
cmd_arch/arm/boot/compressed/piggy.gz := gzip -f -9 \
    < arch/arm/boot/compressed/../Image > \
    arch/arm/boot/compressed/piggy.gz
cmd_arch/arm/boot/compressed/vmlinux := arm-eabi-ld -EL\
    --defsym _kernel_bss_size=1419856 \
    --defsym zreladdr=0x00008000 \
    -p --no-undefined -X -T \
    arch/arm/boot/compressed/vmlinux.lds \
    arch/arm/boot/compressed/head.o \
    arch/arm/boot/compressed/piggy.gzip.o \
    arch/arm/boot/compressed/misc.o \
    arch/arm/boot/compressed/decompress.o \
    arch/arm/boot/compressed/string.o \
    arch/arm/boot/compressed/lib1funcs.o \
    arch/arm/boot/compressed/ashldi3.o  \
    -o arch/arm/boot/compressed/vmlinux
cmd_arch/arm/boot/zImage := arm-eabi-objcopy \
    -O binary -R .comment \
    -S arch/arm/boot/compressed/vmlinux \
    arch/arm/boot/zImage
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
vmlinux.ld
 
 
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
  . = 0;
  _text = .;
  .text : {
  
  
    _start = .;
    *(.start)
    *(.text)
    *(.text.*)
    *(.fixup)
    *(.gnu.warning)
    *(.glue_7t)
    *(.glue_7)
  }
  .rodata : {
    *(.rodata)
    *(.rodata.*)
  }
  .piggydata : {
    *(.piggydata)
  }
  . = ALIGN(4);
  _etext = .;
  .got.plt      : { *(.got.plt) }
  _got_start = .;
  .got          : { *(.got) }
  _got_end = .;
  .pad          : { BYTE(0); . = ALIGN(8); }
  _edata = .;
  . = ALIGN(8);
  __bss_start = .;
  .bss          : { *(.bss) }
  _end = .;
  . = ALIGN(8);     
  .stack        : { *(.stack) }
  .stab 0       : { *(.stab) }
  .stabstr 0        : { *(.stabstr) }
  .stab.excl 0      : { *(.stab.excl) }
  .stab.exclstr 0   : { *(.stab.exclstr) }
  .stab.index 0     : { *(.stab.index) }
  .stab.indexstr 0  : { *(.stab.indexstr) }
  .comment 0        : { *(.comment) }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
参考资料
[1].http://lli_njupt.0fees.net/ar01s07.html?ckattempt=1 
[2].http://cache.baiducontent.com/c?m=9d78d513d99d17b8589c837e7b01d6160e54f6743da791532c94d55f92144c413171e2cb72624d4391d27d1716df4e4b9bf62173471456b28cbc8d5dabba85592e9c60742e13dc0754910eaeb85b388465d54de9d848a7e1a461cfb9d2a48e090cd705523cd3abd50d5603cd1ba34862bdedd813544817ceb06472f82d3173c83447c218aab9657900f5b18d0111853dd71545ccf366ee2915c142f940597f1af75bb67c027a66f74853a11f615d85ec29a1702e5724c213ecfb9fe1b41fd09ab977c3a797b828e122a698bbae30036d&p=c46cce10ba904ead08e2977c0908cd&newp=8570c54ad5c145c30be296645b5f88231610db2151d4d31013&user=baidu&fm=sc&query=ld++%2D%2Dstart%2Dgroup%B5%C4%D7%F7%D3%C3&qid=89430f6200031c87&p1=7