错误:单个指令无法移动立即数

问题描述 投票:0回答:1

我正在尝试将一个值移入寄存器,但是当使用

as -o test.o test.s
组装程序时,我收到消息:

test.s: Assembler messages:
test.s:6: Error: immediate cannot be moved by a single instruction

节目:

.equ SIZE, 2000000000

.global _start

_start:
    mov x1, SIZE

uname -a
产生:

Linux ip-172-31-10-254 5.19.0-1025-aws #26~22.04.1-Ubuntu SMP Mon Apr 24 01:58:03 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux

从错误消息和Error:immediate无法移动单个我推断错误消息与值太大而无法存储在寄存器中有关,但是

2000000000
2^64
小得多。我认为有些东西配置错误。

我该如何解决这个问题?

assembly arm arm64
1个回答
1
投票

显然支持杰斯特的评论。

某些 Arm 汇编语言支持 =label 语法,作为将标签地址获取到寄存器中的一种方式,从而允许链接器为您解析它。具有 PC 相对负载(来自池)的最坏情况。

那么立即数=0x1234呢?一些汇编语言支持这种技巧。

Gnu 汇编器支持这一点,如果你使用 ldr 它会优化(正如 Jester 也指出的那样,32 位)。 (一些arm汇编语言仅生成pc相对负载)。

ldr x1,=0
ldr x1,=1
ldr x1,=2
ldr x1,=3
ldr x1,=0x12345678
ldr x1,=0x123456789ABC

Disassembly of section .text:

0000000000000000 <.text>:
   0:   580000c1    ldr x1, 18 <.text+0x18>
   4:   580000e1    ldr x1, 20 <.text+0x20>
   8:   58000101    ldr x1, 28 <.text+0x28>
   c:   58000121    ldr x1, 30 <.text+0x30>
  10:   58000141    ldr x1, 38 <.text+0x38>
  14:   58000161    ldr x1, 40 <.text+0x40>
    ...
  20:   00000001
  24:   00000000
  28:   00000002
  2c:   00000000
  30:   00000003
  34:   00000000
  38:   12345678
  3c:   00000000
  40:   56789abc
  44:   00001234

32位优化

    ldr r0,=0
    ldr r0,=1
    ldr r0,=2
    ldr r0,=3
    ldr r0,=0x11000000
    ldr r0,=0x00110000
    ldr r0,=0x00001100
    ldr r0,=0x00000011
    ldr r0,=0x12345678


00000000 <.text>:
   0:   e3a00000    mov r0, #0
   4:   e3a00001    mov r0, #1
   8:   e3a00002    mov r0, #2
   c:   e3a00003    mov r0, #3
  10:   e3a00411    mov r0, #285212672  ; 0x11000000
  14:   e3a00811    mov r0, #1114112    ; 0x110000
  18:   e3a00c11    mov r0, #4352   ; 0x1100
  1c:   e3a00011    mov r0, #17
  20:   e51f0004    ldr r0, [pc, #-4]   ; 24 <.text+0x24>
  24:   12345678

我猜测 aarch64 gnu 汇编器将标签视为 64 位,这并不意味着它们无法将其解析为 mov 指令中的立即数。

ldr x1,=0
ldr x1,=1
ldr x1,=2
ldr x1,=3
ldr x1,=0x12345678
mov x1,0
mov x1,1
mov x1,2
mov x1,3
mov w1,0
mov w1,1
mov w1,2
mov w1,3
b .



0000000000000000 <.text>:
   0:   580001c1    ldr x1, 38 <.text+0x38>
   4:   580001e1    ldr x1, 40 <.text+0x40>
   8:   58000201    ldr x1, 48 <.text+0x48>
   c:   58000221    ldr x1, 50 <.text+0x50>
  10:   58000241    ldr x1, 58 <.text+0x58>
  14:   d2800001    mov x1, #0x0                    // #0
  18:   d2800021    mov x1, #0x1                    // #1
  1c:   d2800041    mov x1, #0x2                    // #2
  20:   d2800061    mov x1, #0x3                    // #3
  24:   52800001    mov w1, #0x0                    // #0
  28:   52800021    mov w1, #0x1                    // #1
  2c:   52800041    mov w1, #0x2                    // #2
  30:   52800061    mov w1, #0x3                    // #3
  34:   14000000    b   34 <.text+0x34>
    ...
  40:   00000001
  44:   00000000
  48:   00000002
  4c:   00000000
  50:   00000003
  54:   00000000
  58:   12345678
  5c:   00000000

在指令文档中可以看到有一个16位立即数和一些移位选项。

mov x1,0x1234
mov x1,0xABCD
mov x1,0xABCD0000
mov x1,0xABCD00000000
mov x1,0xABCD000000000000
ldr x1,=2000000000
b .

Disassembly of section .text:

0000000000000000 <.text>:
   0:   d2824681    mov x1, #0x1234                 // #4660
   4:   d29579a1    mov x1, #0xabcd                 // #43981
   8:   d2b579a1    mov x1, #0xabcd0000             // #2882338816
   c:   d2d579a1    mov x1, #0xabcd00000000         // #188896956645376
  10:   d2f579a1    mov x1, #0xabcd000000000000     // #-6067193122998190080
  14:   58000061    ldr x1, 20 <.text+0x20>
  18:   14000000    b   18 <.text+0x18>
  1c:   00000000
  20:   77359400
  24:   00000000

您的值 0x0000000077359400 不符合有效的模式。所以它必须是相对于电脑的负载。

如果您碰巧知道/记住/编写指令集规则的代码,那么您可以使用 mov 来表示简单的值,例如 1,2,3,4...Arm 使用术语别名(其他人可能会说伪指令),但是 mov正如您所看到的,上面的情况实际上是几个不同的指令(movz 表示移位的指令)。

Jester 完全在评论中回答了这个问题,我只是对此进行扩展并调查有关优化的评论。我想看看自己是否缺乏优化。为上面的评论点赞。

我认为根据文档这对您有用,我自己还没有在硬件上尝试过。

.equ SIZE, 2000000000

mov x1, SIZE&0xFFFF0000
movk x1,SIZE&0x0000FFFF

Disassembly of section .text:

0000000000000000 <.text>:
   0:   d2aee6a1    mov x1, #0x77350000             // #1999962112
   4:   f2928001    movk    x1, #0x9400

这可能比负载快,也可能不快(并且占用的空间更少)。

© www.soinside.com 2019 - 2024. All rights reserved.