登录
|
注册会员
开启辅助访问
设为首页
收藏本站
扫一扫关注官方微信
论坛
BBS
M币充值
M currency prepaid phone
M币获取
附件中心
搜索
search
全新论坛MCU智学网上线,欢迎访问新论坛!稀缺资源、技术干货、参考设计、原厂资料尽在MCU智学网
MCU资讯论坛
»
论坛
›
单片机论坛
›
单片机应用于方案
›
浅谈RISC-V GCC之:链接脚本学习笔记(一)
更新自动建库工具PCB Footprint Expert 2023.13 Pro / Library Expert 破解版
浅谈RISC-V GCC之:链接脚本学习笔记(一)
[复制链接]
1616
0
Yu***
注册会员
发表在
单片机/DSP
2021-11-5 15:37:50
|
查看全部
|
阅读模式
本文包含原理图、PCB、源代码、封装库、中英文PDF等资源
您需要
登录
才可以下载或查看,没有帐号?
注册会员
x
我们在用RISC-V GCC做嵌入式开发的时候,免不了要和启动文件和链接文件等打交道,本篇文章记录了一些链接脚本相关的学习笔记。
1.基础概念
链接脚本的主要作用是描述输入文件中的段应当如何映射到输出文件中,并控制输出文件的内存布局。多数链接脚本都执行类似功能。但是,如果需要,链接脚本也可以使用下面所描述的命令指挥链接器进行很多其他操作。
链接器通常使用一个链接脚本。如果没有为其提供一个,链接器将会使用默认的编译在链接器执行文件内部的脚本。可以使用命令’–verbose’显示默认的链接脚本。
为了描述链接脚本语言,我们需要定义一些基本概念和词汇。
链接器将许多输入文件组合成一个输出文件。输出文件和每个输入文件都有一个特定的已知格式成为目标文件格式。每个文件都被称为目标文件。输出文件通常叫做可执行文件,但我们仍将其称为目标文件。每个目标文件在其他东西之间,都有一个段列表。有时把输入文件的段称作输入段,类似的,输出文件的段称作输出段。
每个目标文件中的段都有名字和大小。多数段还有一个相关的数据块,称为 段内容。一个段可能被标记为可加载,表示当输出文件运行时,段内容需要先加载到内存中。一个没有内容的段可能是可分配段,即在内存中留出一段空间(有时还需要清零)。一个即不是加载又不是可分配的段,通常含有一些调试信息。
每个加载或可分配输出段有两个地址。第一个地址为VMA,或者叫做虚地址。这是当输出文件运行时段所拥有的地址。第二个地址是LMA,或者叫加载内存地址。这是段将会被加载的地址。一个它们会产生区别的例子是,当一个数据段加载到ROM, 此后在程序启动时被复制到RAM中(这个技术通常被用来初始化全局变量)。此种情况下,ROM使用LMA地址,RAM使用VMA地址。
如果想查看目标文件中的段,可以用objdump程序的’-h’选项。
每个目标文件还有一个符号列表,称为符号列表。一个符号可能是被定义的或者未定义的。每个符号都有一个名字,且所有已定义的符号在其他信息中间都有一个地址。如果将一个c或者c++程序编译成目标文件,会将所有定义过的函数和全局变量以及静态变量作为已定义符号。所有输入文件引用的未定义的函数或者全局变量会成为未定义符号。
2.常用关键词与用法
ENTRY(symbol) 用来指定程序执行的入口点
MEMORY 内存分配命令
SECTIONS 段命令 描述输出文件的内存和布局
.text 程序代码段
.rodata 只读数据
.data 可读写且需要初始化的数据
.bss 可读写的清零初始化数据
ASSERT 断言
PROVIDE(symbol=expression) 定义一个符号
AT 后跟MEMORY定义的内存区域或者地址
ALIGN 字节对齐
3 . MEMORY
链接器默认的设置允许分配所有可用的内存。你通过MEMORY命令可以重载这些。
MEMORY命令描述了一个内存块在目标中的位置和大小。你可以使用它描述一个可能会在链接器中使用的内存区域,以及那些必须避免使用的内存区域。此后你可以把段放到特定的内存区域里。链接器将会基于内存区域设置段地址,如果区域趋于饱和将会产生警告信息。链接器不会为了把段更好的放入内存区域而打乱段的顺序。
一个链接脚本可能含有许多MEMORY命令,但是,所有定义的内存块都被当作他们是在一个MEMORY命令中定义的一样。MEMORY的语法是:
MEMORY
{
name [(attr)] : ORIGIN = origin, LENGTH = len
...
}
name是链接脚本用来引用内存区域的名字。区域名在链接脚本外部没有任何意义。区域名被存储在一个独立的名字空间,且不会与符号名,文件名,或者段名起冲突。每个内存区域必须在MEMORY命令中有一个不同的名字。但是你此后可以使用REGION_ALIAS命令为已存在的内存区域添加别名。
attr字符是一个可选的属性列表,用来决定是否让一个脚本中没有显式指定映射的输入段使用一个特定的内存区域。就像SECTIONS中进行过的说明,如果你不为一个输入段指定一个输出段,链接器将会创建一个与输入段名字相同的输出段。如果你定义了区域属性,链接器会使用他们来决定创建的输出段存放的内存区域。
attr字符串只能使用下面的字符组成:
‘R’只读段
‘W’读写段
‘X’可执行段
‘A’可分配段
‘I’已初始化段
‘L’类似于’I’
‘!’反转其后面的所有属性
如果一个未映射段匹配了上面除’!’之外的一个属性,它就会被放入该内存区域。’!’属性对该测试取反,所以只有当它不匹配上面列出的行何属性时,一个未映射段才会被放入到内存区域。
origin是一个数字表达式,代表了内存区域的起始地址。表达式必须等价于一个常数并且不能含有任何符号。关键字ORIGIN缩短为org或者o(但不能写成ORG)。
len是一个表达式用来给出内存区域中的字节数大小。类似于origin表达式,表达式必须只能为数字的切必须求值为常数。关键字LENGTH可以被缩写为len或者l。
下面的例子里,我们制定了有两个可分配的内存区域:一个从’0’开始有256k字节,另一个从’0x40000000’开始,由4兆字节。链接器把所有没有显式映射到一个内存区域的段放到’rom’内存区域内,段可以是只读的或者可执行的。链接器将把其它没显式指定内存区域映射的段放到’ram’内存区域。
MEMORY
{
rom (rx) : ORIGIN = 0, LENGTH = 256K
ram (!rx) : org = 0x40000000, l = 4M
}
一旦你定义了一个内存区域,你可以使用’>region’输出段属性指引链接器把特殊输出段放到该内存区域。例如,如果你拥有一个内存区域名为’mem’,你可以在输出段定义中使用’>mem’。参考Output Section Region。如果没有给输出段指出地址,链接器将会把地址放到最先符合要求的内存区域中的可用地址。如果指引给一个内存区域的组合输出段比区域还大,链接器将会提交错误。
可以通过ORIGIN(memory)和LENGTH(memory)函数获得内存区域的起始地址以及长度:
_fstack = ORIGIN(ram) + LENGTH(ram) - 4;
4. 段描述
4.1输出段
完整的输出段描述如下
section [address] [(type)] :
[AT(lma)]
[ALIGN(section_align) | ALIGN_WITH_INPUT]
[SUBALIGN(subsection_align)]
[constraint]
{
output-section-command
output-section-command
...
} [>region] [AT>lma_region] [:phdr :phdr ...] [=fillexp] [,]
地址(address)是一个输出段VMA(虚地址)的表达式。此地址为可选参数,但如果给出了地址,则输出地址就会被精确的设置到给定值。
如果输出的地址没有给定,则依照下面的尝试选择一个地址。此地址将会被调整到符合输出端要求的对齐地址。输出段的对齐要求是所有输入节中含有的对齐要求中最严格的一个。
输出段地址探索如下:
如果为段设置了内存区域,则段被放如该区域,并且段地址为区域中的下一个空闲位置。
如果使用MEMORY命令创建了一个内存区域列表,此时第一个属性匹配段的区域被选择来加载段,段地址为区域中的下一个空闲位置。参见MEMORY。
如果没有指定的内存区域,或者没有匹配段的,则输出地址将会基于当前位置计数器的值
4.2输入段
输入段存在于输出段的内容中,用来指定不同输入段在输出段中的位置,常见的有.text .data .rodat .bss COMMOM等,一个输入段描述由跟随在段名称后面括号包含的一个可选的文件名称列表构成。也可以使用通配符,例如
*main.o(.text)或者直接*(.text)
前一个代表main.o 文件中所有.text段,后一个代表所有参与链接文件中的.text段,当然也可以排除一些文件
EXCLUDE_FILE (*文件名.o) *(.text)
5. 一些内建函数
ABSOLUTE(exp)
返回表达式exp的绝对(非可重分配的,而不是非负)值。主要用来在段定义内为符号分配一个绝对值,通常段定义内的符号值都是相对段地址的。
ADDR(section)
返回名为’section’的段的地址(VMA)。你的脚本必须事先未该段定义了位置。在下面的例子里,start_of_output_1, symbol_1, symbol_2分配了同样的值,除了symbol_1为与段.output1相关的值而其他两个为绝对值:
SECTIONS { ...
.output1 :
{
start_of_output_1 = ABSOLUTE(.);
...
}
.output :
{
symbol_1 = ADDR(.output1);
symbol_2 = start_of_output_1;
}
... }
LENGTH(memory)
返回名为memory的内存的长度。
MAX(exp1, exp2)
返回exp1和exp2最大的
MIN(exp1, exp2)
返回exp1和exp2最小的。
ORIGIN(memory)
返回名为memory的内存区域的起始地址。
SIZEOF(section)
返回名为section段的字节数。如果段还没被分配就是用函数求值,将会产生错误。
RISC-V
,
嵌入式开发
相关帖子
RISC-V MCU IDE MRS(MounRiver Studio)开发之: 设置函数的优化等级
RISC-V MCU IDE MRS(MounRiver Studio)开发之: 编译后打印FLASH及RAM使用占比信息
RISC-V MCU IDE MRS(MounRiver Studio)开发之: 解决编译后显示RAM占用率100%的问题
RISC-V IDE MounRiver Studio V1.60更新点介绍
RISC-V IDE MRS使用笔记(一):Target mode doesn't match
举报
回复
返回列表
*
滑块验证:
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
注册会员
本版积分规则
发表回复
回帖后跳转到最后一页
回复
转播
评分
分享
打开支付宝扫一扫,最高立得1212元红包
搜索
本版
帖子
用户
热搜:
传感器
51串口程序
电子管放大器
夾式電表
夾式電流
Mentor论坛
打印机
版块推荐
百宝箱
My 布拉格
无边框Z9
Z9Max
Z9mini
nubia动态
问题 & 建议
资源分享
爱拍
同城会
牛仔生活
查看论坛所有版块>>
每日签到
论坛任务
摄影技巧
跳蚤市场
互助问答
论坛导读
申请内测
红包中心
每日摇一摇
活动中心
网站地图
官方旗舰店
图文热点
俄罗斯的6H23+6П43推挽电路机器欣赏
AP3215 8-150V 外围简单 宽输入 电压降压BU
产品描述 AP3215是 一系列外围电路简洁的宽输入电压降压BUCK 恒压恒流驱动器 ,适用
VK1056Q QFN246是一个点阵式存储映射的LCD
产品品牌:永嘉微电/VINKA 产品型号:VK1056Q 封装形式:QFN24L 概述 VK1056Q是
超高清图解示波器使用方法
3线串行接口/工作电压工作电压 2.4-5.2V/VK
产品品牌:永嘉微电/VINKA 产品型号:VK1056B/C 封装形式:SOP/SSOP24 概述 VK1
更多
精华推荐
俄罗斯的6H23+6П43推挽电路机器欣赏
AP3215 8-150V 外围简单 宽输入 电压降压BU
VK1056Q QFN246是一个点阵式存储映射的LCD
一个名为伯努瓦(Gislain)的人,用了3年时
AP2121太阳能草坪灯驱动芯片
超高清图解示波器使用方法
3线串行接口/工作电压工作电压 2.4-5.2V/VK
单片机驱动彩屏最简方案:单片机_RA8889最
更多
社区学堂
俄罗斯的6H23+6П43推挽电路机器欣赏
AP3215 8-150V 外围简单 宽输入 电压降
俄罗斯的6H23+6П43推挽电路机器欣赏
AP3215 8-150V 外围简单 宽输入 电压降压BU
产品描述 AP3215是 一系列外围电路简洁的宽输入电压降压BUCK 恒压恒流驱动器 ,适用
VK1056Q QFN246是一个点阵式存储映射的LCD
产品品牌:永嘉微电/VINKA 产品型号:VK1056Q 封装形式:QFN24L 概述 VK1056Q是
更多
客服中心
QQ:187196467
服务时间:周一至周日 8:30-20:30
在线客服
客服微博
产品咨询
售后中心
关注我们
关于我们
关于我们
友情链接
联系我们
帮助中心
网友中心
购买须知
支付方式
服务支持
资源下载
售后服务
定制流程
关注我们
官方微博
官方空间
官方微信
QQ:187196467
周一到周日 8:30-22:00 (全年无休)
7 x 24小时在线客服
手机版
Powered by
MCUZX!
X3.4 © 2008-2015
MCU资讯论坛
版权所有
京ICP备18035221号-2
客服QQ: 187196467
技术支持:
MCU资讯论坛
|
网站地图
快速回复
返回顶部
返回列表