前言

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

构建u-boot.bin过程分析

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

  1. LDSCRIPT_MAKEFILE_DIR = $(dir $(LDSCRIPT))
  2. ifndef LDSCRIPT #如果没有指定LDSCRIPT
  3. #LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug
  4. ifdef CONFIG_SYS_LDSCRIPT #如果指定了CONFIG_SYS_LDSCRIPT,那么LDSCRIPT就用CONFIG_SYS_LDSCRIPT指定的作为链接脚本
  5. # need to strip off double quotes
  6. LDSCRIPT := $(subst ",,$(CONFIG_SYS_LDSCRIPT))
  7. endif
  8. endif
  9. # If there is no specified link script, we look in a number of places for it
  10. ifndef LDSCRIPT #如果还没指定LDSCRIPT(也就是板级没有指定CONFIG_SYS_LDSCRIPT,那么只好根据构建的方式自己采用默认的了
  11. ifeq ($(CONFIG_NAND_U_BOOT),y) #如果是nand boot模式
  12. LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
  13. ifeq ($(wildcard $(LDSCRIPT)),)#如果board/$(BOARDDIR)/u-boot-nand.lds不存在,用$(CPUDIR)/u-boot-nand.lds
  14. LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
  15. endif
  16. endif
  17. ifeq ($(wildcard $(LDSCRIPT)),) #如果nand对应的lds文件不存在,用board/$(BOARDDIR)/u-boot.lds
  18. LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
  19. endif
  20. ifeq ($(wildcard $(LDSCRIPT)),) #如果对应的lds文件还不存在,用$(CPUDIR)/u-boot.lds
  21. LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot.lds
  22. endif
  23. ifeq ($(wildcard $(LDSCRIPT)),) ##如果对应的文件还不存在,用arch/$(ARCH)/cpu/u-boot.lds
  24. LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds
  25. # We don't expect a Makefile here
  26. LDSCRIPT_MAKEFILE_DIR =
  27. endif
  28. ifeq ($(wildcard $(LDSCRIPT)),)
  29. $(error could not find linker script)
  30. endif
  31. endif

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

  1. $ grep -rns CONFIG_SYS_LDSCRIPT include/
  2. include/configs/actux2.h:27:#define CONFIG_SYS_LDSCRIPT "board/actux2/u-boot.lds"
  3. include/configs/MPC8569MDS.h:60:#define CONFIG_SYS_LDSCRIPT $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
  4. include/configs/BSC9131RDB.h:45:#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"
  5. include/configs/actux1.h:27:#define CONFIG_SYS_LDSCRIPT "board/actux1/u-boot.lds"
  6. include/configs/mpq101.h:168:#define CONFIG_SYS_LDSCRIPT "board/mercury/mpq101/u-boot.lds"
  7. include/configs/MVBLUE.h:31:#define CONFIG_SYS_LDSCRIPT "board/mvblue/u-boot.lds"
  8. include/configs/p1_p2_rdb_pc.h:201:#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"
  9. include/configs/MVSMR.h:22:#define CONFIG_SYS_LDSCRIPT "board/matrix_vision/mvsmr/u-boot.lds"
  10. include/configs/sh7757lcr.h:21:#define CONFIG_SYS_LDSCRIPT "board/renesas/sh7757lcr/u-boot.lds"
  11. include/configs/MPC8572DS.h:27:#define CONFIG_SYS_LDSCRIPT $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
  12. include/configs/am335x_evm.h:29:#define CONFIG_SYS_LDSCRIPT "board/ti/am335x/u-boot.lds"
  13. include/configs/Sandpoint8240.h:27:#define CONFIG_SYS_LDSCRIPT "board/sandpoint/u-boot.lds"
  14. include/configs/P1023RDS.h:29:#define CONFIG_SYS_LDSCRIPT $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
  15. include/configs/P1022DS.h:40:#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc85xx/u-boot.lds"
  16. include/configs/P1022DS.h:70:#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc85xx/u-boot.lds"
  17. include/configs/P1022DS.h:117:#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"
  18. include/configs/P1010RDB.h:53:#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"
  19. include/configs/rsdproto.h:27:#define CONFIG_SYS_LDSCRIPT "board/rsdproto/u-boot.lds"
  20. include/configs/uc101.h:22:#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds"
  21. include/configs/MOUSSE.h:37:#define CONFIG_SYS_LDSCRIPT "board/mousse/u-boot.lds"
  22. include/configs/actux3.h:27:#define CONFIG_SYS_LDSCRIPT "board/actux3/u-boot.lds"
  23. include/configs/dvlhost.h:28:#define CONFIG_SYS_LDSCRIPT "board/dvlhost/u-boot.lds"
  24. include/configs/EVB64260.h:30:#define CONFIG_SYS_LDSCRIPT "board/evb64260/u-boot.lds"
  25. include/configs/CATcenter.h:66:#define CONFIG_SYS_LDSCRIPT "board/dave/PPChameleonEVB/u-boot.lds"
  26. include/configs/PPChameleonEVB.h:66:#define CONFIG_SYS_LDSCRIPT "board/dave/PPChameleonEVB/u-boot.lds"
  27. include/configs/MPC8536DS.h:27:#define CONFIG_SYS_LDSCRIPT $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
  28. include/configs/inka4x0.h:31:#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc5xxx/u-boot-customlayout.lds"
  29. include/configs/BSC9132QDS.h:54:#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc85xx/u-boot-nand.lds"
  30. include/configs/sh7752evb.h:20:#define CONFIG_SYS_LDSCRIPT "board/renesas/sh7752evb/u-boot.lds"
  31. include/configs/P1_P2_RDB.h:41:#define CONFIG_SYS_LDSCRIPT $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
  32. 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被构建出来

  1. # Always append ALL so that arch config.mk's can add custom ones
  2. ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map
  3. 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的规则如下:

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

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

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

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

第一个依赖depend

  1. depend dep: $(TIMESTAMP_FILE) $(VERSION_FILE) \
  2. $(obj)include/spl-autoconf.mk \
  3. $(obj)include/tpl-autoconf.mk \
  4. $(obj)include/autoconf.mk \
  5. $(obj)include/generated/generic-asm-offsets.h \
  6. $(obj)include/generated/asm-offsets.h
  7. for dir in $(SUBDIRS) $(CPUDIR) $(LDSCRIPT_MAKEFILE_DIR) ; do \
  8. $(MAKE) -C $$dir _depend ; done

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

  1. ifeq ($(wildcard $(LDSCRIPT)),)
  2. LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds
  3. # We don't expect a Makefile here
  4. LDSCRIPT_MAKEFILE_DIR =
  5. endif
  6. LDSCRIPT_MAKEFILE_DIR = $(dir $(LDSCRIPT))
  7. SUBDIRS = $(SUBDIR_TOOLS)
  8. ifndef CONFIG_SANDBOX
  9. SUBDIRS += $(SUBDIR_EXAMPLES)
  10. endif
  11. CPUDIR=arch/$(ARCH)/cpu/$(CPU)

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

第二个依赖SUBDIR_TOOLS

  1. SUBDIR_TOOLS = tools
  2. SUBDIR_EXAMPLES = examples/standalone examples/api
  3. SUBDIRS = $(SUBDIR_TOOLS)
  4. ifndef CONFIG_SANDBOX
  5. SUBDIRS += $(SUBDIR_EXAMPLES)
  6. endif
  7. $(SUBDIRS): depend
  8. $(MAKE) -C $@ all

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

第三个依赖OBJS

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

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

  1. OBJS = $(CPUDIR)/start.o
  2. ifeq ($(CPU),ppc4xx)
  3. OBJS += $(CPUDIR)/resetvec.o
  4. endif
  5. ifeq ($(CPU),mpc85xx)
  6. OBJS += $(CPUDIR)/resetvec.o
  7. endif
  8. OBJS := $(addprefix $(obj),$(OBJS))

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

第四个依赖LIBBOARD

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

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

  1. BOARD = zynq
  2. VENDOR = xilinx
  3. ifdef VENDOR
  4. BOARDDIR = $(VENDOR)/$(BOARD)
  5. else
  6. BOARDDIR = $(BOARD)
  7. endif
  8. LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).o
  9. LIBBOARD := $(addprefix $(obj),$(LIBBOARD))

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

  1. LIB = $(obj)lib$(BOARD).o
  2. COBJS-y := board.o
  3. # Added by MYIR for MYS-XC7Z010
  4. COBJS-y += myir_init.o
  5. COBJS := $(sort $(COBJS-y))
  6. SRCS := $(COBJS:.o=.c)
  7. OBJS := $(addprefix $(obj),$(COBJS))
  8. $(LIB): $(obj).depend $(OBJS)
  9. $(call cmd_link_o_target, $(OBJS))

第五个依赖LIBS

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

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

  1. LIBS-y += lib/libgeneric.o
  2. LIBS-y += lib/rsa/librsa.o
  3. LIBS-y += lib/lzma/liblzma.o
  4. LIBS-y += lib/lzo/liblzo.o
  5. LIBS-y += lib/zlib/libz.o
  6. LIBS-$(CONFIG_TIZEN) += lib/tizen/libtizen.o
  7. LIBS-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/lib$(VENDOR).o
  8. LIBS-y += $(CPUDIR)/lib$(CPU).o
  9. ifdef SOC
  10. LIBS-y += $(CPUDIR)/$(SOC)/lib$(SOC).o
  11. endif
  12. ifeq ($(CPU),ixp)
  13. LIBS-y += drivers/net/npe/libnpe.o
  14. endif
  15. LIBS-$(CONFIG_OF_EMBED) += dts/libdts.o
  16. LIBS-y += arch/$(ARCH)/lib/lib$(ARCH).o
  17. LIBS-y += fs/libfs.o \
  18. fs/cbfs/libcbfs.o \
  19. fs/cramfs/libcramfs.o \
  20. fs/ext4/libext4fs.o \
  21. fs/fat/libfat.o \
  22. fs/fdos/libfdos.o \
  23. fs/jffs2/libjffs2.o \
  24. fs/reiserfs/libreiserfs.o \
  25. fs/sandbox/libsandboxfs.o \
  26. fs/ubifs/libubifs.o \
  27. fs/yaffs2/libyaffs2.o \
  28. fs/zfs/libzfs.o
  29. LIBS-y += net/libnet.o
  30. LIBS-y += disk/libdisk.o
  31. LIBS-y += drivers/bios_emulator/libatibiosemu.o
  32. LIBS-y += drivers/block/libblock.o
  33. LIBS-$(CONFIG_BOOTCOUNT_LIMIT) += drivers/bootcount/libbootcount.o
  34. LIBS-y += drivers/crypto/libcrypto.o
  35. LIBS-y += drivers/dma/libdma.o
  36. LIBS-y += drivers/fpga/libfpga.o
  37. LIBS-y += drivers/gpio/libgpio.o
  38. LIBS-y += drivers/hwmon/libhwmon.o
  39. LIBS-y += drivers/i2c/libi2c.o
  40. LIBS-y += drivers/input/libinput.o
  41. LIBS-y += drivers/misc/libmisc.o
  42. LIBS-y += drivers/mmc/libmmc.o
  43. LIBS-y += drivers/mtd/libmtd.o
  44. LIBS-y += drivers/mtd/nand/libnand.o
  45. LIBS-y += drivers/mtd/onenand/libonenand.o
  46. LIBS-y += drivers/mtd/ubi/libubi.o
  47. LIBS-y += drivers/mtd/spi/libspi_flash.o
  48. LIBS-y += drivers/net/libnet.o
  49. LIBS-y += drivers/net/phy/libphy.o
  50. LIBS-y += drivers/pci/libpci.o
  51. LIBS-y += drivers/pcmcia/libpcmcia.o
  52. LIBS-y += drivers/power/libpower.o \
  53. drivers/power/fuel_gauge/libfuel_gauge.o \
  54. drivers/power/mfd/libmfd.o \
  55. drivers/power/pmic/libpmic.o \
  56. drivers/power/battery/libbattery.o
  57. LIBS-y += drivers/spi/libspi.o
  58. LIBS-y += drivers/dfu/libdfu.o
  59. ifeq ($(CPU),mpc83xx)
  60. LIBS-y += drivers/qe/libqe.o
  61. LIBS-y += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o
  62. LIBS-y += arch/powerpc/cpu/mpc8xxx/lib8xxx.o
  63. endif
  64. ifeq ($(CPU),mpc85xx)
  65. LIBS-y += drivers/qe/libqe.o
  66. LIBS-y += drivers/net/fm/libfm.o
  67. LIBS-y += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o
  68. LIBS-y += arch/powerpc/cpu/mpc8xxx/lib8xxx.o
  69. endif
  70. ifeq ($(CPU),mpc86xx)
  71. LIBS-y += arch/powerpc/cpu/mpc8xxx/ddr/libddr.o
  72. LIBS-y += arch/powerpc/cpu/mpc8xxx/lib8xxx.o
  73. endif
  74. LIBS-y += drivers/rtc/librtc.o
  75. LIBS-y += drivers/serial/libserial.o
  76. LIBS-y += drivers/sound/libsound.o
  77. LIBS-y += drivers/tpm/libtpm.o
  78. LIBS-y += drivers/twserial/libtws.o
  79. LIBS-y += drivers/usb/eth/libusb_eth.o
  80. LIBS-y += drivers/usb/gadget/libusb_gadget.o
  81. LIBS-y += drivers/usb/host/libusb_host.o
  82. LIBS-y += drivers/usb/musb/libusb_musb.o
  83. LIBS-y += drivers/usb/musb-new/libusb_musb-new.o
  84. LIBS-y += drivers/usb/phy/libusb_phy.o
  85. LIBS-y += drivers/usb/ulpi/libusb_ulpi.o
  86. LIBS-y += drivers/video/libvideo.o
  87. LIBS-y += drivers/watchdog/libwatchdog.o
  88. LIBS-y += common/libcommon.o
  89. LIBS-y += lib/libfdt/libfdt.o
  90. LIBS-y += api/libapi.o
  91. LIBS-y += post/libpost.o
  92. LIBS-y += test/libtest.o
  93. ifneq ($(CONFIG_OMAP_COMMON),)
  94. LIBS-y += $(CPUDIR)/omap-common/libomap-common.o
  95. endif
  96. ifneq (,$(filter $(SOC), mx25 mx27 mx5 mx6 mx31 mx35 mxs vf610))
  97. LIBS-y += arch/$(ARCH)/imx-common/libimx-common.o
  98. endif
  99. ifeq ($(SOC),s5pc1xx)
  100. LIBS-y += $(CPUDIR)/s5p-common/libs5p-common.o
  101. endif
  102. ifeq ($(SOC),exynos)
  103. LIBS-y += $(CPUDIR)/s5p-common/libs5p-common.o
  104. endif
  105. ifneq ($(CONFIG_TEGRA),)
  106. LIBS-y += arch/$(ARCH)/cpu/$(SOC)-common/lib$(SOC)-common.o
  107. LIBS-y += arch/$(ARCH)/cpu/tegra-common/libcputegra-common.o
  108. LIBS-y += $(CPUDIR)/tegra-common/libtegra-common.o
  109. endif
  110. LIBS := $(addprefix $(obj),$(sort $(LIBS-y)))
  111. .PHONY : $(LIBS)

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

第六个依赖LDSCRIPT

  1. $(LDSCRIPT): depend
  2. $(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

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

对应我这里的命令:

  1. 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

分析完依赖

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

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

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

其中GEN_UBOOT定义如下:

  1. ifeq ($(CONFIG_SANDBOX),y)
  2. GEN_UBOOT = \
  3. cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds \
  4. -Wl,--start-group $(__LIBS) -Wl,--end-group \
  5. $(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map -o u-boot
  6. else
  7. GEN_UBOOT = \
  8. cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
  9. $(__OBJS) \
  10. --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
  11. -Map u-boot.map -o u-boot
  12. endif

对应我这里的命令:

  1. 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了:

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

对应我这里的命令:

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

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

  1. ifndef CONFIG_SANDBOX
  2. SUBDIRS += $(SUBDIR_EXAMPLES)
  3. endif
  4. $(SUBDIRS): depend
  5. $(MAKE) -C $@ all

链接脚本分析

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

  1. /*
  2. * Copyright (c) 2004-2008 Texas Instruments
  3. *
  4. * (C) Copyright 2002
  5. * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
  6. *
  7. * SPDX-License-Identifier: GPL-2.0+
  8. */
  9. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")//三个分别指定在缺省、大端、小端情况下的输出可执行文件格式,这里都指定输出格式是elf32,小端和arm体系结构
  10. OUTPUT_ARCH(arm)//输出可执行文件指定为arm体系结构
  11. ENTRY(_start)//指定_start函数为程序的入口。_start在每个CPU目录下的start.S中定义,真正的启动运行地址段由CONFIG_SYS_TEXT_BASE宏定义在编译时由config.mk中定义
  12. 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.
  13. {
  14. . = 0x00000000;//指定定位器符号为0,定系统启动从偏移地址零处开始。
  15. //注意这只是个代码地址偏移值,真正的起始地址是由编译时指定的LDFLAGS_XXX指定的
  16. . = ALIGN(4);//4字节对齐
  17. .text ://这里指定所有文件的.__image_copy_start以及CPUDIR/start.o的.text*以及所有其他文件的.text*都放到.text段
  18. {
  19. *(.__image_copy_start)//u-boot将自己copy到RAM,此为需要copy的程序的start,参考arch/arm/lib/sections.c和arch/arm/lib/relocate.S
  20. CPUDIR/start.o (.text*)//对应到我这里,就是arch/arm/cpu/armv7/start.o文件啦
  21. *(.text*)//其他所有文件的.text*
  22. }
  23. . = ALIGN(4);//修改当前定位寄存器,保持4字节对齐
  24. .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }//指定所有文件的.rodata*放到.rodata段,
  25. //放置前先用SORT_BY_NAME排序,然后用SORT_BY_ALIGNMENT做排序,SORT_BY_ALIGNMENT会根据对齐的
  26. //特性进行降序排序,The difference is SORT_BY_ALIGNMENT will sort sections into descending order by alignment
  27. //before placing them in the output file. Larger alignments are placed before
  28. //smaller alignments in order to reduce the amount of padding necessary.
  29. //在代码段之后,存放read only数据段
  30. . = ALIGN(4);//修改当前定位寄存器,保持4字节对齐
  31. .data : {//所有文件的.data*放到.data段
  32. *(.data*)
  33. }
  34. . = ALIGN(4);//修改当前定位寄存器,保持4字节对齐
  35. . = .;//???
  36. . = ALIGN(4);//修改当前定位寄存器,保持4字节对齐
  37. .u_boot_list : {//所有文件的.u_boot_list*放到.u_boot_list段,且先通过SORT对
  38. //所有.u_boot_list*排序然后通过KEEP告诉连接器,这个段很重要,不要优化掉了哈。
  39. //.data段结束后,紧接着存放u-boot自有的一些function,例如u-boot command等
  40. KEEP(*(SORT(.u_boot_list*)));
  41. }
  42. . = ALIGN(4);//修改当前定位寄存器,保持4字节对齐
  43. .image_copy_end ://同__image_copy_start,参考arch/arm/lib/sections.c和
  44. //arch/arm/lib/relocate.S,里面有注解。
  45. //至此,u-boot需要自拷贝的内容结束,总结一下,包括代码段,数据段,以及u_boot_list
  46. {
  47. *(.__image_copy_end)
  48. }
  49. .rel_dyn_start ://用于用于动态连接的重定位信息的start,参考arch/arm/lib/sections.c ,里面有注解。
  50. //在老的uboot中,如果我们想要uboot启动后把自己拷贝到内存中的某个地方,只要把要拷贝的地址写给TEXT_BASE即可,
  51. //然后boot启动后就会把自己拷贝到TEXT_BASE内的地址处运行,在拷贝之前的代码都是相对的,不能出现绝对的跳转,否则会跑飞。
  52. //在新版的uboot里(2013.07),TEXT_BASE的含义改变了。它表示用户要把这段代码加载到哪里,通常是通过串口等工具。
  53. //然后搬移的时候由uboot自己计算一个地址来进行搬移。
  54. //新版的uboot采用了动态链接技术,在lds文件中有__rel_dyn_start和__rel_dyn_end,这两个符号之间
  55. //的区域存放着动态链接符号,只要给这里面的符号加上一定的偏移,拷贝到内存中代码的后面相应的
  56. //位置处,就可以在绝对跳转中找到正确的函数。*/
  57. {
  58. *(.__rel_dyn_start)
  59. }
  60. .rel.dyn : {//动态链接符存放在的段
  61. *(.rel*)
  62. }
  63. .rel_dyn_end ://动态链接符段结束,参考arch/arm/lib/sections.c ,里面有注解
  64. {
  65. *(.__rel_dyn_end)
  66. }
  67. _end = .;//设置_end的地址为当前定位器,board_f.c里会使用它来计算
  68. /*
  69. * Deprecated: this MMU section is used by pxa at present but
  70. * should not be used by new boards/CPUs.
  71. */
  72. . = ALIGN(4096);
  73. .mmutable : {
  74. *(.mmutable)
  75. }
  76. /*
  77. * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c
  78. * __bss_base and __bss_limit are for linker only (overlay ordering)
  79. */
  80. .bss_start __rel_dyn_start (OVERLAY) : {//参考arch/arm/lib/sections.c ,里面有注解
  81. KEEP(*(.__bss_start));//
  82. __bss_base = .;
  83. }
  84. .bss __bss_base (OVERLAY) : {//未初始化段,存放程序中未初始化的全局变量和静态变量的一块内存区域
  85. *(.bss*)
  86. . = ALIGN(4);
  87. __bss_limit = .;
  88. }
  89. .bss_end __bss_limit (OVERLAY) : {//参考arch/arm/lib/sections.c ,里面有注解
  90. KEEP(*(.__bss_end));
  91. }
  92. /DISCARD/ : { *(.dynsym) }
  93. /DISCARD/ : { *(.dynstr*) }
  94. /DISCARD/ : { *(.dynamic*) }
  95. /DISCARD/ : { *(.plt*) }
  96. /DISCARD/ : { *(.interp*) }
  97. /DISCARD/ : { *(.gnu*) }
  98. /DISCARD/ : { *(.ARM.exidx*) }
  99. /DISCARD/ : { *(.gnu.linkonce.armexidx.*) }
  100. }

在config.mk中:

  1. ifneq ($(CONFIG_SYS_TEXT_BASE),)
  2. LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE)
  3. endif

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

  1. ifeq ($(CONFIG_SANDBOX),y)
  2. GEN_UBOOT = \
  3. cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds \
  4. -Wl,--start-group $(__LIBS) -Wl,--end-group \
  5. $(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map -o u-boot
  6. else
  7. GEN_UBOOT = \
  8. cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
  9. $(__OBJS) \
  10. --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
  11. -Map u-boot.map -o u-boot
  12. 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月

uboot makefile构建分析-续的更多相关文章

  1. uboot makefile构建分析

    前言 几年前分析过uboot的构建及启动过程,做了笔记,但最终没有转为文章.这次又有机会开发嵌入式产品了(之前一年多都是在搞x86 linux),看了下uboot的构建过程,觉得有必要写下整个分析过程 ...

  2. uboot 顶层makefile细节分析

    uboot的源文件众多,学习庞然大物首先找到脊椎--顶层的makfile,逐一破解.但是,uboot的makefile同样是一个庞然大物,所以也要找到它的主线.倘若过分专注部分细节,很难做到把握全局, ...

  3. U-Boot Makefile分析(5)主控Makefile分析

    这次分析源码根目录下的Makefile,它负责读入配置过的信息,通过OBJS.LIBS等变量设置能够参与镜像链接的目标文件,设定编译的目标等等. HOSTARCH := $(shell uname - ...

  4. linux kernel make构建分析

    前言 之前对uboot的构建进行了分析,现在再对linux kernel的构建进行分析.几年前的确也分析过,但是只是停留在笔记层面,没有转为文章,这次下定决定来完善它. 环境 同样,采用的还是zynq ...

  5. openwrt: Makefile 框架分析

    openwrt: Makefile 框架分析 原文链接:blog.chinaunix.net/uid-26675482-id-4704952.html 本篇的主要目的是想通过分析Makefile,了解 ...

  6. u-boot 之配置分析 (2)

    Makefile简要分析所有这些目录的编译连接都是由顶层目录的makefile来确定的. 1.在makefile中有: unconfig: @rm -f $(obj)include/config.h ...

  7. u-boot启动流程分析(2)_板级(board)部分

    转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...

  8. u-boot Makefile整体解析

    一.概述   1.理解u-boot的makefile需要的准备 linux常用命令.shell脚本基础知识.makefile脚本基础知识 2.Makefile的元素 万变不离其宗,无论工程多么复杂,文 ...

  9. [国嵌笔记][030][U-Boot工作流程分析]

    uboot工作流程分析 程序入口 1.打开顶层目录的Makefile,找到目标smdk2440_config的命令中的第三项(smdk2440) 2.进入目录board/samsung/smdk244 ...

随机推荐

  1. 【C++】不要在构造函数或析构函数内调用虚函数

    这个问题来自于<Effective C++>条款9:永远不要在构造函数或析构函数中调用虚函数 . 假设有如下代码: class Transaction {// 所有交易的基类 public ...

  2. 第165天:canvas绘制圆环旋转动画

    canvas绘制圆环旋转动画——面向对象版 1.HTML 注意引入Konva.js库 <!DOCTYPE html> <html lang="en"> &l ...

  3. 对xml的操作使用的类XElement的使用

    操作xml的类比较多,发现XElement类操作xml极其方便,下面列举一些操作方法 1.创建xml XElement xml = new XElement("root", new ...

  4. 【bzoj5206】[Jsoi2017]原力 根号分治+STL-map

    题目描述 一个原力网络可以看成是一个可能存在重边但没有自环的无向图.每条边有一种属性和一个权值.属性可能是R.G.B三种当中的一种,代表这条边上原力的类型.权值是一个正整数,代表这条边上的原力强度.原 ...

  5. P2762 太空飞行计划问题(网络流24题之一)

    题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这些实验需要使用的全部仪器的 ...

  6. 如何使用火狐下的两款接口测试工具RESTClient和HttpRequester发送post请求

    Chrome下有著名的Postman,那火狐也有它的左膀右臂,那就是RESTClient和HttpRequester.这两款工具都是火狐的插件,主要用来模拟发送HTTP请求,HTTP请求最常用的两种方 ...

  7. 使DIV相对窗口大小左右拖动始终水平居中

    <!doctype html> <html> <head> <meta http-equiv="content-type" content ...

  8. [学习笔记]Min-25筛

    %%yyb %%zsy 一. 基本操作:筛1~N中的素数个数.n=1e9 设F(M,j)表示,2~M的所有数中,满足以下条件之一的数的个数:①x是质数②x最小质因子大于(注意是大于没有等号)$P_j$ ...

  9. 【agc004F】Namori

    Portal -->agc004F Solution  好神仙的转化qwq ​  首先我们可以先考虑\(m=n-1\)的情况下,也就是树的情况下要怎么做  我们可以将这个问题转化一下:我们对这颗 ...

  10. iOS9 HTTP请求失败

    iOS9把所有HTTP请求都改成了HTTPS请求,导致应用加载不出数据. 解决方法:在plist中添加以下新字段 App Transport Security Settings:Dictionary ...