ARM内联汇编 - 输入操作数约束包含'='

3
这是我的当前代码:
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的值不会改变。
1个回答

4
错误信息告诉你出了什么问题——= 约束只适用于输出,而你的 asm 模式有两个输入(其中一个令人困惑地称为“dst”)和没有输出。你可能希望将“dst”作为输出:
asm("rev %[dst], %[src]" : [dst]"=r"(val) : [src]"r"(val));

1
asm("rev %[swap], %[swap]" : [swap] "=r" (val) : "0" (val)); 可能更好。您可以使用 "0" 指定符号来表示输入与给定输出相同;这样做有时会生成更好的代码,因为寄存器是相同的。另外,src/dst 很令人困惑,正如您所指出的那样。 - artless noise
@artlessnoise:使用0约束将强制它使用相同的寄存器用于源和目标,这可能需要额外的移动来将它们放在同一位置。使用单独的输入和输出约束允许编译器使用相同的寄存器或不同的寄存器,以哪个更好为准。在这种特定情况下,这是无关紧要的,但使用0永远不会更好。 - Chris Dodd
@artlessnoise:dst 只是一个操作寄存器的标识符名称,因此无法通过任何方式进行计算。如果 val 已经在特定寄存器(例如参数寄存器)中,并且下一步需要在另一个寄存器中使用(例如返回值寄存器),则 0 将需要额外的移动。 - Chris Dodd
即使你禁用SSA(像任何有用的编译器一样),gcc也会执行实时范围分裂,因此val在汇编指令之前和之后具有相同的名称并不意味着它在同一位置。一个0会造成伤害的例子是:如果你有一个函数u32 fn(int ign, u32 val) { asm(...); return val; },使用0将会有3条指令(rev+mov+ret),而不使用则只有rev+ret。 - Chris Dodd
是的,这是真的。虽然它不像OP的代码那样,但我肯定发现当输入和输出相同时使用“0”更容易理解。我刚试过了OP的代码和gcc 4.8.2,两者的代码完全相同。主要是因为在他的示例中,int32hexbinhex在同一个寄存器(R0)中具有val。 “0”注释排除了rev可以用作swap+move,这是确实的。然而,gcc 4.8.2 可以使用您的注释相同的寄存器,因此从代码生成的角度来看,它可能总是更好。 - artless noise

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接