立即数方式(ARM)——彻底解析
2013-12-09 00:48
281 查看
有问题找狗找度娘------站在巨人的肩膀上,深深体会到了。全文转载自:找到原作者,但是作者所有博文里好像没有这篇文章,也就不指出链接了
。
为什么会有这个疑问呢,还是在看U-BOOT第一阶段启动代码里发现的:
立即数方式:每个立即数由一个8位的常数循环右移偶数位得到。其中循环右移的位数由一个4位二进制的两倍表示。如果立即数记作<immediate>,8位常数记作immed_8,4位的循环右移值记作rotate_imm,则有:
<immediate>=immed_8循环右移(2*rotate_imm)
这样并不是每一个32位的常数都是合法的立即数,只有能够通过上面构造方法得到的才是合法的立即数。
下面的常数是合法的立即数:
0xff,0x104,0xff0,oxff00
下面的数不能通过上述构造方法得到,则不是合法的立即数:
0x101,0x102,0xFF1
同时按照上面的构造方法,一个合法的立即数可能有多种编码方式。如0x3f0是一个合法的立即数,它可以采用下面两种的编码方式:
immed_8=0x3f,rotate_imm=oxe或者
immed_8=oxfc,rotate_imm=0xf
转换为二进制形式如下:
ox3f=0000 0000 0000 0000 0000 0000 0011 1111
oxe=14(十进制) 2*14=28
∴,ox3f循环右移28位得到如下:
0000 0000 0000 0000 0000 0011 1111 0000=ox3f0
immed_8=oxfc,rotate_imm=0xf 的转换如下:
oxfc=0000 0000 0000 0000 0000 0000 1111 1100
rotate_imm=oxf=15(十进制) 15*2=30
所以oxfc循环右移30位得到如下结果:
0000 0000 0000 0000 0000 0011 1111 0000=ox3f0
可以看出,结果是一样的!!!
但是,由于这种立即数的构造方法中包含循环移位操作,而循环移位操作会影响CPSR的条件标志位C。因此,痛一个合法的立即数由于采用了不同的编码方式,将使得某些质量的执行产生不同的结果,这是不能允许的。ARM汇编编译器按照下面的规则生成立即数的编码。
1.当立即数数值在0和0xFF范围时,零immmed_8=<immediate>,rotate_imm=0.、
2.其他情况下,汇编编译器选择使rotate_imm数值最小的编码方式。所以ox3f0的正确表示法是第一种。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
解释二:
一条典型的ARM指令语法格式分为如下几个部分:
<opcode> {<cond>} {S} <Rd> ,<Rn>{,<operand2>}
其中,<>内的项是必须的,{}内的项是可选的,如<opcode>是指令助记符,是必须的,而{<cond>}为指令执行条件,是可选的,如果不写则使用默认条件AL(无条件执行)。
opcode 指令助记符,如LDR,STR 等
cond 执行条件,如EQ,NE 等
S 是否影响CPSR 寄存器的值,书写时影响CPSR,否则不影响
Rd 目标寄存器
Rn 第一个操作数的寄存器
operand2 第二个操作数
其指令编码格式如下:
31-28 cond
27-25 001
24-21 opcode
20 S
19-16 Rn
15-12 Rd
11-0 (12位) operand2
对其中的operand2的常数表达式有这样的规定:“该常数必须对应8位位图,即常数是由一个8位的常数循环右移偶数位得到的。”这句话的意思是说,当用12位第二操作数来表示一个32位立即数时,采用的是将8位数通过移位的方式来实现的,其中12位第二操作数的低八位存放被移位的“基本”数(取值范围为0到255),而高四位存放的是循环右移的位数,因为是四位二进制数,所以取值范围位为0到15,而对应的移位位数则为0到30位(因为移动的可能只有31种),也就是说若“移位”数为0,则表示“基本”数不变,若“移位”数为1,则表示将“基本”数在32位数字空间中循环右移2位,若“移位”数为5,则表示将“基本”数在32位数字空间中循环右移10位,若“移位”数为10,则表示将“基本”数在32位数字空间中循环右移20位,依次类推。举例表示:
AND R1,R2,#0xff
当处理器处理这条指令的第二操作数0xff时,因为0xff为8位二进制数,所以处理器就将其直接放进8位“基本”数中,而4位“移位”数则为0.
AND R1,R2,#0x104
当处理器处理这条指令的第二操作数0x104时,因为此时0x104已经超过了8位二进制数,所以处理器就要将其“改造”一下,我们先把0x104转换成二进制0000 0000 0000 0000 0000 0001 0000 0100,我们可以看到,这个数是0000 0000 0000 0000 0000 0000 0100 0001通过循环右移30位得到的,因此改造后的结果是8位“基本”数中存放0100 0001,而“移位”数为15。
AND R1,R2,#0xff000000
当处理器处理这条指令的第二操作数0xff000000时,处理器同样要对其“改造”,我们先把0xff000000转换成二进制1111 1111 0000 0000 0000 0000 0000 0000,我们可以看到,这个数是0000 0000 0000 0000 0000 0000 1111 1111通过循环右移8位得到的,因此改造后的结果是8位“基本”数中存放1111 1111,而“移位”数为4。
我想,通过以上的三个例子,就应该明白了8位位图的原理了。但是,有些数并不符合8位位图的原理,这样的数在进行程序编译时,系统将会提示出错,下面再举几个违反8位位图的例子:比如0x101,转换成二进制后位0000 0000 0000 0000 0000 0001 0000 0001,像这个数,无论向右循环几位,都无法将两个1同时放到低8位中,因此不符合8位位图;再比如0x102,转换成二进制后位0000 0000 0000 0000 0000 0001 0000 0010,如果将两个1同时放到低8位中,即转换成二进制后为0000
0000 0000 0000 0000 0000 1000 0001,需要将此二进制数向右移31位,这也不符合循环右移偶数位的条件,因此0x012也不符合8位位图;再举一个0xff1,转换成二进制后将会有9个1,不可能将其同时放入8位中,因此当然也不符合啦。
通过正反例的比较,可以总结如下:第一,判断一个数是否符合8位位图的原则,首先看这个数转换成二进制后1的个数是否不超过8个,如果不超过8个,再看这n个1(n<=8)是否能同时放到8个二进制位中,如果可以放进去,再看这八个二进制位是否可以循环右移偶数位得到起初被判断的那个数值,如果可以,则此数值即为符合8位位图原理,否则,不符合。第二,用12位的编码来表示一个任意的32位数是不可能的,只能通过循环右移八位二进制数偶数位来得到一部分32位数,其余的无法表示的32位数,只有通过其它途径获得了,比如0xffffff00,可以通过0x000000ff按位取反得到,因此在以后的编程中,一定要注意用到的第二操作数是否符合8位位图。
。
为什么会有这个疑问呢,还是在看U-BOOT第一阶段启动代码里发现的:
mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) orr r0, r0, #0x00000002 @ set bit 2 (A) Align orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache mcr p15, 0, r0, c1, c0, 0问自己几个问题:1、第一次看的时候为什么好像没看到过这段;2、这次看的时候为什么还是没有注意到;
立即数方式:每个立即数由一个8位的常数循环右移偶数位得到。其中循环右移的位数由一个4位二进制的两倍表示。如果立即数记作<immediate>,8位常数记作immed_8,4位的循环右移值记作rotate_imm,则有:
<immediate>=immed_8循环右移(2*rotate_imm)
这样并不是每一个32位的常数都是合法的立即数,只有能够通过上面构造方法得到的才是合法的立即数。
下面的常数是合法的立即数:
0xff,0x104,0xff0,oxff00
下面的数不能通过上述构造方法得到,则不是合法的立即数:
0x101,0x102,0xFF1
同时按照上面的构造方法,一个合法的立即数可能有多种编码方式。如0x3f0是一个合法的立即数,它可以采用下面两种的编码方式:
immed_8=0x3f,rotate_imm=oxe或者
immed_8=oxfc,rotate_imm=0xf
转换为二进制形式如下:
ox3f=0000 0000 0000 0000 0000 0000 0011 1111
oxe=14(十进制) 2*14=28
∴,ox3f循环右移28位得到如下:
0000 0000 0000 0000 0000 0011 1111 0000=ox3f0
immed_8=oxfc,rotate_imm=0xf 的转换如下:
oxfc=0000 0000 0000 0000 0000 0000 1111 1100
rotate_imm=oxf=15(十进制) 15*2=30
所以oxfc循环右移30位得到如下结果:
0000 0000 0000 0000 0000 0011 1111 0000=ox3f0
可以看出,结果是一样的!!!
但是,由于这种立即数的构造方法中包含循环移位操作,而循环移位操作会影响CPSR的条件标志位C。因此,痛一个合法的立即数由于采用了不同的编码方式,将使得某些质量的执行产生不同的结果,这是不能允许的。ARM汇编编译器按照下面的规则生成立即数的编码。
1.当立即数数值在0和0xFF范围时,零immmed_8=<immediate>,rotate_imm=0.、
2.其他情况下,汇编编译器选择使rotate_imm数值最小的编码方式。所以ox3f0的正确表示法是第一种。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
解释二:
一条典型的ARM指令语法格式分为如下几个部分:
<opcode> {<cond>} {S} <Rd> ,<Rn>{,<operand2>}
其中,<>内的项是必须的,{}内的项是可选的,如<opcode>是指令助记符,是必须的,而{<cond>}为指令执行条件,是可选的,如果不写则使用默认条件AL(无条件执行)。
opcode 指令助记符,如LDR,STR 等
cond 执行条件,如EQ,NE 等
S 是否影响CPSR 寄存器的值,书写时影响CPSR,否则不影响
Rd 目标寄存器
Rn 第一个操作数的寄存器
operand2 第二个操作数
其指令编码格式如下:
31-28 cond
27-25 001
24-21 opcode
20 S
19-16 Rn
15-12 Rd
11-0 (12位) operand2
对其中的operand2的常数表达式有这样的规定:“该常数必须对应8位位图,即常数是由一个8位的常数循环右移偶数位得到的。”这句话的意思是说,当用12位第二操作数来表示一个32位立即数时,采用的是将8位数通过移位的方式来实现的,其中12位第二操作数的低八位存放被移位的“基本”数(取值范围为0到255),而高四位存放的是循环右移的位数,因为是四位二进制数,所以取值范围位为0到15,而对应的移位位数则为0到30位(因为移动的可能只有31种),也就是说若“移位”数为0,则表示“基本”数不变,若“移位”数为1,则表示将“基本”数在32位数字空间中循环右移2位,若“移位”数为5,则表示将“基本”数在32位数字空间中循环右移10位,若“移位”数为10,则表示将“基本”数在32位数字空间中循环右移20位,依次类推。举例表示:
AND R1,R2,#0xff
当处理器处理这条指令的第二操作数0xff时,因为0xff为8位二进制数,所以处理器就将其直接放进8位“基本”数中,而4位“移位”数则为0.
AND R1,R2,#0x104
当处理器处理这条指令的第二操作数0x104时,因为此时0x104已经超过了8位二进制数,所以处理器就要将其“改造”一下,我们先把0x104转换成二进制0000 0000 0000 0000 0000 0001 0000 0100,我们可以看到,这个数是0000 0000 0000 0000 0000 0000 0100 0001通过循环右移30位得到的,因此改造后的结果是8位“基本”数中存放0100 0001,而“移位”数为15。
AND R1,R2,#0xff000000
当处理器处理这条指令的第二操作数0xff000000时,处理器同样要对其“改造”,我们先把0xff000000转换成二进制1111 1111 0000 0000 0000 0000 0000 0000,我们可以看到,这个数是0000 0000 0000 0000 0000 0000 1111 1111通过循环右移8位得到的,因此改造后的结果是8位“基本”数中存放1111 1111,而“移位”数为4。
我想,通过以上的三个例子,就应该明白了8位位图的原理了。但是,有些数并不符合8位位图的原理,这样的数在进行程序编译时,系统将会提示出错,下面再举几个违反8位位图的例子:比如0x101,转换成二进制后位0000 0000 0000 0000 0000 0001 0000 0001,像这个数,无论向右循环几位,都无法将两个1同时放到低8位中,因此不符合8位位图;再比如0x102,转换成二进制后位0000 0000 0000 0000 0000 0001 0000 0010,如果将两个1同时放到低8位中,即转换成二进制后为0000
0000 0000 0000 0000 0000 1000 0001,需要将此二进制数向右移31位,这也不符合循环右移偶数位的条件,因此0x012也不符合8位位图;再举一个0xff1,转换成二进制后将会有9个1,不可能将其同时放入8位中,因此当然也不符合啦。
通过正反例的比较,可以总结如下:第一,判断一个数是否符合8位位图的原则,首先看这个数转换成二进制后1的个数是否不超过8个,如果不超过8个,再看这n个1(n<=8)是否能同时放到8个二进制位中,如果可以放进去,再看这八个二进制位是否可以循环右移偶数位得到起初被判断的那个数值,如果可以,则此数值即为符合8位位图原理,否则,不符合。第二,用12位的编码来表示一个任意的32位数是不可能的,只能通过循环右移八位二进制数偶数位来得到一部分32位数,其余的无法表示的32位数,只有通过其它途径获得了,比如0xffffff00,可以通过0x000000ff按位取反得到,因此在以后的编程中,一定要注意用到的第二操作数是否符合8位位图。
相关文章推荐
- 第31课: Spark资源调度分配内幕天机彻底解密:Driver在Cluster模式下的启动、两种不同的资源调度方式源码彻底解析、资源调度内幕总结
- day31:Driver在Cluster模式下的启动、两种不同的资源调度方式源码彻底解析、资源调度
- Spark资源调度分配内幕解密:Driver在Cluster模式下的启动、两种不同的资源调度方式源码彻底解析、资源调度内幕总结
- [Spark内核] 第31课:Spark资源调度分配内幕天机彻底解密:Driver在Cluster模式下的启动、两种不同的资源调度方式源码彻底解析、资源调度内幕总结
- ARM的启动方式和bootloader解析(下)
- Driver在Cluster模式下的启动、两种不同的资源调度方式源码彻底解析、资源调度内幕总结
- 原生解析方式下的生成数据
- 单例模式简单解析--Singleton 单例模式(懒汉方式和饿汉方式)
- 4.1 解析 XML 数据的三种方式详解
- 邻接表建图的三种方式的时空比较(解析+图示)
- Map的存储方式解析
- 浏览器[IE] Ajax Struts Json返回json字符串,解析不了 提示保存或下载 解决方式
- XML的三种解析方式与JSON解析方式
- 用IShellLink解析快捷方式(ShortCut)
- XML解析的两种方式:DOM方式和SAX方式
- Android学习之XML数据的三种解析方式以及生成XML文件
- Android解析XML(PULL方式)
- 清除浮动方式overflow:hidden原理解析
- 苹果希望彻底更改人类工作的方式
- java中解析xml文件的两种方式