在分析uboot的start.S中,看到一些指令,比如:
adr r0, _start
觉得好像可以直接用mov指令实现即可,为啥还要这么麻烦地,去用ldr去实现?
关于此处的代码,为何要用adr指令:
adr r0, _start
而不直接用mov指令直接将_start的值赋值给r0,类似于这样:
mov r0, _start
呢?
其原因主要是,
sub r0, pc, #172
这样的代码,所处理的值,都是相对于PC的偏移量来说的,这样的代码中,没有绝对的物理地址值,都是相对的值,利用产生位置无关代码。因为如果用mov指令:
mov r0, _start
那么就会被编译成这样的代码:
mov r0, 0x33d00000
如果用了上面这样的代码:
mov r0, 0x33d00000
那么,如果整个代码,即要执行的程序的指令,被移动到其他位置,那么
mov r0, 0x33d00000
这行指令,执行的功能,就是跳转到绝对的物理地址,而不是跳转到相对的_start的位置了,就不能实现我们想要的功能了,这样包含了绝对物理地址的代码,也就不是位置无关的代码了。
与此相对,这行指令:
sub r0, pc, #172
即使程序被移动到其他位置,那么该行指令还是可以跳转到相对PC往前172字节的地方,也还是我们想要的_start的位置,这样包含的都是相对的偏移位置的代码,就叫做位置无关代码。其优点就是不用担心你的代码被移动,即使程序的基地址变了,所有的代码的相对位置还是固定的,程序还是可以正常运行的。
关于,之所以不用上面的:
mov r0, 0x33d00000
类似的代码,除了上面说的,不是位置无关的代码之外,其还有个潜在的问题,那就是,关于mov指令的源操作数,此处即为0x33d00000,不一定是合法的mov 指令所允许的值,这也正是下面要详细解释的内容第 3.8 节 “mov指令的操作数的取值范围到底是多少”
【总结】
之所以用adr而不用mov,主要是为了生成地址无关代码,以及由于不方便判断一个数,是否是有效的mov的操作数。