重定位
重定位
文件组成
段是程序的组成元素,将程序分成一个一个程序段。为了便于区分,给每个段起名字,用于标记。在链接的时候,将这些段排布在合适位置。
程序的段名称:
代码段(.text):存放代码指令
只读数据段(.rodata):存放有初值并且const修饰的全局类变量(全局变量或static修饰的局部变量)
数据段(.data):存放有初始值的全局类变量
零初始化段(.bss):存放没有初始值或初始值为0的全局类变量(不包含在elf/bin文件中)
注释段(.comment):存放注释。(不包含在elf/bin文件中)
举例:
char g_charP = “P”; //有初始值的全局变量 放在data段
const char g_charP = “P”;//全局变量 const修饰 放在 rodata段
const char g_charP; //全局变量 没有初始化 存放在bss段
char g_charP = 0; //初始化为0的全局变量 存放在.bss段
char g_charP; // 没有初始化的全局变量 存放.bss段
链接脚本
链接脚本示例:
SECTIONS {
. = 0x80100000; //设定链接地址为0x80100000
. = ALIGN(4); //将当前地址以4字节标准对齐
.text : //创建段,名称为.text
{ //.text包含的内容为所有链接文件的数据段
*(.text) //所有文件的text段
}
. = ALIGN(4); //当前地址4字节对齐
.rodata : { *(.rodata) } // rodata段,放置在data段之后,包含所有文件的只读数据段
. = ALIGN(4);
.data : { *(.data) } //data段,在rodata段之后,包含所有文件的数据段
. = ALIGN(4);
__bss_start = .; //将当前地址存储变量__bss_start
.bss : { *(.bss) *(.COMMON) } //.bss段放置在.data段之,所有文件的bss段及注释段
__bss_end = .; //将当前地址存储在__bss_end变量
}
链接脚本格式:
SECTIONS{
……//secname:段的名称 start段的加载地址也被称为重定位地址(relocation addr)
Secname start BLOCK(align)(NOLOAD):AT(ldadr)//AT 链接脚本函数 ldadr 段的加载地址 默认加载地址等于运行地址
{contents} > region :phdr = fill //{}用来表示段的开始与结束 content 段的内容 由用户指定
……
}
Bin文件分布
在bin文件中,bss段与comment段不包含在bin文件中。如上所示,
是一体式链接脚本,即是各个段是紧挨在一起。与之对应的是分体式链接脚本,
各个段是不紧挨在一起。
单片机非常适合一体式链接,将文件存放在flash中,存放地址也是运行地址(链接地址)。
不用将代码复制到内存占用空间。如果嵌入式系统没有可以直接运行代码的flash,
就需要从存储设备Nand Flash 或SD卡等存储介质复制到内存中。
JTAG等调试器一般只支持一体式链接文件分布格式。
bss段的清除
bin文件中不包含bss段的内容。bss段中的这些值是0。在bin文件中,导致bin文件容量过大。
当程序运行到涉及到bss段上的数据,cpu会从bss段对应的内存地址读取对应的值。为了确保读取到bss段的正确的值,
需要将bss段这一段内存地址的数据清零。
重定位引入
将bin文件下载到mcu的存储介质,bin文件在存储介质中的位置称为 存储地址。在bin文件被执行的过程中,bin文件所在的内存中的地址,称为链接地址。
而在某些情况下,存储地址与链接地址是一致的。比如,将bin文件存储在flash上,存储地址等于链接地址。这样,重定位基本上不动作。
而在某些设备下,比如imx6ul等MCU,将bin文件存储在Nor flash或Nand flash等存储设备,在执行的时候,
需要将bin文件将SDRAM上,才可以执行。在Nor flash中,bin文件的地址是存储地址,SDRAM内存上,bin文件是链接地址。
MCU的Map的示意:
图 3 存储分布示意
重定位的操作,比如将存在于DDR内存上的数据,映射到片内RAM上,是需要用户实现的。
一般是在开始完成的映射工作,在后缀.s的文件,一般利用汇编语言来实现。
当然也可以使用C语言来实现重定位,映射工作。
这样需要从链接文件中,使用链接文件中的变量,
比如前面的__bss_start等变量,保存目前的链接加载地址。
在重定位过程中,有关地址信息可以在链接文件中寻找。
代码全部重定位
为什么会由此想法?
程序的存储与执行,如下所示:
如上图所示;在sd卡或Nor nand中的bin文件,将bin文件,由存储地址加载到DDR中,
链接地址。如果链接地址等于运行地址,那CPU就到链接地址去执行指令(CPU可以执行DDR内部的代码)。
但是CPU去DDR中去执行指令,涉及到内存的访问,自然会降低程序执行速度。
如果将bin文件映射到内部RAM中,那么CPU直接访问片内RAM,可以大大加快程序执行速度。
但是缺点是RAM容量有限。如果bin文件容量过大,到时不能完全存储在内部的RAM中。
备注:重定位之前,不可使用绝对地址
绝对地址:
全局类变量(全局变量,或static修饰的局部变量)
有初始值的数组。(rodata段,需要绝对值来访问)。