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

Posted 苏导

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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示例


与此图对应的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 this exec region
    

这里是比较复杂的例子,即将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 address = execution address
    
        * (+RO)                 ; all RO sections (must include section with 
                                ; initial entry point)
    
    …                         ; rest of scatter-loading description

FIXED属性

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

对应的scatter file如下:

LR_1 0x040000              ; load region starts at 0x40000   
                          ; start of execution region descriptions      
    ER_RO 0x040000         ; load address = execution address
    
        * (+RO)            ; RO sections other than those in init.o
    
    ER_INIT 0x080000 FIXED ; load address and execution address of this
                           ; execution region are fixed at 0x80000
    
        init.o(+RO)        ; all RO sections from init.o
    
    …                    ; rest of scatter-loading description

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

例如一些初始化代码需要放在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

以上是关于[ArmCompiler6--armlink]Keil-MDK中scatter load机制的主要内容,如果未能解决你的问题,请参考以下文章

[ArmCompiler6--armlink]Keil-MDK中scatter file语法

kindeditor 编辑器php的详细配置方法

markdown 重写模块apache di .htaccess untuk melakukan redirect non https ke https dan non www ke www

Kindeditor 编辑区样式结构

1.5KE6.8CA直插TVS二极管,为敏感电子设备保驾护航

java Android cek koneksi ke服务器