u-boot-spl.lds详解

u-boot-spl.lds 源码解读


/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Copyright (c) 2004-2008 Texas Instruments
 *
 * (C) Copyright 2002
 * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
 */

/* 指定输出可执行文件:"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文件.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值