【问题标题】:ARM inline assembly - input operand constraint contains '='ARM 内联汇编 - 输入操作数约束包含“=”
【发布时间】:2013-11-02 00:49:23
【问题描述】:

这是我当前的代码:

void int32hex(u32 val, char *out) {
    asm("rev %[dst], %[src]" :: [dst]"=r"(val), [src]"r"(val));

    binhex((u8*)&val, 4, out);
}

我的想法是获取参数val,使用rev 指令翻转它(字节序),然后将其传递。

根据我的阅读,上面的代码似乎是正确的,目标寄存器有=r 标志,这意味着可以写入该寄存器。但是,当通过 GCC 运行时,出现错误:输入操作数约束包含 '='

如果我将标志更改为简单的r,那么它可以正常编译,但val 的值不会改变。

【问题讨论】:

    标签: c gcc assembly arm inline-assembly


    【解决方案1】:

    错误告诉您出了什么问题——= 约束仅适用于输出,而不适用于输入,并且您的 asm 模式有两个输入(一个容易混淆地称为“dst”)并且没有输出。您可能打算将“dst”作为输出:

    asm("rev %[dst], %[src]" : [dst]"=r"(val) : [src]"r"(val));
    

    【讨论】:

    • asm("rev %[swap], %[swap]" : [swap] "=r" (val) : "0" (val)); 可能会更好。您可以使用“0”说明符来表示输入与给定输出相同;这有时会生成更好的代码,因为寄存器是相同的。此外,您注意到 src/dst 令人困惑。
    • @artlessnoise:使用0 约束将强制它为 src 和 dst 使用相同的寄存器,这可能需要额外的移动才能将它们放到同一个位置。使用单独的输入和输出约束允许编译器使用相同的寄存器或不同的寄存器,以更好者为准。在这种特定情况下,它是无关紧要的,但使用0 永远不会更好。
    • @artlessnoise: dst 只是操作数寄存器的标识符名称,因此无法以任何方式计算。如果val 已经在特定寄存器(可能是参数寄存器)中并且接下来需要在不同的寄存器中(例如,返回值寄存器),0 将需要额外的移动
    • gcc 会进行实时范围分割,即使您禁用 SSA(就像任何有用的编译器一样),所以 val 在 asm 指令之前和之后具有相同名称的事实并不意味着它是在同一个位置。 0 受伤的一个例子——如果你有一个函数 u32 fn(int ign, u32 val) { asm(...); return val; }。使用0 这将是 3 条指令(rev+mov+ret),没有它只会是 rev+ret。
    • 是的,这是真的。虽然它不像 OPs 代码。当输入和输出相同时使用“0”,我肯定会更容易理解。我刚刚用 OPs 代码和 gcc 4.8.2 尝试了这个,两者的代码是相同的。主要是因为在他的例子中,int32hexbinhex 在同一个寄存器(R0)中有val。 “0”注释打折rev 可以用作swap+move,这当然是正确的。但是,gcc 4.8.2 可以在注释中使用相同的寄存器,因此从代码生成的角度来看,它可能总是更好。
    猜你喜欢
    • 1970-01-01
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多