uboot2013.07lds分析
uboot 2013.07 lds 分析
转载自: uboot 2013.07 lds 分
析 .OUTPUT_FORMAT("elf32-littlearm", "elf32-
littlearm",
//指定输出可执行文件是 elf 格式 ,32 位
ARM 指令 ,小端 OUTPUT_ARCH(arm) //指定输出可执行
文件的平台为 ARMENTRY(_start) // 指定函数入口点为 _start 。
cpu/arm920t/start.S
0x00000000; // 指定可执行 image 文件的全局入口点,通常
这个地址都放在 ROM(flash)0x0 位置。
必须使编译器知道这
以4 字节对齐 .text : //代码段
00000000 T __image_copy_start 见 __image_copy_start 等同于 _start
CPUDIR/start.o (.text*) // 代码段的第一个代码部分 ALIGN(4); .rodata :
"elf32-littlearm") 中定义 SECTIONS{
个地址,通常都是修改此处来完成 . = ALIGN(4); // 代码
*(.__image_copy_start) // 在 System.map
匚=f
00000000 T _start, *(.text*)
//其它代码部分
{ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } 对应原来的 U_BOOT_CMD 对于那个的段 .
KEEP(*(SORT(.u_boot_list*))); * 在 System.map 中
0006f52c D _u_boot_list_2_env_clbk_2_flags
0006f534 D _u_boot_list_2_env_clbk_2_loadaddr
0006f53c B __bss_base
0006f53c B __bss_start
0006f53c B monitor_flash_len
0006f53c D __image_copy_end
0006f53c D __rel_dyn_start
//指定只读数据段 . = ALIGN(4); .data : { // 指定读 / 写数据段
*(.data*) ALIGN(4); . = ALIGN(4); .u_boot_list : {
// } . = ALIGN(4);/*
*/ .image_copy_end :
*(.__image_copy_end) } .rel_dyn_start : //0006f53c D __rel_dyn_start
*(.rel*) //.rel 段落保存了相对跳转的地址
和相对 } .rel_dyn_end : //00078874 R
this MMU section is used by pxa at present but should not be used by new boards/CPUs. bss_start and __bss_end, see arch/arm/lib/bss.c *
bss_base and __bss_limit are for linker only
(overlay
容 .bss_start __rel_dyn_start (OVERLAY) :
0006f53c D __image_copy_end
.bss_end __bss_limit (OVERLAY) :
KEEP(*(.__bss_end)); //000bd6a0 B
bss_end } /DISCARD/ : { *(.dynsym) }
*(.__rel_dyn_start) } .rel.dyn :
跳转的类型
rel_dyn_end *(.__rel_dyn_end)
end = .; //00078874 A _end /*
* Deprecated: */
ALIGN(4096); .mmutable :
*(.mmutable) }/* * Compiler-generated
ordering) */ //保存了未初始化的全局变量的内
{ //0006f53c B __bss_start
0006f53c D __rel_dyn_start
KEEP(*(.__bss_start));
bss_base } .bss
bss_base (OVERLAY) : { //0006f53c B __bss_base *(.bss*) . = ALIGN(4);
bss_limit = .; //000bd6a0 B
bss_limi }
/DISCARD/ : { *(.dynstr*) } /DISCARD/ : { *(.dynamic*) } /DISCARD/ : { *(.plt*) } /DISCARD/ : { *(.interp*) }
/DISCARD/ : { *(.gnu*) }}。
U-boot代码解析
u-boot源码解析u-boot介绍Uboot是德国DENX小组的开发用于多种嵌入式CPU的bootloader程序, UBoot不仅仅支持嵌入式Linux系统的引导,当前,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS 嵌入式操作系统。
UBoot除了支持PowerPC系列的处理器外,还能支持MIPS、 x86、ARM、NIOS、XScale等诸多常用系列的处理器。
board:和一些已有开发板有关的文件。
每一个开发板都以一个子目录出现在当前目录中,子目录中存放与开发板相关的配置文件。
它的每个子文件夹里都有如下文件:makefileconfig.mksmdk2410.c 和板子相关的代码(以smdk2410为例)flash.c Flash操作代码memsetup.s 初始化SDRAM代码u-boot.lds 对应的连接文件common:实现uboot命令行下支持的命令,每一条命令都对应一个文件。
例如bootm命令对应就是cmd_bootm.c。
cpu:与特定CPU架构相关目录,每一款Uboot下支持的CPU在该目录下对应一个子目录,比如有子目录arm920t等。
cpu/ 它的每个子文件夹里都有如下文件:makefileconfig.mkcpu.c 和处理器相关的代码interrupts.c 中断处理代码serial.c 串口初始化代码start.s 全局开始启动代码disk:对磁盘的支持。
doc:文档目录。
Uboot有非常完善的文档,推荐大家参考阅读。
drivers:Uboot支持的设备驱动程序都放在该目录,比如各种网卡、支持CFI的Flash、串口和USB等。
fs: 支持的文件系统,Uboot现在支持cramfs、fat、fdos、jffs2和registerfs。
include:Uboot使用的头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的文件。
gcc编程环境基础4--ld命令和u-boot中的lds文件实例和简单实例分析
4.简单例子
5.简单脚本命令
6.对符号的赋值
7. SECTIONS命令
8. MEMORY命令
9. PHDRS命令
10. VERSION命令
11.脚本内的表达式
12.暗含的连接脚本
1.概论
--------------------------------------------------------------------------------
符号(symbol):每个目标文件都有符号表(SYMBOL TABLE),包含已定义的符号(对应全局变量和static变量和定义的函数的名字)和未定义符号(未定义的函数的名字和引用但没定义的符号)信息.
符号值:每个符号对应一个地址,即符号值(这与c程序内变量的值不一样,某种情况下可以把它看成变量的地址).可用nm命令查看它们. (nm的使用方法可参考本blog的GNU binutils笔记)
如果.data section的LMA为0x08050000,显然结果是j=2
如果.data section的LMA为0x08050004,显然结果是j=1
还可这样理解LMA:
.text section内容的开始处包含如下两条指令(intel i386指令是10字节,每行对应5字节):
jmp 0x08048285
-T选项用以指定自己的链接脚本,它将代替默认的连接脚本.你也可以使用<暗含的连接脚本>以增加自定义的链接命令.
以下没有特殊说明,连接器指的是静态连接器.
2.基本概念
--------------------------------------------------------------------------------
UBOOT源码分析
UBOOT源码分析UBOOT是一种开放源码的引导加载程序。
作为嵌入式系统启动的第一阶段,它负责初始化硬件设备、设置系统环境变量、加载内核镜像以及跳转到内核开始执行。
Uboot的源码是开放的,让我们可以深入了解其内部工作机制和自定义一些功能。
Uboot源码的文件组织结构非常清晰,主要分为三个大类:目录、文件和配置。
其中目录包含了一系列相关的文件,文件存放具体的源码实现代码,配置文件包含了针对特定硬件平台的配置选项。
Uboot源码的核心部分是启动代码,位于arch目录下的CPU架构相关目录中。
不同的CPU架构拥有不同的启动代码实现,如arm、x86等。
这些启动代码主要包括以下几个关键功能:1. 初始化硬件设备:Uboot首先需要初始化硬件设备,例如设置时钟、中断控制器、串口等设备。
这些初始化操作是在启动代码中完成的。
通过查看该部分代码,我们可以了解硬件的初始化过程,以及如何配置相关寄存器。
2. 设置启动参数:Uboot启动参数存储在一个称为"bd_info"的数据结构中,它包含了一些关键的设备和内存信息,例如DRAM大小、Flash 大小等。
这些参数是在启动代码中设置的,以便内核启动时能够正确识别硬件情况。
3. 加载内核镜像:Uboot负责加载内核镜像到内存中,以便内核可以正确执行。
在启动代码中,会通过读取Flash设备或者网络等方式,将内核镜像加载到指定的内存地址处。
加载过程中,可能会进行一些校验和修正操作,以确保内核数据的完整性。
4. 启动内核:在内核镜像加载完成后,Uboot会设置一些寄存器的值,并执行一个汇编指令,跳转到内核开始执行。
此时,Uboot的使命即结束,控制权交由内核处理。
除了启动代码,Uboot源码中还包含了许多其他功能模块,如命令行解析器、存储设备驱动、网络协议栈等。
这些功能模块可以根据需求进行配置和编译,以满足不同平台的需求。
例如,可以通过配置文件选择启用一些功能模块,或者自定义一些新的功能。
uboot笔记uboot命令分析+实现
uboot笔记uboot命令分析+实现uboot笔记:uboot命令分析+实现Ubootuboot命令分析+实现先贴⼀个重要结构,位于uboot/include/command.h,这个结构代表每个uboot命令struct cmd_tbl_s {char *name; /* Command Name */int maxargs; /* maximum number of arguments*/int repeatable;/* autorepeat allowed? *//* Implementation function */int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);char *usage; /* Usage message (short)简短⽤法信息*/#ifdef CFG_LONGHELPchar *help; /* Help message (long) 长的帮助信息*/#endif#ifdef CONFIG_AUTO_COMPLETE/* do auto completion on the arguments */ int (*complete)(intargc, char *argv[], charlast_char, intmaxv, char *cmdv[]); #endif};typedefstruct cmd_tbl_s cmd_tbl_t;============================================================uboot的第⼀阶段:硬件相关初始化0.reset执⾏arm920t/start.s 过程如下1.设置cpu svc管理模式2.关看门狗中断,mmu等3.设置时钟,sdram,外部总线4.代码重定位,搬运代码,从flash到sdram5.设置栈,bss段清零, bss⽤于未初始化的全局变量和静态变量6.ldr pc, _start_armboot即进⼊uboot启动的第⼆阶段,调⽤c函数start_armboot()从start_armboot开始经过⼀系列外设初始化⽐如falsh_initnand_init...最后循环调⽤mian_loop()main_loop主要流程{1. ⽣成环境变量mtdparts, 调⽤mtdparts_init2. 在启动过程中若⽆空格键按下则boot_zImage,即run_command(getenv("bootcmd"),0)有空格键按下则run_command("menu",0)3. shell过程,读取⽤户的输⼊并执⾏相应的命令{从控制台获得命令,保存在全局变量comsole_buffer中解析命令⾏字符串,分割命令与参数,最后执⾏run_command(...); }}也就是说在mian_loop中,是处理环境变量和控制台⼈机交互,mian_loop调⽤readline ()读取命令⾏到console_buffer,再把console_buffer复制到lastcommand中去,还要设置flag,最后调⽤run_command (lastcommand, flag)函数,run_command (lastcommand, flag)函数中,⾸先定义cmd_tbl_t *cmdtp,再解析命令⾏。
u_boot移植(五)之分析uboot源码中nand flash操作
u_boot移植(五)之分析uboot源码中nand flash操作一、OneNand 和Nand Flash我们已经能从Nand Flash启动了,启动之后,大家会看到如下效果:可以看出,我们的uboot默认使用的是OneNand。
需要注意的是我们的FSC100上面是没有OneNand的,有的是K9F2G08U0B型号的NAND FLASH。
前面我们了解过Nor Flash 和Nand Flash,那OneNand Flash又是什么呢?二、uboot 源码中Nand Flash部分代码分析我们从Nand Flash初始化看起,打开lib_arm/board.c文件,为了紧抓主线,以下代码只列举出了主线代码。
可以看出,我们可以通过CONFIG_CMD_NAND和CONFIG_CMD_ONENAND两个宏来选择NAND FLASH初始化还是 ONENAND FLASH初始化。
uboot 中默认定义了宏CONFIG_CMD_ONENAND,所以选择的是ONENAND FLASH初始化。
我们的FSC100上面使用的是NAND FLASH,所以我们要定义CONFIG_CMD_NAND宏,取消CONFIG_CMD_ONENAND宏的定义。
嗯!先做个记录:修改include/configs/fsc100.h,定义宏CONFIG_CMD_NAND,取消宏CONFIG_CMD_ONENAND。
好了,接下我们看看nand_init()函数时如何实现的。
看以看出,这段代码调用根据CONFIG_SYS_MAX_NAND_DEVICE宏[默认没有定义]的值来决定系统中Nand Flash设备的个数。
接着调用nand_init_chip()函数完成Nand Flash初始化,然后计算出每块Nand Flash的大小。
最终会输出Nand Flash总的容量。
嗯!做个记录:修改include/configs/fsc100.h,定义宏CONFIG_SYS_MAX_NAND_DEVICE,值为1没有看明白的地方是给nand_init_chip()函数传递的参数,接下来我们来看看他们是如何定义的。
uboot启动流程分析
uboot启动流程分析Uboot启动流程分析。
Uboot是一种常用的嵌入式系统启动加载程序,它的启动流程对于嵌入式系统的正常运行至关重要。
本文将对Uboot启动流程进行分析,以便更好地理解其工作原理。
首先,Uboot的启动流程可以分为以下几个步骤,Reset、初始化、设备初始化、加载内核。
接下来我们将逐一进行详细的分析。
Reset阶段是整个启动流程的起点,当系统上电或者复位时,CPU会跳转到Uboot的入口地址开始执行。
在这个阶段,Uboot会进行一些基本的硬件初始化工作,包括设置栈指针、初始化CPU寄存器等。
接着是初始化阶段,Uboot会进行一系列的初始化工作,包括初始化串口、初始化内存控制器、初始化时钟等。
这些初始化工作是为了确保系统能够正常地运行,并为后续的工作做好准备。
设备初始化阶段是Uboot启动流程中的一个重要环节,它包括对外设的初始化和检测。
在这个阶段,Uboot会初始化各种外设,如网卡、存储设备等,并对其进行检测,以确保它们能够正常工作。
最后一个阶段是加载内核,Uboot会从存储设备中加载操作系统的内核镜像到内存中,并跳转到内核的入口地址开始执行。
在这个过程中,Uboot会进行一些必要的设置,如传递启动参数给内核,并最终将控制权交给内核。
总的来说,Uboot的启动流程是一个非常重要的过程,它涉及到系统的硬件初始化、外设的初始化和内核的加载等工作。
只有当这些工作都顺利完成时,系统才能够正常地启动运行。
因此,对Uboot启动流程的深入理解对于嵌入式系统的开发和调试具有重要意义。
通过本文对Uboot启动流程的分析,相信读者对Uboot的工作原理有了更清晰的认识。
希望本文能够对大家有所帮助,谢谢阅读!。
UBOOT的lds文件
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")/*指定输出可执行文件是elf格式,32位ARM指令,小端*/OUTPUT_ARCH(arm)/*指定输出可执行文件的平台为ARM*/ENTRY(_start)/*指定输出可执行文件的起始代码段为_start*/SECTIONS{/*指定可执行image文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置。
必须使编译器知道这个地址,通常都是修改此处来完成*/. = 0x00000000;/*;从0x0位置开始*/. = ALIGN(4);/*代码以4字节对齐*/.text :{cpu/arm920t/start.o (.text)/*代码的第一个代码部分*/*(.text)/*下面依次为各个text段函数*/}. = ALIGN(4);/*代码以4字节对齐*/.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }/*指定只读数据段*/. = ALIGN(4);/*代码以4字节对齐*/.data : { *(.data) }. = ALIGN(4);/*代码以4字节对齐*/.got : { *(.got) }/*指定got段, got段是uboot自定义的一个段, 非标准段*/. = .;__u_boot_cmd_start = .;/*把__u_boot_cmd_start赋值为当前位置, 即起始位置*/.u_boot_cmd : { *(.u_boot_cmd) }/*指定u_boot_cmd段, uboot把所有的uboot命令放在该段.*/__u_boot_cmd_end = .;/*把__u_boot_cmd_end赋值为当前位置,即结束位置*/. = ALIGN(4);/*代码以4字节对齐*/__bss_start = .;/*把__bss_start赋值为当前位置,即bss段的开始位置*/.bss (NOLOAD) : { *(.bss) . = ALIGN(4); }/*指定bss段,告诉加载器不要加载这个段*/__bss_end = .;/*把_end赋值为当前位置,即bss段的结束位置*/}看完上面的解析思路本来应该是很清晰的,于是乎编译u-boot,查看一下System.map,30100000 T _start30100020 t _undefined_instruction30100024 t _software_interrupt30100028 t _prefetch_abort3010002c t _data_abort30100030 t _not_used30100034 t _irq30100038 t _fiq发现_start 的链接地址不是u-boot.lds中.text 的当前地址0x00000000,而是0x30100000,这就产生很多疑问了:(1) 为什么u-boot.lds指定的 .text 的首地址不起作用?(2) 0x30100000是什么地址,由谁指定.text的首地址是0x30100000的呢?(3) 假如有其他动作改变了 .text 的首地址,那么该动作跟u-boot.lds的优先级又是怎么决定的呢?其实这三个问题都在Makefile的LDFLAGS 变量和u-boot.lds 中找到答案。
lds分析
;指定输出可执行文件是elf格式,32位ARM指令,小端
OUTPUT_ARCH(arm)
;指定输出可执行文件的平台为ARM
ENTRY(_start)
_start = 0;当此段在RAM中执行时_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值为0x33F80000,
即u-boot在把代码拷贝到RAM中去执行的代码段的开始) */
ldr r1, _TEXT_BASE /* 测试判断是从Flash启动,还是RAM */
现在,我们首先开看一看 xloader.lds 的代码:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(XLOADER_ENTRY) SECTIONS {
. = 0x00000000; . = ALIGN(4); .text : {
;指定输出可执行文件的起始代码段为_start.
SECTIONS
{
. = 0x00000000 . = ALIGN(4) .text :
; 从0x0位置开始 ; 代码以4字节对齐 ;指定代码段
{
cpu/arm920t/start.o (.text) ; 代码的第一个码部分 *(.text) ;其它代码部分
uboot命令解释与运行分析
uboot命令解释与运行分析题记: 省略200字这一回来分析一下uboot中命令行的解释, 所以我们直接从main_loop开始分析.1. 从汇编阶段进入c阶段的第一个函数是start_xxx, 如/lib_unicore/board.c中的start_unicoreboot. 前半部分调用了若干初始化函数来进行部分硬件的初始化, 并设置一下环境. 这里不是我们本回要讨论的所以一一跳过. 在start_xxx的最后调用了main_loop(), 而且还是被一个死循环死死圈住了;2. 现在我们已经进入了这个圈套那么只能往里钻了. common/main.c文件中的main_loop().上面代码主要是对自启动部分的描述, 其中命令执行部分是在run_command中进行的, 这个等在后文分析. 如果我们没有bootcmd 或者在延时中被打断, 那么代码会继续向下执行3.read_line()读取到命令行后会调用common/main.c文件中的run_command().现在是分析run_command()的时候了,不管是从环境变量还是终端获得命令,都是由run_command()来处理的.中场休息,下面要进入处理cmdbuf的循环中了, 长征马上开始以;分割. 忽略'\;'for(inquotes = 0, sep = str;*sep; sep++){if((*sep=='\'')&&(*(sep-1)!='\\'))inquotes=!inquotes;if(!inquotes &&(*sep ==';')&&( sep != str)&&(*(sep-1)!='\\'))break;}//如果上面for循环找到一条以';'结束的命令, 那么sep指向命令末尾token = str;if(*sep){str = sep + 1;*sep ='\0';}elsestr = sep;process_macros (token, finaltoken);if((argc = parse_line (finaltoken, argv))== 0){rc =-1;4.就此打断一下, 我们要分析一下find_cmd了, 不能再跳过了. find_cmd()在.u_boot_cmd段中寻找该命令的cmd_tbl_t结构, 找到后返回该结构. 该命令的结构是通过定义在include/command.h中的宏定义U_BOOT_CMD登记进.u_boot_cmd段中的.5. 刚才我们在长征的半路翻越了一座雪山, 现在继续回到while循环中if(cmdtp->cmd == do_bootd){if(flag & CMD_FLAG_BOOTD){puts("'bootd' recursion detected\n");rc =-1;continue;}else{flag |= CMD_FLAG_BOOTD;}}#endif//长征马上结束, 胜利就在眼前! 调用结构体中注册的cmd函数, 何时注册的呢? 上面不远处介绍的U_BOOT_CMD!if((cmdtp->cmd)(cmdtp, flag, argc, argv)!= 0){ rc =-1;}repeatable &= cmdtp->repeatable;if(had_ctrlc ())return-1;}。
uboot 2013 07 运行流程
uboot 2013 07 运行流程board:board/friendlyarm/mini2440目前只支持nor启动1、由编译链接文件u-boot.lds// arch/arm/cpu/u-boot.lds可知,第一个运行的文件为:CPUDIR/start.o//arch/arm/cpu/arm920t/start.S1)设置异常向量2)设置CPU的工作模式3)关中断4)关看门狗5)设置CPU时钟6)配置caches7)禁mmu8)bl lowlevel_init],跳到lowlevel_init.S2、lowlevel_init.S//在samsung/smdk2410/lowlevel_init.S,自己添加进来1)存储控制器初始化:位数,时序等2)返回到start.S,然后bl _main,跳到crt0.S3、crt0.S// arch/arm/lib(此文件官方说明:2013/1/ 8arm: move C runtime setup code in crt0.SMove all the C runtime setup code from every start.Sin arch/arm into arch/arm/lib/crt0.S. This coversthe code sequence from setting up the initial stackto calling into board_init_r().从2013/1/ 8起,把C语言运行环境的设置,放到crt0.S文件)1)堆栈设置2)blboard_init_f4、board_init_f()// arch/arm/lib/board.c1)第一阶段平台的初始化工作timer_init,env_init, ram_init... 计算堆栈addr_sp,设置gd、bd结构体空间,异常中断堆空间,计算出重定向u-boot的位置addr,控制台初始化,打印一些消息2)回到crt0.S设置新的sp and gd3)brelocate_code,跳到relocate.S5、relocate.S//arch/arm/lib1)把U-Boot复制到SDRAM中指定的位置处。
