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
lib-components

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 = .;
}
u-boot.lds

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

 

posted @ 2017-11-12 19:37  bluebluebluesky  阅读(2211)  评论(0编辑  收藏  举报