随着工程规模逐渐扩大,代码、常量、全局变量、栈、堆以及启动区全都拥挤在同一套内存布局里,section的放置只要出现一点混乱,链接阶段就很容易报错。想要弄明白TASKING的section该怎么分配才算合理,以及分配发生重叠后又该怎样处理,关键就在于先把内存的用途清晰地划分开,然后借助LSL文件里的memory定义和section_layout规则来控制它们的位置。根据TASKING官方文档的说明,LSL文件正是用来描述硬件架构、可用的物理内存,以及section的放置方式。
一、TASKING section怎么分配才合理
section的分配不能仅仅盯着当前的工程能不能链接通过,还要为后续功能的增加、变量的扩展以及版本的升级留出足够的余地,常见的思路就是把启动区、普通代码、常量、全局变量、核本地数据、栈堆和特殊保留区彼此分隔开来。
1、先按内存用途进行分区
在Flash里通常要放置程序代码、常量,以及已初始化数据的ROM副本;RAM里则主要存放运行时的数据、未初始化的变量、栈和堆。对于AURIX这类多核工程,还需要把DSPR、PSPR、LMU等区域区分清楚,避免将那些需要高频访问的变量随意丢进共享内存里。
2、用group进行集中管理
可以在LSL文件的section_layout中建立带有明确名称的group,再通过select规则来匹配目标section,同时用run_addr来指定它们的运行位置。TASKING官方知识库建议给group取一个清楚的名字,因为只要分配成功,group的名称就会显示在map文件当中,这样在后期排查的时候就会直观很多。
3、不要让规则顺序变得混乱
同一个section有可能同时命中多条select规则。TASKING文档中说明,链接器只会采用最先匹配上的那一条规则,因此专用的分配规则应当放置在通用规则的前面。如果通配符写得太宽,目标section就有可能提前被其他的group给抢走。
4、把特殊区域保留下来
像Boot Mode Header、CSA、栈、堆、标定区以及升级区,不要丢给链接器自己去自由填充。对那些需要保护的地址范围,可以在LSL里用reserved的方式预留出来,防止普通的section误入进去。
二、TASKING section分配重叠后该怎么处理
section一旦出现重叠,不建议直接手工改动一个地址就继续编译。先要看清楚重叠发生在哪一块内存里,再来判断到底是规则冲突、地址范围写错,还是对内存映射的理解出现了偏差。
1、先去查map文件
打开map文件中的【Used Resources】和【Locate Result】,前者能看到Code、Data、Reserved、Free和Total这些总量,后者则能瞧见section的名称、它属于哪个group、起止地址还有来源的模块。先找到重叠的区域,再顺着线索追到具体的section上去。
2、检查run_addr和地址范围
如果两个group都被固定到了同一段地址,或者某个绝对地址掉进了保留区,冲突就不可避免了。排查时要重点去看run_addr、range、reserved、stack、heap以及启动区的设置,确认这些范围有没有互相覆盖。
3、检查section是否进错了group
假如section并没有进入预期的group,就先核对section_layout后面的space是不是选对了,再去看select的名称是否准确。TASKING官方知识库特意提醒过,space一旦选错,section就可能无法按照预想的那样分配。
4、区分真实冲突和地址映射
TriCore的本地RAM可能同时存在核本地地址和SRI线性地址,这两段地址在物理上完全重叠,实际映射到同一块内存上。TASKING官方的资料也说明,这类地址范围物理上是完全覆盖的,分析容量的时候不能把它们当成两块独立的RAM。
三、TASKING section调整后怎么复核
把section重叠的问题修正完之后,还不能只看到链接器不再报错就觉得万事大吉了,还需要重新核对内存的余量以及最终的运行结果。
1、重新查看Free和Largest gap
Free表示的是总剩余空间,Largest gap则代表了最大的连续空洞。就算总量上还有余裕,也不代表还能塞得下一段大数组或者大缓存,两者必须搭配着一起看。
2、检查ROM副本
初始化变量既会在Flash里保留一份ROM副本,同时也会在RAM里保留一块运行区域。在map文件中,带上方括号的section通常就代表着ROM copy,不要误以为这是重复分配了。
3、对比修改前后的map文件
重点去比较section的地址、所属的group、RAM的占用、Reserved以及剩余的连续空间。如果只是把冲突从一块RAM挪到了另一块RAM里,那后面依然有可能继续出问题。
4、跑一遍下载和启动验证
重新把程序下载进去,检查一下复位入口、全局变量的初始化、栈的使用以及关键任务的运行是否正常。链接通过只不过是布局检查的起点,只有经过运行验证,才能确认section的调整没有破坏启动和访问的路径。
总结
TASKING的section怎么分配才合理,以及分配重叠后该怎么处理,实际操作的顺序可以固定下来:先在LSL里按用途把内存划分清楚,再用带名称的group和准确的select规则把section放置好;一旦出现重叠,就先去查map文件,然后核对run_addr、space、reserved以及物理地址映射。修正完成之后,还要继续检查RAM的余量、ROM副本和启动结果,内存布局才算真正稳定下来。