clang汇编程序的奇怪行为

Sun*_*ary 2 assembly gcc llvm clang

我试图编译Zend引擎的这个溢出检测宏:

#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do {   \
    long __tmpvar;                                                  \
    __asm__( \
        "mul %0, %2, %3\n"                                      \
        "smulh %1, %2, %3\n"                                        \
        "sub %1, %1, %0, asr #63\n"                                 \
            : "=X"(__tmpvar), "=X"(usedval)                         \
            : "X"(a), "X"(b));                                      \
    if (usedval) (dval) = (double) (a) * (double) (b);              \
    else (lval) = __tmpvar;                                         \
} while (0)
Run Code Online (Sandbox Code Playgroud)

并在装配中得到了这个结果:

; InlineAsm Start
mul     x8, x8, x9
smulh   x9, x8, x9
sub x9, x9, x8, asr #63

; InlineAsm End
Run Code Online (Sandbox Code Playgroud)

编译器仅对宏的输入和输出使用2个寄存器,我认为它必须至少为3,并导致错误的计算结果(例如,-1*-1).有什么建议吗?

Seb*_*edl 5

汇编代码有缺陷.来自GCC关于扩展asm的文档:

在所有不必与输入重叠的输出操作数上使用'&'约束修饰符(请参阅修饰符).否则,GCC可以将输出操作数分配到同一寄存器中作为不相关的输入操作数,前提是汇编代码在产生输出之前消耗其输入.如果汇编程序代码实际上包含多个指令,则此假设可能为false.

这基本上表示从您写入未标记为&符号的输出参数的那一刻起,您不能再使用输入参数,因为它们可能已被覆盖.