ARM 内联汇编,寄存器读取顺序不正确

ARM inline assembly, registers are read in an incorrect order

我正在尝试使用内联汇编通过 C 读取 ARM 寄存器,但它没有按照应有的顺序执行。

volatile uint32_t var1 = 0;
volatile uint32_t var2 = 0;
volatile uint32_t var3 = 0;
volatile uint32_t var4 = 0;

__asm volatile(
    "mov r0, #5\n\t"
    "mov r1, #6\n\t"
    "mov r2, #7\n\t"
    "mov r3, #8\n\t"
            
    "mov %0, r0\n\t" 
    "mov %0, r1\n\t"
    "mov %0, r2\n\t" 
    "mov %0, r3\n\t"
            
    : "=r" (var1),
    "=r" (var2),
    "=r" (var3),
    "=r" (var4));

发生的情况是输出是;

var1 = 8
var2 = 5
var3 = 6
var4 = 7

我期待的是;

var1 = 5
var2 = 6
var3 = 7
var4 = 8

好像r0是最后读的,而且是从r1开始的。为什么会这样?

注意:忽略代码的用途或变量的定义方式,它是来自更大应用程序的 copy/paste。这只是这个特定的注册行为有问题。

传入内联汇编的参数需要递增;

"mov %0, r0\n\t" 
"mov %1, r1\n\t"
"mov %2, r2\n\t" 
"mov %3, r3\n\t"

GCC-style 汇编插入旨在为每个 asm("...") 插入 单个指令 ,并且它们要求您提供有关 的准确信息所有 涉及的寄存器。在这种情况下,您没有通知编译器内部使用了寄存器 r0、r1、r2 和 r3,因此它可能认为可以为 var1 到 var4 重用其中的一些寄存器。您还重新使用 %0 作为所有四个最终 mov 指令的目的地,因此所有四个指令实际上都在写入 var1.

此外,这可能是也可能不是您的直接问题,但是 volatile doesn't do what you think it does 并且可能在这里没有完成任何有用的事情。

如何解决?好吧,首先,你不能只写

需要有一个非常有力的理由
uint32_t var1 = 5;
uint32_t var2 = 6;
uint32_t var3 = 7;
uint32_t var4 = 8;

假设 这样的原因,那么您应该改为尝试为每个 asm 编写一条指令,并且根本不使用任何临时寄存器...

asm ("mov %0, #5" : "=r" (var1));
asm ("mov %0, #6" : "=r" (var2));
asm ("mov %0, #7" : "=r" (var3));
asm ("mov %0, #8" : "=r" (var4));

如果你真的绝对必须在一个 asm 中完成一大堆工作,那么你应该考虑的第一件事就是将它放在一个单独的 .S 文件中并使其符合 ABI,以便你可以像普通函数一样调用它:

    .text
    .globl do_the_thing
    .type do_the_thing, @function
_do_the_thing:
    ; all your actual code here
    bx r14
.size do_the_thing, .-do_the_thing

然后在你的 C

   rv = do_the_thing(arg1, arg2, ...);

如果那个没办法,那么,也只有到那时,你才应该坐下来阅读整个Extended Asm" GCC 手册的一章,并找出如何将插入的 complete register-usage 行为楔入约束中。如果您需要这方面的帮助,post 一个新问题,您可以在其中显示您需要插入的 真实 汇编语言结构,而不是一个模糊的示例,因为每个小细节都很重要.