MEMORY
在默认情况下,链接器可以为 section 分配任意位置的存储区域,也可以使用 MEMORY
命令定义存储区域,并通过输出 section 描述的 [AT > REGION] 属性显示地该输出
section 限定于某块存储区域,当存储区域大小不能满足要求时,链接器会报错。
NAME
存储区域的名字,这个名字可以与符号名,文件名,section 名重复,因为它处于一个独
立的名字空间内。
ATTR
定义该存储区域的属性。在默认情况下,当某个输出 section 没有在 SECTIONS 命令内
被引用是,链接器会把该输出 setion 直接拷贝成输出 section,然后将该输出
section 放入内存区域内。如果内存设置了 ATTR 属性,那么该区域只接收满足该属性的
section。ATTR 属性内可以出现七个字符:
-
R 只读 section
-
W 读/写 section
-
X 可执行 section
-
A 可分配的 section
-
I 初始化的 section
-
L 初始化的 section
-
!不能满足该字符之后的任何一个属性的 section
ORIGIN
关键字,区域的开始地址,可以简写成 org 或 o
LENGTH
关键字,区域的大小,可简写成 len 或者 l
一个简单的例子:
MEMORY 与 SECTIONS 的层级关系:
此例子中,把 SECTIONS 命令内未引用的且具有读属性或者写属性的输入 section 放入
rom 区域内,把其他未引用的输入 section 放入 ram. 如果某些输出 section 要被放入
某内存区域内,而该输出 section 又没有指明 ADDRESS 属性,那么链接器将该输出
section 放在区域内下一个能使用位置。
e.g. 三个源文件 DemoA.c,DemoB.c 和 DemoC.c,其中 DemoA.c 引用 DemoA.c 和
DemoB.c 里面的函数,使用 GCC 生成独立的目标文件 DemoA.o,DemoB.o 和 DemoC.o。
ld 使用链接脚本 Demo.lds, 并且在 Demo.lds 里面通过 MEMORY 关键字,以此来创建一
些内存区域:
DemoA.c
DemoB.c
DemoC.c
Demo.lds
使用如下命令进行编译和链接:
通过上面的运行数据可知,在链接脚本里创建了两个内存区域,其中第一个内存区域为只
读区域,起始地址为 0x08060000, 大小为 0x100,根据这个区域的属性,可知输出
DemoRD section 就是只读区域内的,所以输出 DemoRD section 的起始地址为
0x08060000。第二个内存区域为可读可写区域,起始地址为 0x08050000, 大小为
0x4000,根据这个区域的属性,可知输出 DemoText section 就是可读可写的,所以输出
DemoText section 的起始地址为 0x08050000。
上面的形式都是映射的将输出 section 放到符合属性的内存区域内,开发者也可以显示
的将输出 section 放到指定的内存区域内,如下链接脚本
运行下面命令:
通过上面的运行数据可知,DemoText 被放到了内存区域 ram 里面,其起始地址也变成了
0x08050000;DemoData 被放到了内存区域 com 里面,其起始地址变成了 0x08070000;
DemoRD 被放到了内存区域 rom 里面,其起始地址也变成了 0x080600000。
附录
BiscuitOS Home
BiscuitOS Driver
BiscuitOS Kernel Build
Linux Kernel
Bootlin: Elixir Cross Referencer
赞赏一下吧 🙂