0
点赞
收藏
分享

微信扫一扫

[ArmCompiler6--armlink]Keil-MDK中scatter load机制


简述

Keil MDK工具中,Armlink使用scatter加载机制来描述一份image在memory map中的划分。
image的memory map由regions和output sections组成。

Scatter加载

需要使用Scatter加载的场景

  • 复杂的memory map,比如各种切分等
  • 不同类别的memory设备,RAM, ROM, SRAM,外设等
  • 固定函数放在指定位置
  • 使用symbols来识别heap和stack

当使用scatter file时,如下的符号将未被定义

  • Image–RO–Base.
  • Image–RO–Limit.
  • Image–RW–Base.
  • Image–RW–Limit.
  • Image–XO–Base.
  • Image–XO–Limit.
  • Image–ZI–Base.
  • Image–ZI–Limit.
    使用scatter file时,如果没有为stack和heap使用特定region,或没有重新实现__user_setup_stackheap(), 将会产生错误信息。

scatter file指定stack和heap

ARM C库为__user_setup_stackheap()提供了多种实现,并会根据statter file情况自动选择合适的一种实现。当然如果自己实现了user_setup_heap()的话,ARM C库提供的所有实现都会被覆盖。
另外在scatter file中定义两个特别的execution regions(ARM_LIB_HEAP和ARM_LIB_STACK)来选择两种region内存模式,这两种region都有EMPTY属性,一旦使用了这两种region内存模式,ARM C库提供的所有实现也会被无效掉,因为ARM C库中的user_setup_heap()使用了如下的synbols:

  • Image–ARM_LIB_STACK–Base.
  • Image–ARM_LIB_STACK–ZI–Limit.
  • Image–ARM_LIB_HEAP–Base.
  • Image–ARM_LIB_HEAP–ZI–Limit.

需要确保只有一个ARM_LIB_STACK或ARM_LIB_HEAP region的指定,且必须分配空间,因为user_setup_heap()会使用这些数据:

LOAD_FLASH …
{

ARM_LIB_STACK 0x40000 EMPTY -0x20000 ; Stack region growing down
{ }
ARM_LIB_HEAP 0x28000000 EMPTY 0x80000 ; Heap region growing up
{ }

另外也可以只在scatter file中定义ARM_LIB_STACKHEAP,这样user_setup_stackheap()将使用如下symbol的值:

  • Image–ARM_LIB_STACKHEAP–Base
  • Image–ARM_LIB_STACKHEAP–ZI–Limit

复杂image scatter file示例

[ArmCompiler6--armlink]Keil-MDK中scatter load机制_Keil


与此图对应的scatter file如下:

LOAD_ROM_1 0x0000              ; Start address for first load region (0x0000)
{
EXEC_ROM_1 0x0000 ; Start address for first exec region (0x0000)
{
program1.o (+RO) ; Place all code and RO data from
; program1.o into this exec region
}
DRAM 0x18000 0x8000 ; Start address for this exec region (0x18000),
; Maximum size of this exec region (0x8000)
{
program1.o (+RW, +ZI) ; Place all RW and ZI data from
; program1.o into this exec region
}
}
LOAD_ROM_2 0x4000 ; Start address for second load region (0x4000)
{
EXEC_ROM_2 0x4000
{
program2.o (+RO) ; Place all code and RO data from
; program2.o into this exec region
}
SRAM 0x8000 0x8000
{
program2.o (+RW, +ZI) ; Place all RW and ZI data from
; program2.o into

这里是比较复杂的例子,即将program1和program2分别放在两个load region中。在一些不这么复杂的情况下,ARM推荐 *或.ANY 来指代剩下的code和data。

Root execution region的情况

Root region指的是load address和execution address相同的region。
image的初始化entry point必须在root region之内。

ABSOLUTE属性

ABSOLUTE属性可以用来指定root region。
为了使execution region address和load region address一样,如下条件满足其中之一即可:

条件

说明


为execution region和load region设置相同的基地址(base address)


在load region中的第一个execution region添上+0,另外如果该load region中的其余所有execution region都添上+0,除了ZI之后的execution region都是root regions

ABSOLUTE属性用法示例如下:

LR_1 0x040000                   ; load region starts at 0x40000 start of execution region descriptions      
ER_RO 0x040000 ABSOLUTE load

FIXED属性

FIXED属性用于创建固定地址的root regions。

[ArmCompiler6--armlink]Keil-MDK中scatter load机制_scatter_02


对应的scatter file如下:

LR_1 0x040000              ; load region starts at 0x40000 start of execution region descriptions      
ER_RO 0x040000 load RO sections other than those in init.o
}
ER_INIT 0x080000 FIXED ; load address and execution address of

可以使用该属性将某个函数,或一块数据(如常数表、校验值)放置在固定的地址。

例如一些初始化代码需要放在ROM的开头,校验码可能要放在ROM的末尾,那么一些memory内容可能是无用的。使用*或.ANY将其余的code或data填满初始化代码和校验码之间的memory空间。
为维护和调试方便,Keil建议在scatter file中只使用必要的指定地址防止,将大部分的都交给linker来做。

在固定地址放置函数或数据

armlinker允许在固定地址放置一个section,具体如下:

方法

说明


在指定地址定义一个execution region,指定其section描述,且该execution region只包含这一个section


对于特殊名字的section,linker能从section名字获取其地址,这些特殊名字的section称为__at sections

为将一个函数或变量放在指定地址,该函数或变量必须放在它自己的section中:

步骤

说明


将函数或数据item放在其所属的源文件中


使用attribute((section(“name”))),将函数或数据放在自己命名的section中


在汇编语言中使用.section指令,汇编语言中.section是最小的memory放置单元


使用-ffunction_sections编译器选项,该选项会为源文件中的每个函数都产生一个ELF section。该选项对于一些函数而言会增加code size,因为一些共享地址、数据和字符串没有被减去。但是可以在链接时使用armlink –remove将这部分再减去

不使用scatter file而实现函数or数据放置在固定地址

  1. 创建main.c

#include <stdio.h>

extern int sqr(int n1);
const int gValue __attribute__((section(".ARM.__at_0x5000"))) = 3; // Place at 0x5000
int main()
{
int squared;
squared=sqr(gValue);
printf("Value squared is: %d\n", gSquared);
}

  1. function.c

int sqr(int n1)
{
return n1*n1;
}

  1. 编译与链接

armclang -target arm-arm-none-eabi -march=armv8-a -c -g function.c
armclang -target arm-arm-none-eabi -march=armv8-a -c -g main.c
armlink --cpu=8-A.32 --map function.o main.o -o squared.axf

使用scatter的命名section实现函数or数据放置在固定地址

  1. main.c

#include <stdio.h>
extern int sqr(int n1);
int gSquared __attribute__((section("foo"))); // Place in section foo
int main()
{
gSquared=sqr(3);
printf("Value squared is: %d\n", gSquared);
}

  1. function.c

int sqr(int n1)
{
return n1*n1;
}

  1. scatter file

LR1 0x0000 0x20000
{
ER1 0x0 0x2000
{
*(+RO) ; rest of code and read-only data
}
ER2 0x8000 0x2000
{
main.o
}
ER3 0x10000 0x2000
{
function.o
*(foo) ; Place gSquared in ER3
}
; RW and ZI data to be placed at 0x200000
RAM 0x200000 (0x1FF00-0x2000)
{
*(+RW, +ZI)
}
ARM_LIB_STACK 0x800000 EMPTY -0x10000
{
}
ARM_LIB_HEAP +0 EMPTY 0x10000

  1. 编译与链接

armclang -target arm-arm-none-eabi -march=armv8-a -c -g function.c
armclang -target arm-arm-none-eabi -march=armv8-a -c -g main.c
armlink --cpu=8-A.32 --map --scatter=scatter.scat function.o main.o -o squared.axf

使用scatter的指定地址实现函数or数据放置在固定地址

  1. main.c

#include <stdio.h>
extern int sqr(int n1);
// Place at address 0x10000
const int gValue __attribute__((section(".ARM.__at_0x10000"))) = 3;
int main()
{
int squared;
squared=sqr(gValue);
printf("Value squared is: %d\n", squared);
}

  1. function.c

int sqr(int n1)
{
return n1*n1;
}

  1. scatter file

LR1 0x0
{
ER1 0x0
{
*(+RO) ; rest of code and read-only data
}
ER2 +0
{
function.o
*(.ARM.__at_0x10000) ; Place gValue at 0x10000
}
; RW and ZI data to be placed at 0x200000
RAM 0x200000 (0x1FF00-0x2000)
{
*(+RW, +ZI)
}
ARM_LIB_STACK 0x800000 EMPTY -0x10000
{
}
ARM_LIB_HEAP +0 EMPTY 0x10000

  1. 编译与链接

armclang -target arm-arm-none-eabi -march=armv8-a -c -g function.c
armclang -target arm-arm-none-eabi -march=armv8-a -c -g main.c
armlink --cpu=8-A.32 --no_autoat --scatter=scatter.scat --map function.o main.o -o squared.axf


举报

相关推荐

0 条评论