uboot之位置无关代码解析

在之前的话

  新年过去了,那么久没有好好学习,感觉好颓废,现在就uboot的一些基础问题做一些笔记,顺便分享给大家,不过由于见识有限,如果有不足之处请多多指教。

位置无关?什么意思?我们先了解一些基础知识。。。。。

  我们都知道我们写的代码最后是运行在内存(SDRAM或者SRAM,通常是SDRAM)中的,但是在运行之前他们是保存在诸如nand、flash等非易失存储设备中的,而这些存储设备的地址要映射到CPU能够寻找的地址上(一般映射在0X0地址上,这个后面详细解释),这样才能得到要运行的代码。而代码要运行的内存(这里就假设是SDRAM)也要映射到CPU上(肯定是和nand那些存储器不一样的地址,例如三星的2440的就映射到了0x30000000上),所以说存储在nand或者flash的代码最终得复制到内存上运行的。这里就记住代码存储的地方(加载地址)和代码要运行的地方(运行地址)是不一样的

  现在说一下地址映射的问题。在学习ARM时,我们一般会遇到两种启动方式,一个是nand启动,一个是nor启动。这两种启动方式都是映射到0x0地址的,但是映射方式稍有不同。所以先了解一下这两种介质的硬件特性:

     nand:由于nand存储器的硬件特性,代码是无法在他上面运行的,他只有存储代码的功能。

     nor:他不仅可以存储代码,还可以让代码运行,但是他只能进行读,不能进行写的操作,但毕竟是可以运行代码啦。

  所以nand启动的话,如果没有进行特殊手段,代码是无法得到的,在ARM中,他是通过硬件自动把nand前面的4K代码复制到一块映射到0x0地址上的SRAM中的,记住这是硬件自动完成的。这样4K代码就在SRAM上了,我们知道SRAM是能运行代码的(可读可写)。但是这个SRAM只有4K大小,要是存储在nand的代码不止4K,只在SRAM上面运行是无法完成代码设定的所有功能的。为了解决这个问题,于是就在这4K的代码中完成一个可以将nand的代码复制到其他更大的内存上(这里是SDRAM),这样就可以运行所有代码了。

  nor启动的话,由于nor可以运行代码,所以就不用什么SRAM了,直接把nor映射到0x0位置上就可了,如果nor空间够大,甚至可以不用重定位代码,只是nor无法进行写功能,读取的效率又没SDRAM高,加上为了兼容nand启动(不用写两套代码),也就跟nand启动一样只运行前面4K,剩下复制到SDRAM上再继续运行。

  问题又来了,我们知道代码经过编译,链接后才可以得到可以运行的代码,而这代码只有在链接时指定的位置上才能运行。对于2440,链接文件指定的位置一般是在SDRAM上面的,可是nand启动时,前面的4K代码却在SRAM中运行了

  这会有什么问题?我们知道编写好的代码的地址在链接时就已经安排好了。例如2440链接文件指定链接地址是0x30008000,那么所有代码地址就是从0x30008000开始的。而在启动时,代码却是在0x0开始运行的,如果不进行特殊处理,肯定会有问题,比如我们调用一个函数,而这个函数地址是在SDRAM上的(链接时已经确定),并且这时代码还没复制到SDRAM上,也就是说代码还在nand或者在4K的SRAM里面,在SDRAM是找不到要调用的函数的,那样就会无法执行这个函数。

  如果在还在nand里面肯定是没办法了,这个代码是无法运行的必须废弃,如果在4K的SRAM就有办法了。于是就出现了位置无关指令:

    位置无关/相关指令:

      B  BL  ADR  MOV  ADD等,这些指令都是位置无关指令

      LDR  STR等指令是位置有关指令

位置无关什么意思呢?

  既然这个时候SDRAM还没有代码,那就不去那里找了嘛,我们去别的地方找。别的地方是哪里呢?这个时候代码是运行在SRAM上的,处理器的PC寄存器也是指向这个地方的,有4K代码也是在这个地方的。那我就不用链接指定的地址来寻找想要的代码,我设计一些是与PC寄存器指向的位置有联系的寻址指令来寻址,这样PC寄存器指向哪里,我就在哪里找我想要的代码,而不是去链接指定的地址去找。

  位置无关指令就是这样的指令,他不去链接指定位置寻找代码,而是在PC寄存器指向的位置相对它前后32M的范围寻找代码,也就是说只要我想要调用的代码在PC指向位置前后的32M范围内,就能找到(这是硬件完成的,我们知道位置无关指令就是这个意思就行)。当然,我们的SRAM只有4K,所以寻找的范围肯定就只能在这4K里面才行了,超过了也是找不到的。所以要求我们的重定位代码必须在这4K里面,必要的硬件初始化代码,内存初始化代码,nand初始化代码等等,必须在4K以内完成,否则就会出问题。所以位置无关指令的寻址是基于当前PC寄存器位置来寻址的。

下面根据uboot的代码进行讲解

1.内存控制器初始化代码

_TEXT_BASE:

.word     TEXT_BASE   /*根据链接地址得知这是0x30000000*/

.globl lowlevel_init       /*定义lowlevel_init为全局函数*/

lowlevel_init:

ldr     r0, =SMRDATA  /*链接后,SMRDATA是在SDRAM上某个位置的,但是这时候SDRAM还没任何代码,代码现在还在SRAM上,也就说ldr指令是位置相关指令*/

ldr   r1, _TEXT_BASE  /*0x30000000*/

sub  r0, r0, r1          /* SMRDATA减 _TEXT_BASE就是13个寄存器在SRAM上的地址 */

ldr   r1, =BWSCON   /* R1指向内存控制器的寄存器地址上 */

add     r2, r0, #13*4 /*有13个寄存器,每个32位宽度*/

0:

ldr     r3, [r0], #4    /*将13个寄存器的值逐一赋值给对应的寄存器*/

str     r3, [r1], #4

cmp     r2, r0

bne     0b

/* everything is fine now */

mov       pc, lr

.ltorg

/* the literal pools origin */

SMRDATA:            /*  下面是13个寄存器的值  */

.word  … …

.word  … …

… …

2.nor启动的重定位代码

  adr  r0, _start              /*adr是位置无关指令,因为nor启动,这时第一条指令被映射到nor上的0x0位置,所以R0=0x0,如果是RAM启动,那_start就是存在0x30000000了 */

ldr   r1, _TEXT_BASE            /* 位置相关指令,R1=0x30000000 */

/* 判断U-Boot是否是下载到RAM中运行,若是,则不用 再复制到RAM中了,这种情况通常在调试U-Boot时才发生 */

cmp      r0, r1      /*_start等于_TEXT_BASE说明是下载到RAM中运行 */

beq stack_setup

/* 以下直到nand_boot标号前都是NOR Flash启动的代码 */

ldr   r2, _armboot_start  /*这里其实就是_start的地址*/

ldr   r3, _bss_start

sub  r2, r3, r2              /* 得到代码大小   */

add r2, r0, r2              /* 得到代码结束地址   */

/* 搬运U-Boot自身到RAM中*/

copy_loop:

ldmia     r0!, {r3-r10} /* 从地址为[r0]的NOR Flash中读入8个字的数据 */

stmia      r1!, {r3-r10} /* 将r3至r10寄存器的数据复制给地址为[r1]的内存 */

cmp       r0, r2                    /* until source end addreee [r2]    */

ble  copy_loop

b     stack_setup         /* 跳过NAND Flash启动的代码 */

以上就是位置无关代码的解析了,uboot在运行第二阶段之前,绝大部分的指令都是位置无关指令,这样才能保证代码能够运行。

原文地址:https://www.cnblogs.com/PanShen/p/8463108.html

时间: 2024-11-10 15:35:07

uboot之位置无关代码解析的相关文章

对位置无关代码的理解

今天在看uboot编译流程的时候,突然发现对程序的地址相关性的记忆又有点模糊了.搞嵌入式软件就是这个不好,需要学习和掌握很多知识点,才能够对开发中的所有细节都有全面的掌握.可是往往这种掌握又不是很有必要的,因为很多细节性的问题在实际开发过程中,又不一定需要去关注,或者说关注的很少.这就直接导致了学习和掌握了很多细节的知识,往往久了不用,就淡忘了. 比如这里提到的代码地址相关性,以前在搞VxWorks,尤其是bootrom存放位置的时候就有过分析.bootrom编译的时候是不用考虑代码运行位置的,

共享库中的位置无关代码(PIC)

原作者:Eli Bendersky http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/ 在之前的文章里我已经描述过在将共享库载入程序地址空间时需要特殊的处理.简而言之,在链接器创建共享库时,它不能预先知道这个库将在哪里载入.这给在库里访问数据与代码带来了麻烦,应该使得这些访问指向正确的内存位置. 在Linux ELF共享库里解决这个问题有两个主要途径: 1.     

计算机科学基础知识(四)动态库和位置无关代码

一.前言 本文主要描述了动态库以及和动态库有紧密联系的位置无关代码的相关资讯.首先介绍了动态库和位置无关代码的源由,了解这些背景知识有助于理解和学习动态库.随后,我们通过加-fPIC和不加这个编译选项分别编译出两个relocatable object file,看看编译器是如何生成位置无关代码的.最后,我们自己动手编写一个简单的动态库,并解析了一些symbol Visibility.动态符号表等一些相关基本概念. 本文中的描述是基于ARM MCU,GNU/linux平台而言的,本文是个人对动态库

位置无关码

ARM下的位置无关和相关码 为什么需要位置无关码? 见 : U-BOOT详解(什么是<编译地址>?什么是<运行地址>?)  http://bbs.21ic.com/forum.php?mod=viewthread&tid=857037&typeid=114       ARM位置无关代码设计规范  http://wenku.baidu.com/view/5ef25b890b4c2e3f562763a8.html 位置无关可执行文件PIE包括位置无关代码PIC和位置无

位置无关码 位置相关码

在汇编中  使用位置无关码 b,bl 在c语言中 使用位置无关码 不用全局变量  不用静态变量 位置无关码:CPU取指时,总是相对于本条执行指令的相对地址去取指.比如指行一个ADD指令时,PC要取下一指令的地址,就在原来的基础上+4.这就不管你代码放在存储器的任何位置,只要他们的相对地址没有改变,就能正常执行程序.一般上电复位那几条语句就必须是位置无关码指令. 位置相关码:可以这样来说,就是CPU每次取指都从绝对位置去取,而不是上面的相对位置.这个绝对地址就是相对起始地址0来说的.这样,就要求你

代码重定位和位置无关码

通过前面的学习,我们知道,把可执行程序从一个位置复制到另一个位置的过程叫做重定位. 现在有两种方式,第一种是只重定位data段到内存(sdram),为什么需要重定位?因为有些flash的写操作,不是简单地内存访问,通常我们使用sdram这个介质作为程序运行的载体.但是只重定位data段这种方式存在弊端.第一,我们的调试工具通常不支持这种分体形式(比如我们的之前的代码在0地址开始存放text和rodata段,而在间隔很远处sdram 0x30000000存放data段,这就是分体的形式)的代码:第

MPC8313ERDB在Linux从NAND FLASH读取UBoot环境变量的代码分析

[email protected] 一.故事起因 因为文件系统的增大,已经大大的超出了8MB的NOR FLASH,而不得不把内核,文件系统和设备树文件保存到NAND FLASH上.但是因为使用的是RAMDISK,而无法保存一些个别的配置和参数,最简单的需要就是设置系统的IP了,,, 要使用统一的RAMDISK,而实现LINUX启动之后,设置成不能的参数功能,比较方便的就是从UBOOT把这些参数传递过去,这个得到了大家的认证,我们可以直接添加启动参数,然后在内核里面读出来,这种方法比较方法,唯一不

(转)Java二进制指令代码解析

转自http://www.blogjava.net/DLevin/archive/2011/09/13/358497.html Java二进制指令代码解析 Java源码在运行之前都要编译成为字节码格式(如.class文件),然后由ClassLoader将字节码载入运行.在字节码文件中,指令代码只是其中的一部分,里面还记录了字节码文件的编译版本.常量池.访问权限.所有成员变量和成员方法等信息(详见Java字节码格式详解).本文主要简单介绍不同Java指令的功能以及在代码中如何解析二进制指令. Ja

了解动态链接(二)—— 地址无关代码

把指令中需要修改的部分剥离出来,放到数据区,保持指令部分不变,数据部分可以由每个进程拥有一个副本.这就是——地址无关代码(Position-independent Code, PIC),好处是实现指令部分由多进程共享,节省内存. 要实现PIC,就得解决指令中的地址定位问题.指令中的地址引用可分为: 1.模块内部的函数调用和变量访问: 2.模块外部的函数调用和变量访问. 第1种情况,由于大家都在同一个模块中定义,相互之间有一定的相对位置,所以可以通过相对地址调用解决问题. 第2种情况,也就是对于模