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”的倍数;
attributes: 区域属性,可设置如下属性:
RELOC 重新部署,保留定位信息,以便重新定位该段到新的执行区;
OVERLAY 覆盖,允许多个可执行区域在同一个地址,ADS不支持;
execution_region_name: 执行区域名;
start_address: 该执行区的首地址,必须字对齐;
module_select_pattern: 目标文件滤波器,支持通配符“*”和“?”;
*.o匹配所有目标,* (或“.ANY”)匹配所有目标文件和库。
input_section_attr: 每个input_section_attr必须跟随在“+”后;且大小写不敏感;
RO或TEXT, selects both RO-CODE and RO-DATA
RW 或 DATA, selects both RW-CODE and RW-DATA
ENTRY, that is a section containing an ENTRY point.
FIRST,用于指定存放在一个执行区域的第一个或最后一个区域;
input_section_pattern: 段名;
AREA vectors, CODE, READONLY
#pragma arm section [sort_type[[=]"name"]] [,sort_type="name"]*
sort_type: code、rwdata、rodata、zidata
如果“sort_type”指定了但没有指定“name”,那么之前的修改的段名将被恢复成默认值。
#pragma arm section // 恢复所有段名为默认设置。
#pragma arm section rwdata = "SRAM",zidata = "SRAM"
static OS_STK SecondTaskStk[256]; // “rwdata”“zidata”将定位在“sram”段中。
#pragma arm section // 恢复默认设置
Exec_Sram 0x80000000 0x40000
LR_1 0x010000 PI ; The first load region is at 0x010000.
ER_RO 0 ; The PI attribute is inherited from parent.
; The default execution address is 0x010000, but the code can be moved.
*( RO) ; All the RO sections go here.
ER_RW 0 ABSOLUTE ; PI attribute is overridden by ABSOLUTE.
*( RW) ; The RW sections are placed next. They cannot be moved.
ER_ZI 0 ; ER_ZI region placed after ER_RW region.
*( ZI) ; All the ZI sections are placed consecutively here.
LR_1 0x010000 ; The first load region is at 0x010000.
ER_RO 0 ; Default ABSOLUTE attribute is inherited from parent. The execution address
; is 0x010000. The code and ro data cannot be moved.
*( RO) ; All the RO sections go here.
ER_RW 0x018000 PI ; PI attribute overrides ABSOLUTE
*( RW) ; The RW sections are placed at 0x018000 and they can be moved.
ER_ZI 0 ; ER_ZI region placed after ER_RW region.
*( ZI) ; All the ZI sections are placed consecutively here.
Load$$region_name$$Base Load address of the region.
Image$$region_name$$Base Execution address of the region.
Image$$region_name$$Length Execution region length in bytes (multiple of 4).
Image$$region_name$$Limit Address of the byte beyond the end of the execution region.
Image$$region_name$$ZI$$Base Execution address of the ZI output section in this region.
Image$$region_name$$ZI$$Length Length of the ZI output section in bytes (multiple of 4).
Image$$region_name$$ZI$$Limit Address of the byte beyond the end of the ZI output sectionin the execution
SectionName$$Base Input Address of the start of the consolidated section called SectionName.
SectionName$$Limit Input Address of the byte beyond the end of the consolidated section called
region_name: RO、RW、ZI、load_region_name、execution_region_name;
“RAM1”区域的首地址: Image$$RAM1$$Base
上例中“sram”段首地址: sram$$Base
IMPORT |Load$$Exec_RAM1$$Base| // Exec_RAM1 为“RW”段
IMPORT |Image$$Exec_RAM1$$Base|
IMPORT |Image$$Exec_RAM1$$Length|
IMPORT |Image$$Exec_RAM1$$Limit|
LDR R0, =|Load$$Exec_RAM1$$Base|
LDR R1, =|Image$$Exec_RAM1$$Base|
LDR R2, =|Image$$Exec_RAM1$$Limit|
extern unsigned char Load$$Exec_RAM1$$Base;
extern unsigned char Image$$Exec_RAM1$$Base;
extern unsigned char Image$$Exec_RAM1$$Length;
unsigned char * psrc, *pdst;
count = (unsigned int) &Image$$Exec_RAM1$$Length;
psrc = (unsigned char *)&Load$$Exec_RAM1$$Base;
pdst = (unsigned char *)&Image$$Exec_RAM1$$Base;
ROM: 0x00000000 256K ;0x1fc 保留为加密字,程序在ROM中运行;
RAM 0x40000000 16K ;用于全局变量及任务堆栈;
SRAM 0x80000000 512K ;SRAM速度慢,主要用于存放大的数据表;
LOAD_ROM1 0x00000000 0x1f8 ; 指定该加载区域首地址、大小
EXEC_ROM1 0 0x1f8 ; 没有前一加载区域,所以该执行区域首地址为加载去首地址
Startup.o (vectors, FIRST) ; 目标文件的“vectors”段放在该执行区域的第一段
irq.o ( RO) ; 目标文件的所有“RO”段放在该执行区域
LOAD_ROM2 0x00000200 ; 第二个加载区域
* ( RO) ; 所有目标文件和库文件中的“RO”段存放在该区域
* ( RW, ZI) ; 所有目标文件和库文件的“RW”和“ZI”段存放在该区域
* (sram) ; 所有目标文件中的“sram”段存放在该区域
“iap.o”定义在“Exec_RAM1”中运行,所以设置“PI”属性;
在调用“iap.c”中函数之前应该将其从“Load$$Exec_IAP$$Base”复制到指定的“Exec_RAM1”区域;
Load_region1 0x00000000 0x1fc
Startup.o (vectors, FIRST)
Load_region2 0x00000200 0x3e600
Exec_IAP 0 PI // 可能引起链接器未使用该属性警告,忽略
Exec_RAM1 0x40000000 0x4000
Exec_Sram 0x80000000 0x40000
// 移动“IAP.o”中的所有函数到“ImageExecIAPBase”加载区,并调用其中的函数
extern unsigned char Load$$Exec_IAP$$Base;
extern unsigned char Image$$Exec_IAP$$Length;
#define ImageExecIAPBase (0x40000000 0x1000) // 加载区首址
unsigned char * psrc, *pdst;
count = (unsigned int) &Image$$Exec_IAP$$Length;
psrc = (unsigned char *)&Load$$Exec_IAP$$Base;
pdst = (unsigned char *)ImageExecIAPBase;
void (* pfnIAPWrite)(unsigned long, int);
pfnIAPWrite = (void (*)(unsigned long, int))
(unsigned int)IAPWrite - // 被调用函数名
(unsigned int)&Load$$Exec_IAP$$Base);
pfnIAPWrite((int)((CUPDATA *)CODESTARTADDR)->data,
((CUPDATA *)CODESTARTADDR)->length);
这里再用周立功的开发板附带例程里的分散加载文件做例子进行讲解: 硬件配置: 内部 64K RAM: 0x4000 0000 - 0x4000 ffff 外部 2M FLASH:0x8000 0000 - 0x801f ffff 外部 8M RAM: 0x8100 0000 - 0x807f ffff
ROM_LOAD 0x80000000 ;加载时域描述{ ROM_EXEC 0x80000000 ;第一个运行时域描述 { Startup.o (vectors, +First) ;输入段描述:模块startup位于该 ;域的开头(+First),vector为入口点 * (+RO) ;本域包含全部RO代码(*(+RO)) }
IRAM 0x40000000 ;第二个运行时域:将堆栈空间放入 ;片内静态RAM中(0x40000000) { Startup.o (MyStacks) ;本域包含模块STARTUP 的MYSTACKS段 }
STACKS_BOTTOM +0 UNINIT ;将栈底放在堆栈的后面(+0) ;不进行初始化(UNINIT) { Startup.o (StackBottom) }
STACKS 0x40004000 UNINIT ;将STACKS放入40004000 此处地址不能访问 ;如访问将产生预取中止和数据中止异常 { Startup.o (Stacks) }
ERAM 0x81000000 ;将所有RWZI(*(+RW,+ZI))段放入外部RAM中 { * (+RW,+ZI) }
HEAP +0 UNINIT ;在RWZI段后放入堆底 { Startup.o (Heap) }
HEAP_BOTTOM 0x81080000 UNINIT { Startup.o (HeapTop) ;堆顶:放入了外部RAM中(0x81080000) }}
(1)样例中,只有一个加载块ROM_LOAD,包含了所有的代码和数据(存放在ROM),起始地址为0x800000000。这个加载块一共对应七个执行块(ROM_EXEC, IRAM,STACKS_BOTTOM, STAKS,ERAM,HEAP,HEAP_BOTTOM)。(2)RO的代码和数据会从ROM_EXEC开始执行,执行地址与装载地址相同。(3)Startup.o是Startup.s的目标文件(Startup.s也在这个工程下),vectors是在Startup.s定义的段,整个句子的意思是把整个Startup.s编译生成的目标文件(向量表)放在0x8000 0000的第一个位置,即从vectors开始依次从ROM_EXEC的顶部放下来。(4)所有的RW和ZI数据包含在外部RAM执行块里,起始地址为0x81080000。(5)RW数据是从ROM_LOAD copy 过来的,ZI数据是在RAM中初始化的,其位置在RW之上。(6)HEAP是用来定位堆栈的底的,堆栈底的位置在ZI之上所以使用"+0",heap会从此地址增加。(7)STACKS是用来定位堆栈顶的,堆栈顶的位置在可以用来作为存储的内存的顶部。Stacks会从堆栈顶的地址下降。