ARM立即数编码和BIC指令

时间:2020-08-11 14:45:32

标签: assembly arm gnu

我是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)

我知道我在某个地方错了。有人可以纠正我吗?

2 个答案:

答案 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文档,它就会被清楚地描述。