Assembly ARM:为什么立即常数只有12位?

Assembly ARM:为什么立即常数只有12位?,assembly,arm,cpu-architecture,instruction-set,immediate-operand,Assembly,Arm,Cpu Architecture,Instruction Set,Immediate Operand,这意味着什么:我只有12位的立即常数,所以我只能表示0到2^12=4096之间的立即常数吗?如果是寄存器,操作数2可以有32位,但为什么立即数常量只有12位?这个数字来自哪里?它是由指令集定义的。例如,MOV指令编码为 31 28 | 27 26 | 25 | 24 23 22 21 20 | 19 16 | 15 12 | 11 0 | cond | 0 0 | I | 1 1 0 1 S | SBZ | Rd | shi

这意味着什么:我只有12位的立即常数,所以我只能表示0到2^12=4096之间的立即常数吗?如果是寄存器,操作数2可以有32位,但为什么立即数常量只有12位?这个数字来自哪里?

它是由指令集定义的。例如,
MOV
指令编码为

31 28 | 27 26 | 25 | 24 23 22 21 20 | 19   16 | 15    12 | 11        0      |
cond  | 0  0  | I  | 1  1  0  1  S  | SBZ     | Rd       | shifter operand  |

(see "ARM Architecture Reference Manual, 4.1.29 "MOV")
“立即数”常量编码在“移位器操作数”中,该操作数仅为12位。其他指令有类似的定义,有时也有其他宽度


这种限制的存在是因为——与x86不同——ARM上的指令在使用Thumb时总是32位,有时是16位(2)。为了支持不能用12位二进制数字直接表示的值,移位器操作数允许不同的寻址模式(例如左移位、右移位、旋转)。

例如,ARM指令中通常是这样

imm12是0-4095范围内的任何值

这样的指令通常是4字节,32位,但您不需要太多的位来告诉core从2个寄存器中提取并将结果放入另一个寄存器。因此,指令集体系结构允许您以避免额外内存使用的方式使用剩余位。例如,如果要从寄存器中提取256,可以从堆栈中加载该256(这是内存,速度较慢),或者可以将其嵌入到指令中,速度较快。当然,这种方法的缺点是有一个有限的空间,在这种情况下,12位用于这样的操作数使用


即时常数允许的值范围在不同的指令中有所不同,大多数时候,汇编程序似乎会将您的指令更改为其他指令以获得相同的效果,或者提供伪指令来执行类似的工作(如)。然而,它有时无法汇编代码,并且失败了。在这些情况下,最好返回并阅读关于嵌入立即常数的特定指令功能。

Arm指令编码是32位长的,与x8086指令中的指令编码不同,它是固定的。不能在指令本身中编码任意32位常量。如果您查看arm v7指令集,对于算术指令,您可以在指令中直接编码一些32位的数字。这些数字被编码为12位(在指令中编码为12位的32位数字)。查看arm的架构手册。很抱歉,我没有链接给您。

是的,只有12位可用,这意味着只能表示212=4096个不同的值

这些状态可以以恒定步长分布,即从0到4095(忽略负值),也可以非线性分布。如前所述,ARM体系结构使用8个最低有效位(256个值)表示一个数字,使用4个最高有效位(16个状态)将该数字放大或缩小2的幂

由于这种可伸缩性,ARM体系结构能够表示许多原本无法表示的有用的大数字(即使是16位)。不幸的是,4096个州中的一些州现在映射到与所解释的相同的数字,因此使用这种方法只能表示3073个不同的值

想要处理不在3073个有效立即数集合中的立即数的程序员可以使用需要多个时钟周期和/或内存的变通方法,以实现所需的结果


结论:这只是一种分配可用数字的不同方式,而不是(神奇的)用212=4096个状态表示232=4294967296个不同数字的方式

指令并不总是32位的,比如Thumb2。Thumb2和ARM是不同的指令集。但我要补充一点,我认为说立即常数只是“在移位器操作数中编码”也是错误的。有许多类型的直接常数,你描述的不是问题中提到的那个。您提到的被称为“修改的立即常数”A5.2.4。问题所问的与imm12更相关,imm12允许[0-4095]范围内的常量。问题根本没有提到指令或类型。但还好;关于值的范围,答案是不正确的,我会修正它。好的,但这个立即数来自什么类型的寄存器?我的意思是这是什么?1-12是常规的,13,14,15是为其他函数保留的,我想……因为如果它有32位,那么只有一条指令。这个数字是任意的。这是在拥有足够的操作码来做一些有用的事情和为用户提供足够的常量范围之间的平衡。
ldr rX,=constant
是您可能感兴趣的另一种形式。值4096在两条指令中提供“三字节”掩码。
ldr rx,=constant
可能被视为加载32位值的64位指令。这与mips只能有16位值的原因相同。固定指令长度
ldr rX,=constant
术语只是汇编程序的辅助语句,不会直接转换为机器代码。当
常数
可以用12位表示时,它转换为
mov rX,#常数
。否则,该值将存储在汇编程序生成的
ldr rX[pc,#offset]
@ensc附近的某个位置,这正是我的观点。使用
ldr rX,=常数
。如果它需要超过12位,则在代码空间中为64位。。。您可以将其视为64位指令。我知道它们不是按顺序排列的,但它们将位于附近。只有关心缓存效果的人才会关心。通常,您应该在热路径之外加载常量。该区域由
.ltorg
发出,通常称为文字池。另请参见:,