在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > ARM linux解析之zImage鏡像文件的生成

            ARM linux解析之zImage鏡像文件的生成

            作者: 時間:2016-11-11 來源:網(wǎng)絡(luò) 收藏
            最開始做個約定:存放linux代碼的根目錄我們叫做:linux_src,代碼用linux-3.0.46進(jìn)行分析。對于arm系統(tǒng),$(SRCARCH) = ARM。

            可能你會想,究竟linux如何編譯生成它的壓縮內(nèi)核鏡像zImage的呢?哈哈,下面就來做個解析。

            本文引用地址:http://www.biyoush.com/article/201611/316874.htm

            當(dāng)我們在linux_src目錄下輸入命令:

            > make zImage

            就會進(jìn)入linux_src/makfile,然后找zImage目標(biāo),這個目標(biāo)在:

            linux_src/makfile包含的:include $(srctree)/arch/$(SRCARCH)/Makefile里面,

            位于:linux_src/arch/arm/makfile里:

            zImage Image xipImage bootpImage uImage: vmlinux

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

            可以看到zImage依賴于vmlinux,這里的vmlinux指的是linux_src/vmlinux,這是編譯生成的linux內(nèi)核的elf文件。那么vmlinux又是在哪生成的呢?請向下看:

            它的生成規(guī)則在linux_src/makefile文件中,如下:

            #vmlinux image - including updated kernel symbols

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

            ifdef CONFIG_HEADERS_CHECK

            $(Q)$(MAKE) -f $(srctree)/Makefile headers_check

            endif

            ifdef CONFIG_SAMPLES

            $(Q)$(MAKE) $(build)=samples

            endif

            ifdef CONFIG_BUILD_DOCSRC

            $(Q)$(MAKE) $(build)=Documentation

            endif

            $(call vmlinux-modpost)

            $(call if_changed_rule,vmlinux__)

            $(Q)rm -f .old_version

            vmlinux的生成依賴于:$(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o),同樣在linux_src/makefile文件中:

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

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

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

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

            modpost-init := $(filter-out init/built-in.o, $(vmlinux-init))

            vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE

            $(call if_changed_rule,vmlinux-modpost)

            kallsyms.o:= .tmp_kallsyms$(last_kallsyms).o

            這里可以看到vmlinux就是由這些依賴文件通過arch/$(SRCARCH)/kernel/vmlinux.lds鏈接生成的,我就不再每往下解釋了。

            生成了linux_src/vmlinux之后,再回頭看arch/arm/boot/compressed/Makefile文件中的:

            zImage Image xipImage bootpImage uImage: vmlinux

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

            其中$(build)在linux_src/scripts/kbuild.include:

            ###

            # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=

            # Usage:

            # $(Q)$(MAKE) $(build)=dir

            build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj

            因為KBUILD_SRC為空,srctree就是當(dāng)前目錄,故
            build := -f ./scripts/Makefile.build obj

            boot := arch/arm/boot

            ifneq ($(machine-y),)

            MACHINE:= arch/arm/mach-$(word 1,$(machine-y))/

            else

            MACHINE:=

            endif

            machine-$(CONFIG_ARCH_EVB_ARM):= evb_arm

            Kconfig中:CONFIG_ARCH_EVB_ARM = y

            所以對于我們的平臺:

            MACHINE:= arch/arm/mach-evb_arm

            最開始的那一句最終解釋為:

            zImage:vmlinux

            @make –f./scripts/Makefile.build obj=arch/arm/boot MACHINE=arch/arm/mach-evb_armarch/arm/boot/zImage

            下面就是進(jìn)入到linux_src/scripts/Makefile.build這個makefile文件中

            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)

            在這里:

            src:= $(obj) :=arch/arm/boot//這個就是上一個makefile傳下來的值

            kbuild-dir:= $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))

            //這句的意思是,如果src是以/開頭的,則kbuild-dir :=$(src),

            如果不是的就等于kbuild-dir :=$(srctree)/$(src)

            這里kbuild-dir:= ./arm/arm/boot

            kbuild-file :=./arch/arm/boot/Kbuild ./arch/arm/boot/Makefile

            最后一句:

            include ./arch/arm/boot/Kbuild ./arch/arm/boot/Makefile

            可以看到這里是要包含linux_src/arch/arm/boot/Makefile文件,果然在里面找到了我們要的目標(biāo):

            $(obj)/zImage:$(obj)/compressed/vmlinux FORCE

            $(call if_changed,objcopy)

            @echo Kernel: $@ is ready

            再找$(obj)/compressed/vmlinux:

            $(obj)/compressed/vmlinux: $(obj)/Image FORCE

            $(Q)$(MAKE) $(build)=$(obj)/compressed $@

            再接著找$(obj)/Image:

            $(obj)/Image: vmlinux FORCE

            $(call if_changed,objcopy)

            @echo Kernel: $@ is ready

            到這里就可以知道了,哦,原來這個地方也是要vmlinux內(nèi)核elf的啊,這就知道了,無論怎么樣,vmlinux文件都要先生成,否則其他的文件都無法成生。下面來解釋一下:

            $(obj)/Image: vmlinux FORCE

            $(call if_changed,objcopy)

            @echo Kernel: $@ is ready

            這里的Image也就是linux_src/arch/arm/boot/Image,它的生成是通過把linux_src/vmlinux這個elf文件用通過objcopy生成bin文件Image。然后:

            $(obj)/compressed/vmlinux: $(obj)/Image FORCE

            $(Q)$(MAKE) $(build)=$(obj)/compressed $@

            這句和上面分析的類似,就是進(jìn)入linux_src/arch/arm/boot/compress/mafile中生成:

            arch/arm/boot/compress/vmlinux文件,如下:

            $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o

            $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE

            $(call if_changed,ld)

            @$(check_for_bad_syms)

            HEAD= head.o

            OBJS+= misc.o decompress.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.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile $(KCONFIG_CONFIG)

            @sed "$(SEDFLAGS)" < $< > $@

            插曲:關(guān)于if_changed的解釋:

            Kbuild.include:

            # >< substitution is for echo to work,

            # >$< substitution to preserve $ when reloading .cmd file

            # note: when using inline perl scripts [perl -e ...$$t=1;...]

            # in $(cmd_xxx) double $$ your perl vars

            make-cmd= $(subst \,\\,$(subst #,\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))))

            # Find any prerequisites that is newer than target or that does not exist.

            # PHONY targets skipped in both cases.

            any-prereq= $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)

            # Execute command if command has changed or prerequisite(s) are updated.

            #

            if_changed= $(if $(strip $(any-prereq) $(arg-check)),

            @set -e;

            $(echo-cmd) $(cmd_$(1));

            echo cmd_$@ := $(make-cmd) > $(dot-target).cmd)

            if_changed函數(shù)在當(dāng)發(fā)現(xiàn)規(guī)則的依賴有更新,或是目依賴不存在時,再或者是對應(yīng)目標(biāo)的命令行參數(shù)發(fā)生改變時($(strip $(any-prereq) $(arg-check))語句結(jié)果不為空),執(zhí)行后面的語句。

            set -e表示如果命令執(zhí)行有錯那么命令停止執(zhí)行并退出。

            接著$(echo-cmd)用來打印出相關(guān)的編譯命令,接著執(zhí)行$(cmd_$(1)里的命令。

            最后echo cmd_$@ := $(make-cmd) > $(dot-target).cmd將上面執(zhí)行的命令寫入一個叫$(dot-target).cmd的文件中,該文件為隱藏文件,在編譯后的內(nèi)核源碼目錄及其子目錄下隨處可見,比如在init/下可以看到.initramfs.o.cmd,.version.o.cmd等等。

            那么而所有的命令測存在呢?答案是:scripts/Makefile.lib:

            scripts/Makefile.build里面:include scripts/Makefile.lib

            scripts/Makefile.lib:

            # Objcopy

            # ---------------------------------------------------------------------------

            quiet_cmd_objcopy= OBJCOPY$@

            cmd_objcopy= $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@

            # Gzip

            # ---------------------------------------------------------------------------

            quiet_cmd_gzip= GZIP$@

            cmd_gzip= (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || (rm -f $@ ; false)

            言歸正傳,回到上面:

            $(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE

            $(call if_changed,$(suffix_y))

            $(obj)/piggy.$(suffix_y).o:$(obj)/piggy.$(suffix_y) FORCE

            這里的suffix_y在,arch/arm/boot/compressed:

            suffix_$(CONFIG_KERNEL_GZIP) = gzip

            suffix_$(CONFIG_KERNEL_LZO)= lzo

            suffix_$(CONFIG_KERNEL_LZMA) = lzma

            CONFIG_KERNEL_GZIP=y是在init/Kconfig文件里選擇的,menuconfig時配置,我們這里選gzip,則上面的過程為

            使用gzip對arch/arm/boot/Image文件進(jìn)行壓縮,壓縮成piggy.gzip。然后再生成piggy.gzip.o:

            這個是通過piggy.gzip.S文件生成的,內(nèi)容如下:

            .section.piggydata,#alloc

            .globlinput_data

            input_data:

            .incbin"arch/arm/boot/compressed/piggy.gzip"

            .globlinput_data_end

            input_data_end:

            可以看到壓縮后的內(nèi)核文件piggy.gzip是以bin文件的形式編譯成piggy.gzip.o的,并且注意這里的是放在.piggydata段中的,這個在arch/arm/boot/compressed/vmlinux.lds指定的。

            內(nèi)容如下:

            .text : {

            _start = .;

            *(.start)

            *(.text)

            *(.text.*)

            *(.fixup)

            *(.gnu.warning)

            *(.rodata)

            *(.rodata.*)

            *(.glue_7)

            *(.glue_7t)

            *(.piggydata)

            . = ALIGN(4);

            }

            是放在.text段的最后的,并且input_data和input_data_end包含里他們的起止地址。

            最后是arch/arm/boot/compressed/vmlinux.lds文件的生成,這個是以arch/arm/boot/compressed/vmlinux.lds.in為藍(lán)本,只是修改了

            . = TEXT_START;

            這個是在arch/arm/boot/compressed/Makefile中

            SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/

            $(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile $(KCONFIG_CONFIG)

            @sed "$(SEDFLAGS)" < $< > $@

            ifeq ($(CONFIG_ZBOOT_ROM),y)

            ZTEXTADDR:= $(CONFIG_ZBOOT_ROM_TEXT)

            ZBSSADDR:= $(CONFIG_ZBOOT_ROM_BSS)

            else

            ZTEXTADDR:= 0

            ZBSSADDR:= ALIGN(8)

            endif

            就是:TEXT_START = $(ZTEXTADDR)BSS_START = $(ZBSSADDR)

            如果內(nèi)枋是在nor flash中運行的,則選第一個,這時CONFIG_ZBOOT_ROM這個變量會定義,在RAM中運行的話,選第二個。在RAM中運行的代碼是被編譯成與位置無關(guān)的,所以可以加載到任何地方運行。

            所以合起來的解釋是:

            通過以下規(guī)則,最終生成arch/arm/boot/compress/vmlinux

            $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o

            $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE

            $(call if_changed,ld)

            @$(check_for_bad_syms)

            這個arch/arm/boot/compressed/vmlinux和前面的根目錄下生成的vmlinux都是elf文件,但是卻不是同一個東西。它是包令里解壓用的頭文件head.s,解壓程序misc.c,decompress.c的,再加入壓縮內(nèi)核的elf文件,是可以通過trace32加載運行的。

            下面是最后一步:

            $(obj)/Image: vmlinux FORCE

            $(call if_changed,objcopy)

            @echo Kernel: $@ is ready

            這個時候再把arch/arm/boot/compressed/vmlinux通過objcopy生成bin文件zImage,到這里,zImage文件生成完畢。

            最后用個圖表示一下整個zImage的生成過程:

            圖1.ARM linux的zImage生成過程



            關(guān)鍵詞: ARMlinuxzImage鏡像文

            評論


            技術(shù)專區(qū)

            關(guān)閉