Gcc 铿锵汇编程序的奇怪行为

Gcc 铿锵汇编程序的奇怪行为,gcc,assembly,clang,llvm,x86,Gcc,Assembly,Clang,Llvm,X86,我试图编译Zend engine的这个溢出检测宏: #define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do { \ long __tmpvar; \ __asm__( \ "mul %0, %2, %3\n" \

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

#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)
在组装中得到了这个结果:

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

; InlineAsm End

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

汇编代码有问题。根据GCC关于以下方面的文件:

对不能与输入重叠的所有输出操作数使用“&”约束修饰符(请参见修饰符)。否则,GCC可能将输出操作数分配到与不相关的输入操作数相同的寄存器中,前提是汇编器代码在生成输出之前使用其输入。如果汇编代码实际上由多条指令组成,则此假设可能是错误的


这基本上是说,从您写入一个没有用符号标记的输出参数的那一刻起,就不允许再使用输入参数,因为它们可能已被覆盖。

该语法是围绕包装单个insn的概念设计的,该insn在写入其输出之前读取其输入

当您使用多个INSN时,通常需要在约束上使用早期的clobber修饰符(
“=&x”
),以便在读取所有输入之前让编译器知道您写入了输出或读写寄存器。然后它将确保输出寄存器与任何输入寄存器不是同一个寄存器

另请参见TagWiki,以及我的内联asm文档集和答案

您真的需要将所有这些说明放在内联asm中吗?您不能将
long tmp=a*b
作为输入操作数吗?然后,如果编译器需要函数中其他地方的
a*b
,CSE可以看到它

。因此,希望您可以劝说编译器以这种方式执行
sub
。然后它可以使用
subs
sub
设置标志,而不需要在
usedval
上进行单独的测试insn

如果你不能让你的目标编译器生成你想要的代码,那么当然,给内联asm一个机会。但请注意,我见过使用内嵌asm的clang比gcc糟糕得多。它倾向于使内联代码变得更糟糕
x86上的asm。

答案几乎正确,原因错误。“输入参数使用两次”是胡说八道。实际上,在读取最后一个输入参数之前,所有写入的输出参数都需要它。谢谢@Peter Cordes!主要原因是由于该函数是在最新的php源代码中定义的,所以我根本不想弄乱它。宏位于#内,如果仅适用于aarch64。@Sunary。我不认为
long\uu tmpvar=(long)a*(long)b
是“凌乱的”,除非
a
b
有不同的类型,或者在AARC64上编译得不好。
#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do {   \
    long __tmpvar;                                                  \
    __asm__( \
        "mul   %[tmp], %[a], %[b]\n\t"                              \
        "smulh %[uv], %[a], %[b]\n\t"                               \
        "sub   %[uv], %[uv], %[tmp], asr #63\n"                     \
            : [tmp] "=&X"(__tmpvar), [uv] "=&X"(usedval)            \
            : [a] "X"(a), [b] "X"(b));                              \
    if (usedval) (dval) = (double) (a) * (double) (b);              \
    else (lval) = __tmpvar;                                         \
} while (0)