什么是代码重定位

ARM体系结构-代码重定位

一、为什么会有重定位

1、程序的运行过程就是CPU不断的从内存中取出指令,然后执行指令的过程。
2、那么CPU是如何从内存中去去这些指令的呢?当然是通过内存地址来获取。
3、以前使用单片机时,没有仔细思考过这个问题,都是认为程序是烧写到芯片内部的flash中的,也没有仔细思考过,程序是怎么跳转到flash取指令并执行的。
4、对于嵌入式系统来说,它的程序可能会比较大,超出它内部的flash大小,我们的程序无法整个放入到芯片内部的flash中;甚至有些SoC芯片内部根本就没有flash,代码无法放入到芯片内部,只能放在片外flash芯片上,这时芯片就需要外挂flash芯片了—nand flash或者nor flash。
5、对于任何一种SoC芯片来说,上电后PC指针的位置是有硬件设计决定的,一般地,对于cortex-M系列内核的芯片,上电后PC指针都为0,指向0地址处。
6、 对于nand启动,0地址对应片内sram,因为nand控制器上电后自动将nand中的前4k大小拷贝到了sram中,所以此时sram中存在代码(即nand中前4K代码),内核就可以取指令并执行了。
7、对于nor启动,0地址对应nor芯片,我们已经将程序下载到nor上了,所以此时pc也可以取指令并执行了。
8、NAND FLASH因为PC不能直接访问它想要执行器内部的程序,需要将NAND中的代码拷贝到sdram中,所以需要重定位。
9、PC可以可以直接访问NOR FLASH,但是不能向内存一样写NOR FLASH,我们程序中的全局变量,静态变量等都是存在bin文件中,也就是说存在NOR FLASH上的,当程序需要修改这些变量时,无法修改他们,所以需要重定位到SDRAM中。

二、代码重定位思考

1、编译器在编译一段程序时,要经过三个步骤:编译、链接和加载。要对所有目标文件进行重定位,建立符号引用规则,同时为变量、函数等分配地址。
2、程序执行时,把代码加载到链接时指定的地址空间,一保证程序在执行过程中对变量、函数等符号的正确引用,使程序正常运行。
3、但是,在操作系统中,一个进程通常从硬盘等二级存储设备拷贝到内存中去执行,这两者的地址是不同的,因此操作系统要对这个进程进行重定位,才能正确运行该进程。
4、在设计系统引导程序时,也要对代码进行重定位,需要将BootLoader从ROM拷贝到RAM中执行,这些代码即使不在链接时指定的代码地址空间也能正常运行,这就是位置无关代码(position independent code)。
5、PIC的特点是,它被加载到任意地址空间都可以正确的执行。其原理是PIC对常量的操作都是PC+偏移量的寻址方式。即使程序被移动,但是PC也变化了,而偏移量是不变的,所以程序仍然可以找到正确的入口地址或者常量。
6、在设计BootLoader时,一个可行的方法是,将BootLoader链接到ARM里面指定的位置(0x1000000),然后将BootLoader加载到ROM里面的地址0x0处,CPU上电从ROM地址0x0执行。此时BootLoader运行地址为0x0,而链接地址为0x1000000。由于BootLoader头部的一小部分代码是位置无关代码,它仍然可以在地址0x0处运行,并将整个BootLoader拷贝到RAM地址的0x1000000处然后清除bss段并设置堆栈,最后将main()的绝对地址(链接地址),比如0x1000100装入PC,并跳转到RAM里去。至此,BootLoader就在链接时指定的地址处运行了,这是它就可以在ARM里使用文字池(literal pool)里面的绝对地址来进行函数的跳转或者操作常数了,这与重定位之前的情况是一样的。

三、位置无关代码(PIC)

1、在一些场合,一些代码并不在存储这部分代码的地址上执行,比如说放在NOR flash 中的代码可能最终是放在RAM中运行,那么NOR flash中的地址就是加载域,而在RAM中的地址就是运行域。加载域是代码存放的地址,运行域是代码运行时的地址。
2、跳转指令b、bl等,这些指令后面是一个相对地址,而不是绝对地址,比如说b main,这个指令应该怎么理解呢?Main这里究竟是一个什么东西呢?这时候就涉及到链接地址的概念了,链接地址实际上就是连接器对代码中的变量名等进行一个地址的编排,赋予这些抽象的东西一个地址,然后在程序中访问这些变量名、函数名就是在访问一些地址。
3、一般所说的链接地址都是指链接这些代码的起始地址,代码必须放在这个地址开始的地方才可以正常运行,否则的话当去访问、执行某个变量名、函数名对应地址上的代码就会找不到,接着程序就会跑飞。
4、但是b、bl跳转指令并不是一个绝对跳转指令,而是一个相对跳转指令,就是说,这main 标签最后得到的值并不是main被链接器编排后的绝对地址,而是main的绝对地址减去当前这个指令的绝对指令所得到的值,也就是说b、bl访问到的是一个相对地址,不是绝对地址,因此这个语句及其这段代码无论是否放在它的运行域,这段代码都能正常运行,这就是所谓的位置无关代码。
5、基础理解:位置无关码:CPU取指时,总是相对于本条执行指令的相对地址去取指。比如指行一个ADD指令时,PC要取下一指令的地址,就在原来的基础上+4。这就不管你代码放在存储器的任何位置,只要他们的相对地址没有改变,就能正常执行程序。一般上电复位那几条语句就必须是位置无关码指令。

四、位置相关代码

1、可以这样来说,就是CPU每次取指都从绝对位置去取,而不是上面的相对位置。这个绝对地址就是相对起始地址0来说的。这样,就要求你在存放程序时,必须给连接脚本所规定的一样,把代码放到指定位置。

猜你喜欢

转载自blog.csdn.net/weixin_46089486/article/details/108978105