uboot makefile构建分析-续

前言

  这篇博文是 uboot makefile构建分析的续篇,继续分析uboot构建u-boot.bin的过程

构建u-boot.bin过程分析

  makefile一开始,就是确定链接脚本。在构建uboot和kernel的过程,链接脚本是非常重要的。它决定了你程序里面每个段的位置(加载位置和运行位置)。在编译应用程序时,我们一般不需要指定链接脚本,因为链接器这时候会采用默认的,通过命令ld --verbose可以查看默认的链接脚本。之所以uboot和kernel不采用默认的,是因为它们有特殊要求,比如要求哪些部分必须放在最前面,哪些部分放在哪个地址上等等。下面看uboot寻找链接脚本的代码(直接将说明插入到代码了):

LDSCRIPT_MAKEFILE_DIR = $(dir $(LDSCRIPT))                                      
                                                                                
ifndef LDSCRIPT  #如果没有指定LDSCRIPT                                                               
    #LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug                   
    ifdef CONFIG_SYS_LDSCRIPT #如果指定了CONFIG_SYS_LDSCRIPT,那么LDSCRIPT就用CONFIG_SYS_LDSCRIPT指定的作为链接脚本
        # need to strip off double quotes                                       
        LDSCRIPT := $(subst ",,$(CONFIG_SYS_LDSCRIPT))                          
    endif                                                                       
endif                                                                           
                                                                                
# If there is no specified link script, we look in a number of places for it    
ifndef LDSCRIPT  #如果还没指定LDSCRIPT(也就是板级没有指定CONFIG_SYS_LDSCRIPT,那么只好根据构建的方式自己采用默认的了
    ifeq ($(CONFIG_NAND_U_BOOT),y) #如果是nand boot模式                                             
        LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds                 
        ifeq ($(wildcard $(LDSCRIPT)),)#如果board/$(BOARDDIR)/u-boot-nand.lds不存在,用$(CPUDIR)/u-boot-nand.lds                                         
            LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds                     
        endif                                                                   
    endif                                                                       
    ifeq ($(wildcard $(LDSCRIPT)),) #如果nand对应的lds文件不存在,用board/$(BOARDDIR)/u-boot.lds                                            
        LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds                      
    endif                                                                       
    ifeq ($(wildcard $(LDSCRIPT)),) #如果对应的lds文件还不存在,用$(CPUDIR)/u-boot.lds                                            
        LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot.lds                              
    endif                                                                       
    ifeq ($(wildcard $(LDSCRIPT)),) ##如果对应的文件还不存在,用arch/$(ARCH)/cpu/u-boot.lds                                            
        LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds                       
        # We don't expect a Makefile here                                       
        LDSCRIPT_MAKEFILE_DIR =                                                 
    endif                                                                       
    ifeq ($(wildcard $(LDSCRIPT)),)                                             
$(error could not find linker script)                                           
    endif                                                                       
endif  

如果板子有自己对应的链接脚本,不需要通用的,那么可以通过配置LDSCRIPT或者CONFIG_SYS_LDSCRIPT来实现。从上一篇博文 uboot makefile构建分析可以知道,该头文件会在执行第二步配置的时候,会被包含到config.h里。下面是我这个uboot版本里有添加这些宏的板子:

$ grep -rns CONFIG_SYS_LDSCRIPT include/
include/configs/actux2.h:27:#define CONFIG_SYS_LDSCRIPT	"board/actux2/u-boot.lds"
include/configs/MPC8569MDS.h:60:#define CONFIG_SYS_LDSCRIPT $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
include/configs/BSC9131RDB.h:45:#define CONFIG_SYS_LDSCRIPT	"arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"
include/configs/actux1.h:27:#define CONFIG_SYS_LDSCRIPT	"board/actux1/u-boot.lds"
include/configs/mpq101.h:168:#define CONFIG_SYS_LDSCRIPT     "board/mercury/mpq101/u-boot.lds"
include/configs/MVBLUE.h:31:#define CONFIG_SYS_LDSCRIPT	"board/mvblue/u-boot.lds"
include/configs/p1_p2_rdb_pc.h:201:#define CONFIG_SYS_LDSCRIPT		"arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"
include/configs/MVSMR.h:22:#define CONFIG_SYS_LDSCRIPT	"board/matrix_vision/mvsmr/u-boot.lds"
include/configs/sh7757lcr.h:21:#define CONFIG_SYS_LDSCRIPT	"board/renesas/sh7757lcr/u-boot.lds"
include/configs/MPC8572DS.h:27:#define CONFIG_SYS_LDSCRIPT $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
include/configs/am335x_evm.h:29:#define CONFIG_SYS_LDSCRIPT		"board/ti/am335x/u-boot.lds"
include/configs/Sandpoint8240.h:27:#define CONFIG_SYS_LDSCRIPT	"board/sandpoint/u-boot.lds"
include/configs/P1023RDS.h:29:#define CONFIG_SYS_LDSCRIPT $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
include/configs/P1022DS.h:40:#define CONFIG_SYS_LDSCRIPT		"arch/powerpc/cpu/mpc85xx/u-boot.lds"
include/configs/P1022DS.h:70:#define CONFIG_SYS_LDSCRIPT	"arch/powerpc/cpu/mpc85xx/u-boot.lds"
include/configs/P1022DS.h:117:#define CONFIG_SYS_LDSCRIPT	"arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"
include/configs/P1010RDB.h:53:#define CONFIG_SYS_LDSCRIPT	"arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"
include/configs/rsdproto.h:27:#define	CONFIG_SYS_LDSCRIPT	"board/rsdproto/u-boot.lds"
include/configs/uc101.h:22:#define CONFIG_SYS_LDSCRIPT	"arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds"
include/configs/MOUSSE.h:37:#define	CONFIG_SYS_LDSCRIPT	"board/mousse/u-boot.lds"
include/configs/actux3.h:27:#define CONFIG_SYS_LDSCRIPT	"board/actux3/u-boot.lds"
include/configs/dvlhost.h:28:#define CONFIG_SYS_LDSCRIPT	"board/dvlhost/u-boot.lds"
include/configs/EVB64260.h:30:#define	CONFIG_SYS_LDSCRIPT	"board/evb64260/u-boot.lds"
include/configs/CATcenter.h:66:#define CONFIG_SYS_LDSCRIPT	"board/dave/PPChameleonEVB/u-boot.lds"
include/configs/PPChameleonEVB.h:66:#define CONFIG_SYS_LDSCRIPT	"board/dave/PPChameleonEVB/u-boot.lds"
include/configs/MPC8536DS.h:27:#define CONFIG_SYS_LDSCRIPT $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
include/configs/inka4x0.h:31:#define CONFIG_SYS_LDSCRIPT	"arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds"
include/configs/BSC9132QDS.h:54:#define CONFIG_SYS_LDSCRIPT	"arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"
include/configs/sh7752evb.h:20:#define CONFIG_SYS_LDSCRIPT	"board/renesas/sh7752evb/u-boot.lds"
include/configs/P1_P2_RDB.h:41:#define CONFIG_SYS_LDSCRIPT $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
include/configs/Sandpoint8245.h:27:#define CONFIG_SYS_LDSCRIPT	"board/sandpoint/u-boot.lds"

我这里假设板级没有指定LDSCRIPT或者CONFIG_SYS_LDSCRIPT,也不是nand boot模式,board/$(BOARDDIR)和$(CPUDIR)/u-boot.lds下也没有lds文件,那么就用arch/$(ARCH)/cpu/u-boot.lds了(即arch/arm/cpu/u-boot.lds),因为该文件默认就存在。

下面看all目标,因为该目标而导致最终的u-boot.bin被构建出来

# Always append ALL so that arch config.mk's can add custom ones                
ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map 

all:        $(ALL-y) $(SUBDIR_EXAMPLES)  

从上面可知,首先构建u-boot.srec,然后是u-boot.bin,下面重点看u-boot.bin的构建过程,至于u-boot.srec(u-boot.srec是Motorola S-Record格式的image文件,我是从来没用过)和System.map(该文件按链接地址由小到大的顺序列出了所有符号,一般用于调试),就忽略吧,u-boot.bin的规则如下:

$(obj)u-boot.bin:   $(obj)u-boot                                                
        $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@                                 
        $(BOARD_SIZE_CHECK)   

依赖u-boot,于是看u-boot

$(obj)u-boot:   depend                                                         
        $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
        $(GEN_UBOOT)                                                            
ifeq ($(CONFIG_KALLSYMS),y)                                                     
        smap=`$(call SYSTEM_MAP,$(obj)u-boot) |                                
            awk '$$2 ~ /[tTwW]/ {printf $$1 $$3 "\\000"}'` ;                 
        $(CC) $(CFLAGS) -DSYSTEM_MAP=""$${smap}""                            
            -c common/system_map.c -o $(obj)common/system_map.o                 
        $(GEN_UBOOT) $(obj)common/system_map.o                                  
endif 

u-boot依赖一堆,它也是uboot构建主要要做的事情。从这里我们可以知道uboot的构建就是先构建u-boot,然后再生成u-boot.bin。下面继续看u-boot的每一个依赖吧

第一个依赖depend

depend dep: $(TIMESTAMP_FILE) $(VERSION_FILE)                                  
        $(obj)include/spl-autoconf.mk                                          
        $(obj)include/tpl-autoconf.mk                                          
        $(obj)include/autoconf.mk                                              
        $(obj)include/generated/generic-asm-offsets.h                          
        $(obj)include/generated/asm-offsets.h                                   
        for dir in $(SUBDIRS) $(CPUDIR) $(LDSCRIPT_MAKEFILE_DIR) ; do          
            $(MAKE) -C $$dir _depend ; done 

忽略分析它的依赖吧,大部分在执行第二步配置的时候生成的。还一些文件是用于辅佐构建的。直接看命令部分,其中

ifeq ($(wildcard $(LDSCRIPT)),)                                             
        LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds                       
        # We don't expect a Makefile here                                       
        LDSCRIPT_MAKEFILE_DIR =                                                 
endif 
LDSCRIPT_MAKEFILE_DIR = $(dir $(LDSCRIPT))

SUBDIRS = $(SUBDIR_TOOLS)
ifndef CONFIG_SANDBOX                                                           
SUBDIRS += $(SUBDIR_EXAMPLES)                                                   
endif

CPUDIR=arch/$(ARCH)/cpu/$(CPU)

因此,depend会去这些目录(也就是目录tools [examples/standalone、examples/api] arch/arm/cpu/armv7/)执行_depend目标

第二个依赖SUBDIR_TOOLS

SUBDIR_TOOLS = tools
SUBDIR_EXAMPLES = examples/standalone examples/api                              
SUBDIRS = $(SUBDIR_TOOLS)
ifndef CONFIG_SANDBOX                                                           
SUBDIRS += $(SUBDIR_EXAMPLES)                                                   
endif
$(SUBDIRS): depend                                                              
        $(MAKE) -C $@ all

去tools目录下执行all目标。之所以要这么早构建tools下的程序,是因为后面的构建过程会用到它们。

第三个依赖OBJS

$(OBJS):    depend                                                              
        $(MAKE) -C $(CPUDIR) $(if $(REMOTE_BUILD),$@,$(notdir $@)) 

开始执行OBJS里面指定的文件了

OBJS  = $(CPUDIR)/start.o                                                       
ifeq ($(CPU),ppc4xx)                                                            
OBJS += $(CPUDIR)/resetvec.o                                                    
endif                                                                           
ifeq ($(CPU),mpc85xx)                                                           
OBJS += $(CPUDIR)/resetvec.o                                                    
endif                                                                           
                                                                                
OBJS := $(addprefix $(obj),$(OBJS))  

其实就是构建arch/arm/cpu/armv7/start.o(当然是根据arch/arm/cpu/armv7/start.S啦)

第四个依赖LIBBOARD

$(LIBBOARD):    depend $(LIBS)                                                  
        $(MAKE) -C $(dir $(subst $(obj),,$@))  

开始执行LIBBOARD里指定的文件了。注意,它依赖LIBS,也就是说第五个依赖会先执行。

BOARD  = zynq                                                                   
VENDOR = xilinx 

ifdef   VENDOR                                                                  
BOARDDIR = $(VENDOR)/$(BOARD)                                                   
else                                                                            
BOARDDIR = $(BOARD)                                                             
endif  

LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).o                                      
LIBBOARD := $(addprefix $(obj),$(LIBBOARD))

最终就是构建board/$(BOARDDIR)/下的默认目标,我这里就是board/xilinx/zynq/Makefile,对应的它里面的规则:

LIB = $(obj)lib$(BOARD).o                                                       
                                                                                
COBJS-y := board.o                                                              
                                                                                
# Added by MYIR for MYS-XC7Z010                                                 
COBJS-y += myir_init.o                                                          
                                                                                
COBJS   := $(sort $(COBJS-y))                                                   
                                                                                
SRCS    := $(COBJS:.o=.c)                                                       
OBJS    := $(addprefix $(obj),$(COBJS)) 

$(LIB): $(obj).depend $(OBJS)                                                   
    $(call cmd_link_o_target, $(OBJS)) 

第五个依赖LIBS

$(LIBS):    depend $(SUBDIR_TOOLS)                                              
        $(MAKE) -C $(dir $(subst $(obj),,$@)) 

开始执行LIBS里指定的文件了,到这一步,它的依赖在前面都执行完了,直接看LIBS有哪些吧!

LIBS-y += lib/libgeneric.o                                                      
LIBS-y += lib/rsa/librsa.o                                                      
LIBS-y += lib/lzma/liblzma.o                                                    
LIBS-y += lib/lzo/liblzo.o                                                      
LIBS-y += lib/zlib/libz.o                                                       
LIBS-$(CONFIG_TIZEN) += lib/tizen/libtizen.o                                    
LIBS-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/lib$(VENDOR).o         
LIBS-y += $(CPUDIR)/lib$(CPU).o                                                 
ifdef SOC                                                                       
LIBS-y += $(CPUDIR)/$(SOC)/lib$(SOC).o                                          
endif                                                                           
ifeq ($(CPU),ixp)                                                               
LIBS-y += drivers/net/npe/libnpe.o                                              
endif                                                                           
LIBS-$(CONFIG_OF_EMBED) += dts/libdts.o                                         
LIBS-y += arch/$(ARCH)/lib/lib$(ARCH).o                                         
LIBS-y += fs/libfs.o                                                           
    fs/cbfs/libcbfs.o                                                          
    fs/cramfs/libcramfs.o                                                      
    fs/ext4/libext4fs.o                                                        
    fs/fat/libfat.o                                                            
    fs/fdos/libfdos.o                                                          
    fs/jffs2/libjffs2.o                                                        
    fs/reiserfs/libreiserfs.o                                                  
    fs/sandbox/libsandboxfs.o                                                  
    fs/ubifs/libubifs.o                                                        
    fs/yaffs2/libyaffs2.o                                                      
    fs/zfs/libzfs.o                                                             
LIBS-y += net/libnet.o                                                          
LIBS-y += disk/libdisk.o                                                        
LIBS-y += drivers/bios_emulator/libatibiosemu.o                                 
LIBS-y += drivers/block/libblock.o                                              
LIBS-$(CONFIG_BOOTCOUNT_LIMIT) += drivers/bootcount/libbootcount.o              
LIBS-y += drivers/crypto/libcrypto.o                                            
LIBS-y += drivers/dma/libdma.o                                                  
LIBS-y += drivers/fpga/libfpga.o  
LIBS-y += drivers/gpio/libgpio.o                                                
LIBS-y += drivers/hwmon/libhwmon.o                                              
LIBS-y += drivers/i2c/libi2c.o                                                  
LIBS-y += drivers/input/libinput.o                                              
LIBS-y += drivers/misc/libmisc.o                                                
LIBS-y += drivers/mmc/libmmc.o                                                  
LIBS-y += drivers/mtd/libmtd.o                                                  
LIBS-y += drivers/mtd/nand/libnand.o                                            
LIBS-y += drivers/mtd/onenand/libonenand.o                                      
LIBS-y += drivers/mtd/ubi/libubi.o                                              
LIBS-y += drivers/mtd/spi/libspi_flash.o                                        
LIBS-y += drivers/net/libnet.o                                                  
LIBS-y += drivers/net/phy/libphy.o                                              
LIBS-y += drivers/pci/libpci.o                                                  
LIBS-y += drivers/pcmcia/libpcmcia.o                                            
LIBS-y += drivers/power/libpower.o                                             
    drivers/power/fuel_gauge/libfuel_gauge.o                                   
    drivers/power/mfd/libmfd.o                                                 
    drivers/power/pmic/libpmic.o                                               
    drivers/power/battery/libbattery.o                                          
LIBS-y += drivers/spi/libspi.o                                                  
LIBS-y += drivers/dfu/libdfu.o                                                  
ifeq ($(CPU),mpc83xx)                                                           
LIBS-y += drivers/qe/libqe.o                                                    
LIBS-y += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o                                 
LIBS-y += arch/powerpc/cpu/mpc8xxx/lib8xxx.o                                    
endif                                                                           
ifeq ($(CPU),mpc85xx)                                                           
LIBS-y += drivers/qe/libqe.o                                                    
LIBS-y += drivers/net/fm/libfm.o         
LIBS-y += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o                                 
LIBS-y += arch/powerpc/cpu/mpc8xxx/lib8xxx.o                                    
endif                                                                           
ifeq ($(CPU),mpc86xx)                                                           
LIBS-y += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o                                 
LIBS-y += arch/powerpc/cpu/mpc8xxx/lib8xxx.o                                    
endif                                                                           
LIBS-y += drivers/rtc/librtc.o                                                  
LIBS-y += drivers/serial/libserial.o                                            
LIBS-y += drivers/sound/libsound.o                                              
LIBS-y += drivers/tpm/libtpm.o                                                  
LIBS-y += drivers/twserial/libtws.o                                             
LIBS-y += drivers/usb/eth/libusb_eth.o                                          
LIBS-y += drivers/usb/gadget/libusb_gadget.o                                    
LIBS-y += drivers/usb/host/libusb_host.o                                        
LIBS-y += drivers/usb/musb/libusb_musb.o                                        
LIBS-y += drivers/usb/musb-new/libusb_musb-new.o                                
LIBS-y += drivers/usb/phy/libusb_phy.o                                          
LIBS-y += drivers/usb/ulpi/libusb_ulpi.o                                        
LIBS-y += drivers/video/libvideo.o                                              
LIBS-y += drivers/watchdog/libwatchdog.o                                        
LIBS-y += common/libcommon.o                                                    
LIBS-y += lib/libfdt/libfdt.o                                                   
LIBS-y += api/libapi.o                                                          
LIBS-y += post/libpost.o                                                        
LIBS-y += test/libtest.o                                                        
                                                                                
ifneq ($(CONFIG_OMAP_COMMON),)                                                  
LIBS-y += $(CPUDIR)/omap-common/libomap-common.o                                
endif                                                                           
                                                                                
ifneq (,$(filter $(SOC), mx25 mx27 mx5 mx6 mx31 mx35 mxs vf610))                
LIBS-y += arch/$(ARCH)/imx-common/libimx-common.o                               
endif            
                                                                                
ifeq ($(SOC),s5pc1xx)                                                           
LIBS-y += $(CPUDIR)/s5p-common/libs5p-common.o                                  
endif                                                                           
ifeq ($(SOC),exynos)                                                            
LIBS-y += $(CPUDIR)/s5p-common/libs5p-common.o                                  
endif                                                                           
ifneq ($(CONFIG_TEGRA),)                                                        
LIBS-y += arch/$(ARCH)/cpu/$(SOC)-common/lib$(SOC)-common.o                     
LIBS-y += arch/$(ARCH)/cpu/tegra-common/libcputegra-common.o                    
LIBS-y += $(CPUDIR)/tegra-common/libtegra-common.o                              
endif                                                                           
                                                                                
LIBS := $(addprefix $(obj),$(sort $(LIBS-y)))                                   
.PHONY : $(LIBS)                                        

看到它,大概也猜到了,大部分文件的编译都在这。

第六个依赖LDSCRIPT

$(LDSCRIPT):    depend                                                          
        $(MAKE) -C $(dir $@) $(notdir $@)

LDSCRIPT在寻找链接脚本时,我这里的LDSCRIPT已经假设为arch/$(ARCH)/cpu/u-boot.lds了(即arch/arm/cpu/u-boot.lds)。它的命令就是去arch/arm/cpu下执行u-boot.lds目标啦,但是我发现那目录下根本没有makefile!

第七个依赖u-boot.lds

$(obj)u-boot.lds: $(LDSCRIPT)                                                   
        $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$< >$@ 

对应我这里的命令:

arm-xilinx-linux-gnueabi-gcc -E -g  -Os   -ffunction-sections -fdata-sections -fno-common -ffixed-r8 -msoft-float  -fno-strict-aliasing -mno-unaligned-access -D__KERNEL__ -DCONFIG_SYS_TEXT_BASE=0x04000000 -I/home/rongp/company/zynq/Bootloader/u-boot-xlnx/include -fno-builtin -ffreestanding -nostdinc -isystem /home/rongp/company/zynq/Toolchain/CodeSourcery/Sourcery_CodeBench_Lite_for_Xilinx_GNU_Linux/bin/../lib/gcc/arm-xilinx-linux-gnueabi/4.6.1/include -pipe  -DCONFIG_ARM -D__ARM__ -marm -mno-thumb-interwork -mabi=aapcs-linux -mword-relocations -march=armv7-a -include /home/rongp/company/zynq/Bootloader/u-boot-xlnx/include/u-boot/u-boot.lds.h -DCPUDIR=arch/arm/cpu/armv7  -ansi -D__ASSEMBLY__ -P - </home/rongp/company/zynq/Bootloader/u-boot-xlnx/arch/arm/cpu/u-boot.lds >u-boot.lds

分析完依赖

$(obj)u-boot:   depend                                                         
        $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
        $(GEN_UBOOT) 

,下面继续看u-boot对应的命令部分

        $(GEN_UBOOT)                                                                                                                          
ifeq ($(CONFIG_KALLSYMS),y)  #这部分部分析,忽略                                                   
        smap=`$(call SYSTEM_MAP,$(obj)u-boot) |                                
            awk '$$2 ~ /[tTwW]/ {printf $$1 $$3 "\\000"}'` ;                 
        $(CC) $(CFLAGS) -DSYSTEM_MAP=""$${smap}""                            
            -c common/system_map.c -o $(obj)common/system_map.o                 
        $(GEN_UBOOT) $(obj)common/system_map.o                                  
endif 

其中GEN_UBOOT定义如下:

ifeq ($(CONFIG_SANDBOX),y)                                                      
GEN_UBOOT =                                                                    
        cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds                       
            -Wl,--start-group $(__LIBS) -Wl,--end-group                        
            $(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map -o u-boot                  
else                                                                            
GEN_UBOOT =                                                                    
        cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F))                       
            $(__OBJS)                                                          
            --start-group $(__LIBS) --end-group $(PLATFORM_LIBS)               
            -Map u-boot.map -o u-boot                                           
endif  

对应我这里的命令:

cd /home/rongp/company/zynq/Bootloader/u-boot-xlnx && arm-xilinx-linux-gnueabi-ld  -pie -T u-boot.lds --gc-sections -Bstatic -Ttext 0x04000000 arch/arm/cpu/armv7/start.o --start-group api/libapi.o arch/arm/cpu/armv7/libarmv7.o arch/arm/cpu/armv7/zynq/libzynq.o arch/arm/lib/libarm.o common/libcommon.o disk/libdisk.o drivers/bios_emulator/libatibiosemu.o drivers/block/libblock.o drivers/crypto/libcrypto.o drivers/dfu/libdfu.o drivers/dma/libdma.o drivers/fpga/libfpga.o drivers/gpio/libgpio.o drivers/hwmon/libhwmon.o drivers/i2c/libi2c.o drivers/input/libinput.o drivers/misc/libmisc.o drivers/mmc/libmmc.o drivers/mtd/libmtd.o drivers/mtd/nand/libnand.o drivers/mtd/onenand/libonenand.o drivers/mtd/spi/libspi_flash.o drivers/mtd/ubi/libubi.o drivers/net/libnet.o drivers/net/phy/libphy.o drivers/pci/libpci.o drivers/pcmcia/libpcmcia.o drivers/power/battery/libbattery.o drivers/power/fuel_gauge/libfuel_gauge.o drivers/power/libpower.o drivers/power/mfd/libmfd.o drivers/power/pmic/libpmic.o drivers/rtc/librtc.o drivers/serial/libserial.o drivers/sound/libsound.o drivers/spi/libspi.o drivers/tpm/libtpm.o drivers/twserial/libtws.o drivers/usb/eth/libusb_eth.o drivers/usb/gadget/libusb_gadget.o drivers/usb/host/libusb_host.o drivers/usb/musb-new/libusb_musb-new.o drivers/usb/musb/libusb_musb.o drivers/usb/phy/libusb_phy.o drivers/usb/ulpi/libusb_ulpi.o drivers/video/libvideo.o drivers/watchdog/libwatchdog.o fs/cbfs/libcbfs.o fs/cramfs/libcramfs.o fs/ext4/libext4fs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o fs/libfs.o fs/reiserfs/libreiserfs.o fs/sandbox/libsandboxfs.o fs/ubifs/libubifs.o fs/yaffs2/libyaffs2.o fs/zfs/libzfs.o lib/libfdt/libfdt.o lib/libgeneric.o lib/lzma/liblzma.o lib/lzo/liblzo.o lib/rsa/librsa.o lib/zlib/libz.o net/libnet.o post/libpost.o test/libtest.o board/xilinx/zynq/libzynq.o --end-group /home/rongp/company/zynq/Bootloader/u-boot-xlnx/arch/arm/lib/eabi_compat.o  -L /home/rongp/company/zynq/Toolchain/CodeSourcery/Sourcery_CodeBench_Lite_for_Xilinx_GNU_Linux/bin/../lib/gcc/arm-xilinx-linux-gnueabi/4.6.1 -lgcc -Map u-boot.map -o u-boot

u-boot是ELF格式二进制的image文件,u-boot.bin是原始的二进制image文件。构建完u-boot,接着就是构建uboot.bin了:

$(obj)u-boot.bin:   $(obj)u-boot                                                
        $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@                                 
        $(BOARD_SIZE_CHECK)   

对应我这里的命令:

arm-xilinx-linux-gnueabi-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin

all目标还会构建SUBDIR_EXAMPLES,它对应的规则:

ifndef CONFIG_SANDBOX                                                           
SUBDIRS += $(SUBDIR_EXAMPLES)                                                   
endif  

$(SUBDIRS): depend                                                              
        $(MAKE) -C $@ all

链接脚本分析

最后再分析下链接脚本吧!先贴出我这里使用到的arch/arm/cpu/u-boot.lds(说明直接嵌入到脚本中):

/*
 * Copyright (c) 2004-2008 Texas Instruments
 *
 * (C) Copyright 2002
 * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")//三个分别指定在缺省、大端、小端情况下的输出可执行文件格式,这里都指定输出格式是elf32,小端和arm体系结构
OUTPUT_ARCH(arm)//输出可执行文件指定为arm体系结构
ENTRY(_start)//指定_start函数为程序的入口。_start在每个CPU目录下的start.S中定义,真正的启动运行地址段由CONFIG_SYS_TEXT_BASE宏定义在编译时由config.mk中定义
SECTIONS //每个链接脚本都会有一个SECTIONS,它里面会有很多section用于描述每个段最终存放到输出文件的位置。The SECTIONS command tells the linker how to map input sections into output sections, and how to place the output sections in memory.
{
	. = 0x00000000;//指定定位器符号为0,定系统启动从偏移地址零处开始。
//注意这只是个代码地址偏移值,真正的起始地址是由编译时指定的LDFLAGS_XXX指定的

	. = ALIGN(4);//4字节对齐
	.text ://这里指定所有文件的.__image_copy_start以及CPUDIR/start.o的.text*以及所有其他文件的.text*都放到.text段
	{
		*(.__image_copy_start)//u-boot将自己copy到RAM,此为需要copy的程序的start,参考arch/arm/lib/sections.c和arch/arm/lib/relocate.S
		CPUDIR/start.o (.text*)//对应到我这里,就是arch/arm/cpu/armv7/start.o文件啦
		*(.text*)//其他所有文件的.text*
	}

	. = ALIGN(4);//修改当前定位寄存器,保持4字节对齐
	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }//指定所有文件的.rodata*放到.rodata段,
//放置前先用SORT_BY_NAME排序,然后用SORT_BY_ALIGNMENT做排序,SORT_BY_ALIGNMENT会根据对齐的
//特性进行降序排序,The difference is SORT_BY_ALIGNMENT will sort sections into descending order by alignment 
//before placing them in the output file. Larger alignments are placed before 
//smaller alignments in order to reduce the amount of padding necessary. 
//在代码段之后,存放read only数据段

	. = ALIGN(4);//修改当前定位寄存器,保持4字节对齐
	.data : {//所有文件的.data*放到.data段
		*(.data*)
	}

	. = ALIGN(4);//修改当前定位寄存器,保持4字节对齐

	. = .;//???

	. = ALIGN(4);//修改当前定位寄存器,保持4字节对齐
	.u_boot_list : {//所有文件的.u_boot_list*放到.u_boot_list段,且先通过SORT对
//所有.u_boot_list*排序然后通过KEEP告诉连接器,这个段很重要,不要优化掉了哈。
//.data段结束后,紧接着存放u-boot自有的一些function,例如u-boot command等
		KEEP(*(SORT(.u_boot_list*)));
	}

	. = ALIGN(4);//修改当前定位寄存器,保持4字节对齐

	.image_copy_end ://同__image_copy_start,参考arch/arm/lib/sections.c和
//arch/arm/lib/relocate.S,里面有注解。
//至此,u-boot需要自拷贝的内容结束,总结一下,包括代码段,数据段,以及u_boot_list
	{
		*(.__image_copy_end)
	}

	.rel_dyn_start ://用于用于动态连接的重定位信息的start,参考arch/arm/lib/sections.c ,里面有注解。
//在老的uboot中,如果我们想要uboot启动后把自己拷贝到内存中的某个地方,只要把要拷贝的地址写给TEXT_BASE即可,
//然后boot启动后就会把自己拷贝到TEXT_BASE内的地址处运行,在拷贝之前的代码都是相对的,不能出现绝对的跳转,否则会跑飞。
//在新版的uboot里(2013.07),TEXT_BASE的含义改变了。它表示用户要把这段代码加载到哪里,通常是通过串口等工具。
//然后搬移的时候由uboot自己计算一个地址来进行搬移。
//新版的uboot采用了动态链接技术,在lds文件中有__rel_dyn_start和__rel_dyn_end,这两个符号之间
//的区域存放着动态链接符号,只要给这里面的符号加上一定的偏移,拷贝到内存中代码的后面相应的
//位置处,就可以在绝对跳转中找到正确的函数。*/

	{
		*(.__rel_dyn_start)
	}

	.rel.dyn : {//动态链接符存放在的段
		*(.rel*)
	}

	.rel_dyn_end ://动态链接符段结束,参考arch/arm/lib/sections.c ,里面有注解
	{
		*(.__rel_dyn_end)
	}

	_end = .;//设置_end的地址为当前定位器,board_f.c里会使用它来计算

	/*
	 * Deprecated: this MMU section is used by pxa at present but
	 * should not be used by new boards/CPUs.
	 */
	. = ALIGN(4096);
	.mmutable : {
		*(.mmutable)
	}

/*
 * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c
 * __bss_base and __bss_limit are for linker only (overlay ordering)
 */

	.bss_start __rel_dyn_start (OVERLAY) : {//参考arch/arm/lib/sections.c ,里面有注解
		KEEP(*(.__bss_start));//
		__bss_base = .;
	}

	.bss __bss_base (OVERLAY) : {//未初始化段,存放程序中未初始化的全局变量和静态变量的一块内存区域
		*(.bss*)
		 . = ALIGN(4);
		 __bss_limit = .;
	}

	.bss_end __bss_limit (OVERLAY) : {//参考arch/arm/lib/sections.c ,里面有注解
		KEEP(*(.__bss_end));
	}

	/DISCARD/ : { *(.dynsym) }
	/DISCARD/ : { *(.dynstr*) }
	/DISCARD/ : { *(.dynamic*) }
	/DISCARD/ : { *(.plt*) }
	/DISCARD/ : { *(.interp*) }
	/DISCARD/ : { *(.gnu*) }
	/DISCARD/ : { *(.ARM.exidx*) }
	/DISCARD/ : { *(.gnu.linkonce.armexidx.*) }
}

在config.mk中:

ifneq ($(CONFIG_SYS_TEXT_BASE),)                                                
LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE)                                
endif       

在生成elf可执行文件u-boot的命令中就指定了链接标志LDFLAGS

ifeq ($(CONFIG_SANDBOX),y)                                                      
GEN_UBOOT =                                                                    
        cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds                       
            -Wl,--start-group $(__LIBS) -Wl,--end-group                        
            $(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map -o u-boot                  
else                                                                            
GEN_UBOOT =                                                                    
        cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F))                       
            $(__OBJS)                                                          
            --start-group $(__LIBS) --end-group $(PLATFORM_LIBS)               
            -Map u-boot.map -o u-boot                                           
endif  

这说明只需要定义CONFIG_SYS_TEXT_BASE,编译的时候就会去设置text段的base地址。至于在哪里设置,相信大家可以猜到了,当然是板级相关的头文件啦,并且在执行第二步配置的时候会被处理,放到config.mk里去。另外需要说明一下,$(@F)表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那么"$(@F)"就是"foo.o","$(@F)"相当于函数"$(notdir $@)",对应到这里,
$(LDFLAGS_$(@F))就是LDFLAGS_u-boot啦,因为我们的目标为$(obj)u-boot

另外,关于OVERLAY。每一个输出节可以有一个类型。类型是一个放在括号中的关键字,已定义的类型如下所示:
NOLOAD' 这个节应当被标式讵不可载入,所以当程序运行时,它不会被载入到内存中。 DSECT'
COPY' INFO'
`OVERLAY'
支持这些类型名只是为了向下兼容,它们很少使用。它们都具有相同的效果:这个节应当被标式讵不可分配,所以当程序运行时,没有内存为这个节分配。

补充1:

标准应用程序包括 3 类标准段空间:.text 运行代段;.data 全局变量等具有初始值的数据空间;.bss暂态变量,堆栈等数据空间;

补充2:

.rodata,.u_boot_list.image_copy_end 等段空间由程序员设计需要而自行定义的段空间;

总的来说,uboot的链接脚本还是很简单的。

总结

  构建u-boot.bin,会先在tools [examples/standalone、examples/api] arch/arm/cpu/armv7/目录下构建_depend目标,然后去tools下构建all目标,再然后构建arch/arm/cpu/armv7/start.o,然后执行LIBS构建(LIBS由lib/ fs/ drivers/ common/ api/ post/ test/ arch/arm/cpu/armv7/ arch/arm/cpu/armv7/zynq/ arch/arm/lib/ disk/ net/下的部分文件构成),然后构建board/xilinx/zynq/Makefile下的默认目标,以及$(obj)u-boot.lds,最后基于以上构建的来构建u-boot以及u-boot.bin。当然,不同的板子,构建过程多少会有些差异,不过大体思想是一样的。本文如果有错误的地方,欢迎大家指出!

完!
2016年7月

原文地址:https://www.cnblogs.com/rongpmcu/p/7662794.html