分类: LINUX
2009-05-02 14:22:30
说完配置我们再回到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-boot是elf格式的文件,不能直接在裸机上运行(当然这也不是绝对的,主要是因为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/i
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-boot就ok了。
恩,最后在总结一下上面编译的整个过程:
l 编译cpu/$(CPU)/start.o,当然不同的cpu可能还需要编译一些特别的文件;
l 执行你配置的平台的相关目录,以及通用目录下面的Makefile,编成对应的.o,.a文件;
l 将上面的.o, .a文件按照相关的配置与对应的链接脚本进行链接生成u-boot
l 之后使用对应的工具从u-boot生成你的目标文件,如u-boot.bin,u-boot.srec
上面说了那么多都是分析整个移植过程的内部实现,比较枯燥,但是只有了解了上面的东西才可以说懂移植,不然别人只要一问你为什么是这样的,你就回答不出来了。
整个的流程如下,当然这个是 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 s
board下:
cp -r samsung/smdk2410 myboard
3). 将不是arm平台下面的lib全部删了,只留下lib_arm, lib_generic
4). 在 include/configs下
cp smdk2410.h myboard.h
上面就是增加一种平台的基本步骤,因为有时候你的开发板的一些硬件结构跟已有的平台不同,所以你还需要根据你的平台对源码进行修改,这样你必须先对uboot的源代码比较熟悉才可以做到。