IAR Embedded Workbench for Arm通常使用ICF文件控制程序在Flash和RAM中的布局,代码区、数据区、栈、堆以及部分启动相关段都会受到链接配置影响。工程能够正常编译、链接,却在下载后停在复位阶段、跑不到main、出现HardFault或直接无法下载时,可以把链接器配置和芯片实际存储布局放在一起核对,尤其要检查工程选择的器件、ROM起始地址、RAM范围和启动代码使用的地址。
一、IAR怎么配置链接器脚本
IAR会根据工程选择的器件自动匹配默认链接配置。项目没有特殊存储布局时可以直接使用默认配置;涉及Bootloader、外部RAM、分区固件等情况,再复制ICF并修改项目自己的版本。
1、选择工程使用的ICF文件
①打开IAR工程,进入【Project】→【Options】。
②切换到【General Options】→【Target】,检查当前【Device】是否与实际芯片一致。
③进入【Linker】→【Config】。
④默认配置可以保持【Override default】关闭,此时IAR会按照当前Device选择链接配置。
⑤需要使用项目自己的ICF时,勾选【Override default】。
⑥点击路径右侧的浏览按钮,选择准备使用的【.icf】文件。
⑦项目自己的脚本可以放在工程目录,通过【$PROJ_DIR$】引用,移动工程后路径不容易失效。
⑧点击【OK】保存,再执行一次【Project】→【Rebuild All】。
不要直接修改IAR安装目录里的模板ICF。可以复制一份到工程目录,再让【Linker】→【Config】指向复制后的文件。
2、设置Flash和RAM地址范围
ICF里常见的是先定义ROM、RAM起止地址,再建立对应Region。
define symbol __ICFEDIT_region_ROM_start__=0x08000000;
define symbol __ICFEDIT_region_ROM_end__=0x0807FFFF;
define symbol __ICFEDIT_region_RAM_start__=0x20000000;
define symbol __ICFEDIT_region_RAM_end__=0x2001FFFF;
①打开当前工程实际使用的【.icf】文件。
②找到【ICFEDIT_region_ROM_start】和【ICFEDIT_region_ROM_end】。
③对照芯片Memory Map填写Flash可用范围。
④找到【ICFEDIT_region_RAM_start】和【ICFEDIT_region_RAM_end】。
⑤填写当前芯片实际存在的SRAM范围。
⑥工程带Bootloader时,把应用程序ROM起始地址改到Bootloader预留空间之后。
⑦芯片存在多块不连续RAM时,不要直接把中间不存在的地址连成一整块,需要按实际Memory Region分别处理。
⑧保存ICF并重新链接,查看【Map File】里的Section地址。
3、配置栈、堆和Section放置位置
①在ICF中找到【CSTACK】对应的Block定义。
②检查【ICFEDIT_size_cstack】设置值。
③项目使用动态内存时,再检查【HEAP】及【ICFEDIT_size_heap】。
④找到ROM放置规则,确认【readonly】内容被放入代码Region。
⑤找到RAM放置规则,确认【readwrite】、栈和堆进入有效RAM区域。
⑥有指定地址的数据段时,检查【place at】或【place in】使用的Region。
⑦重新Build后打开【Linker Map】或.map文件,查看各Section实际起始地址和占用空间。
RAM本身比较紧张时,还要看CSTACK、HEAP、全局变量三者是否已经把可用空间占满。
二、链接器脚本设置错误导致程序无法启动如何排查
程序下载后没有进入main,可以先区分是镜像被放到了错误地址,还是复位之后在启动代码阶段出了问题。链接已经成功并不代表这些地址一定和目标板一致。
1、检查工程器件和Flash起始地址
①进入【Project】→【Options】→【General Options】→【Target】。
②核对【Device】型号。
③再进入【Linker】→【Config】,确认当前加载的是哪一份【.icf】。
④打开ICF,检查【ROM_start】和芯片Flash起始地址。
⑤工程有Bootloader时,确认应用程序入口没有仍然使用裸机工程的Flash起始位置。
⑥打开生成的【.map】文件,找到代码段和中断向量表所在地址。
⑦对照下载工具实际写入地址,检查两边是否一致。
如果Debugger在下载阶段直接报Write Failure,也要检查程序是不是被链接到了目标设备不存在或不可写的地址区域。
2、检查中断向量表和程序入口
Cortex-M程序复位后会从向量表读取初始栈地址和复位处理函数地址,链接位置错了,程序可能还没进入C运行库就停下来。
①打开【.map】文件,查找中断向量相关Section。
②确认向量表位于当前应用要求的Flash地址。
③项目带Bootloader时,核对应用向量表地址和Bootloader跳转地址。
④检查链接器入口设置有没有被手工改动。
⑤进入【Project】→【Options】→【Linker】相关设置,检查【Override default program entry】。
⑥普通IAR C/C++工程没有特殊启动要求时,不要随意改掉默认程序入口【__iar_program_start】。
⑦进入C-SPY后在复位处理函数附近下断点,确认CPU实际跳到了哪个地址。
3、检查RAM、CSTACK和初始化数据
程序能进入Reset Handler,却在进入main前异常,更适合检查RAM布局和运行库初始化。
①在【.map】文件中查看【CSTACK】地址。
②确认CSTACK完整位于有效RAM范围。
③检查RAM结束地址有没有超出当前芯片容量。
④查看全局变量和静态变量所在Section。
⑤检查ICF中的【initialize by copy】配置,确认需要初始化的readwrite数据能够从ROM复制到RAM。
⑥项目把部分数据放到自定义Section时,确认该Section已经在ICF中安排位置。
⑦进入Debugger查看SP值,确认初始栈指针落在有效RAM中。
⑧如果启动阶段直接进入HardFault,再检查Fault寄存器和当时的SP、PC地址。
三、修改ICF后怎么确认配置已经恢复
链接脚本改完后,可以用Map文件和调试器各检查一次。这样能把“链接结果正确”和“芯片实际能运行”分开确认。
1、查看Map文件中的实际内存布局
①进入【Project】→【Options】→【Linker】→【List】。
②启用链接Map输出。
③重新执行【Rebuild All】。
④打开生成的【.map】文件。
⑤检查ROM中代码、常量和向量表的位置。
⑥检查RAM中的readwrite、CSTACK和HEAP位置。
⑦确认各Section没有超出ICF定义的Region。
⑧带Bootloader的工程再核对应用起始地址和预留区边界。
2、从复位入口单步检查启动过程
①进入【Project】→【Download and Debug】。
②复位目标板。
③在复位处理函数或【__iar_program_start】附近设置断点。
④单步运行启动代码。
⑤查看PC是否落在有效Flash区域。
⑥查看SP是否处于有效RAM范围。
⑦继续执行到main。
⑧如果在进入main前停止,就结合当前PC地址回到Map文件查对应Section。
这种检查方式能很快分清ICF地址问题、启动文件问题和应用代码问题,不用一看到无法启动就反复修改链接脚本。
总结
IAR链接器脚本出错后,程序可能仍然能够完成编译和链接,所以排查时不能只看Build是否成功。芯片型号、Flash和RAM边界、向量表、程序入口以及栈和数据段的位置都要和目标硬件对应。工程涉及Bootloader或自定义内存分区时,更应保留独立ICF并结合Map文件核对实际布局。如需进一步了解IAR链接器脚本配置、ICF内存布局与程序启动异常排查方法,欢迎联系咨询。