项目当中使用的是一颗MIPS CPU,存储空间是标准的MIPS内存分配,内存被划分为几个部分,概括如下:
Boot room, boot code存储空间;
iram, code 存储空间;
dram,data存储空间;
也就是说code和data有各自独立的存储空间,分开放置。
我们平常用gcc和ld生成一个可执行文件的时候,例如在命令行输入gcc -o test test.c,生成的可执行文件是一个文件哦,也就是说code和data都在一份可执行文件里面。我们把这份可执行文件烧写到flash里面,然后cpu再从flash里面取指令执行。
可是在前面,我们明明规划了code和data都各自独立的存储空间啊。有心人会问,是的啊,你讲的没错,可是这是怎么一回事呢?
好,那我们回到开始,先从为什么会有code和data各自规划一块存储空间的概念。这其实得从“冯诺依曼结构”和“哈佛”结构说起。
“冯诺依曼结构”,是指程序和数据存储空间并不是分开的,而是在一块存储器里面,所以程序和数据的访问位宽是相等的。
“哈佛结构”,是指程序和数据存储空间是分开的,各自有一块存储器,所以程序和数据的访问位宽可以不相等。
现在的处理器基本上都是属于上面2种架构,例如x86, arm, mips等。
说完这个,一切都清楚了。对了,我所用的MIPS恰好是“哈佛结构”的啰!
那么“哈佛结构”的处理器,明明生成的可执行文件,也就是通常所说的bin文件,只有一份啊,所以程序和数据都在同一份bin文件的,例如test.bin。我们将test.bin烧入到flash之后。
在哈佛架构的处理器上,这份可执行文件是怎么执行的呢?
好问题。
我们知道对于一个C程序,在其编译链接时,代码会放在text段,常量是存储在rodata段,初始化的全局变量或者初始化的静态变量的值会放在data段,未初始化的全局变量或者静态变量会放在bss段。
而字符串指针变量例如char *string = "abcdef",字符串"abcdef"是存储在const段,string这个指针变量的值为字符串"abcdef"的地址,也就是rodata段中的某个地址。
text段和rodata段,都是存放在room中,而data和bss开始是存放在bin file中,但在C程序的main函数开始跑之前,是需要被搬运到RAM中的。
所以我们需要在bootloader中,用汇编语言写一段代码,将bin file中的data段copy到RAM中,bss段不必搬,只需要将bss段在RAM中的地址区间清零就可以了。
然后再将sp指针指向RAM的最高地址就可以了。
在这个搬运的过程中,就会运用到LMA和VMA了。
LMA就是load address,也就是加载地址;
VMA就是virtual address,也就是运行地址。
具体是什么意思。例如我们刚才讲到的test.bin,那么程序和数据都会按顺序存储在里面啊,顺序请参考http://www.cnblogs.com/ironx/p/4954845.html中的“目标文件在其存储器映像文件中的布局”。
在那篇文章的对应章节中,描述的就是LMA,也就是程序和数据在bin文件中的存储地址,VMA也就是data和bss段在RAM中的运行地址。
而我们在bootloader中的汇编代码里面,需要将data段copy到RAM中,并清零bss段。
这个时候,汇编代码会把数据从其LMA处,copy到VMA处,也就是从bin文件的存储地址复制到RAM中的运行地址处。
一个典型的bootloader搬运代码如下所示:
既然bootloader会用到LMA和VMA,那么LMA和VMA在哪里定义呢,就是在ld脚本中啦,ld脚本就规定程序和数据在bin文件里面是什么存储的,以及运行时在rom和ram中是怎么存储的文件。
请参考http://www.cnblogs.com/ironx/p/4954845.html
原文:http://www.cnblogs.com/ironx/p/4963018.html