在ARM处理器的汇编语言中,对指令语法格局中的
首要从ARM指令系统的语法格局说起。
一条ARM指令语法格局分为如下几个部分:
其间,<>内的项是有必要的,{}内的项是可选的,如
Opcode
Cond
Rn
shifter_operand
其指令编码格局如下:
31-28 |
27-25 |
24-21 |
20 |
19-16 |
15-12 |
11-0 |
cond |
001 |
opcode |
S |
Rn |
Rd |
shifter_operand |
当第2 个操作数的方式为:#immed_8r常数表达式时“该常数有必要对应8位位图,即常数是由一个8位的常数循环移位偶数位得到的。”
其意思是这样:
#immed_8r在芯片处理时表明一个32位数,可是它是由一个8位数(比方:01011010,即0x5A)经过循环移位偶数位得到(1000 0000 0000 0000 0000 0000 0001 0110,便是0x5A经过循环右移2位(偶数位)的到的)。
而1010 0000 0000 0000 0000 0000 0001 0110,就不契合这样的规则,编译时必定犯错。由于你或许经过将1011 0101循环右移位得到它,可是不或许经过循环移位偶数位得到。1011 0000 0000 0000 0000 0000 0001 0110,也不契合这样的规则,很明显:1 0110 1011 有9位。
为什么要有这样的规则?
要从指令编码格局来解说(这便是我为什么一开始讲的是指令编码格局),仔细看表格中的shifter_operand所占的位数:12位。要用一个12位的编码来表明恣意的32位数是肯定不或许的(12位数有2^12种或许,而32位数有2^32种)。
可是又要用12位的编码来表明32位数,怎么办?
只需在表明数的数量上做约束。经过编码来完成用12位的编码来表明32位数。
在12位的shifter_operand中:8位存数据,4位存移位的次数。
8位存数据:解说了“该常数有必要对应8位位图”。
4位存移位的次数:解说了为什么只能移偶数位。4位只需16种或许值,而32位数能够循环移位32次(32种或许),那就只好约束:只能移偶数位(两位两位地移,如同一个16位数在移位,16种移位或许)。这样就处理了能表明的状况是实际状况一半的对立。
所以对#immed_8r常数表达式的约束是处理指令编码的第二个操作数位数不足以表明32位操作数的无法之举,但在我看来:这个能够说是聪明的做法。由于假如直接用12位数来表明32位操作数,只能表明0 到(2^12-1)。大于(2^12-1)的数就没办法表明了。并且细细想来“8位存数据,4位存移位的次数”,应该是最好的组合了(我并未想过一切的组合,仅仅趁便试了几个)。
ARM指令第二操作数#immed_8r详解
大多数ARM通用数据处理指令有一个灵敏的第2操作数(flexible second operand),这儿这解说一下其间的一种格局,#immed_8r常量的表达式。常量有必要对应于8位位图(pattern)。该位图在32位字中,被循环移位偶数位(0,2,4,…28,30)。合法常量0xff,0xff000,0xf000000f。不合法常量:0x101,0xff04
ARM 在32位形式下,一条指令长度为32位,在上述数据处理指令中,操作数2为12位。所以像0x7f02这样的数,要两条指令才干完结。
MOV
ORR
所以直接是找不到0x7f02的
关于循环移位,其实arm中只需循环右移(ROR)。0x7f到0x7f00是经过循环右移24次才完成的,这儿每次移动2位所以是12次(0xc)
在 ARM 数据处理指令中, 当参加操作的第二操作数为当即数时, 每个当即数都是选用一个8位的常数循环右移偶数位而直接得到, 其间循环右移的位数有一个4位二进制的2倍表明. 则有用当即数可表明为:
举个比方吧.
0x3FC(0000 0000 0000 0000 0000 0011 1111 1100) 是由 0xff 循环右移 2 位得到的;
200(0000 0000 0000 0000 0000 0000 1100 1000) 是由 0xc8 循环右移 2 位得到的, 它们都是合法的.
而 0x1FE(0000 0000 0000 0000 0000 0001 1111 1110) 和
511(0000 0000 0000 0000 0000 0001 1111 1111) 无法看成是8位的常数循环右移偶数位而得到的, 因而是不合法的.
指令操作数当即数时分,每个当即数由一个8位的常数循环右移偶数位得到。
打个比方:
1.当即数0xF200是由0xCF2直接表明的,便是由8位的0xF2循环右移24(2*12)得到的
immed_8 == 0xF2;
2.当即数0x3F0是由0xE3F直接表明的,便是由8位的0x3F循环右移28(2*14)得到的
immed_8 == 0x3F;
或许
当即数0x3F0是由0xFFC直接表明的,便是由8位的0xFC循环右移30(2*15)得到的
immed_8 == 0xFC;
表明办法有好几种
PS:其实你没必要一个一个的算,只需运用LDR伪指令就能够了,例如:
ldr r1, =12345678
编译器自然会给你做作业,实际的编程中应该也是这个居多吧
比较下来, 咱们能够这样总结:
- 判别一个数是否契合8位位图的准则, 首要看这个数的二进制表明中1的个数是否不超越8个.
假如不超越8个, 再看这n个1(n<=8)是否能一起放到8个二进制位中, 假如能够放进去, 再看这八个二进制位是否能够循环右移偶数位得到咱们欲运用的数. 假如能够, 则此数契合8位位图原理, 是合法的当即数. 不然, 不契合. - 无法表明的32位数, 只需经过逻辑或算术运算等其它途径获得了. 比方0xffffff00, 能够经过0x000000ff按位取反得到.
因而今后的编程中, 时间查看用到的第二操作数是否契合8位位图是一件千万不能忽略的事. 至于为什么要将这12位