0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Keil分散加载文件浅析

灵动MM32MCU 来源:灵动MM32MCU 作者:灵动MM32MCU 2023-11-17 10:00 次阅读

1

ARM映像文件组成

ARM 映像文件其实就是源文件经编译器生成的目标文件,一般是bin文件或者hex文件,可以直接烧录到ROM中执行(一般是内部FLASH),这个文件称为可执行映像文件(image file)。

映像文件一般由域组成,域最多由三个输出段组成(RO,RW,ZI)组成,输出段又由输入段组成。所谓域,指的就是整个映像文件所处在的区域,它又分为加载域和运行域。我们输入的代码,一般有代码部分和数据部分,这就是所谓的输入段,经过编译后就变成了映像文件中的RO段和RW段,还有所谓的ZI段,这就是输出段。

加载域:映像文件被静态存放的工作区域。

运行域:程序运行起来的存储区域。

程序在存储状态时,RO段及RW段都被保存在ROM区。

当程序开始运行时,内核直接从 ROM 中读取代码,并且在执行主体代码前,会先执行一段加载代码,它把 RW 段数据从 ROM 复制到 RAM,并且在 RAM加入 ZI 段,ZI 段的数据都被初始化为 0。加载完后 RAM 区准备完毕,正式开始执行主体程序。

2

分散加载机制

分散加载机制允许开发者为代码或数据变量在加载和执行时指定不同的存储空间,通知链接器把程序的某一部分链接在存储器的某个地址空间。

2.1 何时使用分散加载

实现嵌入式系统通常需要分散加载,这些系统使用ROM、RAM和内存映射的外设。通常需要分散加载的情况如下:

1)复杂内存映射:

必须放置在许多不同内存区域的代码和数据需要详细的指令来说明在内存空间中放置这些部分的位置。

2)不同类型的内存:

许多系统包含各种物理存储设备,如FLASH、ROM、SDRAM和快速SRAM。分散加载描述可以将代码和数据与最合适的内存类型相匹配。例如,中断代码可以放在快速的SRAM中以改善中断响应时间,但不常用的配置信息可以放在较慢的闪存中。

3)内存映射的外设:

分散加载描述可以将数据段放置在内存映射中的精确地址上,以便可以访问内存映射的外设。

4)函数在固定位置:

即使周围的应用程序已被修改和重新编译,也可以将函数放置在内存中的相同位置。这对于跳转表的实现很有用。

5)使用符号来标识堆和堆栈:

在链接应用程序时,可以为堆和堆栈位置定义符号。

2.2 怎么使用分散加载

1)对于具有简单内存映射(仅有SRAM和ROM)的image文件,可以仅使用链接器命令行选项或scatter文件来指定内存映射。下图显示了一个简单的内存映射:

d0f6fe42-8478-11ee-939d-92fbcf53809c.png

2)对于具有复杂内存映射(具有DRAM、SRAM、ROM2、ROM1等)的image文件,不能仅使用链接器命令行选项指定内存映射,需要使用scatter文件。下图显示了一个复杂的内存映射:

d1036fe2-8478-11ee-939d-92fbcf53809c.png

3

分散加载文件说明

分散加载文件(scatter file)是一个文本文件,它的作用是可以用于描述 ARM 链接器生成映像文件所需要的信息。如果不使用分散加载文件来指定,那么 ARM 链接器会按照默认的方式来生成映像文件。Keil的分散加载主要是通过 .sct 文件实现的,链接器根据 .sct 文件的配置分配各个段区地址,生成分散加载代码。

编写分散加载文件中可以指定下列信息:

1)各个加载域的加载起始地址、最大尺寸和属性。

2)各个加载域中包含的输出段。

3)各个运行域的运行起始地址、最大尺寸、存储访问特性和属性。

4)各个运行域中包含的输入段。

一个Scatter文件包含若干个加载域,一个加载域包含若干个输出段,一个输出段由若干个具有相同属性的输入段组成。

4

分散加载文件语法

Scatter文件是一个文本文件,使用BNF语法来描述ARM链接器生成映像文件时所需要的信息。

BNF符号与语法:

" :由双引号标识的符号保持其字面原意,如A”+”B表示A+B。

A ::= B :定义A为B。

[A] :用来表示可选部分,如A[B]C表示ABC或AC

A+ :用来表示A可以重复任意次,如A+表示A,AA,AAA,......

A* :同A+。

A | B :用来表示选择其一,不能全选。如A|B表示A或者B。

(AB) :表示一个整体,通常其他符号一起使用,如(AB)+(C|D)表示ABC,ABD,ABABC,ABABD,......

一个Scatter文件包含一个或多个加载区域,每个加载区域可以包含一个或多个执行区域。下图显示了典型的Scatter文件的组成结构:

d10edf58-8478-11ee-939d-92fbcf53809c.png

4.1 加载域描述

加载域可以包含一个或多个执行域。

加载域描述的语法如下:

load_region_description::=
load_region_name(base_address|("+"offset))[attribute_list][max_size]
"{"
execution_region_description+
"}"

1)load_region_name:命名加载区域。你可以使用带引号的名字。只有在使用任何与区域相关的链接器定义的符号时,该名称才区分大小写。

2)base_address:指定区域内对象的链接地址。base_address必须满足加载区域的对齐约束。

3)+offset:描述基址,该基址在前面的加载区域的末尾以外偏移字段。偏移量的值必须是0取4的模。如果这是第一个加载区域,那么+offset表示基址从零开始偏移字段。如果使用+offset,则加载区域可能会从前一个加载区域继承某些属性。

4)attribute_list:指定加载区域内容的属性。

5)max_size:指定加载区域的最大大小。这是在进行任何解压缩或零初始化之前加载区域的大小。如果指定了可选的max_size值,那么如果分配给该区域的字段超过max_size, armlink将生成一个错误。

6)execution_region_description:指定执行区域的名称、地址和内容。

4.2 执行域描述

执行域指定在运行时将输入段放置在目标内存中的位置。

执行域描述的语法如下:

execution_region_description::=
exec_region_name(base_address|"+"offset)[attribute_list][max_size|length]
"{"
input_section_description*
"}"

1)exec_region_name:命名执行区域。你可以使用带引号的名字。只有在使用任何与区域相关的链接器定义的符号时,该名称才区分大小写。

2)base_address:指定区域内对象的链接地址。Base_address必须与字对齐。

注意:在执行区域上使用ALIGN会导致加载地址和执行地址对齐。

+offset:描述一个基址,该基址在前面执行区域的末尾以外偏移字段。偏移量的值必须是0取4的模。如果这是加载区的第一个执行区,则+offset表示基址在包含加载区的基址之后开始偏移字段。如果使用+offset,则执行区域可能会从父加载区域继承某些属性,或者从同一加载区域内的前一个执行区域继承某些属性。

4)attribute_list:指定执行区域内容的属性。

5)max_size:对于标记为EMPTY或FILL的执行区域,max_size值被解释为该区域的长度。否则,max_size值将被解释为执行区域的最大大小。

6)-length:只能与EMPTY一起使用,表示在内存中增长的堆栈。如果长度为负值,则base_address被视为该区域的结束地址。

7)input_section_description:指定输入段的内容。

4.3 输入段描述

输入段描述指定将哪些输入段加载到执行区域。

输入段描述的语法是:

input_section_description::=
module_select_pattern["("input_section_selector(","input_section_selector)*")"]
input_section_selector::="+"input_section_attr
|input_section_pattern
|input_section_type
|input_symbol_pattern
|section_properties

1)module_select_pattern:

一种由文本构成的模式。当module_select_pattern匹配以下选项之一时,输入段匹配模块选择器模式:

包含该段的目标文件的名称。

库成员的名称(不带前导路径名)。

提取部分的库的全名(包括路径名)。如果名称包含空格,请使用通配符以简化搜索。

例如,使用*libname来匹配C:lib dirlibname.lib。

通配符 * 匹配零个或多个字符,? 匹配任意单个字符。匹配不区分大小写,即使在文件命名区分大小写的主机上也是如此。使用 *.o 匹配所有对象,使用 * 来匹配所有的目标文件和库。可以使用带引号的文件名,例如”file one.o”。

在一个Scatter文件中不能有两个 * 选择器。但是可以使用两个修改过的选择器,例如*A和*B,并且可以将. any选择器与*模块选择器一起使用。*模块选择器的优先级高于.any。如果文件中包含*选择器的部分被删除,则. any选择器将变为活动的。

2)input_section_attr:

与输入部分属性匹配的属性选择器。每个input_section_attr后面跟着一个+。选择器不区分大小写,可以识别以下选择器:

RO-CODE

RO-DATA

RO,同时选择RO-CODE和RO-DATA

RW-DATA

RW-CODE

RW,同时选择RW-CODE和RW-DATA

XO

ZI

ENTRY,包含入口点的部分。

可以识别以下同义词:

CODE代表RO-CODE

CONST代表RO-DATA

TEXT代表RO

DATA代表RW

BSS代表ZI

可以识别以下伪属性:

FIRST

LAST

如果放置顺序很重要,则使用FIRST和LAST标记执行区域中的第一部分和最后一部分。例如,如果特定的输入部分必须在区域中位于第一个,并且包含校验和的输入部分必须位于最后。

FIRST和LAST必须不违反基本属性排序顺序。例如,FIRST RW放在任何只读代码或只读数据之后。

一个执行区域只能有一个FIRST或一个LAST属性,并且它必须遵循一个input_section_selector。例如:

*(section, +FIRST) 这种模式是正确的。

*(+FIRST, section) 此模式不正确,并产生错误消息。

3)input_section_pattern:

一种模式,不区分大小写,与输入段名匹配。它是由文字构成的。通配符 * 匹配0个或多个字符,而 ? 匹配任何单个字符。可以使用带引号的输入段名。

如果使用多个input_section_pattern,请确保在不同的执行区域中没有重复的模式,以避免歧义错误。

4)input_section_type:

与输入段类型进行比较的数字。支持十进制或十六进制。

5)input_symbol_pattern:

可以通过该段定义的全局符号名选择输入段。全局名称能够使你从部分链接的对象中选择具有相同名称的单个段。

6)section_properties:

section属性可以是+FIRST、+LAST和OVERALIGN值。OVERALIGN的值必须是2的正幂,且必须大于或等于4。

5

如何打开.sct文件

在Options for Targets->Linker界面,Keil默认选择了“Use Memory Layout from Target Dialog”,勾掉复选框里面的对号,就可以使用自己定义的分散加载文件。

d11d61ae-8478-11ee-939d-92fbcf53809c.png

6

练习

根据前面介绍的语法编辑 .sct文件,将函数和数据放到指定地址:

1)在LR_ROM加载域中定义2个执行域RW_RAM1、RW_RAM2:

RW_RAM1基地址为0x20001000,域大小为0x400,将TEST_FUNCTION_ADDR段最先加载到本域的起始地址。

RW_RAM2基地址为0x20001400,域大小为0x400,将TEST_DATA_ADDR段最先加载到本域的起始地址。

LR_ROM__RO_BASE__RO_SIZE{;loadregionsize_region
ER_ROM__RO_BASE__RO_SIZE{;loadaddress=executionaddress
*.o(RESET,+First)
*(InRoot$$Sections)
;*(Veneer$$CMSE);uncommentforsecureapplications
.ANY(+RO)
.ANY(+XO)
}

RW_RAM__RW_BASE__RW_SIZE{;RWdata
.ANY(+RW+ZI)
}

RW_RAM10x200010000x400{;RWdata
*.o(TEST_FUNCTION_ADDR,+First)
}

RW_RAM20x200014000x400{;RWdata
*.o(TEST_DATA_ADDR,+First)
}

#if__HEAP_SIZE>0
ARM_LIB_HEAP__HEAP_BASEEMPTY__HEAP_SIZE{;Reserveemptyregionforheap
}
#endif

ARM_LIB_STACK__STACK_TOPEMPTY-__STACK_SIZE{;Reserveemptyregionforstack
}
}

2)使用__attribute__((section("section_name"))) 定义函数和数据如下:

(表示将函数或数据放入指定名为"section_name"的段)

uint32_ttest_data__attribute__((section("TEST_DATA_ADDR")));
voidtest_function(void)__attribute__((section("TEST_FUNCTION_ADDR")));

3)调用上述函数和数据:

intmain(void)
{
test_function();

while(1)
{
test_data++;
if(test_data>=1000)
{
test_data=0;
}
}
}

编译后查看map文件中内存映射部分:

d13a11f0-8478-11ee-939d-92fbcf53809c.png

TEST_FUNCTION_ADDR段对应的执行域基地址为0x20001000,TEST_DATA_ADDR段对应的执行域基地址为0x20001400,和在Scatter文件定义一致,即将函数和数据放到了指定地址。

7

小结

分散加载文件(scatter file)是一个文本文件,用于描述 ARM 链接器生成映像文件所需要的信息,在一些应用场景中嵌入式系统可能会使用分散加载。本章节简要介绍了分散加载文件的基本概念和语法,旨在对分散加载文件有初步认识,具体内容可以参考官方文档或查阅资料进行详细了解。


审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • ARM
    ARM
    +关注

    关注

    134

    文章

    9097

    浏览量

    367648
  • SDRAM
    +关注

    关注

    7

    文章

    423

    浏览量

    55233
  • 存储器
    +关注

    关注

    38

    文章

    7493

    浏览量

    163865
  • ROM
    ROM
    +关注

    关注

    4

    文章

    572

    浏览量

    85775
  • keil
    +关注

    关注

    68

    文章

    1213

    浏览量

    166903
  • 内存映射
    +关注

    关注

    0

    文章

    14

    浏览量

    7416
  • 灵动微
    +关注

    关注

    4

    文章

    174

    浏览量

    22671
  • MM32
    +关注

    关注

    1

    文章

    106

    浏览量

    770

原文标题:灵动微课堂 (第278讲)|Keil分散加载文件浅析

文章出处:【微信号:MindMotion-MMCU,微信公众号:灵动MM32MCU】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何把文件系统烧到EMMC并从EMMC加载

    如何下载并从SD卡加载文件系统,提到过可以从EMMC引导系统,本篇将为您介绍如何把文件系统烧到EMMC,并从EMMC加载
    的头像 发表于 10-30 16:06 3007次阅读
    如何把<b class='flag-5'>文件</b>系统烧到EMMC并从EMMC<b class='flag-5'>加载</b>

    ARM分散加载及应用

    从ARM ELF目标文件主要构成出发,详细介绍了分散加载的基本原理、分散加载文件的语法、分散
    发表于 05-04 16:09

    单片机中的分散加载文件主要包括哪几类呢

    单片机中的分散加载文件主要包括哪几类呢?
    发表于 01-27 08:00

    什么是分散加载文件

    分散加载的作用是什么?什么是分散加载文件
    发表于 02-16 06:48

    请问怎样去修改STM32F2中ROM分区的分散加载文件

    的sector。应用程序跑在后面。但是这样的作法弊端就是需要两份程序。 另一个方法是我在想,通过修改链接文件,例如MDK下修改分散加载文件让其中保存参数的sector不放任何东西。修改例如下面这样
    发表于 07-22 10:10

    求助,关于mdk5分散加载文件的问题

    有没有人能解释一下,分散加载文件应该怎么写
    发表于 11-02 07:23

    如何使用BitTorrent下载文件

    如何使用BitTorrent下载文件 若要使用BitTorrent下载文件,您需要安装BitTorrent客户端软件。您也可能需要调整防火墙和网络路由器的设置(如果使用)
    发表于 08-03 09:26 8742次阅读

    周立功单片机:分散加载文件浅释

    Scatter-Loading Description File 分散加载文件
    发表于 03-13 14:19 98次下载

    使用KEIL载文件到单片机外置存储器的方法

    使用KEIL载文件到单片机外置存储器给单片机下载程序的原理实用性要解决的难点怎样编写bootloader使用KEIL载文件给单片机下载程序的原理给单片机下载程序一般有两种方法:1,
    发表于 11-17 11:21 11次下载
    使用<b class='flag-5'>KEIL</b>下<b class='flag-5'>载文件</b>到单片机外置存储器的方法

    单片机中分散加载文件介绍

    单片机中分散加载文件介绍
    发表于 12-03 10:51 2次下载
    单片机中<b class='flag-5'>分散</b><b class='flag-5'>加载文件</b>介绍

    ARM分散加载文件

    分散加载作用:可以将代码放入不同的存储空间。1.基本概念了解分散加载文件之前,首先需要了解Code、RO-Data、RW-Data、ZI-Data。Code:程序代码RO-Data:程
    发表于 12-20 19:10 7次下载
    ARM<b class='flag-5'>分散</b><b class='flag-5'>加载文件</b>

    什么是分散加载文件?何时进行分散加载

    分散加载文件(scatter file)是一个文本文件,它的作用是可以用于描述 ARM 链接器生成映像文件所需要的信息。
    的头像 发表于 09-14 10:38 2798次阅读

    什么是分散加载文件

    分散加载文件(scatter file)是一个文本文件,它的作用是可以用于描述 ARM 链接器生成映像文件所需要的信息。 如果不使用 scatter file
    的头像 发表于 01-30 14:12 2827次阅读
    什么是<b class='flag-5'>分散</b><b class='flag-5'>加载文件</b>?

    AN024 GD32F4xx_Keil分散加载说明

    AN024 GD32F4xx_Keil分散加载说明
    发表于 02-27 18:25 1次下载
    AN024 GD32F4xx_<b class='flag-5'>Keil</b><b class='flag-5'>分散</b><b class='flag-5'>加载</b>说明

    深入分析一下MDK的分散加载文件

    ARM C 库提供了函数 __user_setup_stackheap() 的多个实现,并且可以根据分散文件中提供的信息自动选择正确的一种。
    发表于 04-28 14:21 806次阅读
    深入分析一下MDK的<b class='flag-5'>分散</b><b class='flag-5'>加载文件</b>