GNU ARM 汇编程序在错误消息中给出看似无关的寄存器

GNU ARM assembler giving a seemingly irrelevant register in error message

目标

我正在使用 LDREX 和 STREX 指令为 CortexM7 目标使用 gcc 内联汇编构建互斥基元,遵循 ARM 的 Barrier Litmus Tests and Cookbook 文档。

代码

static inline void testAcquireLock(unsigned int *lock) {
  unsigned int tempStore1 = 0;
  unsigned int tempStore2 = 0;

  __asm__ volatile(
      "Loop%=:                         \n\t" // "%=" generates unique #
      "LDREX %[ts1], %[lock]           \n\t" // exclusive read lock
      "CMP %[ts1], #0                  \n\t" // check if 0
      "ITT EQ                          \n\t" // block for below conds.
      "STREXEQ %[ts1], %[ts2], %[lock] \n\t" // attempt to ex. store new value
      "CMPEQ %[ts1], #0                \n\t" // test if store suceeded
      "BNE Loop%=                      \n\t" // retry if not
      "DMB                             \n\t" // mem barrier for subsequent reads
      : [lock] "+l"(*lock), [ts1] "=l"(tempStore1), [ts2] "=l"(tempStore2)
      : // inputs
      : "memory");
}

错误信息

唯一显示的错误如下。汇编程序正在引用 R15,生成的程序集中似乎没有使用它?错误消息中的第 191 行对应于上面看到的第一条 LDREX 指令。

[build] /tmp/ccEU4dXd.s: Assembler messages:
[build] /tmp/ccEU4dXd.s:191: Error: r15 not allowed here -- `ldrex r1,r3'
[build] /tmp/ccEU4dXd.s:194: Error: r15 not allowed here -- `strexeq r1,r2,r3'

Build/Compiler 选项

该项目使用以下编译器设置通过 CMake 配置:

target_compile_options(testing
PRIVATE
    -mcpu=cortex-m7
    -mfpu=fpv5-d16
    -mfloat-abi=hard
    -mthumb
    -Wall
    -fdata-sections
    -ffunction-sections
)

导致错误的编译命令:

[build] /usr/bin/arm-none-eabi-gcc -DSTM32F777xx -DUSE_HAL_DRIVER -I<removed>  -g   -mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb -Wall -fdata-sections -ffunction-sections -std=gnu11 -o <removed>.c.obj   -c <removed>.c

研究/我尝试过的

  1. 阅读后我意识到 armv7 有两个(指令集?语法解析器?),并且处理器可以处于这些(ARM 和 THUMB)的两种模式之一。但是我不是很明白这一点,以及它如何影响手写汇编的解析。

  2. 我怀疑是因为处理器是thumb模式(-mthumb),跟我的inline alias constraints有关系? Per documentation 我尝试在“+l”、“+r”、“+h”之间切换,但似乎没有任何改变。

  3. 我尝试使用硬编码寄存器“r3、r4、r5”而不是内联别名,但出现了同样的错误。

根据@jester 的帮助,我意识到我对锁的 GCC-inline 变量别名有错误的约束。它应该是“+m”,指定内存地址而不是寄存器。

我也是 de-referencing 锁的地址,而我本应将其作为指针保留。

我将 [lock] "+l"(*lock) 更改为 [lock] "+m"(lock),现在可以构建了。