Clang 集成汇编器和 "invalid operand for instruction"

Clang integrated assembler and "invalid operand for instruction"

我们在默认配置中使用 Clang。在默认配置中,使用 Clang 的集成汇编程序(而不是系统汇编程序,如 GAS)。我无法确定以下问题的确切问题(并修复):

$ make
clang++ -DNDEBUG -g2 -O3 -Wall -fPIC -march=native -pipe -c gcm.cpp
...
gcm.cpp:676:3: error: invalid operand for instruction
                AS2(    movd    WORD_REG(di), xmm...
                ^
./cpu.h:221:20: note: expanded from macro 'AS2'
        #define AS2(x, y) GNU_AS2(x, y)
                          ^
./cpu.h:216:27: note: expanded from macro 'GNU_AS2'
        #define GNU_AS2(x, y) "\n\t" #x ", " #y ";"
                             ^
<inline asm>:110:12: note: instantiated into assembly here
        movd rdi, xmm0;
                  ^~~~~
gcm.cpp:685:3: error: invalid operand for instruction
                AS2(    movd    WORD_REG(di), xmm...
                ^
./cpu.h:221:20: note: expanded from macro 'AS2'
        #define AS2(x, y) GNU_AS2(x, y)
                          ^
./cpu.h:216:27: note: expanded from macro 'GNU_AS2'
        #define GNU_AS2(x, y) "\n\t" #x ", " #y ";"
                                 ^
<inline asm>:117:12: note: instantiated into assembly here
        movd rdi, xmm1;
                  ^~~~~

认为以上错误可能与Inline Assembly and Compatibility有关。但据我所知,rdi是64位,xmm1是128位,movd指定操作数大小,所以兼容性问题应该不适用。

上面的代码有什么问题?


您可以在 Crypto++ gcm.cpp Source File 在线查看源文件。如果您安装了 Clang,这个问题应该很容易重现:

git clone https://github.com/weidai11/cryptopp.git cryptopp-asm
cd cryptopp-asm
export CXX=clang++
make GAS210_OR_LATER=1 GAS219_OR_LATER=1 GAS219_OR_LATER=1

或者:

# Try to make just gcm.o
make GAS210_OR_LATER=1 GAS219_OR_LATER=1 GAS219_OR_LATER=1 gcm.o

奇怪的 make 行是由于 LLVM Bug 24200 - With integrated assembler enabled, failed to fetch version string of assembler.

r/m64, xmm 在 Intel 的软件开发人员手册中未被列为 MOVD 指令的有效操作数组合。但是,支持以下两种形式:

MOVD r/m32, xmm
SSE2 Move doubleword from xmm register to r/m32.

MOVQ r/m64, xmm
SSE2 Move quadword from xmm register to r/m64.

这让我怀疑在构建 64 位目标时 MOVD 指令需要是 MOVQ,或者 rdi 应该被 edi(尽管这可能会影响依赖于 rdi 前 32 位的代码的其他部分)。