#ldscript#
ldscipt是gcc下的链接脚本, 顾名思义, 就是告诉别人, 这些代码该怎么链接.
链接就是,将多个目标文件合并为一个目标文件,称作可执行文件。
每个目标文件都包含一连串的section,最常见,最基础的至少有:
.text,代码段,就是CPU要运行的指令代码;
.data,数据段,程序中包含的一些数据,放在这个段里;
.bss,未初始化段,记录了程序里有哪些未初始化的变量,就相当于只记录对应的名字,留着程序运行前去初始化为0,所以,此处并不占用具体空间。
###基本格式###
section_name vma : AT(lma)
{
output-section-command
output-section-command
...
} [AT>lma_region]
例如:
.text 0x30000000 : AT(0x40000000)
{
*(.text)
}
表示的是代码的运行时地址为 0x30000000 。假如你的ROM在 0x0 地址,程序放在ROM中,那个时候程序是不能正常运行的(位置无关代码除外),必须将代码COPY到VMA也就是0x30000000 中才能正常运行。至于那个 AT(lma) 的关键字,只指示代码连接的时候应该放在什么地方,注意好这个英文是 load memory address,是指程序应该装载在什么地方。elf格式的文件里面不但包含了代码,还包含了各种各样的信息,例如上面说的每个段的lma和vma,还有其他信息都包含在里面了。默认状态下,lma 是等于当前的vma的.。但关键字AT指明了LMA。接下来就说说LMA和VMA是何方神圣了。
#VMA#
英文解释:
VMA(Virtual Memory Address):the address the section will have when the output file is run;
那啥是虚拟内存地址呢?就是你程序运行时,程序所在的地址。
此处所谓的虚拟,一般来说,指的是启用了MMU之后,才有了虚拟地址和实地址。
此处,我们可以简单的理解为,就是内存的实际地址即可。
程序运行前,要把程序的内容,拷贝到对应的内存地址处,然后才能运行的。
#LMA#
英文解释: LMA(Load Memory Address): the address at which the section will be loaded. 因为我们知道程序运行前要经过:编译,链接,装载,运行等过程。装载到哪呢?没错,就是LMA对应的地址里。
#LMA与VMA的区别# 如果将程序运行比作吃饭,LMA就好比是厨房,食物需要在厨房准备好。VMA好比是餐厅,在餐厅享受食物。 大多数情况下,那么LMA和VMA是一样的,也就是,程序被加载到内存的什么地方,也就在什么地方运行。 不过也有特例,这里举一个嵌入式的例子,和一个我在写kernel中实际遇到的例子。 ###1. 嵌入式的例子###
因为嵌入式系统中ram内存空间有限,所以一般把程序放在flash中。flash比较于ram写入速度较慢。但flash的空间容量大,所以人们想到将代码放到flash中(因为只读不写),把数据放在ram中,以节约资源。但在运行的时候,代码还是要出现在ram中,怎么办呢?就是将代码段的LMA设置为flash的地址,这样代码就会临时放在flash中,节约资源。等到需要运行的时候,再载入运行地址VMA中。所以这种情况下,VMA不等于LMA。
###2. 自身实际遇到的例子###
因为为了模仿linux的内核运行地址(从线性空间3GB以上地址运行),所以我的内核代码的运行地址也设为3GB,但是我是用GRUB加载内核代码的,GRUB要求的是要在0x100000开始加载。怎么办?就用VMA=3GB,LMA=grub
要求的地址。