Keil中的链接器脚本文件即分散加载文件能够控制代码和变量的存放地址。编译器将C语言转成汇编代码后再转成二进制bin文件,bin文件在存储器里比如Flash中如何存放,则会受到分散加载文件的影响。

01

编译和链接

在Keil中,链接器脚本文件(分散加载文件,Scatter-Loading File)用于控制代码和数据在内存中的分布。它通常以.sct为扩展名,由ARM链接器(armlink)使用。对于Keil,先是armcc编译器对每个单独的.c文件编译生成.o文件,然后使用armlink链接器组合所有的.o文件,即结合分散加载文件即SCT文件,为其各自分配存储地址。SCT文件用户可自己编辑,从而指定代码和数据的存储地址

02


查看链接器脚本文件

2.1、通过Keil工程Linker选项查看

  • 打开 Keil 工程(.uvprojx 或 .uvmpw)。

  • 点击菜单栏 Options for Target(或按 Alt F7)。

  • 切换到 Linker 选项卡。

  • 在 Use Memory Layout from Target Dialog 下方,可以看到:

    • 如果勾选了 Use Memory Layout from Target Dialog,则内存分布由 Target 选项卡中的设置决定即Target选项卡下的配置。

    • 如果取消勾选,可以手动指定 .sct 文件路径:点击Edit按键则进入sct文件的编辑界面

2.2、在工程目录里查看

  • 默认情况下,Keil会自动生成.sct文件,存放在Objects或Listings目录下,文件名通常为【工程名.sct】。

  • 也可以手动创建 .sct文件并指定路径。

03


内存分配基础(1):基础概念

修改链接器脚本文件

3.1、通过Keil工程Target选项修改

  • 进入 Options for Target → Target 选项卡。

  • 在 Read/Write Memory Areas 和 Code Memory Areas 中:

    • 可以添加、修改RAM和Flash的地址范围,可以任意对片上或片外的Flash或RAM存储器进行地址段的划分,从而可以实现将指定的变量或者函数、文件存放到指定的地址段上,例如

//片上Flash起始地址 0x0800 0000,片外Flash起始地址 0x70000000//片上Flash的第一个地址段IROM1 (Flash): 0x080000000x0000D000 //片上Flash的第二个地址段 IROM2 (Flash): 0x0800D0000x00002000  //【片外Flash】由外部总线FSMC扩展,为第三个Flash地址段 EXROM(Flash): 0x70000000,0x1000 
//片上RAM起始地址 0x2000 0000, 片外RAM起始地址 0x60000000//片上RAM的第一个地址段 IRAM1 (RAM):   0x200000000x00002000 //片上RAM的第二个地址段 IRAM2 (RAM):   0x200020000x00003000  //【片外RAM】由外部总线FSMC扩展,为第三个RAM地址段EXRAM(RAM):   0x600000000x00001000  
  • 修改后,Keil 会自动更新 .sct 文件,生成3个Flash地址段和3个RAM地址段

  • 然后可以将指定的变量或者函数、文件存放到上述任意的3个FLash段和3个RAM段,其中,RO只读变量需要放到Flash段,ZI变量放到RAM段,而函数理论上既可以放到FLash段(烧写到Flash里),也可以放到RAM段(烧写到RAM里),ZW变量则是初值要放到Flash段里,运行后则复制到RAM段里。例如:

    • 调整led.c文件里的代码存放地址、RO只读变量的存放地址、ZI变量(局部变量)的存放地址、ZW变量的存放地址,则需要右键工程目录里的led.c文件,选择Options for File

    • 可以看到列举出了led.c中的Code代码和Const、ZI、ZW等变量,其中代码和只读变量既可以存放到Flash中,也可以存放到RAM里,因此存放地址可以存前面3个Flash地址段和3个RAM地址段里选择;而ZI和ZW变量只能存放到RAM里,存放地址只能存前面设置的3个RAM段里选择。

    • 比如将led.c文件里的Code和RO变量选择放置到IROM2段即地址0x0800D000起始地址段,那么编译后通过map文件查看led.c中的函数LED_Init()的存放地址

3.2、手动编辑.sct文件

  • 取消勾选 Use Memory Layout from Target Dialog。

  • 点击 Scatter File 旁边的 … 按钮,选择或创建 .sct 文件。

  • 编辑 .sct 文件,调整内存布局:设置不同的地址段。

  • 基础语法

语法
说明
LR_IROM1
加载域(Load Region)名称,名字自定义
0x08000000
加载域起始地址即程序存放的起始地址
0x00080000
加载域的空间大小即留给程序的最大存储空间
ER_IROM1
执行域(Execution Region)名称,名字自定义
*.o
*表示通配符,*.o表示所有以.o为结尾的文件
*.o (RESET, First)
存放所有.o文件时将RESET段(中断向量表)的变量放在最开头的位置,其他.o存放顺序不做严格要求
*(InRoot$$Sections)
表示所有的系统初始化代码即 C 库的初始化代码(如 __main
.ANY ( RO)
代表程序里用到的所有只读(Read-Only)数据,因为是.ANY
.ANY ( RW ZI)
代表程序里用到的所有可读写(RW)和零初始化(ZI)数据,因为是.ANY
ZI
代表程序里用到的Zero-Initialized 数据(如未初始化的全局变量),因为是.ANY

04


总结

  • 对于Keil,先是armcc编译器对每个单独的.c文件编译生成.o文件,然后使用armlink链接器组合所有的.o文件,即结合分散加载文件即.sct文件,为其各自分配存储地址。.sct文件用户可自己编辑,从而指定代码和数据的存储地址。

  • 可以添加、修改RAM和Flash的地址范围,可以任意对片上或片外的Flash或RAM存储器进行地址段的划分,从而可以实现将指定的变量或者函数、文件存放到指定的存储器地址段上。
  • 代码和只读变量既可以存放到Flash中(烧写到Flash),也可以存放到RAM里(烧写到RAM里),因此存放地址可以选择Flash地址段和RAM地址段;而ZI和ZW变量只能存放到RAM里,存放地址只能从前面设置的RAM段里选择。
  • *表示通配符,*.o表示所有以.o为结尾的文件。