如何得到Start.S就是U-boot的入口

    前言:

    我们分析一个工程的时候,想知道它的结构,它是如何链接的,最好的方法就是分析它的Makefile。

  U-boot编译步骤:

    1、配置:make  xxx_config

    2、编译:make

    注:先配置再编译的由来,是u-boot README说明文档得来。

在分析Makefile之前,我们发现U-boot目录下这么多的Makefile,这么多的文件,我们应该如何进行查找呢。

顺藤摸瓜法:

    我们以make 100ask24x0_config 配置为例:

    1、首先编译U-boot ,拷贝到ubuntu 的/mnt 共享目录里 ,打开主目录下的Makefile,搜索100ask24x0_config 。

        得到如下代码:

        100ask24x0_config : unconfig

@$(MKCONFIG) $(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0

   2、想弄明白上诉代码,我们需要先知道:MKCONFIG所代表的含义,所以我们在主Makefile中再查找MKCONFIG所在的定义,得到如下代码:

        MKCONFIG := $(SRCTREE)/mkconfig

        export MKCONFIG

这句话由语义看出,MKCONFIG 是由原码树mkconfig文件得到。

3、我们查看主目录下是否有mkconfig这个文件。查看得到确实有这个文件,所以

@$(MKCONFIG) $(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0   这句话翻译过来就是:

mkconfig 100ask24x0_config  arm arm920t 100ask24x0 NULL s3c24x0

$0              $1                            $2      $3           $4              $5       $6          注:下文计算参数需用。

4、分析mkconfig文件

-----------------------------------------------------------------------------------------------------------

  while [ $# -gt 0 ] ; do            #分析上述命令传入的参数

case "$1" in
--) shift ; break ;;            #是否有--
-a) shift ; APPEND=yes ;;  #是否有-a
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;   #是否有-n
*)  break ;;
esac

done                                        注:我们发现并没有这些参数,该段可省略不看。

---------------------------------------------------------------------------------------------------------------

[ "${BOARD_NAME}" ] || BOARD_NAME="$1"   

                                           #如果BOARD_NAME已经定义,不会执行BOARD_NAME="$1",否则执行BOARD_NAME="$1"

[ $# -lt 4 ] && exit 1          #如果参数个数小于4个--退出
[ $# -gt 6 ] && exit 1         #如果参数个数大于6个--退出

echo "Configuring for ${BOARD_NAME} board..."     #参数个数合法,打印这句话

---------------------------------------------------------------------------------------------------------------

if [ "$SRCTREE" != "$OBJTREE" ] ; then   #如果SRCTREE变量不等于OBJTREE变量,则执行下列创建目录、删除等一系列操作

mkdir -p ${OBJTREE}/include               注:在主Makefile中查找这两个定义,它们是相等的,所以执行else分支。

mkdir -p ${OBJTREE}/include2                    主Makefile :

cd ${OBJTREE}/include2                                          OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
rm -f asm
ln -s ${SRCTREE}/include/asm-$2 asm                       如果BUILD_DIR被定义,则使用BUILD_DIR,没定义使用CURDIR
LNPREFIX="../../include2/asm/"                         SRCTREE := $(CURDIR)     当前目录
cd ../include
rm -rf asm-$2                                                             我们发现BUILD_DIR没有定义,OBJTREE、SRCTREE都是 当前目录
rm -f asm
mkdir asm-$2
ln -s asm-$2 asm
else
cd ./include                                       
rm -f asm
ln -s asm-$2 asm        #替换$2   ln -s asm-arm asm,创建了asm链接指向asm-arm

fi                                              注:asm 是指向架构的链接,这样头文件会自动选择链接指向的构架

---------------------------------------------------------------------------------------------------------------

rm -f asm-$2/arch                #rm -f asm-asm/arch

if [ -z "$6" -o "$6" = "NULL" ] ; then  #我们有第六个参数,所以执行else分支
ln -s ${LNPREFIX}arch-$3 asm-$2/arch    #LNPREFIX   无定义
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch    #ln -s arch-s3c24x0 asm-asm/arch

fi

f [ "$2" = "arm" ] ; then      #第二个参数是arm  成立
rm -f asm-$2/proc          # rm -f asm-arm/proc 
ln -s ${LNPREFIX}proc-armv asm-$2/proc      #ln -s proc-armv asm-arm/proc
fi

---------------------------------------------------------------------------------------------------------------

echo "ARCH   = $2" >  config.mk          #新建config.mk 文件,里面填写ARCH = arm
echo "CPU    = $3" >> config.mk                                                             CPU = arm920t
echo "BOARD  = $4" >> config.mk                                                          BOARD = 100ask24x0
                                                                                                                   SOC    = s3c24x0
[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk

[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC    = $6" >> config.mk           

---------------------------------------------------------------------------------------------------------------

创建单板相关的头文件

if [ "$APPEND" = "yes" ]   # Append 定义为no 执行else分支
then
echo >> config.h
else
> config.h            # 创建config.h
fi
echo "/* Automatically generated - do not edit */" >>config.h  

echo "#include <configs/$1.h>" >>config.h              #include <configs/100ask24x0_config.h>

exit 0

该文件分析得到:100ask24x0_config.h 为我们的配置文件。

配置过程总结:

    就是根据mkconfig这个脚本文件,来判断解析参数,生成cpu构架指向链接,生成含有ARCH、CPU、BOARD 、SOC等信息的 config.mk文件以供主Makefile使用及创建单板相关的头文件。

5、分析编译过程

#前面版本号之类的省略

include $(OBJTREE)/include/config.mk                    #此处包含了配置过程中生成的config.mk文件,替换主Makefile的变量

export ARCH CPU BOARD VENDOR SOC             选择交叉编译工具链、库等

OBJS  = cpu/$(CPU)/start.o                                  #此处根据config.mk文件选择 使用哪一个Start.o

LIBS  = lib_generic/libgeneric.a                             #此处根据config.mk文件选择库
LIBS += board/$(BOARDDIR)/lib$(BOARD).a

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

LIBS += lib_$(ARCH)/lib$(ARCH).a
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
LIBS += net/libnet.a
LIBS += disk/libdisk.a
LIBS += rtc/librtc.a
LIBS += dtt/libdtt.a
LIBS += drivers/libdrivers.a
LIBS += drivers/nand/libnand.a
LIBS += drivers/nand_legacy/libnand_legacy.a
LIBS += drivers/usb/libusb.a
LIBS += drivers/sk98lin/libsk98lin.a
LIBS += common/libcommon.a

LIBS += $(BOARDLIBS)

---------------------------------------------------------------------------------------------------------------

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

all: $(ALL)                                     #主编译依赖关系

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

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

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

$(obj)u-boot.img: $(obj)u-boot.bin
./tools/mkimage -A $(ARCH) -T firmware -C none \
-a $(TEXT_BASE) -e 0 \
-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \
-d $< $@

$(obj)u-boot.dis: $(obj)u-boot
$(OBJDUMP) -d $< > $@

$(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

分析起来很麻烦,我们直接编译,找到该处:

UNDEF_SYM=`arm-linux-objdump -x lib_generic/libgeneric.a board/100ask24x0/lib100ask24x0.a cpu/arm920t/libarm920t.a cpu/arm920t/s3c24x0/libs3c24x0.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/usb/libusb.a drivers/sk98lin/libsk98lin.a common/libcommon.a |sed  -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd /work/system/u-boot-1.1.6 && arm-linux-ld -Bstatic -T /work/system/u-boot-1.1.6/board/100ask24x0/u-boot.lds -Ttext 0x33F80000  $UNDEF_SYM cpu/arm920t/start.o \
--start-group lib_generic/libgeneric.a board/100ask24x0/lib100ask24x0.a cpu/arm920t/libarm920t.a cpu/arm920t/s3c24x0/libs3c24x0.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/usb/libusb.a drivers/sk98lin/libsk98lin.a common/libcommon.a --end-group -L /work/tools/gcc-3.4.5-glibc-2.3.6/lib/gcc/arm-linux/3.4.5 -lgcc \
-Map u-boot.map -o u-boot
arm-linux-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec

arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin

上文蓝色部分,得到了链接文件u-boot.lds   代码段的基地址:0x33F80000   及文件Start.o。

然后就是所有用到的库。

6、链接脚本分析: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;           /* -Ttext 0x33F80000   指定排放开始地址为:0x00000000+0x33F80000  */


. = ALIGN(4);
.text      :                       /* 第一个排放的内容,cpu/arm920t/start.o,由此我们得到,U-boot第一个文件为Start.S */
{
 cpu/arm920t/start.o (.text)                   /* start.o的代码段 */
          board/100ask24x0/boot_init.o (.text)      /* boot_init.o的代码段 */
 *(.text)                                                     /* 所有文件的代码段 */
}


. = ALIGN(4); 
.rodata : { *(.rodata) }                     /*  所有文件的只读数据段 */


. = ALIGN(4);
.data : { *(.data) }                       /* 所有文件的数据段  */


. = ALIGN(4);                            /*  全局变量地址段 */
.got : { *(.got) }


. = .;
__u_boot_cmd_start = .;                            /* u-boot 命令段 ,只有U-boot自己有*/
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;


. = ALIGN(4);                                    /* bss 段  */
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值