我是ARM世界的新手。在 ARM Cortex-A系列:程序员指南(第71页)中,有一个BIC指令示例:
BIC R0, R0, #0x800
根据文本,这基本上清除了R0中的位11。我了解BIC在这里像R0 = R0 & (~val)
一样工作(请纠正我)。但是我在这里不明白的是,#0x800
是照原样被转换为1000 0000 0000
的。相反,应该按照即时编码规则将其分为4位:8位部分。
根据我对常数的ARM编码的理解:
0x800 = 0000 1000 0000 0000
在这些位中,我们仅考虑用于编码的最后12位,在这12位中-前4位决定以2为步长的右旋转,后8位是右旋转的数字(将其视为32位)。因此,在这种情况下,由于后8位全为零,因此我应该在2 * 8右旋转后得到FFFF 0000
。
对于上面完整的BIC指令,则应将其视为:
R0 = R0 & (0000 FFFF)
我知道我在某个地方错了。有人可以纠正我吗?
答案 0 :(得分:4)
简短的答案是,您的程序集中未包含编码的文字字段,而是包含了您实际要使用的具有含义的值。汇编器的工作包括为指定的汇编确定(最好的,如果有的话)指令编码。
汇编器负责将汇编中提供的编码值编码到指令的文字字段中。 #0x800
是文字。作为汇编程序员,您只需要确保文字是可编码的即可。
必须计算编码的旋转数,这会很烦人并且容易出错。这种转换类型在汇编代码和机器代码之间有很大的不同。要查看实际生成的文字字段,请查看汇编后的结果。
这还会导致某些ISA中的汇编代码和机器代码之间存在非一对一的关系。
值0x800
直接是0b1000_0000_0000
。
组装
BIC R0, R0, #0x800
给我
02 0B C0 E3
因此Operand2
字段为0xB02
。这意味着立即数为0x02
,而旋转数为0xB
。取0x00000002
并向右旋转2 * 0xB
,我们得到预期的0x800
。
答案 1 :(得分:2)
只要自己尝试一下,看看。
.syntax unified
bic r0,r0,#0x800
.thumb
bic r0,r0,#0x800
Disassembly of section .text:
00000000 <.text>:
0: e3c00b02 bic r0, r0, #2048 ; 0x800
4: f420 6000 bic.w r0, r0, #2048 ; 0x800
A1编码
e3c00b02
101100000010 (b02)
1011 00000010
将位模式00000010向右移11 * 2个位置,与向左移10个相同
00000010 0000000000
000000100000000000
000000 1000 0000 0000
0x800
T1编码
f420 6000
1111010000100000 0110000000000000
xxxxx1xxxxxxxxxx x110xxxx00000000
11100 0000000
11100 abcdefg
1bcdefg0 shifted left 3
1abc defg 0000
1000 0000 0000
0x800
所有内容在ARM文档中都有明确描述。该指令指向文档(ARM ARM)的一部分,该部分显示了立即数的编码。这不是技巧,这是ARM。它不一定直接映射到指令中,ARM因其桶形移位器而闻名。
我避免使用的ARM的一个文档(类型)是程序员指南,它不是他们的更好的文档之一。
您需要有关内核的技术参考手册(ARM TRM)和该内核中的体系结构(在这种情况下为armv7-ar)的体系结构参考手册(ARM ARM)。
对于ARM(目前缺乏更好的术语,是aarch32),它是8个有效位,因此可以移位偶数次。
bic r0,r0,#0x102
100000010 (0x102)
10000001 (0x81)
不起作用
so.s:2: Error: invalid constant (102) after fixup
但是
bic r0,r0,#0x204
确实(0x81 >> 30)
拇指
bic r0,r0,#0x00220022
很好,但不适合手臂
so.s:3: Error: invalid constant (220022) after fixup
只需阅读ARM文档,它就会被清楚地描述。