Chinaunix首页 | 论坛 | 博客
  • 博客访问: 829113
  • 博文数量: 281
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2770
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-02 19:45
个人简介

邮箱:zhuimengcanyang@163.com 痴爱嵌入式技术的蜗牛

文章分类
文章存档

2020年(1)

2018年(1)

2017年(56)

2016年(72)

2015年(151)

分类: 嵌入式

2015-07-06 16:15:06

转载:http://blog.csdn.net/ustc_dylan/article/details/6965330
自己稍微整理了一下。

重定位:
应用程序必须经过编译、汇编和链接后才变成可执行文件,在链接时,要对所有目标文件进行重定位
(relocation),建立符号引用规则,同时为变量、函数等分配运行地址。当程序执行时,系统必须把代码加载到链接时所指定的地址空间,以保证程序在执行过程中对变量、函数等符号的正确引用,使程序正常运行。在具有操作系统的系统中,重定位过程由操作系统自动完成。  

运行地址:就是链接地址
在设计
Bootloader程序时,必须在裸机环境中进行,这时Bootloader映像文件的运行地址必须由程序员设定。通常情况下,将Bootloader程序下载到ROM0x0地址进行启动,而在大多数应用系统中,为了快速启动,首先将Bootloader程序拷贝到SDRAM中再运行。一般情况下,这两者的地址并不相同。


首先来看下面的链接脚本文件:

SECTIONS {   
   . = BOOTADDR;
              // Bootloader的开始地址
    . = ALIGN(4);              //代码以4字节对齐
    .text : { *(.text) }       // 指定代码段
    
    . = ALIGN(4);
    .rodata : {*(.rodata*)}    // 指定只读数据段
    
    . = ALIGN(4);
    .data : { *(.data) }       // 指定读/写数据段
    
    . = ALIGN(4);
    __bss_start = .;
    .bss : { *(.bss)  *(COMMON) }  // 指定bss段
    __bss_end = .;
}

需要指出的是,链接脚本中所描述的输出段地址为虚拟地址
VMAVirtualMemoryAddress)。这里的虚拟地址仅指映像文件执行时,各输出段所重定位到相应的存储地址空间,与映像文件烧写到的实际的地址无关(即映像的加载地址)。因此,上面的链接脚本实际上指定了Bootloader映像在执行时,将被重定位到BOOTADDR开始的存储地址空间,以保证在相关位置对符号进行正确引用,使程序正常运行。

假设这里指定BOOTADDR= 0x0。以
ARM为例,ARM处理器复位后总是从0x0地址取第1条指令,因此只需把BOOTADDR设置为0,再把编译后生成的可执行二进制文件下载到ROM0x0地址开始的存储空间,程序便可正常引导;但是,一旦在链接时指定映像文件从0x0地址开始,那么Bootloader就只能在0x0地址开始的ROM空间内运行,而无法拷贝到SDRAM空间运行实现快速引导。当然,搬运代码最后的跳转语句可以写成绝对地址,如jmp 0x10000,这样可以正确的跳到RAM中的0x10000地址处,但当继续执行碰到其他符号地址计算,或全局数据访问的时候,由于此时不是位置无关代码,此时地址的计算需要查询map表,但是map表中的地址仍然在ROM空间中,所以还会跳回ROM空间,另外,还会有其他问题,如动态内存申请等。

有了位置无关代码,只需修改链接脚本文件的BOOTADDR=0x10000即可,即将整个镜像文件都映射到RAM空间,但是bootloader最开始的搬运代码必须是位置无关的代码,这样虽然搬运代码被映射到RAM地址空间,但它在0x0开始的ROM中也能正确执行,搬运代码最后的跳转语句就可以跳转到某个标号了,因为此时标号的地址已经被映射到了RAM空间,之后的代码执行将没有任何问题。



当然,可以将搬运代码和搬运完成跳转到RAM的代码分段映射,即搬运代码映射到ROM地址空间,其他代码(包括全局变量等等)映射到RAM空间。但是这样会存在一个问题:
生成的bin文件变得非常大。生成的bin文件将会按照映射到地址空间来生成,如果ROM空间与RAM空间地址不连续,假设ROM地址空间为0x0 ~ 0x1000,RAM地址空间为0x10000~0x20000,那么,0x1000~0x10000之间的地址空间都被填充为0,除非在生成bin文件时重新进行拼装。


如何编写位置无关代码呢?

引用同一位置无关段或相对位置固定的另一位置无关段中的符号时,必须是基于PC的符号引用,即使用相对于当前PC的偏移量来实现跳转或进行常量访问。

1.位置无关的程序跳转。使用相对跳转指令实现程序跳转。指令中所跳转的目标地址用基于当前PC的偏移量来表示,与链接时分配给地址标号的绝对地址值无关,因而代码可以在任何位置进行跳转,实现位置无关性。

2.位置无关的常量访问。在应用程序中,经常要读写相关寄存器以完成必要的硬件初始化。为增强程序的可读性,利用EQU伪指令对一些常量进行赋值,但在访问过程中,必须实现位置无关性。

3. 使用绝对地址进行跳转,一般是在不同的位置无关代码段之间跳转。

最后,总结一下位置无关代码段的优点:

1.简化设计,方便实现系统的快速引导。位置无关代码可以避免在引导时进行地址映射,并方便地跳转到RAM中实现快速引导

2.实现复位处理智能化。位置无关的代码可以被加载到任意地址空间运行

3.便于调试。Bootloader的调试通常也是一个繁琐的过程,使用位置无关代码,则可以将映像文件加载到RAM中进行调试,这既能真实地反映程序从ROM中进行系统引导的情况,又可以避免频繁烧写程序存储器。



还有一篇博客可以看一看:
http://blog.chinaunix.net/uid-20528014-id-4445271.html

阅读(938) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~