IAR中文网站 > 热门推荐 > IAR链接脚本怎么改内存分区 IAR链接脚本改完后段地址为什么会冲突
IAR链接脚本怎么改内存分区 IAR链接脚本改完后段地址为什么会冲突
发布时间:2026/06/04 13:36:03

  在一颗Flash里面同时放进Bootloader、主应用程序、参数区和固件升级区的时候,软件默认的内存划分往往就不够用了。在IAR开发环境底下,经常是通过一个以.icf作为后缀的链接配置文件,来安排代码和数据的存放位置的,ILINK链接器会根据这份文件里对memory、region、block和section placement的定义,把各个段分配到可以使用的内存当中去。调整这个文件的时候,不能只去改一个起始地址,还要把预留的空间、初始化数据块还有栈空间这些因素也一起考虑进来,否则很容易在链接阶段就出问题。

  一、怎样调整链接文件里的内存划分

 

  动手修改链接配置以前,先要把芯片的参考手册和最近一次编译生成的map文件都打开,对照着看清楚Flash和RAM的物理范围,以及Bootloader、应用程序、参数区各自已经占用了哪一段空间。不要直接去改开发工具安装目录里默认的那份.icf文件,更稳当的办法是把它复制一份放到当前工程目录下面,单独进行维护,这样既不会影响其他项目,也方便后续追溯变更。

 

  1、先找到当前工程正在使用的.icf文件

 

  通过菜单栏里的【Project】→【Options】→【Linker】→【Config】这条路径,就能看到目前链接步骤所引用的配置文件是哪一份。不同芯片的工程里面,这个文件的名称会有差别,不过里面常见的内容通常都包括对ROM_region、RAM_region、CSTACK以及HEAP这些区域的描述。把这份文件复制到工程目录以后,再回到刚才的选项窗口,把路径重新指向这份新拷贝,后面所有的修改都在这份副本上进行。

 

  2、调整ROM和RAM的起止范围

 

  打开.icf文件,在定义区域的那部分内容里(一般用define region来描述),去修改ROM和RAM的起始地址和结束地址。比如Bootloader往往占据了Flash的前面一部分空间,那么主应用程序的ROM起始位置就得跟着往后挪,不能跟Bootloader的尾巴叠在一起。IAR的官方示例里经常能看到,用define region来声明一段可用的内存范围,然后再用place in这样的指令,把只读的代码段放进ROM,把需要读写的数据段还有STACK放进RAM,调整的时候要把这两类区域都照顾到。

 

  3、给一些特殊的数据单独划出存放区域

 

  如果工程里还需要存放校准参数、固件升级的状态标记,或者一些掉电后不能丢失的变量,那就有必要在.icf文件里专门新建一个区域,然后再通过自定义的section来指定这些数据具体落在哪里。在C源代码这边,可以借助#pragma location来把某个变量放到一段固定的地址,或者放到一个用户自己命名的section里面。按照IAR官方文档的说明,location既可以作用在某个绝对地址上,也可以指向一个自定义的section名称,这给固定位置的数据放置提供了比较大的灵活度。

 

  二、链接文件改完以后为什么会出现段地址冲突

 

  段地址发生冲突,大多数时候并不是因为.icf文件本身的语法写错了,而是因为两个不同的区域实际上重叠到了同一段地址空间里。链接器在发现没有办法把某个段塞进给它分配的范围时,就会在构建过程中直接报错,不给通过。

 

  1、ROM的各个分区之间发生了重叠

 

  最常见的情况,就是Bootloader、App、参数区和中断向量表这几块空间之间,没有留出明确的分界线。可能已经把应用程序的起点往后移了,但ROM的整体结束地址还继续沿用之前的值,而另一个固定的数据块又被指定到了同一个范围里面,这样一来,这几个区域在链接时就会挤在一起,互相踩踏;排查这类问题时,要先把各个分区的起止地址画出来对比,看看有没有交叠的地方。

 

  2、RAM区域没有把栈和堆的空间扣除干净

 

  RAM区域除了要放下全局变量和静态变量,还要腾出地方给STACK、HEAP,以及.data、.bss、.noinit这些段来使用。在IAR的初始化流程里面,.data段在运行的时候是放在RAM里的,但它对应的那一份初始化数据会预先保存在ROM中,启动时再由启动代码复制到RAM去;正因为存在这种搬运关系,如果只看变量本身占了多少字节,很容易低估整块RAM实际需要的容量,链接时就可能发现尾部空间不足。

  3、固定地址的段不小心放进了已经占用的区域

 

  用#pragma location去指定某个变量的绝对地址时,要提前检查这块地址是不是已经被其他section给用掉了。像参数存储区、Flash配置字、版本信息这类数据,经常都会用到固定地址,一旦地址写错,普通的代码段仍然有可能继续往这个方向扩展,最终两个段就又重叠到一起了;所以每次分配固定地址前,最好先在map文件里确认一下那片空间的使用情况。

 

  4、只改了一个构建配置下的链接文件

 

  IAR工程通常会区分Debug和Release这些构建配置,每一套配置都可以有自己独立的链接脚本。如果在Debug配置下面把.icf文件改了,Release配置并不会自己跟着一起变化,还是继续用原来那份旧的文件。当你切换了一下构建配置,突然发现冒出一堆链接错误时,第一步就要去检查当前这次构建实际引用的到底是哪一份链接脚本,避免在错误的文件上找原因。

 

  三、链接脚本修改完成之后怎样做复核

 

  调整完内存分区以后,不能光看编译有没有通过,还得再去确认最终各个段落在存储器里的实际地址,是不是跟设计时画好的分配图一致,这一步如果省掉了,很可能把问题留到上板运行的时候才暴露出来。

 

  1、生成并查看map文件

 

  通过【Project】→【Options】→【Linker】→【List】这条路径,把map文件的输出功能打开,然后重新执行一次完整构建。拿到map文件以后,重点去查看每一个section的起始地址和大小,还有STACK和HEAP最终被安排到了什么位置,同时要留意ROM的尾部还剩下多少空间,RAM的尾部是不是也还有余量,这些剩余空间是以后再加功能时的安全垫。

 

  2、核对初始化相关的数据块

 

  检查.data、.bss、.noinit这些标准段,以及你自己定义的那些自定义section,确认它们确实都落进了预想的内存区域里。按照IAR官方的说明,initialize by copy这种机制会把需要初始化的读写数据拆成两块来处理:初始化内容留在ROM里,运行时的数据放在RAM里;所以在看map文件的时候,要把这两部分的地址分开确认,防止漏看了ROM里那份额外的占用。

 

  3、重新把固件下载到目标板进行验证

 

  链接这一步跑通以后,还需要把生成的程序下载到实际的板子上去,验证设备能不能正常启动、固件升级流程是否可靠、掉电后参数能不能被正确保存和读取。特别是当Bootloader和App同时存在于一颗Flash里的时候,还要额外核对中断向量表的起始地址、两个程序之间跳转的入口地址是否正确,避免出现文件生成成功了,但设备一上电却卡住不动的情况。

  总结

 

  关于IAR下面链接脚本怎样修改内存分区,以及修改之后段地址为什么会发生冲突,处理起来的顺序大致可以归纳成:先把.icf文件复制到工程目录下面单独管理,再去调整ROM和RAM的范围以及特殊数据区的划分,最后通过查看map文件来确认实际的段地址是不是符合原来的设计。如果出现了段地址冲突,排查时的优先级可以这样排:先检查各个分区之间有没有重叠、栈和堆的占用是不是被低估了、固定地址的段是不是放错了地方,以及当前构建配置下到底用的是哪一份链接脚本。链接脚本所做的改动虽然范围不大,但它直接决定程序能不能跑起来,因此每次修改过后,都必须重新完成一次构建,并且拿到目标板上做实机验证,才能算真正把调整工作做完。

135 2431 0251