嵌入式Linux引导过程之1.1——Xloader的xloader.lds
本文中的所有代码版本都是基于ST的SpearPlus开发板的。
xloader是在系统上电之后,执行完ROM中的frimware后最先开始执行的用户程序,它的体积很小,执行的功能也很简单,主要是对系统时 钟以及外部SDRAM进行初始化,初始化完成之后就检查Flash中的uboot image是否准备好,如果准备好了就将Flash中的uboot image根据image header中指定的load address加载到外部SDRAM中,然后就跳转到uboot执行代码。
这里,我试图从头开始,在源代码级别上来分析整个系统的引导过程。
像Xloader或者uboot之类的程序,并不像我们平常写的应用程序那样,程序的入口函数直接找main函数就行。对于这种系统程序,在最开始 看代码,尤其是要找到最开始执行的代码的位置的时候,最好的一个方法就是找到整个工程的.lds文件,也就是链接脚本文件(linker loader script)。它定义了整个工程在编译之后的链接过程,以及各个输入目标文件中的各个段在输出目标文件中的分布。详细的关于lds文件的介绍可以参考 gnu的在线文档:http://sourceware.org/binutils/docs/ld/index.html。其中的第三节Linker
Script对链接脚本文件进行了介绍。
现在,我们首先开看一看xloader.lds的代码:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(XLOADER_ENTRY)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
./obj/init.o (.text)
*(.text)
}
.rodata . :
{
*(.rodata)
}
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
下面,我们对这一段代码逐句进行分析。
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
在GNU的文档中,是这么定义的:
OUTPUT_FORMAT(default, big, little),在链接的时候,如果使用了-EB的命令行参数,则使用这里的big参数指定的字节序,如果使用了-EL的命令行参数,则使用这里的 little参数指定的字节序,如果没有使用任何命令行参数,则使用这里的default参数指定的字节序。
由xloader.lds中的定义可见,不管在链接的时候使用了何种命令行参数,输出的目标文件都是使用elf32-littlearm方式的字节序。
OUTPUT_ARCH(arm)
在GNU的文档中,是这么定义的:
OUTPUT_ARCH(bfdarch),也就是指定了目标的体系结构,在这里,SpearPlus内部使用的处理器核是arm926ejs的,因此体系结构也就是arm。
ENTRY(XLOADER_ENTRY)
在GNU的文档中,是这么定义的:
ENTRY(symbol)
There are several ways to set the entry point. The linker will set the entry point by trying each of the following methods in order, and stopping when one of them succeeds:
* the `-e' entry command-line option;
* the ENTRY(symbol) command in a linker script;
* the value of the symbol start, if defined;
* the address of the first byte of the `.text' section, if present;
* The address 0.
也就是说,ENTRY(XLOADER_ENTRY)定义了整个程序的入口处,也就是在标号XLOADER_ENTRY处。整个程序将从这里开始运行。
接下来的部分,是对整个输出目标文件中各个段的存储位置的定义。
在GNU的文档中,是这么定义的:
SECTIONS
{
sections-command
sections-command
...
}
对于其中的每一个sections-command,其完整的定义如下:
The full description of an output section looks like this:
section [address] [(type)] :
[AT(lma)] [ALIGN(section_align)] [SUBALIGN(subsection_align)]
{
output-section-command
output-section-command
...
} [>region] [AT>lma_region] [:phdr :phdr ...] [=fillexp]
Most output sections do not use most of the optional section attributes.
The whitespace around section is required, so that the section name is unambiguous. The colon and the curly braces are also required. The line breaks and other white space are optional.
下面来看看xloader.lds中SECTIONS的定义:
SECTIONS
{
/* location counter设置为0x00000000,其实由于在Makefile中的
* 链接选项中使用了-Ttext $(TEXT_BASE),而TEXT_BASE=0xD2800B00
* 因此,此处的设置其实是没有作用的,代码运行的时候将运行在TEXT_BASE地址
*/
. = 0x00000000;
. = ALIGN(4); /* 四字节对齐 */
/* 将所有输入目标文件中的.text段即代码段放在此处,并且,输出目标文件中的.text段中的
* 开头部分存放init.o的.text段。也就是运行的第一条代码,也就是XLOADER_ENTRY
* 标号对应的代码就在init.o当中
*/
.text :
{
./obj/init.o (.text)
*(.text)
}
/* 紧接着.text段,存放所有输入目标文件中的.rodata段,也就是
* 只读数据段。此处注意.rodata后跟着的.,这个.表示当前location counter,
* 对应于上述完整描述sections中的[address]
* 此处表示.rodata段紧接着.text段存放,而不用任何对齐
*/
.rodata . :
{
*(.rodata)
}
. = ALIGN(4); /* 四字节对齐 */
/* 将所有输入目标文件中的.data读写数据段存储在此处
* 所有全局手动初始化的变量存储在该段中,并且在输出目标文件中已经分配了存储空间
*/
.data : { *(.data) }
. = ALIGN(4); /* 四字节对齐 */
/* .got段是GLOBAL OFFSET TABLE,具体的作用还没有搞清楚 */
.got : { *(.got) }
. = ALIGN(4); /* 四字节对齐 */
/* .bss段的开始,所有全局未初始化变量的大小等信息存储在该段中
* 但是在输出的目标文件中并不为这些变量分配存储空间,
* 而是交给操作系统在初始化的时候分配内存,然后紧跟在.data段后面并初始化为零
* 另外,此处还定义了两个标号分别表示.bss的开始和结束(也是整个目标文件的结束)
*/
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
从这里,我们能够得到的最关键的信息是:整个程序的入口在标号XLOADER_ENTRY处,并且该标号定义在init.o目标文件中,因为整个最终的链接之后的目标文件中,位于最开头的就是init.o目标文件。
于是,我们可以根据这个线索来继续追踪整个的引导过程了。
参考文章:
对.lds连接脚本文件的分析
http://blog.csdn.net/tony821224/archive/2008/01/18/2051755.aspx
Documentation for binutils 2.18--ld
http://sourceware.org/binutils/docs/ld/index.html
.bss段和.data段的区别
http://www.w3china.org/blog/more.asp?name=FoxWolf&id=29997
什么是bss段
http://blog.csdn.net/bobocheng1231/archive/2008/02/23/2115289.aspx
嵌入式Linux引导过程之1.1——Xloader的xloader.lds的更多相关文章
- 嵌入式Linux引导过程之1.6——Xloader的Xloader_Entry
我们已经看完了XLOADER_ENTRY里调用的前两个标号的代码,分别是sys_init和ddr_init.对于一个嵌入式系统来说,这两 个部分的代码是在一开始就执行的,至少是在从bootrom里面的 ...
- 嵌入式Linux引导过程之1.4——Xloader的ddr_init
这里我们来看XLOADER_ENTRY中调用的第二个标号ddr_init处的代码,这部分代码的作用是对外部内存SDRAM进行初始化,在我 spearplus开发板中,使用的是DDR SDRAM.在调用 ...
- 嵌入式Linux引导过程之1.5——从BootRom到Xloader
在开始看Xloader_Entry的代码之前,我想先总结一下从芯片上电到开始运行Xloader的代码的过程,这是我目前理解的一个过程,可能有所出入,待以后继续完善. 当 系统上电之后,首先会将PC寄存 ...
- 嵌入式Linux引导过程之1.3——Xloader的sys_init
上一篇文章对XLOADER_ENTRY进行了分析,看到其中调用的第一个标号就是sys_init,本文就对这个标号对应的代码段进行粗略的分析,这里我也还有好多没有搞明白的,就先留着,日后慢慢明白,先把自 ...
- 嵌入式Linux引导过程之1.2——Xloader的XLOADER_ENTRY
根据上文中获得的线索,本文分析init.S中的XLOADER_ENTRY. 在init.S中,定义了好多与平台相关的寄存器地址宏以及好多其他函数,我们在用到的时候再回过头来分析,这里,我们只看其中的一 ...
- 嵌入式linux加载引导内核和根文件系统的方法
总体来说,嵌入式Linux内核和根文件的引导与PC机差不多.嵌入式linux内核和根文件系统可以存放在各种可能的存储设备中,一般情况下我 们将内核和根文件系统直接烧入到Flash中(包括NOR和NAN ...
- linux引导流程
本章重点: 1.linux引导流程 2.linux运行级别 3.linux启动服务管理 4.GRUB配置与应用 5.启动故障分析解决 linux启动流程 1.固件(fireware):固话在硬件上的程 ...
- 嵌入式Linux内核制作【转】
本文转载自:http://blog.csdn.net/coding__madman/article/details/51291316 1. Linux体系结构 从整体上来分,linux可以分为User ...
- 《嵌入式Linux基础教程学习笔记一》
常用书目下载地址:http://www.cnblogs.com/pengdonglin137/p/3688029.html 第二章 1.进程上下文和中断上下文(Page20) 当应用程序执行系统调用, ...
随机推荐
- 【转】Shell执行MySql操作
mysql -hhostname -Pport -uusername -ppassword -e 相关mysql的sql语句,不用在mysql的提示符下运行mysql,即可以在shell中操作m ...
- Win10下通过IIS调试ASP程序遇到的问题和解决方案
最近维护了以前别人的写的一个ASP的系统,记录一下调试过程中的问题和解决方案. 环境篇 万维网发布服务(W3SVC)已经停止 问题: 万维网发布服务(W3SVC)已经停止.除非万维网发布服务(W3SV ...
- 面试中的DNS
DNS 当DNS客户机需要在程序中使用名称时,它会查询DNS服务器来解析该名称.客户机发送的每条查询信息包括三条信息:指定的DNS域名,指定的查询类型,DNS域名的指定类别. DNS基于UDP服务,端 ...
- [HTTP] PHP 实现 HTTP Server 原理
单进程服务器简陋版: <?php /** * Single http server. * * Access http://127.0.0.1:8081 * * @license Apache-2 ...
- python threading queue模块中join setDaemon及task_done的使用方法及示例
threading: t.setDaemon(True) 将线程设置成守护线程,主进行结束后,此线程也会被强制结束.如果线程没有设置此值,则主线程执行完毕后还会等待此线程执行. t. ...
- Spring MVC + Spring + Mybitis开发Java Web程序基础
Spring MVC + Spring + Mybitis是除了SSH外的另外一种常见的web框架组合. Java web开发和普通的Java应用程序开发是不太一样的,下面是一个Java web开发在 ...
- POJ Ikki's Story IV - Panda's Trick [2-SAT]
题意: 圆上n个点,m对点之间连边,连在园内或园外,所有边不相交是否可行 发现两对点连线都在内相交则都在外也相交,那么只有一个在内一个在外啦,转化为$2-SAT$问题 #include <ios ...
- 小甲鱼OD学习第9讲
这次我们的任务是破解这个要注册的软件,如下图所示 当我们输入账号密码的时候,它会提示输入的账号密码是无效的,如下图 我们把程序载入OD,然后在查找字符串那里输入提示的无效账号密码的字符串,如下图 然后 ...
- 第三方页面嵌入到web项目的方案 之 使用iframe嵌入
有些项目中可能会遇到这样的需求, 需要在一个项目中嵌入其他的项目的页面或者功能.并且需要这两个页面之间能够进行交互. 本文主要介绍如何实现这种第三方应用的嵌入, 主要有以下几个方向: 1.iframe ...
- PHP Extension开发(Zephir版本)
上篇介绍了C语言开发PHP扩展的方法, 现在介绍使用Zephir开发扩展的方法. 关于Zephir需要简单介绍一下: Zephir 是为PHP开发人员提供的能够编写可编译/静态类型的高级语言.是优秀的 ...