在ARM汇编的数据处理指令中经常会运用到常数,而ARM汇编中规则运用的常数有必要是当即数。
在评论什么是当即数,为什么有当即数,怎样快速判别当即数之前,咱们先来弄了解一个问题:什么不是当即数。
汇编指令是对数据(指令、数据)方针的操作,很要害的一个问题咱们怎样寻觅咱们的操作方针?汇编指令是一门关于寻址的艺术。ARM有九种寻址办法:1.寄存器寻址2.当即寻址3.寄存器移位寻址4.寄存器直接寻址5.基址寻址6.多寄存器寻址7.仓库寻址8.块复制寻址9.相对寻址。 九中寻址办法都是再告知咱们怎样寻觅咱们的操作方针,其间当即数寻址相关于其他寻址办法有什么不同?
为了了解ARM指令是怎样完成对数据方针操作,咱们需求知道ARM指令的机器码格局。(了解的能够直接跳到怎样快速判别合法当即数)(ARM指令的典型编码格局如下:)
ARM指令语法格局如下:
opcode{
各个部分解说如下:
*cond(bit[31:28]):指令的条件码助记符,默许是al(无条件履行)
*type(bit[27:32]):指令码类型,依据其编码的不同,所代表的类型:00:数据处理指令及杂类Load/Store指令;01:Load/Store指令;10:批量Load/Store指令及分支指令;11:协处理指令与软中止指令
*X(bit[25]):第二操作数类型标志码。(X=0表明第二操作数是移位寄存器,X=1表明第二操作数是当即数)
*opcode(bit[24:21]):指令助记符,如mov
*S(bit[20]):指令的履行是否影响CPSR(当时程序状况寄存器)的值(S:state)
*Rn(bit[19:16]):包括第一个操作数的寄存器编码(RegisterNum)
*Rd(bit[15:12]):方针寄存器编码(RegisterDestination)
*opcode2(bit[11:0]):第二操作数
ARM指令的第二操作数用法比较灵敏,有如下几种状况。
* 当即数
* 寄存器
* 寄存器移位
ARM指令里有两个操作数Rn,opcode2和一个意图寄存器Rd(用于寄存操作成果),Rn为包括第一个操作数的寄存器地址,opcode2有三种办法:当即数办法、寄存器办法、寄存器移位办法,其间寄存器和寄存器位移办法也都是存储的寄存器地址所以要经过寄存器直接取得数据方针,也就对错当即,而当即数办法不同,指令中opcode2数据域不是地址而是数据自身,所以叫当即数。也便是说其它寻值办法终究操作的数据方针是放在Rn或opcode2所指向的寄存器地址中的数据,明显当即数操作方针也需求依据地址寻觅,但它地点的地址比较特别,或许说它存储的方位比较特别,由于它直接存储在指令opcode2中。
而opcode2只要12位,也便是说opcode2所表明的当即数有必定约束0-4095,为了进一步扩展12bit数据所能表明数的规模,ARM规则了数据的格局:也即
当即数是由一个8位的常数循环右移偶数位得到的,其间循环右移 的位数由一个4位2进制的两倍表明,公式如下:
immediate=immed_8<<(2*rotate_imm4) “<<”表明循环右移 简略的说一个常数假如能够由一个8位的常数循环移位偶数位得到,那么便是当即数。
为什么会有当即数这样的规则呢?这是由于一切的ARM指令是精简指令集,指令长度固定都是32位,关于ARM数据处理指令天然也是相同。数据处理指令大致可包括3类,数据传送指令、数据算术逻辑运算指令和数据比较指令。在一条ARM数据处理指令中,除了要包括处理的数据值外,还要标识ARM指令称号,操控位,寄存器等其他信息。这样在一条ARM数据处理指令中,能用于表明要处理的数据值的位数只能小于32位。
ARM在指令格局中设定,只能用指令机器码32位中的低12位来表明要操作的常数。ARM处理器是按32位来处理数据的,ARM处理器处理的数据是32位,假如简略的用这12位来表明,明显规模太小了,为了扩展到32位,因而运用了结构的办法,在12位顶用8位表明根本数据值,用4位表明位移值,经过用8位根本数据值往右循环移动4位位移值*2次,来表明要操作的常数。这儿要着重终究的循环次数是4位位移值乘以2得到的,所以得到的终究循环次数必定是一个偶数,为什么要乘以2呢,本质仍是由于规模不行,4位表明位移次数,最大才15次,加上8位数据仍是不行32位,这样只能经过ALU的内部结构设计将4位位移次数乘以2,这样就能用12位表明32位常数了。
经过循环偶数位得的到操作数,扩展了操作数的规模,但也带来了问题,并不是每个数据都能经过8位根本数据循环移动偶数为得到,假如你在ARM数据处理指令中运用的操作数,不是当即数,比方MOV R1,#0x12345678,编译器就会报错,所以咱们在运用前有必要进行判别,这也是许多ARM相关求职书面考试中常考的一道标题。
那怎样怎样快速判别一个数是否是当即数?关于简略的数字咱们能够直接判别,比方小于255的数字必定是当即数。对相对杂乱的数字进行判别就需求先把它转换为2进制办法,然后依据界说进行判别了。我这儿总结了个比较快速的办法:(简而言之,便是运用当即数的生成办法,敏捷逆推到合法的8位常熟)
1、把数据转换成二进制办法,从低位到高位写成4位1组的办法,最高位一组不行四位的,在最高位前面补0。
2、数1的个数,假如大于8个必定不是当即数,假如小于等于8进行下面过程。
3、假如数据中心有接连的大于等于24个0,循环左移4的倍数,使高位全为0。
4、找到最高位的1,去掉前面最大偶数个0。
5、找到最低位的1,去掉后边最大偶数个0。
6、数剩余的位数,假如小于等于8位,那么这个数便是当即数,反之就不是当即数。
针对或许现的状况,举5个典型比方:
(1)0x4FF (2)0x122 (3)0x234 (4)0xF000000F (5)0x8000007F
例1: 0x4FF
第一步:0100 1111 1111
第二步:其间1的个数是9个,大于8个,断定不是当即数
例2: 0x122
第一步: 0001 0010 0010
第二步: 其间1的个数4个,小于8,持续
第三步: 其间没有接连大于等于24个0,持续
第四部: xx01 0010 0010 (最高位前面有3个0,最大偶数2,去掉2个0)
第五步: xx10 0011 0010 (最低位后边只要1个0,最大偶数0)
第六部: 剩余10 0011 0010 共10位,大于8,断定0x122不是当即数
例3: 0x234
第一步: 0010 0011 0100
第二步: 其间1的个数4个,小于8,持续
第三步: 其间没有接连大于等于24个0,持续
第四部: xx10 0011 0100
第五步: xx10 0011 01xx
第六部: 剩余10 0011 01 共8位,等于8,断定0x234是当即数
例4: 0xF000000F
第一步: 1111 0000 0000 0000 0000 0000 0000 1111
第二步: 其间1的个数8个,没有大于8,持续
第三步: 其间有接连24个0,循环左移4位,使高位全为0
0000 0000 0000 0000 0000 0000 0000 1111 1111
第四部: xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 1111
第五步: xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 1111
第六部: 剩余1111 1111共8位,等于8,断定0xF000000F是当即数
例5: 0x8000007F
第一步: 1000 0000 0000 0000 0000 0000 0111 1111
第二步: 其间1的个数8个,没有大于8,持续
第三步: 其间有接连24个0,循环左移4位,使高位全为0
0000 0000 0000 0000 0000 0000 0111 1111 1000
第四部: xxxx xxxx xxxx xxxx xxxx xxxx 0111 1111 10xx
第五步: xxxx xxxx xxxx xxxx xxxx xxxx 0111 1111 10xx
第六部: 剩余0111 1111 10共10位,等于8,断定0x7000008F是当即数
问题还没有完毕,咱们在ARM汇编中怎样躲避当即数这个问题呢,其实能够运用ARM汇编LDR伪指令,例如直接把MOV指令变为, LDR R1,=0x12345678这样编译器就不会报错了。但这种办法也有坏处会添加开支和影响履行功率。一起ARM汇编中还有有用数的概念,比方 MOV R1,#0xFFFFFFFF 指令中 0xFFFFFFFF 不是当即数,可是是有用数,编译器最主动把原指令变换为 MVN R1,#0,也不会报错。有用数断定:原数是当即数或许原数反码是当即数。
期望对我们有协助。