【问题标题】:C variable usage in assembly, how to choose 32bit operands in arm aarch64汇编中的C变量使用,arm aarch64中如何选择32位操作数
【发布时间】:2015-11-16 18:40:42
【问题描述】:

我正在尝试在汇编中使用 C 变量。目的是读取一个 32bit 的内存,并赋值给一个 C 变量。

uint32_t ASMRegRd32(uint32_t addr) {

uint32_t data;

    asm volatile (

        "ldr %0, [%1]"          "\n"

        : "=r" (data)

        : "r"(addr)

          );

return data;

}

遗憾的是,在 AARCH64 上,ldr 指令返回一个 64 位值,因为编译器正在选择一个 64 位操作数 Xt。

如何限制它使用 32 位操作数?
这应该工作吗?

ldr w0, [%1];

mov %0, w0;

【问题讨论】:

  • 你的意思是ldr %w0, [%1]?因为看起来您正在尝试使用x86 Operand Modifiers。我不会说 aarch64(根本不会),但我很确定 x86 修饰符在这里不起作用。如果你这样做(说 aarch64 汇编器),你可以尝试浏览实际的 gcc code 以获取约束。也许你会在那里看到一些你可以使用的东西。
  • 您需要写%w0 而不是只写%0 才能得到w0 而不是x0。 Clang 应该得到一个警告告诉
  • 是的,我的意思是 %w0。它奏效了。谢谢。

标签: c gcc arm inline-assembly arm64


【解决方案1】:

您使用约束模板修饰符“w”。

asm (
    "ldr %w[DST],[%[SRC]]" "\n"
    : [DST] "=r" (data) // 32 bit variable
    : [SRC] "X" (addr) // source address variable (expands into a x register)
);

【讨论】:

  • +1 是的,显然需要一个操作数修饰符,因为uint32_t 选择了一个 64 位寄存器!?! (godbolt.org/z/h3gXGF),但这仍然没有告诉编译器addr 指向的内存是输入,以及指针值本身。 "memory" clobber,或者像 "m"(*addr) 这样的内存源操作数。否则,死存储消除可能会删除在内联汇编读取之前更新该内存的存储。
【解决方案2】:

如果您不想在 A32 编译器中重新编译代码,也许您应该像下面这样更改您的 API。

uint32_t ASMRegRd32(uint64_t addr) {

uint32_t data;

asm volatile (
    "ldrh w0, [%1]\n"
    : "=&r" (data)
    : "r"(addr)
    : "cc"
      );

return data;

}

因为默认寄存器是64位的,所以64位到32位的var addr转换会导致程序core dump。

【讨论】:

  • @MarcGlisse 因为 ARM 返回值总是存储在寄存器 x0/w0 中。
  • 您在某种程度上依赖于寄存器分配器可能将 x0 分配给内联汇编中的数据这一事实。这在某些情况下可能有效,但它太脆弱了。
  • 使用“%w0”,因为在使用此 API 之前我必须将 w0 推送/弹出到堆栈,这对我来说就像 200% 的额外代码。谢谢
猜你喜欢
  • 2020-04-11
  • 1970-01-01
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-17
相关资源
最近更新 更多