Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/silverlight/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 在ml64中的xmm和通用寄存器之间移动四字?_Assembly_X86 64_Masm_Sse_Gnu Assembler - Fatal编程技术网

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

Assembly 在ml64中的xmm和通用寄存器之间移动四字?,assembly,x86-64,masm,sse,gnu-assembler,Assembly,X86 64,Masm,Sse,Gnu Assembler,在为微软x64汇编程序编写的一个简单程序中,我想在SSE寄存器(比如xmm0)和通用寄存器(比如rcx)之间移动一个64位值,如下所示: 这两行分别从ml64.exe生成以下错误消息: 错误A2152:协处理器寄存器不能是第一个操作数 错误A2070:指令操作数无效 但是,显然可以在x64中完成此简单任务。例如,以下是一个运行正常的x64程序,我可以在气体中组装和运行: 与预期一样,此程序的返回值为1,main()的objdump输出为: 1004010d0: b9 01 00 00 0

在为微软x64汇编程序编写的一个简单程序中,我想在SSE寄存器(比如xmm0)和通用寄存器(比如rcx)之间移动一个64位值,如下所示:

这两行分别从
ml64.exe
生成以下错误消息:

  • 错误A2152:协处理器寄存器不能是第一个操作数
  • 错误A2070:指令操作数无效
但是,显然可以在x64中完成此简单任务。例如,以下是一个运行正常的x64程序,我可以在气体中组装和运行:

与预期一样,此程序的返回值为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
产生上述错误,
MOV
指令无法在通用寄存器和
xmm
寄存器之间移动数据,那么如何在MASM中实现这一点。您要查找的指令是英特尔标准中定义的
MOVQ
(与您显示的A&T语法代码类似)。(此处提取HTML:)

ML64不接受MOVQ的事实与英特尔的手册不一致,因此——至少在我看来——是一个bug(或者至少是不一致)

ML64似乎使用了
MOVD
来代替它,即使对于64位寄存器也是如此。您可以通过反汇编它生成的代码来验证这一点


请注意,有两种不同的
movq
指令(不单独计算加载和存储表单):

  • 一种是form,即MMX/SSE2指令,它在向量寄存器或加载/存储之间进行复制。这存在于32位模式下的MMX(和SSE2),操作码总是意味着64位传输(零扩展到128位,使用XMM目标)。ML64对此表单使用
    movq

  • 另一种是64位版本的,可以在XMM或MMX寄存器和GP整数寄存器(如RCX或内存)之间移动数据。此表单是x86-64(包括MMX和SSE2)的新表单;操作码与
    movd
    相同,64位操作数大小的前缀为REX.W。ML64显然总是对此窗体使用
    movd
    ,而与实际操作数大小无关

XMM寄存器和内存之间的64位加载或存储可以使用任一操作码,但第一种形式较短,不需要REX前缀


(AT&T语法
movq%rax,%rcx
只是带有
q
操作数大小后缀的
mov
;在这种情况下
q
不是真正的助记符的一部分。)

有趣的是,在这种情况下
movq
不是AT&T的发明,这就是实际的指令。请参阅指令集参考。PS:您也可以将objdump转换为英特尔语法。@Jester,我忘了提到
ml64.exe
分别拒绝
movq
(如果我用它代替
mov
),并显示错误消息“error A2150:字寄存器不能作为第一个操作数”和“error A2070:无效的指令操作数”。在我用GAS组装的简单程序上使用MSFT的
dumpbin.exe
,我发现MSFT列出的指令与
movd
相同,所以我尝试了一下,它成功了。如果没有其他人这样做,我会把它作为答案发布。奇怪的是,
movd
应该是32位版本。@Jester:没错。可能是MASM中的一个bug。请参阅上面的帖子和评论。我确实拆开了。ml64似乎接受
movd
,但发出
movq
。目前,我已经发布了一个;不久前我也有同样的问题,所以我的答案是我的记忆。如果你看一下操作码,我想这种行为在某种程度上是有意义的,但我认为它们绝对应该遵守英特尔(或AMD)的助记符命名约定——否则就会陷入混乱。知道你也有同样的问题是很有帮助的!你有空去投票表决“复制”计数吗?@0xbe5077ed投票表决了错误报告,尽管我不知道如何增加“复制”计数……我在你的答案中添加了一个关于不同操作码及其来源的部分。很容易推测,这个ML64设计选择可能是某种使汇编程序内部在将助记符解析为操作码方面更容易的黑客行为。但是其他汇编器对此没有问题,即使是带有
q
操作数大小后缀的
mov
的GAS也只能通过操作数来消除歧义:
.text
    .globl main
main:
    movl $1, %ecx
    movq %rcx, %xmm0
    movq %xmm0, %rax
    ret
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