Chinaunix首页 | 论坛 | 博客
  • 博客访问: 34413
  • 博文数量: 9
  • 博客积分: 450
  • 博客等级: 下士
  • 技术积分: 110
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-05 09:09
文章分类

全部博文(9)

文章存档

2011年(1)

2009年(8)

我的朋友
最近访客

分类: LINUX

2009-05-02 14:22:30

1.u-boot的编译与链接过程

         说完配置我们再回到Makefile中来看看编译与链接,面对Makefile的时候首先我们就会想到最后的目标文件u-boot.bin(通常情况下我们都是使用u-boot.bin的,因此这里我也只是介绍它,实际上可以烧到板子上的有很多种格式的,如.srec等等)是怎样产生的:

 

 316 $(obj)u-boot.bin:       $(obj)u-boot

 

 317                 $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@

 ......

 341 $(obj)u-boot:    depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT)

 342                UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \

 343                sed  -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\

 344                 cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \

 345                         --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \

 346                         -Map u-boot.map -o u-boot

 

可以看到u-boot.bin 是用$(OBJCOPY) u-boot生成的,u-bootelf格式的文件,不能直接在裸机上运行(当然这也不是绝对的,主要是因为u-boot中没有加载器,如果你为u-boot写一个加载器就可以跑elf文件了),所以需要用$(OBJCOPY) u-boot转换成二进制u-boot.bin文件, 但是u-boot的产生依赖于depend$(SUBDIRS)$(OBJS)$(LIBBOARD)$(LIBS)$(LDSCRIPT),这里介绍一下这几个依赖目标:

 

a. 目标 depend

 394 depend dep:     $(TIMESTAMP_FILE) $(VERSION_FILE)

 395                 for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done

 生成$(SUBDIRS)中的每个子目录的.depend文件,这个.depend文件中记录了每个目标文件的依赖文件,因此,修改了某一个文件后,基于这个.depend文件才可以对所有的依赖文件进行重新编译,生产的方法如上:进入子目录中执行make _depend

 

b.  $(SUBDIRS)

 279 # The "tools" are needed early, so put this first

 280 # Don't include stuff already done in $(LIBS)

 281 SUBDIRS = tools \

 282           examples \

 283           api_examples

 284

 285 .PHONY : $(SUBDIRS)

 ......

 357 $(SUBDIRS):     depend $(obj)include/autoconf.mk

 358                 $(MAKE) -C $@ all

 进入各个子目录中执行make

 

c.  $(OBJS)

 197 OBJS  = cpu/$(CPU)/start.o

 ......

 348 $(OBJS):        depend $(obj)include/autoconf.mk

 349                 $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))

 OBJS  = cpu/$(CPU)/start.o, 即为'cpu/arm920t/start.o',而要产生cpu/arm920t/start.o需要进入cpu/$(CPU)进行编译。

 

d.  $(LIBBOARD)

  config.mk:

95 ifdef       VENDOR

96 BOARDDIR = $(VENDOR)/$(BOARD)

97 else

98 BOARDDIR = $(BOARD)

99 endif

 Makefiel:

 273 LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).a

 274 LIBBOARD := $(addprefix $(obj),$(LIBBOARD))

 ......

 354 $(LIBBOARD):    depend $(LIBS) $(obj)include/autoconf.mk

 355                 $(MAKE) -C $(dir $(subst $(obj),,$@))

这个也很好理解就是产生board/$(BOARDDIR)/lib$(BOARD).a,对2410来说,因为VENDIR=Samsung,所以这里BOARDDIR = $(VENDOR)/$(BOARD),因此LIBBOARD = board/samsung/smdk2410/libsmdk2410.a

 

e. $(LIBS)

 211 LIBS  = lib_generic/libgeneric.a

 212 LIBS += lib_generic/lzma/liblzma.a

 213 LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \

 214         "board/$(VENDOR)/common/lib$(VENDOR).a"; fi)

 215 LIBS += cpu/$(CPU)/lib$(CPU).a

 216 ifdef SOC

 217 LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a

 218 endif

 219 ifeq ($(CPU),ixp)

 220 LIBS += cpu/ixp/npe/libnpe.a

 221 endif

 222 LIBS += lib_$(ARCH)/lib$(ARCH).a

 223 LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \

 224         fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/yaffs2/libyaffs2.a

 225 LIBS += net/libnet.a

 226 LIBS += disk/libdisk.a

 227 LIBS += drivers/bios_emulator/libatibiosemu.a

 228 LIBS += drivers/block/libblock.a

 229 LIBS += drivers/dma/libdma.a

 230 LIBS += drivers/fpga/libfpga.a

 231 LIBS += drivers/gpio/libgpio.a

 232 LIBS += drivers/hwmon/libhwmon.a

 233 LIBS += drivers/i2c/libi2c.a

 234 LIBS += drivers/input/libinput.a

 235 LIBS += drivers/misc/libmisc.a

 236 LIBS += drivers/mmc/libmmc.a

 237 LIBS += drivers/mtd/libmtd.a

 238 LIBS += drivers/mtd/nand/libnand.a

 239 LIBS += drivers/mtd/nand_legacy/libnand_legacy.a

 240 LIBS += drivers/mtd/onenand/libonenand.a

 241 LIBS += drivers/mtd/ubi/libubi.a

 242 LIBS += drivers/mtd/spi/libspi_flash.a

 243 LIBS += drivers/net/libnet.a

 244 LIBS += drivers/net/phy/libphy.a

 245 LIBS += drivers/net/sk98lin/libsk98lin.a

 246 LIBS += drivers/pci/libpci.a

 247 LIBS += drivers/pcmcia/libpcmcia.a

 248 LIBS += drivers/spi/libspi.a

 249 ifeq ($(CPU),mpc83xx)

 250 LIBS += drivers/qe/qe.a

 251 endif

 252 ifeq ($(CPU),mpc85xx)

 253 LIBS += drivers/qe/qe.a

 254 LIBS += cpu/mpc8xxx/ddr/libddr.a

 255 TAG_SUBDIRS += cpu/mpc8xxx

 256 endif

 257 ifeq ($(CPU),mpc86xx)

 258 LIBS += cpu/mpc8xxx/ddr/libddr.a

 259 TAG_SUBDIRS += cpu/mpc8xxx

 260 endif

 261 LIBS += drivers/rtc/librtc.a

 262 LIBS += drivers/serial/libserial.a

 263 LIBS += drivers/usb/libusb.a

 264 LIBS += drivers/video/libvideo.a

 265 LIBS += common/libcommon.a

 266 LIBS += libfdt/libfdt.a

 267 LIBS += api/libapi.a

 268 LIBS += post/libpost.a

 269

 270 LIBS := $(addprefix $(obj),$(LIBS))

 ...... 

 351 $(LIBS):        depend $(obj)include/autoconf.mk $(SUBDIRS)

 352                 $(MAKE) -C $(dir $(subst $(obj),,$@))

可以看到上面的LIBS包括的目标非常多,都是将子目录的源码编成*.a库文件,通过执行每个目录的Makefile来实现。

 

f. $(LDSCRIPT)

config.mk中:

113 ifndef LDSCRIPT

114 #LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug

115 ifeq ($(CONFIG_NAND_U_BOOT),y)

116 LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds

117 else

118 LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds

119 endif

120 endif

 

Makefile:

 360 $(LDSCRIPT):    depend $(obj)include/autoconf.mk

 361                 $(MAKE) -C $(dir $@) $(notdir $@)

 

这里其实就是执行链接是所需要的链接脚本,这里我需要特别强调链接脚本,链接脚本是程序链接的依据,它规定了可执行文件中的程序的输出格式是大端还是小端,程序如何来布局(第一条指令是那一条,各个依赖文件是如何组成最后的目标文件的),程序的入口是那里(只对elf文件有用),特别的是你还可以在链接脚本中定义变量,如果你想编写直接在uboot执行的代码,则在生成可执行文件的时候必须要有一个自己的链接脚本,这样程序才会按照你的想法进行布局和正确的执行。个人觉得链接脚本很重要,但是似乎这方面的资料非常的少。

 24 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

 25 /*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/

 26 OUTPUT_ARCH(arm)

 27 ENTRY(_start)

 28 SECTIONS

 29 {

 30         . = 0x00000000;

 31

 32         . = ALIGN(4);

 33         .text      :

 34         {

 35           cpu/arm920t/start.o   (.text)

 36           *(.text)

 37         }

 38

 39         . = ALIGN(4);

 40         .rodata : { *(.rodata) }

 41

 42         . = ALIGN(4);

 43         .data : { *(.data) }

 44

 45         . = ALIGN(4);

 46         .got : { *(.got) }

 47

 48         . = .;

 49         __u_boot_cmd_start = .;

 50         .u_boot_cmd : { *(.u_boot_cmd) }

 51         __u_boot_cmd_end = .;

 52

 53         . = ALIGN(4);

 54         __bss_start = .;

 55         .bss (NOLOAD) : { *(.bss) . = ALIGN(4); }

 56         _end = .;

 57 }

 

具体的语法我就不说了,有兴趣的朋友可以去看看这篇文章:,里面语法还是说的很详细的。这里重点提一下:

 33         .text      :

 34        

 35           cpu/arm920t/start.o   (.text)

 36           *(.text)

 37         }

 

这里说的就是代码段的布局,最后的目标文件中代码段先是cpu/arm920t/start.o的代码,之后才是其他文件的代码段,这样就可以保证start.s中的第一条语句放在程序的最前面。

 

         这样上面的几个依赖目标就说完了,最后执行前面的344-346行进行链接,生成u-bootok了。

 

        恩,最后在总结一下上面编译的整个过程:

l        编译cpu/$(CPU)/start.o,当然不同的cpu可能还需要编译一些特别的文件;

l        执行你配置的平台的相关目录,以及通用目录下面的Makefile,编成对应的.o,.a文件;

l        将上面的.o, .a文件按照相关的配置与对应的链接脚本进行链接生成u-boot

l        之后使用对应的工具从u-boot生成你的目标文件,如u-boot.bin,u-boot.srec

 

2.u-boot的移植

         上面说了那么多都是分析整个移植过程的内部实现,比较枯燥,但是只有了解了上面的东西才可以说懂移植,不然别人只要一问你为什么是这样的,你就回答不出来了。

         整个的流程如下,当然这个是 u-boot的文档中说的步骤,你也可以自己去看看文档是怎么说的,网上的文章说的东西都是从那里出来的,不过不同的环境处理可能会稍稍不同,应该按照实际的做,不要局限在文档里面,毕竟只是参考罢了。

         这里假设我们的开发板在u-boot中没有列出来,但是他跟smdk2410非常的类似,那么我们应该按照下面的步骤来做:

    1). 修改Makefile,增加我们板子对应的配置项:

           myboard_config : unconfig

             @$(MKCONFIG) $(@:_config=) arm arm920t myboard null mycpu

    2). board cpu 目录下增加对应board cpu的目录:

       cpu/arm920t下:

                   cp -r s3c24x0 mycpu

           board下:

                  cp -r samsung/smdk2410 myboard

    3). 将不是arm平台下面的lib全部删了,只留下lib_arm, lib_generic

    4). include/configs

           cp smdk2410.h myboard.h

        上面就是增加一种平台的基本步骤,因为有时候你的开发板的一些硬件结构跟已有的平台不同,所以你还需要根据你的平台对源码进行修改,这样你必须先对uboot的源代码比较熟悉才可以做到

阅读(1331) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~