2

我有一个 RPi4,我正在尝试在汇编中编写一些代码以循环 1000 次。当我设置较少的循环数时,代码可以正常工作,但是当我尝试将其设置为 1001 时,会gcc说:

loop.s: Assembler messages:
loop.s:15: Error: invalid constant (3e9) after fixup

这是代码:

.data
ms3: .asciz "%d\n"
.text
.global main
.extern printf
main:
    push {ip, lr}
    mov r1, #0
    mov r5, #1001

loop1000:
    push {r1}
    ldr r0, =ms3
    bl printf
    pop {r1}
    add r1, #1
    cmp r1, r5
    bne loop1000
    pop {ip, pc}
4

1 回答 1

4

汇编语言是由工具而不是目标定义的,因此指令的解决方案和确切语法会有所不同。您提到了 gcc,这意味着 gnu 汇编器,尽管 gcc 被输入汇编语言是另一种 gnu arm 汇编语言

使用 gnu 汇编器, ldr = 伪指令将尝试使用最佳指令,否则它将执行相对于 pc 的加载。如果你想要完全控制,那么只使用 ldr = 东西作为标签(显然是它的初衷)

.cpu arm7tdmi
ldr r5,=1001
ldr r5,=0x00990000
ldr r5,=0x00990099
ldr r5,=0x90000009


.thumb
.cpu cortex-m0
ldr r5,=1001

.cpu cortex-m3
ldr r5,=1001
movw r5,#1001
ldr r5,=0x00990099
.align

Disassembly of section .text:

00000000 <.text>:
   0:   e59f5018    ldr r5, [pc, #24]   ; 20 <.text+0x20>
   4:   e3a05899    mov r5, #10027008   ; 0x990000
   8:   e59f5014    ldr r5, [pc, #20]   ; 24 <.text+0x24>
   c:   e3a05299    mov r5, #-1879048183    ; 0x90000009
  10:   4d03        ldr r5, [pc, #12]   ; (20 <.text+0x20>)
  12:   f240 35e9   movw    r5, #1001   ; 0x3e9
  16:   f240 35e9   movw    r5, #1001   ; 0x3e9
  1a:   f04f 1599   mov.w   r5, #10027161   ; 0x990099
  1e:   bf00        nop
  20:   000003e9    andeq   r0, r0, r9, ror #7
  24:   00990099    umullseq    r0, r9, r9, r0

从你的问题开始。

  10:   4d03        ldr r5, [pc, #12]   ; (20 <.text+0x20>)

1001 (0x3e9) 不适合 mov 立即拇指指令的 8 位立即数,无旋转。所以使用 ldr = 汇编器创建了一个相对于 pc 的负载,这有利有弊。

仅在某些支持较大立即数的处理器上才有 thumb2 扩展

  12:   f240 35e9   movw    r5, #1001   ; 0x3e9

它甚至可以做这样奇怪的事情。

  1a:   f04f 1599   mov.w   r5, #10027161   ; 0x990099

ldr = 和直接使用 movw 都会产生相同的指令(如预期的那样)。

  12:   f240 35e9   movw    r5, #1001   ; 0x3e9
  16:   f240 35e9   movw    r5, #1001   ; 0x3e9

评论中有一些混乱(每个人都需要阅读文档,而不仅仅是 OP)

   0:   e59f5018    ldr r5, [pc, #24]   ; 20 <.text+0x20>
   4:   e3a05899    mov r5, #10027008   ; 0x990000
   8:   e59f5014    ldr r5, [pc, #20]   ; 24 <.text+0x24>
   c:   e3a05299    mov r5, #-1879048183    ; 0x90000009

arm 模式不能做 0x00990099 的事情,但它可以做 8 个非零位在偶数边界 0x00990000 和 0x90000009 上旋转,但不能做 0x000001FE、0x102 等。

arm 使用 32 位指令,像 mips 和其他指令一样,在可能的立即数位数方面受到限制,同时为操作码留出了空间,因为没有更好的术语。拇指是 16 位,因此可立即使用的空间要少得多。thumb2 扩展添加了额外的指令,这些指令采用 2x16 位,但通常不能使用 arm 编码,但由于某种原因没有使用您在 arm 指令中看到的相同立即方案,所以您有这个反射和移位的东西,而不仅仅是移位事物。

所有这些都在您编写/学习汇编语言时应该随身携带的 arm 文档中。

汇编语言是由工具(汇编程序)而不是目标定义的,因此 gnu 汇编程序和 kiel 以及 ARMasm 和其他人预计会有不同的汇编语言(主要在非指令区域),他们确实如此。对于任何其他目标(x86、mips 等)也是如此,这是一般规则,通常没有标准化的汇编语言,当然对于主线指令集也没有。

说 ldr rx,=label/address 技巧与 gnu 汇编器一起导致了最佳指令,但它的伪代码不是真正的指令,因此预计某些汇编器根本不支持它,而一些支持它的汇编器可能从字面上实现一个 pc 相对负载而不是优化(在可能有一个命令行选项来启用/禁用优化的可能性范围内)。

您为拇指而构建,而拇指则仅限于未移位的 8 位立即数。如果您的 cpu 恰好也支持 thumb2,那么您可以告诉汇编器该命令行或代码中,它将生成优化指令和/或您可以直接指定指令。如果不支持 thumb2,那么您可以直接制作 pc 相对负载

mov r5,hello
...
hello: .word 1001

或者使用 ldr 等于的东西,或者使用多条指令 3 左移 8 orred 与 0xE9,那种东西。

编辑

只为杰克...

.thumb

.cpu cortex-m0
ldr r5,=1001

.cpu cortex-m3
ldr r5,=1001

.align

arm-none-eabi-as --version
GNU assembler (GNU Binutils) 2.34
Copyright (C) 2020 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `arm-none-eabi'.

00000000 <.text>:
   0:   4d01        ldr r5, [pc, #4]    ; (8 <.text+0x8>)
   2:   f240 35e9   movw    r5, #1001   ; 0x3e9
   6:   bf00        nop
   8:   000003e9    andeq   r0, r0, r9, ror #7

对于 armv6m(和 armv4t、armv5t、armv6、当前 armv8ms),您不能使用 movw,这是 OPs 错误消息所暗示的。

对于 armv7、armv7m,您可以使用 ldr 指令生成它,而不必根据您选择的立即数不断更改您的代码,如果您使用 gnu 汇编程序,那么 ldr equals 是最好的方法。

arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00000000 <.text>:
   0:   4d01        ldr r5, [pc, #4]    ; (8 <.text+0x8>)
   2:   f240 35e9   movw    r5, #1001   ; 0x3e9
   6:   bf00        nop
   8:   000003e9    andeq   r0, r0, r9, ror #7

现在,虽然通过 gcc 提供汇编语言是另一种汇编语言,但当使用 ldr equals 时,它仍然可以按预期生成理想的指令。可以使用 movw 的地方可以使用,不能使用的地方不可以,但让我们试试这个。

.thumb

.cpu cortex-m0
ldr r5,=1001

.cpu cortex-m3
movw r5,#1001

.align

没什么好抱怨的。结果相同。

尝试您的建议:

.thumb

.cpu cortex-m0
movw r5,#1001

.cpu cortex-m3
movw r5,#1001

.align

arm-none-eabi-gcc so.s -c -o so.o
so.s: Assembler messages:
so.s:6: Error: selected processor does not support `movw r5,#1001' in Thumb mode

现在你必须去重新编写你的代码。movw 不是一个好的解决方案。

编辑 2(对于 OP)

底线,简短的回答...您收到该消息的原因是您无法生成具有该立即值的 thumb mov 立即指令,因为您将在 arm 文档中看到您没有那么多位。如果当您说 rapi 4 时,您的意思是树莓派 4,它是一个 armv8,它支持支持 thumb2 扩展的 aarch32 (armv7-a)(armv6-m 后包含 movw)

.thumb
ldr r5,=1001
.align

使用 ldr equals 发现最优指令

arm-none-eabi-as -march=armv7a so.s -o so.o
arm-none-eabi-objdump -D so.o

so.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <.text>:
   0:   f240 35e9   movw    r5, #1001   ; 0x3e9

如果你愿意,然后直接使用它

.thumb
ldr r5,=1001
movw r5,#1001
.align

Disassembly of section .text:

00000000 <.text>:
   0:   f240 35e9   movw    r5, #1001   ; 0x3e9
   4:   f240 35e9   movw    r5, #1001   ; 0x3e9

如果这确实是 raspberry pi 4,那么您需要 armv7-ar 架构参考手册来涵盖 aarch32 的内容,并需要 armv8(不是 8m)架构参考手册来涵盖 aarch64 的内容。还有一个不同的 gnu 工具链,因为它是一个完全不同的指令集(aarch64-whatever-whatever vs arm-whatever-whatever)。在 aarch64 中(还没有)没有拇指指令。

于 2020-05-14T15:37:38.427 回答