链接脚本文件(GCC)[转贴]
2012-10-29 07:04
239 查看
链接定位是系统级软件开发过程中必不可少的一部分,嵌入式软件开发均属于系统级开发,绝大部分嵌入式软件都涉及到链接定位脚本文件;链接定位脚本使得我们的目标代码组织更加灵活.
1)链接定位脚本文件说明
链接定位过程一般由链接器根据链接定位脚本完成,比较简单的系统可以通过设置链接器开关选项取代链接定位脚本;链接定位的关键是链接定位脚本的编写.我们从典型的目标文件结构开始,来介绍链接定位脚本文件的编写.下面是该系统一个目标文件的典型组织:
![](http://img.blog.163.com/photo/vc9_3dRx5Dj_SeSA3j06_Q==/3716032642534738997.jpg)
其中第二栏开始分别展示了该文件各个段(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编译器使用 */
FAQ
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__ = .;
1)链接定位脚本文件说明
链接定位过程一般由链接器根据链接定位脚本完成,比较简单的系统可以通过设置链接器开关选项取代链接定位脚本;链接定位的关键是链接定位脚本的编写.我们从典型的目标文件结构开始,来介绍链接定位脚本文件的编写.下面是该系统一个目标文件的典型组织:
![](http://img.blog.163.com/photo/vc9_3dRx5Dj_SeSA3j06_Q==/3716032642534738997.jpg)
其中第二栏开始分别展示了该文件各个段(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编译器使用 */
FAQ
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__ = .;
相关文章推荐
- Linux下GCC编译器链接任意目录下库文件(解决错误“/usr/bin/ld: cannot find -lxxx”)
- 链接脚本文件是什么,怎样编写
- Keil5.15使用GCC编译器链接.a库文件
- 转—gcc指定库路径,头文件路径以及实现静态动态链接
- gcc与obj文件,动态链接文件和ELF文件
- Python脚本--批量更改本地md文件的图片链接
- u-boot中.lds链接脚本文件的分析
- 程序中引入库文件的头文件 编译时并不需要显示的用gcc去链接他的库文件 why?
- gcc编译链接时头文件和库文件的搜索顺序
- Source Insight将gcc的输出结果链接到文件+行
- 链接脚本.lds文件分析
- linux删除无效链接文件脚本分享
- 揪出gcc默认使用的ld链接脚本
- arm-linux-ld命令 ld链接脚本(不错,推荐可以学习一些lds链接脚本文件)
- 链接 - YOLO训练的配置文件参数解释和计算anchor脚本
- 内核的链接脚本文件vmlinux.lds.S
- gcc指定头文件路径及动态链接库路径
- 1.预处理,生成预编译文件(.文件): Gcc –E hello.c –o hello.i 2.编译,生成汇编代码(.s文件): Gcc –S hello.i –o hello.s 3.汇编,生成目标文件(.o文件): Gcc –c hello.s –o hello.o 4.链接,生成可执行文件: linux笔记
- gcc指定头文件路径及动态链接库路径
- Linux开发常见问题:GCC:链接器输入文件未使用,因为链接尚未完成