StonyGround

The heart is a bloom , shoots up through the stony ground.

0%

Linker Scripts链接器脚本语法

Linker Scripts链接器脚本语法

最近在学习自制操作系统,遇到了链接脚本(Linker Scripts),之前没有接触过,在此记下笔记以及遇到的场景。

LMA与VMA

LMA英文原版解释:load memory address:the address at which the section will be loaded。

什么是load memory address,内存装载地址呢?此处,单单从名字上,我们就可以看出几层意思:

load,装载。为什么要装载呢?因为,如果想要使你的程序(即经历过,由你的源码,通过编译器的编译,链接器的链接,形成的那个可执行文件),能在内存里面运行,那么肯定涉及到这一点。就是,有人,把你的这个程序从此处常见的存储器硬盘里面,搬到内存里面去了,然后才有可能运行。而这里的装载,就是对应这个意思。就是把程序,从硬盘里面,装载load,到内存里面去了。对应的,放在内存哪里去了呢?就是LMA,load memory address,就是把你的程序中的对应的内容,详细点说就是,把其中的.text代码段,.data数据段等内容,搬到,也就是copy拷贝到,内存的LMA地址处了。。。

memory内存

上面已经解释过了,这里再多说几句。

程序运行的本质,就是CPU读取到指令,然后执行,这里就涉及到,如果想要你的程序运行,首先,你应该把对应的指令放在合适的地方,CPU才能读到,才能执行。

此处合适的地方,有人想到,直接放到硬盘这里,CPU过来读取,然后执行不就可以了吗,还不用这么麻烦地将(指令)代码搬来搬去的,多省事。但是实际上,系统就是这么笨地搬来搬去的,原因在于,从硬盘上直接读取指令,速度比直接从内存,一般pc上各种类型的ram,比如DDR,此处统称为memory/内存,要慢很多倍,所以,系统才会不嫌弃麻烦,把代码拷贝到内存里面去,然后从内存里面读取指令,然后执行,这样效率高很多。

所以,此处简单说就是,为了总体效率,对于普通系统,比如PC,程序的执行都是在memory,内存里面执行的。因此,一句话总结就是:代码被装载到内存的某个地方,那个地方的地址就叫做LMA。

VMA英文原版解释:virtual memory address:the address the section will have when output file is run。

那啥是虚拟内存地址呢?简单说就是,你程序运行时候所对应的地址。

此处所谓的虚拟,一般来说,指的是启用了mmu之后,才有了虚拟地址和实地址。此处,我们可以简单地理解为,就是内存的实际地址。程序运行前,要把程序的内容,拷贝到对应的内存地址出,才能运行的。

因此,一句话总结就是:代码要运行的时候,此时对应的地址,就是VMA。

大多数情况下,LMA和VMA是一样的。也就是被加载到内存的什么地方,也就在什么地方运行。

如果是嵌入式系统,也就是相对的“少数情况”,LMA和VMA不一样。而其中最常见的一种情况就是,程序被放到ROM中,比如设置为只读的Nor Flash中,也就是LMA的地址是Nor Flash的地址,比如随便举例为0x10000000,而程序要运行的时候的地址是内存地址,比如0x30000000,也就是VMA是0x30000000,这时候就要我们自己保证,在程序运行之前,把自己的程序,从LMA= 0x10000000拷贝到VMA=0x30000000处,然后程序才可以正常运行。

有人会问,反正对于ROM来说,CPU也是可以直接从ROM里面读取代码,然后运行的。为何还要前面提到的,弄个LMA和VMA不同,搬来搬去的呢?因为ROM,顾名思义,是只读的,只能读取,不能写入的。

而程序中的代码段,由于只是被读取,不涉及到修改写入,是没有问题的。但是对于数据段和bss段来说,里面的所有的程序的变量,多数都是在运行的时候,不仅要读取,而且要被修改成新的值,然后写入新的值的,所以还是放到ROM里面,就没法修改写入了。而且,另一个原因是,CPU从ROM,比如常见的Nor Flash中读取代码的速度,要远远小于从RAM,比如常见的SDRAM,中读取的速度,所以,才会牵扯到将代码烧写到ROM里面,然后代码的最开始,将此部分程序reload,重载。也就是从此处的ROM的地址,即LMA,重新拷贝到SDRAM中去,也就是VMA的地方,然后从那里运行。

后记

关于LMA和VMA:

linker,链接器的作用:

将LMA写到(可执行的)二进制文件里面去。

解析符号。即,把不同的符号,根据符号表中的信息,转换成对应的地址。此处只涉及VMA,即程序运行时候的地址。

loader,装载器的作用:

从二进制文件中读出对应的段的信息,比如text,data,bss等段的信息,将内容拷贝到对应的LMA的地址处。此谓,装载(对应内容)到装载地址(LMA)。

如果发现VMA != LMA,即程序运行时候的地址,和刚刚把程序内容拷贝到的地址LMA,两者不一样,那么就要把对应的内容,此处主要是data,数据段的内容,从刚装载到的位置,LMA处,拷贝到VMA处,这样程序运行的时候,找到对应的VMA处的变量,才能找到对应的值,程序才能正常运行。