您的位置:首页 > 其它

(二) u-boot 配置、编译过程分析

2017-07-28 18:50 441 查看
由于u-boot比较庞大,所以我们分开来分析,对于一个大型的项目我们想快速的了解其代码架构和内容,最方便的方法就是分析Makefile,所以我用uboot-1.1.6来分析Makefile。通过对u-boot的分析想要得到以下内容:

 1. U-boot的入口

 2. 链接地址

 由顶层Readme文件说明,可以知道如果要使用开发板board/,就先执行
make <boadr_name>_config
命令进行配置,然后执行
make all
,就可以生成如下3个文件

U-Boot.bin: 二进制可执行文件,它就是直接烧入NandFlash、NORFlash的文件

U-Boot:ELF格式的可执行文件

U-Boot.srec:Motorola S-Record格式的可执行文件

一、U-boot配置过程分析

① 先从Makefile文件中分析一下配置过程

搜索
100ask24x0_config


② 配置执行
make 100ask24x0_config
的时候,就相当执行这条命令:

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


③ 我们先在Makefile文件中搜索一下 MKCONFIG看一下是什么东西?

OBJTREE     := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE     := $(CURDIR)
TOPDIR      := $(SRCTREE)
LNDIR       := $(OBJTREE)
export  TOPDIR SRCTREE OBJTREE

MKCONFIG    := $(SRCTREE)/mkconfig
export MKCONFIG


④ 从上可以看出,在源文件的目录下面有一个mkconfig文件;

我们执行配置命令的时候,就相当执行这条脚本命令:

mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0


@代表的是目标100ask24x0_config, 那么$(@:_config=)就是将100ask24x0_config中的_config替换为空,得到100ask24x0

⑤ 接着需要打开mkconfig文件分析。mkconfig文件代码如下:

#!/bin/sh -e
## 上面这句指定执行该脚本所使用的解释器, -e相当于使用/bin/bash
# Script to create header files and links to configure
# U-Boot for a specific board.
#
# Parameters:  Target  Architecture  CPU  Board [VENDOR] [SOC]
#
# (C) 2002-2006 DENX Software Engineering, Wolfgang Denk <wd@denx.de>
#
# mkconfig    100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0
# $0			$1         $2   $3       $4       $5     $6
APPEND=no   # Default: Create new config file
BOARD_NAME=""   # Name to print in make output

#分析传入的参数里面有没有 "--",“-a”等
while [ $# -gt 0 ] ; do
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
*)  break ;;
esac
done

#判断BOARD_NAME有没有定义,如果没有则为:$1,其中$1为传入的第一个参数,依次类推

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

#判断参数的个数,不合条件就退出
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1

#打印这一句话
echo "Configuring for ${BOARD_NAME} board..."

#
# Create link to architecture specific headers
#

#判断源代码目录和目标文件目录是否一致
#如果这两个不相等,可以看一下makefile文件,这两个是从makefile里面来的
if [ "$SRCTREE" != "$OBJTREE" ] ; then
mkdir -p ${OBJTREE}/include
mkdir -p ${OBJTREE}/include2
cd ${OBJTREE}/include2
rm -f asm
ln -s ${SRCTREE}/include/asm-$2 asm
LNPREFIX="../../include2/asm/"
cd ../include
rm -rf asm-$2
rm -f asm
mkdir asm-$2
ln -s asm-$2 asm
else
#两个相等,程序进入这个分支
cd ./include
rm -f asm
#建立一个asm的链接文件,它指向asm-;配置的时候临时生成指向某一个架构,如果为i386架构,则为asm-i386
ln -s asm-$2 asm #ln -s asm-arm asm
fi

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

#如果第六个参数为NULL或者为空 LNPREFIX没有被定义
if [ -z "$6" -o "$6" = "NULL" ] ; then
ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
#我们这里执行这个分支
#建立一个链接文件,指向${LNPREFIX}arch-$6,其中$6为传进来的参数
ln -s ${LNPREFIX}arch-$6 asm-$2/arch  # ln -s arch-s3c24x0 asm-arm/arch
fi

if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc # ln -s proc-armv asm-arm/proc
fi

#
# Create include file for Make
#
#新建一个config.mk文件,> 表示新建
# >新建 >>追加
echo "ARCH   = $2" >  config.mk
#在config.mk追加, >> 表示追加
echo "CPU    = $3" >> config.mk
echo "BOARD  = $4" >> config.mk

#判断第5个参数,追加 VENDOR = xx
[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk

#判断第6个参数,追加 SOC    =  xx
[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC    = $6" >> config.mk

#
# Create board specific header file
#
if [ "$APPEND" = "yes" ]   # Append to existing config file
then
echo >> config.h
else
> config.h      # Create new config file
fi

#把以下内容追加到config.h文件中去
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include <configs/$1.h>" >>config.h
#其中 #include <configs/$1.h>  就是生成的配置文件

exit 0


⑥ 总结一下:在我们的配置过程中我们主要有一下工作:

# mkconfig    100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0
# $0			$1       $2   $3       $4       $5     $6


1.        开发板名称BOARD_NAME = $1 = 100ask24x0
2.        创建于开发板相关的头文件的链接,如下:


ln -s asm-arm($2) asm
ln -s arch-s3c24x0($6) asm-arm($2)/arch
ln -s proc-armv asm-arm($2)/proc  # 如果$2不是arm的话,此行没有


3.        创建顶层Makefile包含的文件include/config.mk,如下所示:


ARCH   = $2 = arm
CPU    = $3 = arm920t
BOARD  = $4 = 100ask24x0
VENDOR = $5 = NULL # $5为空,或者是NULL的话,此行没有
SOC    = $6 = s3c24x0 # $6为空,或者是NULL的话,此行没有


4.        创建开发板相关头文件include/config.h


/* Automatically generated - do not edit */
#include <configs/100ask24x0($1).h>


从上面我们可以知道,如果要在board目录下新建一个开发板的目录,则在include/configs目录下也要建立一个文件
<board_name.h>
,里面存放的就是
<board_name>
的配置信息。

U-boot还没有类似Linux一样的可视化配置界面(比如使用make menuconfig来配置),要手动修改配置文件
include/configs/<board_name>.h
来裁减、设置 U-Boot。

二、U-boot编译过程分析

① 接着分析一下编译过程,在makefile文件里面,有如下代码:

include $(OBJTREE)/include/config.mk


这里的config.mk就是上面配置生成的配置文件,这就将配置与编译结合起来了;

注:在我们执行make的时候其将会生成第一个目标也就是all,以all为突破口我们找到all.

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


而u-boot.srec u-boot.bin又依赖于u-boot

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


 ② 通过展开编译命令(当然有点麻烦)我们可以直接执行
make
/
make all
然后找到和这条命令相似的命令,通过得到的命令我们可以顺利的找到其在编译过程中所用到的链接器脚本



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 \


打开u-boot-1.1.6/board/100ask24x0/u-boot.lds

/*
* (C) Copyright 2002
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)//入口地址_start
SECTIONS
{
. = 0x00000000;

. = ALIGN(4);
.text      : //代码段排布
{
cpu/arm920t/start.o   (.text) //先是该代码,最先连接运行
board/100ask24x0/boot_init.o (.text)
*(.text)
}

. = 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);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}


③ 在连接脚本中,最先连接运行的是
cpu/arm920t/start.o
,在cpu/arm920t/start.S我们可以轻松找到其所有代码的入口

.globl _start
_start: b       reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq

_undefined_instruction: .word undefined_instruction
_software_interrupt:    .word software_interrupt
_prefetch_abort:    .word prefetch_abort
_data_abort:        .word data_abort
_not_used:      .word not_used
_irq:           .word irq
_fiq:           .word fiq

.balignl 16,0xdeadbeef
...................


④ 至此我们找到了正个程序的入口,但是其的链接地址又在什么地方呢?

- Ⅰ .我们先来搜索一下上面的连接地址0x33F80000



board/100ask24x0/config.mk:25:TEXT_BASE = 0x33F80000


- Ⅱ.我们进入board/100ask24x0/config.mk一探究竟



TEXT_BASE = 0x33F80000


- Ⅲ.我们主Makefile中怎样连接到这里的呢,目标u-boot有一个配置符号,很熟悉:





我们再来回顾一遍,通过make后逆向的过程验证一下:



⑤ 我们来小结一下U-boot编译中获得的东西:

第一个文件:cpu/arm920t/start.S

链接地址:board/100ask24x0/config.mk -> 0x33F80000

三、总结:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: