工程换了一颗容量更小的芯片,或者接入引导程序后,原来正常的链接布局就可能出问题。有时链接器提示段无法放置,有时构建能够完成,下载时却发现地址不属于目标器件。两种情况都要从芯片内存定义和实际段地址查起。下面以TASKING VX-toolset for TriCore的Eclipse工程为例说明,其他工具链的界面和芯片定义应以对应版本为准。
一、Tasking怎样设置链接器内存布局与段映射
TASKING通过LSL文件描述硬件内存和段放置规则。应先确认工程使用的芯片与脚本,再调整具体段的位置。
1、确认当前构建使用哪份脚本
项目里存在多个LSL文件时,编辑器中打开的文件未必参与当前链接。调试与发布配置也可能引用不同脚本。
①打开工程属性,进入【C/C++Build】→【Settings】,在【Configuration】中选定本次构建配置。
②在【Tool Settings】→【Linker】→【Script File】中,检查【Linker script file(.lsl)】。
③核对构建输出中的【--lsl-file】或【-d】参数,并检查脚本包含的芯片定义文件。
④对照目标器件型号,核对【C/C++Build】→【Processor】中的处理器设置。
2、按真实容量建立内存映射
①打开实际参与链接的【.lsl】文件,找到对应的【memory】和【map】定义。
②对照芯片手册,核对【size】、【type】以及映射中的【dest】、【src_offset】和【dest_offset】。
③在内存分配方案中标明引导程序、应用程序和固定保留区,再配置相应布局限制。
内存定义告诉链接器有哪些资源,映射描述这些资源在地址空间中的位置。脚本中的容量如果大于实物,链接器仍可能按照错误模型完成分配。片上内存优先采用对应芯片的官方定义,应用工程再增加必要的布局约束,避免直接修改工具链安装目录中的公共文件。
3、把目标段放进明确的组
①在合适的【section_layout】中建立具名【group】,使用【select】选择目标段。
②设置【run_addr】指向目标内存;例如使用【mem:mpe:dspr0】表示对应芯片定义中的内存对象。
③按布局要求设置【ordered】或【contiguous】,通过【Linker】→【Map File】启用【Generate map file】。
④构建后在【Locate Result:Sections】中检查段名、组名和最终地址。
选择表达式应从实际输出段名出发。先用精确名称验证归组结果,再扩大匹配范围,可以减少误选。排序和连续放置也应按需求使用;连续组需要一整块可用空间,不能仅凭内存剩余总量判断是否放得下。
二、Tasking程序段地址超出目标芯片范围如何定位
定位时应保留最早出现的链接诊断,并区分真实越界、地址别名和分配空间不足。链接失败时,旧的映射文件不能代表本次结果。
1、核对段末地址和实际物理内存
①在本次生成的【.map】中找到异常段,记录【Space addr】、【Chip addr】、段大小和所属内存。
②对照芯片手册,核算段起始地址加长度减一得到的末地址。
③检查【map】定义,确认异常地址对应的物理内存及访问映射。
例如可用区域为0x80010000至0x8001FFFF,段从0x8001F000开始、长度为0x2000,其末地址就会越界。TriCore还可能通过不同地址访问同一物理内存,不能只因地址前缀不同便认定越界,也不能把这些别名当作额外容量。
2、检查段是否进入预期地址空间
段没有进入指定组时,要同时检查段名、地址空间和选择顺序。近寻址数据与普通数据的布局条件可能不同。
①在【Link Result】中找到异常输入段,确认实际名称和来源模块。
②对照【section_layout】检查所属地址空间;区分【linear】与【abs18】等布局。
③检查前面是否已有【select】规则匹配该段,调整过宽的选择表达式。
④重新构建,在【Group】列确认段已进入指定组。
同一地址空间中的段会受到选择规则先后顺序影响。单纯在文件末尾增加一条规则,可能无法改变已经被前面规则选中的段。具名组能让这类问题在映射结果中更容易识别。
3、检查连续空间、保留区与芯片版本
①在【Used Resources】中同时查看【Free】和【Largest gap】,比较目标组所需容量。
②检查【Reserved】对应的栈、堆、CSA、固定保留区和对齐占用。
③核对当前芯片定义是否包含仅仿真型号具备的内存,并检查相关宏条件。
剩余总量足够,仍可能因最大连续空洞不足而无法放置。排查时不要直接扩大内存容量或缩小栈来消除错误。应先确认大组是否确实需要连续,再决定调整分组、搬移数据或减少占用;正式芯片不具备的仿真内存也必须排除。
三、Tasking调整段映射后如何核验加载与运行地址
段成功放入目标区域后,还要确认初始化内容和启动过程与新布局一致。尤其是初始化数据和搬到RAM执行的代码,需要分别检查运行位置与装载位置。
1、核对初始化段的两份位置
①在【.map】中查找目标【.data】段及对应的ROM副本,分别记录RAM地址与Flash地址。
②需要单独限制副本位置时,使用带【load_addr】的组选择对应段,并核对最终映射。
③对RAM执行代码,检查布局中的【copy】设置以及启动代码对复制表的处理。
初始化数据会同时占用运行内存和保存初值的存储空间。只检查RAM余量,可能漏掉Flash中的副本越界。运行地址和装载地址应通过相应组分别约束,不能在同一个组中同时设置两者。
2、用完整重建和上板结果确认布局
①执行【Project】→【Clean...】,启用【Start a build immediately】后重新构建。
②检查新生成的【.map】和【.elf】,确认时间、构建配置及关键段地址一致。
③下载程序,检查启动入口、初始化变量和搬移代码的执行结果。
④对多核共享数据,核对各核使用的地址映射及缓存一致性要求。
总结
TASKING的内存布局依赖脚本中的硬件模型,也受段属性、寻址方式和分组约束影响。程序地址异常时,把实际芯片容量、链接命令和映射结果放在一起核对,通常比反复修改固定地址更有效。工程更换器件、加入引导程序或调整多核分工后,都适合重新检查整套分配方案,并给后续增长留出余量。希望这些方法能帮助你找到地址异常的具体环节;遇到某个段始终无法归组时,也可以结合段名和链接诊断继续分析。