ARM链接脚本

来源:互联网 发布:做淘宝仓库打包员累吗 编辑:程序博客网 时间:2024/05/19 02:18


链接定位是系统级软件开发过程中必不可少的一部分,嵌入式软件开发均属于系统级开发,绝大部分嵌入式软件都涉及到链接定位脚本文件;链接定位脚本使得我们的目标代码组织更加灵活。

1. 链接定位脚本文件说明

链接定位过程一般由链接器根据链接定位脚本完成,比较简单的系统可以通过设置链接器开关选项取代链接定位脚本;链接定位的关键是链接定位脚本的编写。我们从典型的目标文件结构开始,来介绍链接定位脚本文件的编写。下面是该系统一个目标文件的典型组织:

图A-1 目标文件典型组织图

其中第二栏开始分别展示了该文件各个段(Sections)的属性:名称(Name)、类型(Type)、地址(Addr)、偏移(Offs)、大小(Size)、固定单元大小(Es)、标志(Flg)、连接依赖(Lk)、附加属性(Inf)、字节对其宽度(Al)。

地址部分(Addr)描述了这一段在目标系统中的地址,而偏移(Offs)则记载了该段在目标文件中的偏移,大小(size)表示该段的实际长度;比如上图中.Text段的地址为0x0c700000,偏移为0x008000,大小为0x00d950,说明该段位于文件的偏移0x008000处,它将被下载到目标板0x0c700000处。

从段的分类来看,第7段以后的内容仅仅与调试有关,涉及到定位的也就是前面几段:.text、.data、.rodata、.bss,下面是一个具体的链接定位脚本文件:

SECTIONS 

     . = 0x0c200000;          /*赋当前地址,后续的代码将从该地址开始存放 */

    .text: { (.text) }      /*.text段表示代码段,从0x0c200000开始放置代码*/

 

Image_RW_Base = .;      /* RW(可写数据)基址,实际上是在这里声明了一个全局符号,我们可以在程序中使用该符号,它等同于在代码中声明一个全局变量,但它的值由链接器指定,在这里“=.”表示该符号的值等于当前地址;下面的定义类似*/

 

     .data : { (.data) }         /*数据段, 保存已经初始化的全局数据   */

.rodata : { *(.rodata) }    /*只读数据段, 保存已经初始化的全局只读数据*/

    

     Image_ZI_Base = .;          /*ZI基地址, 需要清零的区域 zero init*/

     .bss : { *(.bss) }          /*堆栈段,未初始化的全局变量也保存在此*/

    

     __bss_start__ = .;          /* bss的基地址*/

     __bss_end__ = .;            /* bss的结束地址*/

    

     __EH_FRAME_BEGIN__ = .;    /* FRAME开始地址(基地址)*/

     __EH_FRAME_END__ = .;      /* FRAME结束地址,gcc编译器使用 */

     PROVIDE (__stack = .);     /* 当前地址赋给栈,栈地址一般是可读写区最高处*/

    

     end = .;                    /* 结束地址*/

     _end = .;                   /* 结束地址*/

    

     .debug_info     0 : { *(.debug_info)  }  /*调试信息*/

     .debug_line     0 : { *(.debug_line)  }  /*调试信息*/

     .debug_abbrev   0 : { *(.debug_abbrev)}  /*调试信息*/

     .debug_frame    0 : { *(.debug_frame) }  /*调试信息*/

text段是程序代码段,紧随其后的是几个符号定义,它们是由编译器在编译连接时自动计算的,当我们在链接定位文件中申明这些符号后,编译连接时,该符号的值会自动代入到源程序的引用中,如果你想进一步了解连接定位的一些含义,可以参考编程手册中的ld一章。

data段的起始位置也是由连接定位文件所确定,大小在编译连接时自动分配,它和我们的程序大小没有关系,但和程序使用到的全局变量,常量数量相关。

bss的初始值也是由我们自己定义的连接定位文件所确定,我们应该将它定义在可读写的RAM区内,stack的顶部在可读写的RAM区的最后,我们可以非常灵活的定义其起点和大小,但对大部分情况来说,程序区在ROM或FLASH中,可读写区域在SRAM或DRAM中,我们可以考虑一下自己程序规模,函数调用规模,存储器组织,然后参照一个连接定位文件稍加修改就可以了。

2. 链接定位脚本修改实例

SECTIONS 

     . = 0x00000000;                  /*将代码段起始地址修改到0*/

     .text : { *(.text) }                        

     Image_RW_Base = .;                 

     .=0xc0000000                       /*设置数据段从0xc0000000开始存放*/

     .data : { *(.data) }                    

    

.=0xd0000000                           /*设置只读数据段从0xd0000000开始存放*/

.rodata : {*(.rodata) }                 

    

     Image_ZI_Base = .;                  

     .bss : { *(.bss) }                     

     Image_ZI_Limit = .;                 

 

     /*申明一个符号download_size */

     download_size =SIZEOF(.text)+SIZEOF(.data)+SIZEOF(.rodata)+SIZEOF(.bss);

 

     __bss_start__ = .;                   

     __bss_end__ = .;                    

    

     __EH_FRAME_BEGIN__ = .;         

     __EH_FRAME_END__ = .;           

PROVIDE (__stack =.);           

    

     end = .;                         

     _end = .;                         

    

     .debug_info     0 : { *(.debug_info)  } 

     .debug_line     0 : { *(.debug_line)  } 

     .debug_abbrev   0 : { *(.debug_abbrev)}

     .debug_frame    0 : { *(.debug_frame) }

}

 

原创粉丝点击