u-boot-spl.lds详解

U-Boot2018.11 下ARMV7 u-boot-spl.lds详解

    • u-boot-spl.lds 源码解读
    • 相关知识总结
      • [汇编]SECTIONS
      • [汇编]arm的.text段/.code段/.bss段....
      • 总结

u-boot-spl.lds 源码解读


/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Copyright (c) 2004-2008 Texas Instruments
 *
 * (C) Copyright 2002
 * Gary Jennejohn, DENX Software Engineering, 
 */

/* 指定输出可执行文件:"elf32位小端格式" */
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/* 指定输出可执行文件的目标架构:"arm" */
OUTPUT_ARCH(arm)
/* 指定输出可执行文件的入口地址(起始代码段):"_start" */
ENTRY(_start)
SECTIONS
{
	/* 
	 * 设置0的原因是,arm内核的处理器,三点后默认是从0x00000000处启动
	 * 1.以stm32为例片内的nor-flash起始地址是0x08000000,这里是我们烧写u-boot.bin的位置
	 * 2.上电后,系统会自动将该地址(0x0800:0000)映射到0x0000:0000(硬件完成)
	 */
	. = 0x00000000;
	
	/* 
	 * 代码以4字节对齐 .text为代码段
	 * 各个段按先后顺序依次排列 
	 * 在cortex-m的内核中,首地址存放的是主堆栈的地址,其次存放中断向量表
	 */
	. = ALIGN(4);
	.text :
	{
		__image_copy_start = .; /* u-boot里默认会将u-boot的镜像拷贝到ram(sdram,ddr....)中执行 */
		*(.vectors)				/* 存放的是中断向量表 */
		CPUDIR/start.o (.text*) /* 存放CPUDIR/start.o中的所有.text段 */
		*(.text*)					/* 存放其他.o中的所有.text段 */
		*(.glue*)					/* 存放其他.o中的所有.glue段 */
	}
	/* 从上面的结构中可以发现这种格式都是:地址(.段) 这样的形式出现 */

	/* 
	 * .rodata段,确保是以4字节对齐处开始 
	 */
	. = ALIGN(4);	
	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }	/* 从名称上就可以知道,按名称依次存放其他.o文件中的.rodata */

	/* 
	 *data段,确保是以4字节对齐处开始 
	 */
	. = ALIGN(4);	
	.data : {
		*(.data*) 
	}

	/* 
	 * u_boot_list段,确保是以4字节对齐处开始 
	 * 这里存放的都是u_boot_list中的函数
	 * 例如:base/bdinfo/blkcache/cmp....
	 * 具体的可参看./u-boot.map .u_boot_list
	 * tips:要想优化编译出来的u-boot.bin大小,可以参看此文件进行对照裁剪
	 */
	. = ALIGN(4);
	.u_boot_list : {
		KEEP(*(SORT(.u_boot_list*)));
	}

	/* 
	 * binman_sym_table段,确保是以4字节对齐处开始 
	 * binman实现的功能是让c代码通过binman_*的函数接口字节调用镜像中的个别函数
	 * 具体可参看binman_sym.h中的接口
	 */
	. = ALIGN(4);
	.binman_sym_table : {
		__binman_sym_start = .;
		KEEP(*(SORT(.binman_sym*)));
		__binman_sym_end = .;
	}

	/* 
	 * __image_copy_end段,确保是以4字节对齐处开始 
	 * 镜像拷贝的完成
	 */
	. = ALIGN(4);

	__image_copy_end = .;

	.rel.dyn : {
		__rel_dyn_start = .;
		*(.rel*)
		__rel_dyn_end = .;
	}

	.end :
	{
		*(.__end)
	}
	/* bin文件结束 */
	_image_binary_end = .;

	.bss __rel_dyn_start (OVERLAY) : {
		__bss_start = .;
		*(.bss*)
		 . = ALIGN(4);
		__bss_end = .;
	}
	__bss_size = __bss_end - __bss_start;
	.dynsym _image_binary_end : { *(.dynsym) }
	.dynbss : { *(.dynbss) }
	.dynstr : { *(.dynstr*) }
	.dynamic : { *(.dynamic*) }
	.hash : { *(.hash*) }
	.plt : { *(.plt*) }
	.interp : { *(.interp*) }
	.gnu : { *(.gnu*) }
	.ARM.exidx : { *(.ARM.exidx*) }
}

#if defined(CONFIG_SPL_MAX_SIZE)
ASSERT(__image_copy_end - __image_copy_start < (CONFIG_SPL_MAX_SIZE), \
	"SPL image too big");
#endif

#if defined(CONFIG_SPL_BSS_MAX_SIZE)
ASSERT(__bss_end - __bss_start < (CONFIG_SPL_BSS_MAX_SIZE), \
	"SPL image BSS too big");
#endif

#if defined(CONFIG_SPL_MAX_FOOTPRINT)
ASSERT(__bss_end - _start < (CONFIG_SPL_MAX_FOOTPRINT), \
	"SPL image plus BSS too big");
#endif


相关知识总结

[汇编]SECTIONS

SECTIONS {
...
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
  { contents } >region :phdr =fill
...
}

SECTIONS
{
    . = 0x00000000;      // 应该是存储地址,存储地址(加载的地址)
    . = ALIGN(4);        // 4字节对齐
    .text      :         //此处应该是secname 段名
   {
         cpu/arm920t/start.o (.text)//大括号,contents段,指示该段存放的内容
        *(.text)
   }
   . = ALIGN(4);                    //以下类似
   .rodata : { *(.rodata) }
标示 规则
secname 段名, 比如常见的.text/.data等等
contents 决定哪些内容存放在此段
start 本段的连接地址(实际运行地址)
AT(ldadr) 存储地址(加载的地址)

[汇编]arm的.text段/.code段/.bss段…

  • bss段(bsssegment)
    通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS段属于静态内存分配.

  • data段(datasegment)
    通常是指用来存放程序中已初始化的全局变量的一块内存区域。BSS段属于静态内存分配.

  • text段(textsegment)
    通常是指用来存放程序执行代码的一块内存区域。就是我们编写的程序代码(函数等等).

  • rodata段(rodatasegment)
    通常是指用来存放C中的字符串和宏定义的常量.

总结

总的来说,我们能大概的了解到我们编写的c/c++源代码大概经历先单个编译产生.o,这里面包含了这个文件的.text/.bss/.data等等段,而我们的链接文件,最后会大一统,将工程下的所有目标文件,按链接脚本的规则(按各种段分门别类的)把各个文件汇总,最终产生.bin文件.

你可能感兴趣的:(u-boot)