在ml64的xmm和通用寄存器之间移动四字



在为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不是真正助记符的一部分。)

最新更新