u-boot.bin生成过程分析
ELF格式“u-boot”文件的生成规则如下,下面对应Makefile的执行过程分别分析各个依赖。
$(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT) UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\ cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \ --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \ -Map u-boot.map -o u-boot
1.1 depend依赖,下面的make规则有两个目标,depend和dep 。用depend和dep一样,两个名字而已。
depend dep: for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done
对应的makefile执行过程的打印信息如下:
for dir in tools examples post post/cpu ; do make -C $dir _depend ; done
1.2 $(SUBDIRS)依赖,$(SUBDIRS) = tools examples post post/cpu
$(SUBDIRS):
$(MAKE) -C $@ all
对应的makefile执行过程的打印信息如下:
make -C tools all make -C examples all make -C post all make -C post/cpu all
1.2.1 tool
在tool目录下编译出以下几个可执行文件:
img2srec
mkimage
envcrc
gen_eth_addr
bmp_logo
1.2.2 example
在example目录下生成可执行文件hello_world,-Ttext 0xc10000指定链接地址,-e hello_world指定函数入口地址为int hello_world (int argc, char *argv[]),
可仿照该示例在u-boot中写自己的应用程序。
$(AR)用来打包静态库,可参考 静态库 DIY ar crv, 下面打印信息 a - stubs.o即是$(AR)指令执行输出的日志,表示添加了stubs.o到静态库中。
$(CC) $(CFLAGS) -c -o hello_world.o hello_world.c $(CC) $(CFLAGS) -c -o stubs.o stubs.c $(AR) crv libstubs.a stubs.o a - stubs.o $(LD) -g -Ttext 0xc100000 \ -o hello_world -e hello_world hello_world.o libstubs.a \ -L$($(shell dirname `$(CC) -print-libgcc-file-name`)) -lgcc $(OBJCOPY) -O srec hello_world hello_world.srec 2>/dev/null $(OBJCOPY) -O binary hello_world hello_world.bin 2>/dev/null
1.2.3 post
生成静态库libpost.a。从下面的信息可以大概了解libpost.a的组成及提供的功能。
$(CC) $(AFLAGS) -c -o cache_8xx.o cache_8xx.S $(CC) $(CFLAGS) -c -o cache.o cache.c $(CC) $(CFLAGS) -c -o codec.o codec.c $(CC) $(CFLAGS) -c -o cpu.o cpu.c $(CC) $(CFLAGS) -c -o dsp.o dsp.c $(CC) $(CFLAGS) -c -o ether.o ether.c $(CC) $(CFLAGS) -c -o i2c.o i2c.c $(CC) $(CFLAGS) -c -o memory.o memory.c $(CC) $(CFLAGS) -c -o post.o post.c $(CC) $(CFLAGS) -c -o rtc.o rtc.c $(CC) $(CFLAGS) -c -o spr.o spr.c $(CC) $(CFLAGS) -c -o sysmon.o sysmon.c $(CC) $(CFLAGS) -c -o tests.o tests.c $(CC) $(CFLAGS) -c -o uart.o uart.c $(CC) $(CFLAGS) -c -o usb.o usb.c $(CC) $(CFLAGS) -c -o watchdog.o watchdog.c $(AR) crv libpost.a stubs.o cache_8xx.o \ cache.o codec.o cpu.o dsp.o ether.o \ i2c.o memory.o post.o rtc.o \ spr.o sysmon.o tests.o uart.o \ usb.o watchdog.o
1.2.4 post/cpu
生成静态库libcpu.a。从下面的信息可以大概了解libcpu.a的组成及提供的功能。
$(CC) $(AFLAGS) -c -o asm.o asm.S $(CC) $(CFLAGS) -c -o cmp.o cmp.c $(CC) $(CFLAGS) -c -o cmpi.o cmpi.c $(CC) $(CFLAGS) -c -o two.o two.c $(CC) $(CFLAGS) -c -o twox.o twox.c $(CC) $(CFLAGS) -c -o three.o three.c $(CC) $(CFLAGS) -c -o threex.o threex.c $(CC) $(CFLAGS) -c -o threei.o threei.c $(CC) $(CFLAGS) -c -o andi.o andi.c $(CC) $(CFLAGS) -c -o srawi.o srawi.c $(CC) $(CFLAGS) -c -o rlwnm.o rlwnm.c $(CC) $(CFLAGS) -c -o rlwinm.o rlwinm.c $(CC) $(CFLAGS) -c -o rlwimi.o rlwimi.c $(CC) $(CFLAGS) -c -o store.o store.c $(CC) $(CFLAGS) -c -o load.o load.c $(CC) $(CFLAGS) -c -o cr.o cr.c $(CC) $(CFLAGS) -c -o b.o b.c $(CC) $(CFLAGS) -c -o multi.o multi.c $(CC) $(CFLAGS) -c -o string.o string.c $(CC) $(CFLAGS) -c -o complex.o complex.c $(AR) crv libcpu.a asm.o \ cmp.o cmpi.o two.o twox.o three.o threex.o threei.o \ andi.o srawi.o rlwnm.o rlwinm.o rlwimi.o \ store.o load.o cr.o b.o multi.o string.o complex.o
1.3 $(OBJS)依赖,$(OBJS) = cpu/s3c64xx/start.o
$(OBJS): $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
对应的makefile执行过程的打印信息如下:
make -C cpu/s3c64xx start.o /usr/local/arm/4.3.2/bin/arm-linux-gcc -D__ASSEMBLY__ -g -Os -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float -D__KERNEL__ -DTEXT_BASE=0xCFE00000 -I/home/yjg/arm6410/qudong/01-uboot/uboot_ok6410/include -fno-builtin -ffreestanding -nostdinc -isystem /usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/include -pipe -DCONFIG_ARM -D__ARM__ -march=armv5t -c -o start.o start.S
上面最后一条执行即
arm-linux-gcc $(AFLAGS) -c -o start.o start.S
1.4 $(LIBS)依赖 ,$(LIBS)展开如下:
$(LIBS) =
lib_generic/libgeneric.a
board/samsung/smdk6410/libsmdk6410.a
cpu/s3c64xx/libs3c64xx.a
cpu/s3c64xx/s3c6410/libs3c6410.a
lib_arm/libarm.a
fs/cramfs/libcramfs.a
fs/fat/libfat.a
fs/fdos/libfdos.a
fs/jffs2/libjffs2.a
fs/reiserfs/libreiserfs.a
fs/ext2/libext2fs.a
net/libnet.a
disk/libdisk.a
rtc/librtc.a
dtt/libdtt.a
drivers/libdrivers.a
drivers/nand/libnand.a
drivers/nand_legacy/libnand_legacy.a
drivers/onenand/libonenand.a
drivers/sk98lin/libsk98lin.a
post/libpost.a
post/cpu/libcpu.a
common/libcommon.a
其中与平台相关的是下面几个库
board/samsung/smdk6410/libsmdk6410.a cpu/s3c64xx/libs3c64xx.a cpu/s3c64xx/s3c6410/libs3c6410.a lib_arm/libarm.a
该目标的规则如下,LIBS表示的每个库文件,都是由进入相应的子目录执行“make”命令编译得到的。
$(LIBS):
$(MAKE) -C $(dir $(subst $(obj),,$@))
例如,对于LIBS中的“common/libcommon.a”成员,程序将进入common目录执行make命令,生成libcommon.a,最终生成libcommon.a的链接命令如下:
/usr/local/arm/4.3.2/bin/arm-linux-ar crv libcommon.a main.o ACEX1K.o altera.o bedbug.o circbuf.o cmd_ace.o cmd_autoscript.o cmd_bdinfo.o cmd_bedbug.o cmd_bmp.o cmd_boot.o cmd_bootm.o cmd_cache.o cmd_console.o cmd_date.o cmd_dcr.o cmd_diag.o cmd_display.o cmd_doc.o cmd_dtt.o cmd_eeprom.o cmd_elf.o cmd_ext2.o cmd_fat.o cmd_fdc.o cmd_fdos.o cmd_flash.o cmd_fpga.o cmd_i2c.o cmd_ide.o cmd_immap.o cmd_itest.o cmd_jffs2.o cmd_load.o cmd_log.o cmd_mem.o cmd_mii.o cmd_misc.o cmd_mmc.o cmd_nand.o cmd_net.o cmd_nvedit.o cmd_pci.o cmd_pcmcia.o cmd_portio.o cmd_reginfo.o cmd_reiser.o cmd_scsi.o cmd_spi.o cmd_universe.o cmd_usb.o cmd_vfd.o command.o console.o cyclon2.o devices.o dlmalloc.o docecc.o environment.o env_common.o env_nand.o env_dataflash.o env_flash.o env_eeprom.o env_nvram.o env_nowhere.o env_movi.o env_onenand.o exports.o flash.o fpga.o ft_build.o hush.o kgdb.o lcd.o lists.o lynxkdi.o memsize.o miiphybb.o miiphyutil.o s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o spartan3.o usb.o usb_kbd.o usb_storage.o virtex2.o xilinx.o crc16.o xyzModem.o cmd_mac.o cmd_onenand.o cmd_usbd.o cmd_movi.o
上面执行的即为
arm-linux-ar crv $@ $^
以上各种库所包含的*.o文件整理如下:
lib_generic/libgeneric.a : bzlib.o bzlib_crctable.o bzlib_decompress.o \ bzlib_randtable.o bzlib_huffman.o \ crc32.o ctype.o display_options.o div64.o ldiv.o \ string.o vsprintf.o zlib.o board/samsung/smdk6410/libsmdk6410.a : smdk6410.o flash.o \ lowlevel_init.o cpu/s3c64xx/libs3c64xx.a : nand_cp.o i2c.o serial.o usb_ohci.o \ interrupts.o cpu.o nand.o onenand.o onenand_cp.o \ usbd-otg-hs.o hs_mmc.o movi.o cpu/s3c64xx/s3c6410/libs3c6410.a : cpu_init.o \ speed.o lib_arm/libarm.a : _ashldi3.o _ashrdi3.o _divsi3.o _modsi3.o _udivsi3.o _umodsi3.o \ armlinux.o board.o \ cache.o div0.o fs/cramfs/libcramfs.a : cramfs.o uncompress.o fs/fat/libfat.a : fat.o file.o fs/fdos/libfdos.a : fat.o vfat.o dev.o fdos.o fs.o subdir.o fs/jffs2/libjffs2.a : jffs2_1pass.o compr_rtime.o compr_rubin.o compr_zlib.o mini_inflate.o \ compr_lzo.o compr_lzari.o fs/reiserfs/libreiserfs.a: reiserfs.o dev.o mode_string.o fs/ext2/libext2fs.a ext2fs.o dev.o net/libnet.a : net.o tftp.o bootp.o rarp.o eth.o nfs.o sntp.o disk/libdisk.a : part.o part_mac.o part_dos.o part_iso.o part_amiga.o rtc/librtc.a : date.o \ bf533_rtc.o ds12887.o ds1302.o ds1306.o ds1307.o \ ds1337.o ds1374.o ds1556.o ds164x.o ds174x.o \ m41t11.o max6900.o m48t35ax.o mc146818.o mk48t59.o \ mpc5xxx.o mpc8xx.o pcf8563.o s3c24x0_rtc.o rs5c372.o \ s3c24xx_rtc.o s3c64xx_rtc.o dtt/libdtt.a : lm75.o ds1621.o adm1021.o drivers/libdrivers.a : 3c589.o 5701rls.o ali512x.o atmel_usart.o \ bcm570x.o bcm570x_autoneg.o cfb_console.o cfi_flash.o \ cs8900.o ct69000.o dataflash.o dc2114x.o dm9000x.o \ e1000.o eepro100.o \ i8042.o inca-ip_sw.o keyboard.o \ lan91c96.o \ natsemi.o ne2000.o netarm_eth.o netconsole.o \ ns16550.o ns8382x.o ns87308.o ns7520_eth.o omap1510_i2c.o \ omap24xx_i2c.o pci.o pci_auto.o pci_indirect.o \ pcnet.o plb2800_eth.o \ ps2ser.o ps2mult.o pc_keyb.o \ rtl8019.o rtl8139.o rtl8169.o \ s3c4510b_eth.o s3c4510b_uart.o \ sed13806.o sed156x.o \ serial.o serial_max3100.o \ serial_pl010.o serial_pl011.o serial_xuartlite.o \ sl811_usb.o sm501.o smc91111.o smiLynxEM.o \ status_led.o sym53c8xx.o ahci.o \ ti_pci1410a.o tigon3.o tsec.o \ usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \ videomodes.o w83c553f.o \ ks8695eth.o \ pxa_pcmcia.o mpc8xx_pcmcia.o tqm8xx_pcmcia.o \ rpx_pcmcia.o \ fsl_i2c.o \ smc911x.o drivers/nand/libnand.a : nand.o nand_base.o nand_ids.o nand_ecc.o nand_bbt.o nand_util.o drivers/nand_legacy/libnand_legacy.a : nand_legacy.o drivers/onenand/libonenand.a : onenand.o generic.o s3c_onenand.o drivers/sk98lin/libsk98lin.a : skge.o skaddr.o skgehwt.o skgeinit.o skgepnmi.o skgesirq.o \ ski2c.o sklm80.o skqueue.o skrlmt.o sktimer.o skvpd.o \ skxmac2.o skcsum.o post/libpost.a : stubs.o cache_8xx.o \ cache.o codec.o cpu.o dsp.o ether.o \ i2c.o memory.o post.o rtc.o \ spr.o sysmon.o tests.o uart.o \ usb.o watchdog.o post/cpu/libcpu.a : asm.o \ cmp.o cmpi.o two.o twox.o three.o threex.o threei.o \ andi.o srawi.o rlwnm.o rlwinm.o rlwimi.o \ store.o load.o cr.o b.o multi.o string.o complex.o common/libcommon.a : main.o ACEX1K.o altera.o bedbug.o circbuf.o \ cmd_ace.o cmd_autoscript.o \ cmd_bdinfo.o cmd_bedbug.o cmd_bmp.o cmd_boot.o cmd_bootm.o \ cmd_cache.o cmd_console.o \ cmd_date.o cmd_dcr.o cmd_diag.o cmd_display.o cmd_doc.o cmd_dtt.o \ cmd_eeprom.o cmd_elf.o cmd_ext2.o \ cmd_fat.o cmd_fdc.o cmd_fdos.o cmd_flash.o cmd_fpga.o \ cmd_i2c.o cmd_ide.o cmd_immap.o cmd_itest.o cmd_jffs2.o \ cmd_load.o cmd_log.o \ cmd_mem.o cmd_mii.o cmd_misc.o cmd_mmc.o \ cmd_nand.o cmd_net.o cmd_nvedit.o \ cmd_pci.o cmd_pcmcia.o cmd_portio.o \ cmd_reginfo.o cmd_reiser.o cmd_scsi.o cmd_spi.o cmd_universe.o \ cmd_usb.o cmd_vfd.o \ command.o console.o cyclon2.o devices.o dlmalloc.o docecc.o \ environment.o env_common.o \ env_nand.o env_dataflash.o env_flash.o env_eeprom.o \ env_nvram.o env_nowhere.o env_movi.o env_onenand.o \ exports.o \ flash.o fpga.o ft_build.o \ hush.o kgdb.o lcd.o lists.o lynxkdi.o \ memsize.o miiphybb.o miiphyutil.o \ s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o spartan3.o \ usb.o usb_kbd.o usb_storage.o \ virtex2.o xilinx.o crc16.o xyzModem.o cmd_mac.o cmd_onenand.o \ cmd_usbd.o cmd_movi.o
1.5 $(LDSCRIPT)依赖,展开为$(LDSCRIPT) = /home/yjg/arm6410/qudong/01-uboot/uboot_ok6410/board/samsung/smdk6410/u-boot.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/ OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { . = 0x00000000; . = ALIGN(4); .text : { cpu/s3c64xx/start.o (.text) cpu/s3c64xx/s3c6410/cpu_init.o (.text) cpu/s3c64xx/onenand_cp.o (.text) cpu/s3c64xx/nand_cp.o (.text) cpu/s3c64xx/movi.o (.text) *(.text) lib_arm/div0.o } . = ALIGN(4); .rodata : { *(.rodata) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); .got : { *(.got) } __u_boot_cmd_start = .; .u_boot_cmd : { *(.u_boot_cmd) } __u_boot_cmd_end = .; . = ALIGN(4); .mmudata : { *(.mmudata) } . = ALIGN(4); __bss_start = .; .bss : { *(.bss) } _end = .; }
1.6 最后分析生成u-boot镜像的命令
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\ cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \ --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \ -Map u-boot.map -o u-boot
对应的makefile执行过程的打印信息如下:
1.UNDEF_SYM=`/usr/local/arm/4.3.2/bin/arm-linux-objdump -x lib_generic/libgeneric.a board/samsung/smdk6410/libsmdk6410.a cpu/s3c64xx/libs3c64xx.a cpu/s3c64xx/s3c6410/libs3c6410.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/nand/libnand.a drivers/nand_legacy/libnand_legacy.a drivers/onenand/libonenand.a drivers/sk98lin/libsk98lin.a post/libpost.a post/cpu/libcpu.a common/libcommon.a |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\ 2.cd /home/yjg/arm6410/qudong/01-uboot/uboot_ok6410 && /usr/local/arm/4.3.2/bin/arm-linux-ld -Bstatic -T /home/yjg/arm6410/qudong/01-uboot/uboot_ok6410/board/samsung/smdk6410/u-boot.lds -Ttext 0xCFE00000 $UNDEF_SYM cpu/s3c64xx/start.o \ --start-group lib_generic/libgeneric.a board/samsung/smdk6410/libsmdk6410.a cpu/s3c64xx/libs3c64xx.a cpu/s3c64xx/s3c6410/libs3c6410.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/nand/libnand.a drivers/nand_legacy/libnand_legacy.a drivers/onenand/libonenand.a drivers/sk98lin/libsk98lin.a post/libpost.a post/cpu/libcpu.a common/libcommon.a --end-group -L /usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/armv4t -lgcc \ -Map u-boot.map -o u-boot
上述最后的链接过程等价于
arm-linux-ld $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) -Map u-boot.map -o u-boot
其中 LDFLAGS : -Bstatic -T /home/yjg/arm6410/qudong/01-uboot/uboot_ok6410/board/samsung/smdk6410/u-boot.lds -Ttext 0xCFE00000
-Bstatic表示使用静态方式链接库文件
-Tu-boot.lds指定连接器脚本文件
-Ttext 0xCFE00000指定代码段的起始地址
--start-group...--end-group指定一组需要链接的库文件
链接器LD去load对应的库(lib,module)的时候,可能会遇到这些情况: (1)A库,引用了B库中funcInB(),但是先ld A库,导致找不到对应的funInB而链接报错 (2)A库和B库,互相都包含对应所引用到的函数,即互相引用/循环引用,ld编译器会因为找不到A库中所引用的B库的中的函数(或者反过来B库引用A库中的函数)而报错。 此时,用"–start-group和 –end-group“,通知ld链接器,去在–start-group和–end-group中间的这些库函数,多花点时间,对于这些库,都从头到尾,多查几遍,去找找那些还没有找到的所引用的函数,是不是在另外的库中有这些函数,以此解决: (1)A库引用到了后来才加载的B库中的函数 (2)解决循环引用
-Map u-boot.map表示产生符号表u-boot.map
1.7 u-boot转换为其它格式
生成u-boot.bin
$(obj)u-boot.bin: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ /usr/local/arm/4.3.2/bin/arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin
生成u-boot.srec
$(obj)u-boot.srec: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@ /usr/local/arm/4.3.2/bin/arm-linux-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec
生成u-boot.hex
$(obj)u-boot.hex: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ /usr/local/arm/4.3.2/bin/arm-linux-objcopy --gap-fill=0xff -O ihex u-boot u-boot.hex