链接脚本是由若干条命令组成,每个命令是由关键字组成
/ * */ 里面放的是注释信息。
/* Entry Point */
/* 入口地址 */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
_Min_Heap_Size = 0x200 ; /* required amount of heap */
_Min_Stack_Size = 0x400 ; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K
}
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
}
可以简单分析出:
;
作为语句结束。每个符号的值都可以作为符号的地址,显示在map文件中。SYMBOL = EXPRESSION ;
SYMBOL += EXPRESSION ;
SYMBOL -= EXPRESSION ;
SYMBOL *= EXPRESSION ;
SYMBOL /= EXPRESSION ;
SYMBOL <<= EXPRESSION ;
SYMBOL >>= EXPRESSION ;
SYMBOL &= EXPRESSION ;
SYMBOL |= EXPRESSION ;
除了上述几种常见算数运算以外,还支持 .
运算符,表示当前地址,执行程序的一个位置,可以是RAM空间,也可以是FLASH空间。举例说明: test_point = . ;
注意:赋值语句包含4个语法元素:符号名、操作符、表达式、分号;一个也不能少。
符号可以在 1. 全局位置位置,2. SECTION的全局位置,3. 具体的section描述内部.
PROVIDE命令 该关键字用于定义这类符号:在目标文件内被引用,但没有在任何目标文件内被定义的符号。
MEMORY {
NAME1 [(ATTR)] : ORIGIN = ORIGIN1, LENGTH = LEN2
NAME2 [(ATTR)] : ORIGIN = ORIGIN2, LENGTH = LEN2
...
}
① NAME: 存储区名字
② ORIGIN: 区域的开始地址,必须是数字,可以有运算,但是不可以有符号。支持K, M符号,例如2K, 1M
③ LENGTH : 区域的长度,必须位数字,可以有运算,但是不可以有符号。支持K, M符号,例如2K, 1M
④ ATTR 区域属性,ATTR可以出现以下几个属性:
R 只读section
W 读/写section
X 可执行section
A ‘可分配的’section
I 初始化了的section
L 同I
! 不满足该字符之后的任何一个属性的section
例如:
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 512K
}
定义RAM区域属性是 读+写+可执行,区域从0x2000 0000开始,长度为64K,正好符合STM32F103ZET6芯片使用的最大RAM空间。同时属性也是和RAM特性保持一致。
定义FLASH区域属性是 读+可执行,区域从0x0800 0000开始,长度为512K,正好符合STM32F103ZET6芯片使用的最大FLASH空间。同时属性和FLASH保持一致。
可以将RAM空间或者FLASH空间分割成几块MEMORY区域,但是不允许重叠。
SECTIONS
{
SECTIONS-COMMAND
SECTIONS-COMMAND
...
}
SECTIONS-COMMAND 常用的有 1, 符号赋值 2. 输出段描述 3. 输入段描述 下面简单对几个COMMOND做分析
.
来使用。SECTION [ADDRESS] [(TYPE)] : [AT(LMA)]
{
OUTPUT-SECTION-COMMAND
OUTPUT-SECTION-COMMAND
...
} [>REGION] [AT>LMA_REGION] [:PHDR :PHDR ...] [=FILLEXP]
[] 内参数是可选内容,可以不写
最简单格式
SECTION :
{
OUTPUT-SECTION-COMMAND
OUTPUT-SECTION-COMMAND
...
}
SECTION 段名字,用来区分各个section的
ADDRESS : 来指定当前SECTION所使用的VMA ,可以是一个表达式。如果没有该选项且有REGION选项,那么连接器将根据REGION设置VMA;如果也没有 REGION选项,那么连接器将根据定位符号‘.’的值设置该section的VMA,将定位符号的值调整到满足输出section对齐要求后的值,输出 section的对齐要求为:该输出section描述内用到的所有输入section的对齐要求中最严格的。
例子:
·.text . : { *(.text) }
和
.text : { *(.text) }
这两个描述是截然不同的,第一个将.text section的VMA设置为定位符号的值,而第二个则是设置成定位符号的修调值,满足对齐要求后的。
ADDRESS可以是一个任意表达式,比如ALIGN(0x10)这将把该section的VMA设置成定位符号的修调值,满足16字节对齐后的。
注意:设置ADDRESS值,将更改定位符号的值。
TYPE :每个输出section都有一个类型,如果没有指定TYPE类型,那么连接器根据输出section引用的输入section的类型设置该输出section的类型。它可以为以下五种值,
NOLOAD
:该section在程序运行时,不被载入内存。
DSECT
,COPY
,INFO
,OVERLAY
:这些类型很少被使用,为了向后兼容才被保留下来。这种类型的section必须被标记为“不可加载的”,以便在程序运行不为它们分配内存。
AT(LMA) 一般来说LMA和VMA是同一个地址,但是也可以通过AT命令来手动指定加载地址(LMA) LMA是一个地址或者符号
OUTPUT-SECTION-COMMAND 命令,可以是
REGION 指定输出的内存段,必须是MEMORY中已经定义的
AT>LMA_REGION 可以使用AT指令,重新指定LMA到一个MEMORY段
FILLEXP 将section中所有未使用的位置,填充上FILLEXP值,有效数据为两个字节,例如 FILLEXP=0x9090
3. 输入段描述
基本语法:FILENAME([EXCLUDE_FILE (FILENAME1 FILENAME2 …) SECTION1 SECTION2 …)
FILENAM 可以是一个带有相对路径的目标文件名,同时支持通配符格式。如果是库内目标文件名字的话,不需要带有路径,只保留文件名就行。
EXCLUDE_FILE(file1, file2) 除file1, file2之外的所有目标文件
SECTION 可以是一个setcion名字或者是一个字符串
下面举例说明:
① * (.text)
第一个*代表所有文件 总体就是,所有输入目标文件的 .text 段
② data.o (.data)
data.o这个目标文件的所有.,data段
③ ifx*.o (.text, .data)
所有以 ifx
为开头的目标文件的所有.text和.data段。其中Ifx*.o是不带路径的,也就是选取的库内目标文件或者同目录下的目标文件。
④ *(EXCLUDE_FILE(file1.o, *file2.o) (.text))
除了file.o文件和所有以file2为结尾的目标文件以外的所有文件的.text段
通配符可以使用
字符串模式内可存在以下通配符:
* :表示任意多个字符
? :表示任意一个字符
[CHARS] :表示任意一个CHARS内的字符,可用-号表示范围,如:a-z
可以将多个 input section 组成 output section 例如:
SECTIONS {
.text : { *(.text) }
.DATA : { [A-Z]*(.data) }
.data : { *(.data) }
.bss : { *(.bss) }
}
① 所有文件的.text
输入段,组成.text
输出段
② [A-Z]开头的文件的.data
输入端,组成.DATA
输出段
③ 剩余文件的 .data
输入段,组成.data
输出段
④ 所有文件的 .bss
输入段,组成 .bss
输出段