一、必须知道的几个概念。
1、链接地址和运行地址。
①运行地址,顾名思义就是程序运行的时候的地址,也就是你用工具将代码下载到RAM的那个地址,也叫加载地址。
②链接地址,由链接脚本指定的地址。为什么需要链接脚本指定地址呢?你想一下,在c语言编程中,当我们需要调用一个A函数的时候,编译器是怎么找到这个A函数?编译器肯定是知道它被放在哪里才可以找到它。那就是链接脚本的作用,链接脚本其实在程序被执行之前都已经指定A函数一个地址编号,以后所有的函数调用我们都会去这个地址编号那里寻找A函数。有点类似于c语言的指针变量。
2、位置有关码与位置无关码。
①位置有关码,就是这句代码的执行正确与否还需要取决于当前的地址,也就是说跟地址已经绑定了的,例如:ldr PC, _main,就是PC指针必须跳转到_main(函数名就是一个地址)这个地址去,代码执行成功与否就相当于受到了这个地址的约束,假如这个地址的内容不存放_main这个函数,就会出错了。
②位置无关码,就是这句代码在哪里运行都可以的,跟所处的地址无关,跟位置有关码相反。
二、重定位需要理解的一些问题。
1、链接地址跟运行地址不同的情况下会出现什么情况?
答:以上面举的函数A为例,当链接地址跟运行地址不同的时候,假如链接地址是0x1000,运行地址(加载地址)是0x0000,链接脚本指定函数A将来是要存放到(基地址+偏移量)=0x1000+0x0001=0x1001地址的,但是程序在下载的时候却把这个程序下载到0x0000,所以函数A的地址实际上是存放在(基地址+偏移量)=0x0000+0x0001=0x0001这个地址的。当程序运行到一行位置有关码例如:ldr PC, A ,编译器首先就会按照链接脚本指定的A的那个地址0x1001寻找A函数,但是因为加载地址跟链接地址不同的原因,实际上A函数已经被放到了0x0001,所以执行就会出错。所以,当这两个地址不同的时候,执行一段位置有关码的时候就会发生不可预估的错误。
2、为什么会出现链接地址跟运行地址不同的情况?
答:当一块芯片启动的时候,依靠内部的SRAM,可以运行一小段代码,而因为DDR还没初始化,注定了开始的运行地址是在内部SRAM中的。当我们需要运行一个操作系统,那么点的内存怎么够运行呢?所以这时候就需要初始化DDR才可,而因为我们知道这代码将来都是在DDR上面运行的,所以链接脚本指定的链接地址肯定是DDR上面的地址,所以这就出现了链接地址跟运行地址不同的情况了。
3、什么是重定位?
答:由于出现1这样的问题,就需要使用重定位这种方式解决上面的问题了。那什么是重定位呢?重定位就是在链接地址跟运行地址不同的情况下,执行一段位置无关码,这段位置无关码的作用就是将原来的那份代码全部复制到链接地址那里去,然后自己再长跳转到新的那份代码的刚刚执行的那个位置。这样就实现了链接地址跟运行地址一致的情况了。
4、为什么需要重定位?
答:就是链接地址跟运行地址不同,在这个情况下我们可以有两种方案:
①全部使用位置无关码。
②进行重定位让这两个地址相同。
我们知道,如果是一个小代码,使用①时可以的,但是一个大的代码文件很难保证全部都使用位置无关码的,这也是不现实的,所以必须使用重定位解决这个问题。