【问题标题】:GCC ARM register expected预期 GCC ARM 寄存器
【发布时间】:2014-06-01 11:06:36
【问题描述】:

我正在尝试将 bunny 移植到 armv7h,它使用了一些我无法转换为 asm 的 x86 asm 内容。

static __inline__ void atomic_inc(volatile int* ptr){
    __asm__ __volatile__("lock incl %0": "=m" (*ptr): "m" (*ptr));
}    

static __inline__ void atomic_dec(volatile int* ptr){
    __asm__ __volatile__("lock decl %0": "=m" (*ptr): "m" (*ptr));
}

有什么,我试过了

"ADD/SUB %0 %0": "=r" (*ptr): "m" (*ptr));

两个都给

Error: ARM register expected -- `add [r3] [r3]'

Error: ARM register expected -- `sub [r4] [r4]'

编译使用:

armv7l-unknown-linux-gnueabihf-gcc -Wall -O3 -funroll-loops -fno-strict-aliasing
-ffast-math -Wno-pointer-sign -mcpu=cortex-a15 -mfpu=neon -marm

【问题讨论】:

  • "m" 是错误的约束,首先(它应该是“0”,我认为 - 我讨厌 GCC 的扩展 asm 有多么令人困惑)。更一般地说,这不会是原子的。简单搜索 ARM 参考手册或在此处将告诉您如何使用 LDREX/STREX 实现原子。
  • @Notlikethat 尝试给出“警告匹配约束不允许注册”并且仍然错误。

标签: c gcc assembly arm inline-assembly


【解决方案1】:

线索在于错误信息——完全准确。

ARM 算术指令占用三个operands:

ADD{S} rd, rs, <operand>

SUB{S} rd, rs, <operand>

operand 是其中之一:

  • 一个寄存器
  • 立即数
  • 按常数移位的寄存器
  • 一个寄存器被另一个寄存器移位

在你的情况下,我想你会想要一个直接常量 1,它会给出一个汇编指令

ADD rd, rd, #1

但是,这忽略了您试图实现内存位置的原子增量的根本缺陷。为了实现ptr 的取消引用,编译器正在从内存指令生成负载。它不会立即明显地生成结果的存储。即使这样做,这充其量也只是 3 条指令(加载、递增、存储)的非原子序列。

我建议您查看GCC's atomic intrinsics 而不是自己滚动。

【讨论】:

  • 我没有自己滚动,它已经在源代码中了。我对 ARM asm 不是很熟悉,这应该很明显。 ADD rd, rd, #1 将如何转换为内联 asm?
  • @user3696583 询问 asm 意味着您正在自行开发。为什么不使用__sync_fetch_and_add(ptr,1),它在 x86 和 arm 上也能正常工作?
  • 如果是这种情况,则该实现从根本上被破坏,并且没有提供这些函数的调用者所期望的线程安全优势。实现此功能的最简单方法是使用 C++11 的 std::atomic - 它提供了真正原子的 ++ 运算符。 C11 的atomic_compare_exchange_weak 也可以循环使用,但这需要更多的努力。
  • @user3696583 我和@Marc Glisse 一起讨论这个问题。在汇编程序中正确实现原子操作是很困难的——尤其是在正确的位置获得内存屏障。通常实现需要使用自旋锁和LDREX and STREX 指令。鉴于您刚刚提出了一个关于 ARM 汇编程序的非常基本的问题,并且未能发现现有方法的明显问题,因此您在汇编程序中手动处理这个问题的机会很小。使用已知的工作实现,仅出于可移植性的原因,首选来自 C11 或 C++11 的实现,而不是 GCC 的内在函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-28
  • 2011-02-23
  • 1970-01-01
  • 2017-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多