代码改变世界

精解一些ARM指令

2012-05-25 16:45  至上  阅读(541)  评论(0编辑  收藏  举报

其实ldr指令分两种:

1)ldr r0,#100   这是ldr指令

2) ldr r0,=10000  这是ldr伪指令 编译器在编译伪指令的时候会把伪指令编译成多条指令机器码  (伪操作是不会被编译成指令机器码的)

这源于一个问题:ldr r0,#10000 在编译这条指令的时候,是会出错的,下面解释下为什么?

在指令编码的时候,32位中有12位是用来表示立即数的,其中高4位表示循环右移的位数,后8位表示右移前的数,

一个立即数是这样表示的:将低8位补0扩展为32位,然后循环右移X位,(X为高4位表示的无符号整数*2)例如:低12位为0x512,则表示的立即数是0x04800000

其实这样表示的立即数的范围是-2的31次方到2的31次方-1,只不过只能表示这其中的2的21次方个数字而已。其中10000就不在其中,所以有了上面的错误。

ARM为什么这么设计呢?按他得说法是:绝大部分数8位就可以表示了,8位不能表示的就是小概率事件。

然后特殊的事情用特殊的办法解决,先把立即数放到某个内存地址中去,然后从这个内存地址中把立即数取到寄存器中。这就是第二条指令的本意,有点烦,但这是小概率事件。

第二条指令在编译时替换为:ldr r0,[pc,#-4]   DCD 10000  其中DCD是给10000分配一个字,4个字节的存储空间,放在文字池中,然后通过相对地址去取这个数,相对地址的计算就是编译器的事了。

 

关于BL跳转指令只能在正负32MB范围内的解释:

BL指令在编码的时候,有24位用于表示相对地址的,(BL跳转的范围有限,这也是ldr给pc赋值跳转的区别),其中最高位是符号位,余下23位表示相对地址,BL都是跳转到某个指令的执行处,一个指令都是占4个字节,就是4个地址,属于字对齐,最低2位地址固定为0,所以可以看做是有25位表示相对地址,所以就有了正负32MB的地址空间。(每个程序运行的时候都有一个运行地址,称之为整个程序的基址)