SCT分散加载实现CLI

ARM映像文件

ARM映像文件是一个层次性结构的文件,其中包含了域(region)、输出段(output section)和输入段(input section)。各部分关系如下:

  • 一个映像文件由一个或多个域组成
  • 每个域包含一个或多个输出段
  • 每个输出段包含一个或多个输入段
  • 各输入段包含了目标文件中的代码和数据

输入段中包含了4类内容:代码、已经初始化的数据、未经初始化的存储区域、内容初始化成0的存储区域。每个输入段有相应的属性,可以为只读的(RO)、可读写的(RW)以及初始化成0的(ZI)。ARM连接器根据各输入段的属性将这些输入段分组,再组成不同的输出段以及域。

一个输出段中包含了一系列的具有相同的RORWZI属性的输入段。输出段的属性与其中包含的输入段的属性相同。在一个输出段内部,各输入段是按照一定的规则排序的,这个后面再补充。

一个域中包含了1~3个输出段,其中各输出段的属性各不相同。各输出段的排列顺序是由其属性决定的。其中,RO属性的输出段排在最前面,其次是RW属性的输出段,最后是ZI属性的输出段。一个域通常映射到一个物理存储器上,如ROMRAM等。

 

ARM映像文件各组成部分的地址映射

分散加载机制允许为链接器指定映像的存储器映射信息,可实现对映像组件分组和布局的全面控制。分散加载通常仅用于具有复杂存储器映射的映像(尽管也可用于简单映像),也就是适合加载和执行时内存映射中的多个区是分散的情况。

要构建映像的存储器映射,链接器必须有:描述节如何分组成区的分组信息、描述映像区在存储器映射中的放置地址的放置信息。

分散加载区域分两类:

  • 加载区:该映像文件开始运行前存放的区域,即当系统启动或加载时应用程序存放的区域。
  • 执行区:映像文件运行时的区域,即系统启动后,应用程序进行执行和数据访问的存储器区域,系统在实时运行时可以有一个或多个执行块。

 

分散加载文件(即scatter file,后缀为.scf)

分散加载文件是一个文本文件,通过编写一个分散加载文件来指定ARM连接器在生成映像文件时如何分配RO,RW,ZI等数据的存放地址。如果不用SCATTER文件指定,那么ARM连接器会按照默认的方式来生成映像文件,一般情况下我们是不需要使用分散加载文件的。

但在某些场合,我们希望把某些数据放在指定的地址处,那么这时候SCATTER文件就发挥了非常大的作用。而且SCATTER文件用起来非常简单好用。

举个例子:比如像LPC2378芯片具有多个不连续的SRAM,通用的RAM32KB,可是32KB不够用,我想把某个.C中的RW数据放在USBSRAM中,那么就可以通过SCATTER文件来完成这个功能。

分散加载文件的语法:

load_region_name  start_address | "+"offset  [attributes] [max_size]

{

    execution_region_name  start_address | "+"offset  [attributes][max_size]

    {

        module_select_pattern  ["("

                                    ("+" input_section_attr | input_section_pattern)

                                    ([","] "+" input_section_attr | "," input_section_pattern)) *

                               ")"]

    }

}
  • load_region:          加载区,用来保存永久性数据(程序和只读变量)的区域;
  • execution_region:     执行区,程序执行时,从加载区域将数据复制到相应执行区后才能被正确执行;
  • load_region_name:     加载区域名,用于“Linker”区别不同的加载区域,最多31个字符;
  • start_address:        起始地址,指示区域的首地址;
  • +offset:              前一个加载区域尾地址+offset 做为当前的起始地址,且“offset”应为“0”或“4”的倍数;

以上请上网查阅。

 

 

本文如下:

; *************************************************************

; *** Scatter-Loading Description File generated by uVision ***

; *************************************************************



LR_IROM1 0x08000000 0x00100000  {    ; load region size_region

  ER_IROM1 0x08000000 0x00100000  {  ; load address = execution address

   *.o (RESET, +First)

   *(InRoot$$Sections)

   .ANY (+RO)

  }

  CMDREG +0

  {

   .ANY(cmd)

  }

  RW_IRAM1 0x20000000 0x00020000  {  ; RW data

   .ANY (+RW +ZI)

  }

}

红色部分是新添加的。

CMDREG 表示region

+0 表示紧跟在上一个区域

.ANY表示属性

Cmd表示段

map文件看到如下

 

 

Keil 设置

Options->linker

 

    1. 去掉Use Memory Layout from Target Dialog,然后Scatter File才可以编辑
    2. 电机Edit后面可以编辑sct文件,如上面提到的
    3. 注意: Misc controls一定要添加--keep=strcmd_*

不然会被编译器优化点,这时map文件看不到CMDREG区域内容

 

 

使用Scatter存储来实现读取

  1. 定义

typedef int(*CLI_handler)();
struct cmd_tbl_s {
         char *name;                             /* Command Name                   */
         int              maxargs;               /* maximum number of arguments         */
         CLI_handler cmd;                        /* Implementation function         */
         char *usage;                           /* Usage message  (short)      */
};


typedef struct cmd_tbl_s         cmd_tbl_t;

 

 

定义宏

#define REGISTER_CMD(name,maxargs,handler,usage) \
         const cmd_tbl_t strcmd_##name __attribute__ ((section ("cmd"))) =  {#name, maxargs, handler, usage}


REGISTER_CMD(
         ver,
         1,
         do_version,
         "print monitor version"
);

这个宏可以在任何包含以上宏的文件里面实现,更加灵活。

引用

extern unsigned char Load$$CMDREG$$Base[];

extern unsigned char Load$$CMDREG$$Limit[];



 unsigned long cmd_addr = (unsigned long)Load$$CMDREG$$Base;

 unsigned long cmd_end = (unsigned long)Load$$CMDREG$$Limit;   

   

红色部分表示上面的CMDREG区域

强制转换

CLI_cmd_start =(cmd_tbl_t  *)cmd_addr;

CLI_cmd_end  = (cmd_tbl_t  *)cmd_end;

 

编译该区域,提取字段

cmd_tbl_t *cmdtp;

int len = CLI_cmd_end - CLI_cmd_start;



for (cmdtp = CLI_cmd_start; cmdtp != CLI_cmd_start + len; cmdtp++)
{      

    if(0 == strcmp(name, cmdtp->name))
    {
        *cmd = cmdtp;
        break;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值