【问题标题】:Questions on atomic_add function of arch/arm64/include/asm/atomic.h关于arch/arm64/include/asm/atomic.h的atomic_add函数的问题
【发布时间】:2021-07-21 04:34:11
【问题描述】:

我对基于 Linux 内核的 C 编码风格非常陌生。我试图从“arch/arm64/include/asm/atomic.h”文件(here 的第 112-124 行)中了解“atomic_add”函数的以下实现。

static inline void atomic_add(int i, atomic_t *v)
{ 
    unsigned long tmp;
    int result;
    asm volatile("// atomic_add\n"
        "1: ldxr    %w0, %2\n"
        "   add %w0, %w0, %w3\n"
        "   stxr    %w1, %w0, %2\n"
        "   cbnz    %w1, 1b"
        : "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
        : "Ir" (I));

}

请帮助我理解以下问题。

  1. %w0 或 %w3 是什么意思?我知道 %2 指的是计数器值。

  2. %w0 是指(结果)变量还是通用寄存器?

  3. 约束字符串“Ir”是否代表“立即寄存器”?

【问题讨论】:

  • %0 指的是第一个参数。 w 是一个修饰符。有一些关于手臂修饰符here 的讨论。特别是,您可能会发现指向 armclang 的链接很有用。 "Ir" 是约束并且被记录在here.

标签: linux-kernel embedded-linux atomic inline-assembly arm64


【解决方案1】:
  1. w 是一个模板修饰符。它使内联汇编包含寄存器的 32 位名称(w0 等),而不是默认的 64 位名称(x0)。请参阅 David Wohlferd 链接的 documentation。你也可以try it,注意如果你写%0而不是%w0,生成的指令使用64位x寄存器。这不是您想要的,因为这些应该是 32 位加载和存储。

  2. 两者兼而有之。与 GCC 样式的扩展 asm 一样,%w0 指的是内联 asm 的操作数编号 0(如前所述,w 修饰符使用其 32 位名称)。这是用"=&r" (result) 声明的那个。由于约束是r,这个操作数将被分配一个通用寄存器,并且所有在asm 代码中提到的%0(分别为%w0)都将被替换为该寄存器的名称。在上面的 Godbolt 示例中,编译器选择了 x9(分别为 w9)。

    (result) 表示在 asm 语句之后,编译器应该将 w9 中剩余的内容存储在变量 result 中。它可以通过存储到内存或mov 到用于result 的任何寄存器来执行此操作,或者它可以只在该变量本身中分配result。运气好的话,优化器应该选择后者;并且由于result 没有用于asm 之后的任何内容,因此它不应该对该寄存器做任何进一步的事情。所以实际上,一个输出操作数带有一个之后不使用的变量是一种告诉编译器“请选择一个我可以用作暂存器的寄存器”的方式。

  3. 这是两个约束,Ir。约束由 GCC 记录:simplemachine-specific,当给出多个约束时,编译器可以选择满足其中任何一个。

    I 要求一个适合在 AArch64 add 指令中使用的立即数,即一个 12 位零扩展数,可选地移位 12 位,这是一个编译时常数。如您所知,r 要求提供通用寄存器。因此,如果您编写 atomic_add(1, &c)atomic_add(1+1+1, &c)atomic_add(4095, &c)atomic_add(4096, &c) 中的任何一个,asm 语句的第二行将立即发出 add 指令,并将您的常量直接编码到指令中: add w9, w9, #1 等等。但是,如果您编写atomic_add(4097, &c)atomic_add(my_variable, &c),编译器将在asm 之前生成附加代码,以将适当的值加载到某个寄存器(例如w13)并在asm 中发出add w9, w9, w13。这让编译器可以尽可能生成更有效的即时add,同时通常仍能获得正确的代码。

【讨论】:

  • 可能不会有什么坏处,提到使用atomic builtins 可能会更好地提供新代码,而不是尝试使用内联汇编来滚动您自己的代码。事实上,一个论点can be made 根本不使用内联asm...
  • @DavidWohlferd:除非它是为 Linux 内核编写的新代码,否则它当然应该使用现有的atomic_add 函数。但是,是的,人们不应该将其移植到他们自己的用户空间代码中,而只是将其作为理解内核如何完成工作的一种方式。
  • 建立在 Peter 所说的基础上,特别是对于 Linux 内核,内核内存模型接近不完全与 C11 相同记忆模型。例如,请参阅这篇 2018 年的论文,探讨其中的一些差异。 open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0124r6.html.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-12
  • 1970-01-01
相关资源
最近更新 更多