uboot启动流程(1)之链接脚本u-boot.lds详解

大部分转载了大神的博客:uboot启动流程(1)之链接脚本u-boot.lds详解_蒋文韬的博客-CSDN博客

部分穿插了对自身平台内容的理解。

=========================================================================

要分析 uboot 的启动流程,首先要找到“入口”,找到第一行程序在哪里。程序的链接是由链接脚本来决定的,所以通过链接脚本可以找到程序的入口。如果没有编译过 uboot 的话链接脚本为arch/arm/cpu/u-boot.lds。但是这个不是最终使用的链接脚本,最终的链接脚本是在这个链接脚本的基础上生成的。编译一下 uboot,编译完成以后就会在 uboot 根目录下生成 u-boot.lds文件

 只有编译 u-boot 以后才会在根目录下出现 u-boot.lds 文件!

打开 u-boot.lds,内容如下(以下文件内容是我所用的A40/T3平台)

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
 . = 0x4A000000;
 . = ALIGN(4);
 
 .head :
 {
	*(.__image_copy_start)
	arch/arm/cpu/armv7/spare_head.o (.data*)
 }
 
 .hash :
 {
	arch/arm/cpu/armv7/uboot_hash.o(.data*)
 }

 . = ALIGN(4);
 .text :
 {
	*(.vectors)
	arch/arm/cpu/armv7/start.o (.text*)
	*(.text*)
 }

 . = ALIGN(4);
 .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
 . = ALIGN(4);
 .data : 
 {
	*(.data*)
 }

 . = ALIGN(4);
 . = .;
 . = ALIGN(4);
 .u_boot_list : 
 {
	KEEP(*(SORT(.u_boot_list*)));
 }
 
 . = ALIGN(4);
 .image_copy_end :
 {
	*(.__image_copy_end)
 }
 
 .rel_dyn_start :
 {
	*(.__rel_dyn_start)
 }
 
 .rel.dyn : 
 {
	*(.rel*)
 }
 
 .rel_dyn_end :
 {
	*(.__rel_dyn_end)
 }
 
 .end :
 {
	*(.__end)
 }
 
 _image_binary_end = .;
 . = ALIGN(4096);
 .mmutable : {
  *(.mmutable)
 }
 .bss_start __rel_dyn_start (OVERLAY) : {
  KEEP(*(.__bss_start));
  __bss_base = .;
 }
 .bss __bss_base (OVERLAY) : {
  *(.bss*)
   . = ALIGN(4);
   __bss_limit = .;
 }
 .bss_end __bss_limit (OVERLAY) : {
  KEEP(*(.__bss_end));
 }
 .dynsym _image_binary_end : { *(.dynsym) }
 .dynbss : { *(.dynbss) }
 .dynstr : { *(.dynstr*) }
 .dynamic : { *(.dynamic*) }
 .plt : { *(.plt*) }
 .interp : { *(.interp*) }
 .gnu.hash : { *(.gnu.hash) }
 .gnu : { *(.gnu*) }
 .ARM.exidx : { *(.ARM.exidx*) }
 .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
}

第 3 行为代码当前入口点:_start, _start 在文件 arch/arm/lib/vectors.S 中有定义

uboot启动流程(1)之链接脚本u-boot.lds详解_第1张图片

=========================================================================

(注:我的A40/T3平台略有不同,使用了一个“reset_vec”变量,但该变量实际指向的还是“reset”)

uboot启动流程(1)之链接脚本u-boot.lds详解_第2张图片

 uboot启动流程(1)之链接脚本u-boot.lds详解_第3张图片

=========================================================================

可以看出,_start 后面就是中断向量表,从图中的“.section “.vectors”, "ax”可以得到,此代码存放在.vectors 段里面。使用如下命令在 uboot 中查找“__image_copy_start”:
grep -nR “__image_copy_start”打开 u-boot.map
uboot启动流程(1)之链接脚本u-boot.lds详解_第4张图片

 打开 u-boot.map

uboot启动流程(1)之链接脚本u-boot.lds详解_第5张图片

 

u-boot.map 是 uboot 的映射文件,可以从此文件看到某个文件或者函数链接到了哪个地址,从图中的 932 行可以看到__image_copy_start 为 0X87800000,而.text 的起始地址也是0X87800000。

=========================================================================

(注:以下时我的A40/T3平台的u-boot.map

uboot启动流程(1)之链接脚本u-boot.lds详解_第6张图片

 可以看到A40/T3平台'__image_copy_start'的起始地址是0x4a000000,但是.text 的起始地址是0x4a000640,因为在.text前还有个.head段和.hash段,从spare_head.o和uboot_hash.o可以看出这两段代码是在:spare_head.c 和 uboot_hash.c 文件中,如下:

spare_head.c文件:

/*
 * (C) Copyright 2007-2013
 * Allwinner Technology Co., Ltd. 
 * Jerry Wang 
 *
    ...... 此处略去
 *
 * 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
 */

#include 
#include 
extern char uboot_hash_value[64];
#pragma pack(1)
struct spare_boot_head_t  uboot_spare_head = 
{
    {
        /* jump_instruction */          
        ...... 此处略去
    }
};

#pragma pack()
/*******************************************************************************
*
*                  关于Boot_file_head中的jump_instruction字段
*
*  jump_instruction字段存放的是一条跳转指令:( B  BACK_OF_Boot_file_head ),此跳
*转指令被执行后,程序将跳转到Boot_file_head后面第一条指令。
*
*  ARM指令中的B指令编码如下:
*          +--------+---------+------------------------------+
*          | 31--28 | 27--24  |            23--0             |
*          +--------+---------+------------------------------+
*          |  cond  | 1 0 1 0 |        signed_immed_24       |
*          +--------+---------+------------------------------+
*  《ARM Architecture Reference Manual》对于此指令有如下解释:
*  Syntax :
*  B{}  
*        Is the condition under which the instruction is executed. If the
*               is ommitted, the AL(always,its code is 0b1110 )is used.
*    
*              Specified the address to branch to. The branch target address is
*              calculated by:
*              1.  Sign-extending the 24-bit signed(wro's complement)immediate
*                  to 32 bits.
*              2.  Shifting the result left two bits.
*              3.  Adding to the contents of the PC, which contains the address
*                  of the branch instruction plus 8.
*
*  由此可知,此指令编码的最高8位为:0b11101010,低24位根据Boot_file_head的大小动
*态生成,所以指令的组装过程如下:
*  ( sizeof( boot_file_head_t ) + sizeof( int ) - 1 ) / sizeof( int )    求出文件头
*                                              占用的“字”的个数
*  - 2                                         减去PC预取的指令条数
*  & 0x00FFFFFF                                求出signed-immed-24
*  | 0xEA000000                                组装成B指令
*
*******************************************************************************/

该文件中就是对定义的 “struct spare_boot_head_t  uboot_spare_head” 结构体变量赋值,该结构体变量的定义如下:

struct spare_boot_head_t
{
	struct spare_boot_ctrl_head    boot_head;
	struct spare_boot_data_head    boot_data;
	struct spare_boot_ext_head     boot_ext[16];
};

内部是定义了三个结构体变量,这三个结构体的定义可以自行看代码,计算后的大小也是0x600与.head段的大小相对应。

 uboot_hash.c 文件

/*
 * (C) Copyright 2007-2013
 * Allwinner Technology Co., Ltd. 
 * Jerry Wang 
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
    ...... 此处略去
 *
 * 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
 */
 #include 
 char uboot_hash_value[64] = {0x38};

而uboot_hash.c 文件只是定义了一个64字节的数组,即0x40的大小,与.hash段的大小相对应

至于以上两段是用来干嘛的,暂时还未深究,留待后面再去挖掘

因此该A40/T3平台.text 的起始地址是0x4a000640

=========================================================================

继续回到u-boot.lds中,第 11 行是 vectors 段,vectors 段保存中断向量表,从vector.S中我们知道了 vectors.S 的代码是存在 vectors 段中的。从u-boot.map可以看出,vectors 段的起始地址也是0X87800000,说明整个 uboot 的起始地址就是 0X87800000,这也是为什么我们裸机例程的链接起始地址选择 0X87800000 了,目的就是为了和 uboot一致。
第 12 行将 arch/arm/cpu/armv7/start.s 编译出来的代码放到中断向量表后面。
第 13 行为 text 段,其他的代码段就放到这里
在 u-boot.lds 中有一些跟地址有关的“变量”需要我们注意一下,后面分析 u-boot 源码的时候会用到,这些变量要最终编译完成才能确定的!!!比如我编译完成以后这些“变量”的值

变量 数值 描述
__image_copy_start 0x87800000 uboot 拷贝的首地址
__image_copy_end 0x8785dd54 uboot 拷贝的结束地址
__rel_dyn_start 0x8785dd54 .rel.dyn 段起始地址
__rel_dyn_end 0x878668f4 .rel.dyn 段结束地址
_image_binary_end 0x878668f4 镜像结束地址
__bss_start 0x8785dd54 .bss 段起始地址
__bss_end 0x878a8e74 .bss 段结束地址

“变量”值可以在 u-boot.map 文件中查找,除了__image_copy_start以外,其他的变量值每次编译的时候可能会变化,如果修改了 uboot 代码、修改了 uboot 配置、选用不同的优化等级等等都会影响到这些值。所以,一切以实际值为准!

你可能感兴趣的:(#,Uboot,linux,内核,驱动程序,uboot)