在为Microsoft的x64汇编器编写的一个简单程序中,我想在SSE寄存器(例如xmm0)和通用寄存器(例如rcx)之间移动一个64位值,如MASM>:
中的mov xmm0, rcx
...
mov rcx, xmm0
>这两行分别从ml64.exe
生成以下错误消息:
- 错误:协处理器寄存器不能作为第一操作数
- 错误A2070:无效指令操作数
然而,在x64中显然可以完成这个简单的任务。例如,下面是一个可以运行的x64程序,我可以使用GCC 4.8.2>:
在GAS <AT&T语法中组装和运行它.text
.globl main
main:
movl $1, %ecx
movq %rcx, %xmm0
movq %xmm0, %rax
ret
>如预期,程序返回值为1,main()
的objdump
输出为:
1004010d0: b9 01 00 00 00 mov $0x1,%ecx
1004010d5: 66 48 0f 6e c1 movq %rcx,%xmm0
1004010da: 66 48 0f 7e c0 movq %xmm0,%rax
1004010df: c3 retq
所以我的问题是,如果ml64.exe
产生上述错误,我如何在MASM中实现这一点?
MOV
指令不能在通用寄存器和xmm
寄存器之间移动数据。您要查找的指令是MOVQ
(与您所显示的A&T语法代码一样),如英特尔指令集手册中定义的那样。(HTML节选:https://www.felixcloutier.com/x86/movd:movq)
ML64不接受MOVQ
的事实与英特尔的手册不一致,因此-至少在我看来-一个bug(或至少不一致)。
ML64似乎确实使用MOVD
来代替它,即使是64位寄存器。您可以通过反汇编它生成的代码来验证这一点。
请注意,有两个不同的movq
指令(不计算加载和存储形式作为单独的):
-
一个是
movq xmm, xmm/m64
形式,MMX/SSE2指令在矢量寄存器或加载/存储之间复制。这在使用MMX(和SSE2)的32位模式下存在,并且操作码总是暗示64位传输(使用XMM目标从0扩展到128)。ML64对这个表单使用movq
。 -
另一个是64位版本的
movd xmm, r/m32
,它可以在XMM或MMX寄存器和gp整数寄存器(如RCX)或内存之间移动数据。这种形式在x86-64(包括MMX和SSE2)中是新的;操作码与movd
相同,带有REX。W前缀表示64位操作数大小。ML64显然总是对这种形式使用movd
,而不管实际操作数的大小。
在XMM寄存器和内存之间的64位加载或存储可以使用任何一种操作码,但第一种形式更短,不需要REX前缀。
(AT&T语法movq %rax, %rcx
只是mov
加上q
operand-size后缀;在这种情况下,q
不是真正助记符的一部分。)