u-boot编译(三) 含有u-boot.lds文件位置的重要信息

 

1、编译最终要生成的文件是$(obj)u-boot.bin文件:

ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND)

all:  $(ALL)

 

$(obj)u-boot.bin是最终目标“all”的依赖文件,由make的规则可以知道,make会在当前文件中找目标为$(obj)u-boot.bin 的依赖性,再根据目标$(obj)u-boot.bin 的规则生成$(obj)u-boot.bin 文件。那我们就去找到$(obj)u-boot.bin 这个目标,如下:

 

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

 

$(obj)u-boot.bin这个目标又依赖于$(obj)u-boot,显然要想生成$(obj)u-boot.bin文件,就要找到 $(obj)u-boot这个目标。那我们先看一下生成$(obj)u-boot.bin文件的命令: 

$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@  ,我们将其展开,给到如下结果:


OBJCOPY = $(CROSS_COMPILE)objcopy

CROSS_COMPILE = arm-linux-

所以  OBJCOPY = arm-linux - objcopy
OBJCFLAGS += --gap-fill=0xff

 $< =  $(obj)u-boot             ("$<"表示第一个依赖目标文件)

$@ = $(obj)u-boot.bin        ("$@"表示目标集)

 

 arm-linux - objcopy   --gap-fill=0xff  -O binary   $(obj)u-boot   $(obj)u-boot.bin      ,想要知道这条命令的含义,那么就得知道arm-linux-objcopy这个命令的使用。从“objcopy”这个字眼大概可以知道这是一个目标文件(obj)的拷贝,从哪里拷贝到哪里呢?当然是从  “$(obj)u-boot”   拷贝到“$(obj)u-boot.bin  ”因为我们这一步要得到的就是  “$(obj)u-boot.bin  ”这个目标文件,这个文件的拷贝是以怎么的方式进行的呢?这就得看选项  “--gap-fill=0xff  -O binary   ”

gap-fill=0xff  指明了用oxff来填充section之间的空隙。

-O binary    在拷贝的时候进行格式转换,说明了“$(obj)u-boot.bin  ”这个文件是一个binary(二进制)目标文件。

 3、上面我们说了要想生成$(obj)u-boot这个依赖文件,就得找得$(obj)u-boot这个目标。


 $(obj)u-boot: depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
       $(GEN_UBOOT)

 

这个目标的命令是: $(GEN_UBOOT) ,再去找变量GEN_UBOOT的定义,如下:

 

GEN_UBOOT = \
  UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
  sed  -n -e 's/.*\($(SYM_PREFIX)__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

 

GEN_UBOOT 这个变量在“u-boot编译(二)”已经初步的分析过了,这里就直接引用过来,然后进一步深入分析:

先列举出这些变量,如下:

 OBJDUMP =arm-linux-objdump

 LIBBOARD = board/samsung/smdk2410/libsmdk2410.a      

LIBS就是libs库(这里都是.a静态库),内容比较多就不列举出来了,详细请看“u-boot编译(二)”这一节

LNDIR := $(OBJTREE)

  LD = arm-linux-ld

LDFLAGS += -Bstatic -T $(obj)u-boot.lds $(PLATFORM_LDFLAGS)

  __OBJS := $(subst $(obj),,$(OBJS))

  __LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))

 

展开结果为:

GEN_UBOOT = \
       UNDEF_SYM=`arm-linux-objdump -x board/samsung/smdk2410/libsmdk2410.a  $(LIBS) | \
      sed  -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\


      cd  $(OBJTREE) && arm-linux-ld -Bstatic -T $(obj)u-boot.lds $(PLATFORM_LDFLAGS)      

      $$UNDEF_SYM    $(__OBJS) \
      --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
      -Map u-boot.map -o u-boot

 

 

我们也暂且不看 $(obj)u-boot的依赖文件,先来看一下, $(obj)u-boot这个目标是如何组织生成 $(obj)u-boot这个文件的。

 

        UNDEF_SYM=`arm-linux-objdump -x board/samsung/smdk2410/libsmdk2410.a  $(LIBS) | \
      sed  -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\

就是使用“sed”命令修改库文件的内容,

 



$(obj)u-boot.lds 是一个链接脚本,用他来组织程序的存放位置,因此有必要来先分析这个文件。我们知道$(obj)u-boot.lds 是“$(obj)u-boot”这个目标的依赖文件,所以我们可以找到$(obj)u-boot.lds这个目标,看它是如何组织生成$(obj)u-boot.lds这个链接脚本文件

 

 $(obj)u-boot.lds文件分析

我们可以在Makefile找到这个目标:

 

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

 以上执行结果实质上是将cpu/arm920t/u-boot.lds经编译器简单预处理后输出到u-boot顶层目录下的u-boot文件。

 $(obj)u-boot.lds这个目标又依赖于:$(LDSCRIPT)

$(LDSCRIPT): depend
  $(MAKE) -C $(dir $@) $(notdir $@)


$(LDSCRIPT)又依赖于“depend”

 

depend dep: $(TIMESTAMP_FILE) $(VERSION_FILE) $(obj)include/autoconf.mk
  for dir in $(SUBDIRS) cpu/$(CPU) $(dir $(LDSCRIPT)) ; do \
   $(MAKE) -C $$dir _depend ; done

 

$(TIMESTAMP_FILE) $(VERSION_FILE)是时间戳和版本信息,我们重点不再这里,我们的重点是查看如何组织生成

 $(obj)u-boot.lds这个脚本文件,

 

for dir in $(SUBDIRS) cpu/$(CPU) $(dir $(LDSCRIPT)) ; do \
   $(MAKE) -C $$dir _depend ; done

这是个 for ...  in .... do 语句

 

SUBDIRS = tools  examples/standalone  examples/api

CPU=arm920t

LDSCRIPT :=  $(TOPDIR)/lib_$(ARCH)/config.mk  =  $(TOPDIR)/lib_armconfig.mk  

 

这里特别要注意“LDSCRIPT”这个变量:

一开始我就特么纠结,因为这个变量在在顶层的config.mk里有定义,LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds,以为要找的u-boot.lds文件在这个目录下,但是打开这个目录并未发现u-boot.lds这个文件,于是我就开始怀疑,在这之前可能定义过“LDSCRIPT”这个变量了,因为顶层的config.mk详细的定义是这样的:

ifndef LDSCRIPT
#LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug
ifeq ($(CONFIG_NAND_U_BOOT),y)
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
else
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
endif

 

也就是在这之前没有定义过"LDSCPIPT",那么这里才定义。于是我用source insight这个软件去查找这个变量,发现在lib_arm/config.mk这个文件里有定义  "LDSCPIPT"这个变量 :LDSCRIPT := $(SRCTREE)/cpu/$(CPU)/u-boot.lds,那我就去找到哪个文件里包含了这个目录,通过顶层config.mk文件往上查找,可以找到:

 

ifdef ARCH
sinclude $(TOPDIR)/lib_$(ARCH)/config.mk   # include architecture dependend rules
endif

 

这里的ARCH=arm,这不正是我们刚才找到的lib_arm/config.mk这个文件吗,所以LDSCRIPT 这个变量实际是在LDSCRIPT := $(SRCTREE)/cpu/$(CPU)/u-boot.lds 。因为老版本的u-boot与新版本的u-boot  u-boot.lds 文件位置不一样,有些书写的针对的是老版本的(这里分析的是u-boot-2013.03),这里要特别注意,因为有可能你找到的 u-boot.lds 并不是你使用的 u-boot.lds 文件。


 

这里$(MAKE) 是make的递归调用,-C是执行后面目录下的makefile,那我们就列出上面的目录:

 tools 

 examples/standalone 

 examples/api

 cpu/arm920t

$(SRCTREE)/cpu/$(CPU)/u-boot.lds 

 _depend

就是执行这几个目录下的makefile

 

为了知道$(obj)u-boot.lds这个脚本文件是怎么生成的,我们就反回去看:

 

$(LDSCRIPT): depend
    $(MAKE) -C $(dir $@) $(notdir $@)

 

命令展开结果为:$(MAKE) -C  $(SRCTREE)/cpu/arm920t     u-boot.lds

 

 那我们就去cpu/arm920t

 

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

 

以上执行结果实质上是将cpu/arm920t/u-boot.lds经编译器简单预处理后输出到u-boot顶层目录下的u-boot文件。

默认变量“ CPP”  :C 程序的预处理器(输出是标准输出设备)。默认命令是“$(CC) –E”。

-Dmacro:定义宏macro,宏的内容定义为字符串`1'. 这里

-D__ASSEMBLY__ 相当于  #define __ASSEMBLY__   ‘1’ 。-D 是选项,__ASSEMBLY__ 相当于一个宏。

转自: http://blog.sina.com.cn/s/blog_13f1300a80102w7o6.html

猜你喜欢

转载自blog.csdn.net/nicholas_duan/article/details/91184488
今日推荐