重定位

重定位

文件组成

段是程序的组成元素,将程序分成一个一个程序段。为了便于区分,给每个段起名字,用于标记。在链接的时候,将这些段排布在合适位置。

程序的段名称:

代码段(.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段,需要绝对值来访问)。

 

posted @ 2022-08-10 19:06  JwChu  阅读(244)  评论(0编辑  收藏  举报