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 位的代码的其他部分)。
我们在默认配置中使用 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 位的代码的其他部分)。