ARM指令中如何判断一个立即数是有效立数

在ARM处理器的汇编语言中,对指令语法格式中的<shifter_operand>的常数表达式有这样的规定:“该常数必须对应8位位图,即常数是由一个8位的常数循环移位偶数位得到的。”<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

首先从ARM指令系统的语法格式说起。

一条ARM指令语法格式分为如下几个部分:

<opcode>{<cond>}{S} <Rd>,<Rn>{,<shifter_operand>}

其中,<>内的项是必须的,{}内的项是可选的,如<opcode>是指令助记符,是必须的,而{<cond>}为指令执行条件,是可选的,如果不写则使用默认条件AL(无条件执行)。

Opcode   指令助记符,如LDR,STR 等

Cond       执行条件,如EQ,NE 等

S           是否影响CPSR 寄存器的值,书写时影响CPSR,否则不影响

Rd          目标寄存器

Rn          第一个操作数的寄存器

shifter_operand      第二个操作数

其指令编码格式如下:

31-28

27-25

24-21

20

19-16

15-12

11-0 (12位)

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     R3, #0x7F00    ;E3 A0 3C 7F 该指令自己完成0x7f移位

ORR     R1, R3, #2

所以直接是找不到0x7f02的

关于循环移位,其实arm中只有循环右移(ROR)。0x7f到0x7f00是通过循环右移24次才实现的,这里每次移动2位所以是12次(0xc)

在 ARM 数据处理指令中, 当参与操作的第二操作数为立即数时, 每个立即数都是采用一个8位的常数循环右移偶数位而间接得到, 其中循环右移的位数有一个4位二进制的2倍表示. 则有效立即数可表示为: <immediate> := immed_8; 循环右移(2×rotate_imm). 其中: <immediate> 代表立即数, immed_8 代表8位常数,  即所谓的"8位图", rotate_imm 代表4位的循环右移值. 这样一来出现了一个问题: 尽管表示的范围变大了, 但是12位所能表现的数字的个数是一定的. 因此, ARM 规定并不是所有的32位常数都是合法的立即数, 只有通过上面的构造方法得到的才是合法的立即数, 编译的时候才不会报错.

举个例子吧.
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位的常数循环右移偶数位得到。

<immediate>= immed_8 循环右移( 2*rotate_imm)

打个比如:
1.立即数0xF200是由0xCF2间接表示的,即是由8位的0xF2循环右移24(2*12)得到的
immed_8 == 0xF2;   rotate_imm == 0xC

2.立即数0x3F0是由0xE3F间接表示的,即是由8位的0x3F循环右移28(2*14)得到的
immed_8 == 0x3F;   rotate_imm == 0xE
或者
立即数0x3F0是由0xFFC间接表示的,即是由8位的0xFC循环右移30(2*15)得到的
immed_8 == 0xFC;   rotate_imm == 0xF

表示方法有好几种

PS:其实你没必要一个一个的算,只要利用LDR伪指令就可以了,例如:
ldr r1, =12345678
编译器自然会给你做工作,现实的编程中应该也是这个居多吧

比较下来, 我们可以这样总结:

  1. 判断一个数是否符合8位位图的原则, 首先看这个数的二进制表示中1的个数是否不超过8个. 如果不超过8个, 再看这n个1(n<=8)是否能同时放到8个二进制位中, 如果可以放进去, 再看这八个二进制位是否可以循环右移偶数位得到我们欲使用的数. 如果可以, 则此数符合8位位图原理, 是合法的立即数. 否则, 不符合.
  2. 无法表示的32位数, 只有通过逻辑或算术运算等其它途径获得了. 比如0xffffff00, 可以通过0x000000ff按位取反得到.

因此以后的编程中, 时刻检查用到的第二操作数是否符合8位位图是一件千万不能疏忽的事. 至于为什么要将这12位 operand2 "八四开", 这个问题就要请教大牛了.

ARM指令中如何判断一个立即数是 有效立即数相关推荐

  1. ARM指令中如何判断一个立即数是有效立即数

    ARM指令中如何判断一个立即数是有效立数 在ARM处理器的汇编语言中,对指令语法格式中的<shifter_operand>的常数表达式有这样的规定:"该常数必须对应8位位图,即常 ...

  2. shell中如何判断一个变量是否为空

    shell中如何判断一个变量是否为空 shell编程中,对参数的错误检查项中,包含了变量是否赋值(即一个变量是否为空),判断变量为空方法如下: 1.变量通过" "引号引起来 #!/ ...

  3. java怎么统计随机数出现次数,Excel统计出现次数、个数的VBA代码 java中怎么判断一个字符串中包含某个字符或字...

    延伸:java中怎么判断一个字符串中包含某个字符或字符 描述:...一个字符串中包含某个字符的单词说出现的次数 c#什么方法可以判断字符串中包含某个字符的个数? JAVA判断字符串数组中是否包含某字符 ...

  4. python判断回文数_Python实现判断一个整数是否为回文数算法示例

    本文实例讲述了Python实现判断一个整数是否为回文数算法.分享给大家供大家参考,具体如下: 第一个思路是先将整数转换为字符串,再将字符串翻转并与原字符串做比较 def isPalindrome(se ...

  5. 在shell中如何判断一个变量是否为空

    在shell中如何判断一个变量是否为空 判断一个脚本中的变量是否为空,我写了一个这样的shell脚本: #!/bin/sh #filename: test.sh para1= if [ ! -n $p ...

  6. (c语言)判断一个正整数是否是回文数

    (c语言)判断一个正整数是否是回文数 回文数是指从左到右和从右到左读这个数是一样的.例如:1,101,1221都是回文数. #include<stdio.h> #include<st ...

  7. 17.判断一个整数是否是回文数

    回文数(或迴文數)是指一个像14641这样"对称"的数,即:将这个数的数字按相反的顺序重新排列后,所得到的数和原来的数一样. 判定一个正整数是否是一个回文数.例如12121是回文数 ...

  8. python判断回文_Python实现判断一个整数是否为回文数算法示例

    本文实例讲述了Python实现判断一个整数是否为回文数算法.分享给大家供大家参考,具体如下: 第一个思路是先将整数转换为字符串,再将字符串翻转并与原字符串做比较 def isPalindrome(se ...

  9. 【Python】Python实验:回文是一个正向和逆向都相同的整数,如123454321、463364、9889。编写函数判断一个整数是否是回文数。

    回文是一个正向和逆向都相同的整数,如123454321.463364.9889.编写函数判断一个整数是否是回文数. 算法源码 def huiwen(n):if n==n[::-1]: ##正序和倒序是 ...

最新文章

  1. linux在内核下使用iic,实例解析linux内核I2C体系结构(2)
  2. bzoj1799 数位dp
  3. 禅修笔记——硅谷最受欢迎的情商课
  4. P1582 倒水(二进制)
  5. Java 打飞机(小游戏)[版权非本人 本人制作收藏整理]
  6. 【动态规划】求最长不下降序列
  7. 关于ArcGIS Rest API
  8. C++中Future和Promise的一种简单实现
  9. kafka tool报错:Error fetching datea.Offset out of range
  10. idea 点击右侧栏找不到git或者svngit的基本使用
  11. 大班线描机器人_大班美术教案机器人
  12. Git检出指定的目录-稀疏检出
  13. 自反馈与 Mandelbrot set
  14. iOS 25个性能优化/内存优化常用方法
  15. HTML从入门到入土 - CSS基础
  16. c语言中next如何用,C++ STL prev()和next()函数用法详解
  17. oracle同一个库不同用户,oracle同一个库上面,不同用户相互赋予权限
  18. FFmpeg - Windows下使用MSYS2和VS编译FFmpeg
  19. red hat enterprise linux yum,Red Hat Enterprise Linux7.x(RHEL7.x)更换CentOS YUM源
  20. 什么是冒泡,怎么阻止冒泡,冒泡排序

热门文章

  1. JavaScript算法之指针思想
  2. Linux Inotify详解
  3. Redis的SDS+IntSet+Dict
  4. python比matlab的优点_python与matlab的优势对比
  5. 做服装设计师需要具备哪些技能?
  6. oracle数据库报错12505,Oracle SQL Developer连接报错(ORA-12505)的解决方案(两种)
  7. 阿里云峰会 | 深化城市计算场景能力,为企业数智化建设提供助推力
  8. 三只猫。。。俺家小豹小的时候,哪个更可爱呢???
  9. in-sight 电子表格 相机设置实例
  10. html5购物车数字加减,jQuery实现购物车数字加减效果