我刚开始学习ARM汇编语言,不清楚如何使用MOV将立即数转移到寄存器中。
从 ARM 参考手册和我的教科书中,都说 MOV 指令后面的立即数范围是 0-255。但是当我在自己的 PC 上使用 ADS 1.2 IDE 进行测试时,指令
MOV R2, #0xFFFFFFFF
表现良好。根据规范,数字 0xFFFFFFFF 是否超出范围?
我刚开始学习ARM汇编语言,不清楚如何使用MOV将立即数转移到寄存器中。
从 ARM 参考手册和我的教科书中,都说 MOV 指令后面的立即数范围是 0-255。但是当我在自己的 PC 上使用 ADS 1.2 IDE 进行测试时,指令
MOV R2, #0xFFFFFFFF
表现良好。根据规范,数字 0xFFFFFFFF 是否超出范围?
请记住,作为合并到 ARM 操作码中的桶形移位器的一部分,ARM 可以对立即数执行一组特定的操作。
这篇小文章对 ARM 汇编程序可以用来将大立即数放入 ARM 指令的小可用空间中的一些技巧进行了最清晰的解释:
本文讨论了在生成 MVN 操作码以加载立即值的按位补码的具体示例中可能使用的技巧。
这些类型的操作不能用所有的立即数来完成,但是 ARM 汇编器据说对此非常聪明(C 编译器当然也是如此)。如果无法执行移位/补码技巧,则通常将从 PC 相对位置加载该值,或者可能通过从多个指令“构建”该值来加载该值。
一条 ARM 指令只能编码一个立即数,该常数可以表示为一个 8 位立即数,按 2 的任意偶数次幂移位。
但是,还有一条MVN
指令,它类似于MOV
但将所有位反转。因此,虽然MOV R2, #0xFFFFFFFF
不能编码为MOV
指令,但可以编码为MVN R2, #0
. 汇编器可能会很好地为您执行此转换。
MOV 指令可以接受 imm16 值或 Operator2 值(由于指令长度与内存对齐相反),它必须符合以下任何规则(复制自 CortexM 指令集手册,X 和 Y 是任何十六进制值):
这就是接受 0xFFFFFFFF 的原因(符合第四条规则)。
如果你想组装你自己的 32 位常数,你可以使用指令MOVT,它写入寄存器的上半部分。
很难确定给定的常数是否在有效范围内。
就像 Matthew 已经提到的那样,汇编器通过用类似的否定指令替换给定的指令来帮助您,例如 mov/mvn、cmp/cmn、tst/tne 等。
您可能会从原始值的符号扩展中看到伪影。如果您用来查看反汇编的工具将 0..255 作为有符号字节处理,那么当它将它加载到更大的 int 类型(或寄存器)中时,它将用原始的符号位填充所有高位价值。或者换一种说法,如果 0xFF 是有符号字节,它的十进制值为 -1。把它放到一个 32 位寄存器中,十六进制看起来像 0xFFFFFFFF,它的十进制值仍然是 -1。
尝试使用没有设置高位的值,例如 0x7F。由于未设置符号位,我猜当加载到更大的 int 类型寄存器或字段时,它将用零填充高位。
编译器/汇编器也可能截断您提供的任何值。我认为这是源代码错误,但汇编程序是有趣的野兽。如果给它 0x7FF,它会编译为 0x7FF(未截断,大于 0..255)还是 0xFFFFFFFF(截断为 0..255,有符号字节)?
如果您想将 0xffffffff 移动到寄存器中,您可以随时执行以下操作:
MOV R0, #-1
因为 0xffffffff 是 -1 的补码表示
一种可能性是 ARM 汇编程序丢弃了数字的有效位并仅使用最低的 FF。
MOV 指令是许多 CPU 指令集中的主要内容,通常汇编器会解析目标寄存器的大小和提供的立即数。
例如,x86 集中的以下 MOV 指令是
MOV BL, 80h, ; 8bit
MOV BX, ACACh ;16bit
MOV EBX, 12123434h ; 32bit