基础知识
在ARM中,机器指令的格式大致有以下几种:
立即寻址的方式
立即寻址
- 在立即寻址,操作数本身直接在指令中给出,取出指令也就获得了操作数,这个操作数也称为立即数。例子如下
ADD R0, R1, #0xF ;R0=R1+15
MOV R0, #0x55 ;R0=0x55
在这两个例子中0xF和0x55就是立即数。(立即数要以#开头)
抛出问题
- 我们知道因为ARM指令长度是32-bit的,所以立即数不可能还有32-bit。
- ARM在指令格式中设定,只能用指令机器码32位中的低12位来表示要操作的常数。
- 但是简单的用这12位来表示,显然范围太小了,为了扩展到32-bit,因此使用了构造的方法,在12位中用8位来表示基本数据值,用4位表示移位值,通过用8位基本数据值往右循环移动4位位移值×2次,来表示要操作的常数。
- 这里要强调终的循环次数是4位位移值乘以2得到的,所以得到的终循环次数肯定是一个偶数,为什么要乘以2呢,实质还是因为范围不够,4位表示位移次数,大才15次,加上8位数据还是不够32位,这样只能通过ALU的内部结构设计将4位位移次数乘以2,这样就能用12位表示32位常数了。
具体点的定义:
立即数 = immed_8 循环右移 (2 * Rotate_imm)
如果存在一个 Rotate_imm 能够让该立即数由 immed_8 循环右移 2×Rotate_imm 位( 偶数位 )表示,那么这个立即数就是合法的。
那么什么样的立即数才是合法的?
合法立即数的判断
- 把数据转化二进制形式,4位一组,不够的补0
- 数1的个数,大于8个肯定不是立即数
- 如果小于8个,如果数据是两端为1,中间有连续的大于等于24个0,循环左移4的倍数,使高位全为0
- 比如
1111 0000 0000 0000 0000 0000 0000 1111
- 比如
- 找到最高位的1,尽可能多的去掉前面的0(去掉的0必须是偶数个)
- 比如
0001 0010 0010
,最高位的1前面有3个0,所以去掉2个0,即××01 0010 0010
- 比如
- 找到最低位的1,尽可能多的去掉后面的0(去掉的0必须是偶数个)
- 比如
0001 0010 0010
,最低位的1后面有1个0,所以出掉0个0,即××01 0010 0010
- 比如
- 数剩下的位数,如果小于等于8位,那么这个数就是立即数,反之就不是立即数
举几个例子
(1)0x4FF
0100 1111 1111
- 有9个1,大于8,所以不是立即数
(2)0x122
0001 0010 0010
- 3个1,小于8
- 不满足中间有24个0
- 最高位的1前面有3个0,所以去掉2个0,即
××01 0010 0010
- 最低位的1后面又1个0,所以去掉0个0,即
××01 0010 0010
- 剩下
××01 0010 0010
共10位,大于8,所以不是立即数
(3)0x234
0010 0011 0100
- 4个1,小于8
- 不满足中间有24个0
- 最高位的1前面有2个0,所以去掉2个0,即
××10 0011 0100
- 最低为的1后面又2个0,所以去掉2个0,即
××10 0011 01××
- 剩下的共8位,等于8,是立即数
(4)0xF000000F
1111 0000 0000 0000 0000 0000 0000 1111
- 8个1,不大于8
- 满足中间有24个0,循环左移4位,使高位全为0,即
0000 0000 0000 0000 0000 0000 1111 1111
- 最高位的1前面有24个0,所以去掉24个0,即
×××× ×××× ×××× ×××× ×××× ×××× 1111 1111
- 最低为的1后面没有0
- 剩下的共8位,是立即数
(5)0x8000007F
1000 0000 0000 0000 0000 0000 0111 1111
- 8个1,不大于8
- 满足中间有24个0,循环左移4位,是高位全为0,即
0000 0000 0000 0000 0000 0000 0111 1111 1000
- 最高位的1前面有24个0,所以去掉24个0,即
xxxx xxxx xxxx xxxx xxxx xxxx 0111 1111 1000
- 最低为的1后面有3个0,所以去掉2个0,即
xxxx xxxx xxxx xxxx xxxx xxxx 0111 1111 10xx
- 剩下的共10位,大于8,不是立即数
如何规避立即数
- 可以通过使用 LDR 伪指令代替
- 例如直接把MOV指令变为, LDR R1,=0x12345678这样编译器就不会报错。
总结
适合自己的方法才是最好了,真正理解了才能叫懂了!
才疏学浅,望雅正!