xmm8 寄存器值是否在调用中保留?

Is xmm8 register value preserved across calls?

我的 Windows 使用 Visual Studio 2017 编译的程序执行以下操作:

在第一次调用中,默认参数得到正确的 35.05。在第二次调用中,该值是垃圾。

我查看了生成的程序集,在第一次使用默认参数调用时,35.05 从内存位置复制到 xmm8,然后复制到堆栈(它是第 5 个参数)并进行调用:

0033d   48 8b 01     mov     rax, QWORD PTR [rcx]
00340   41 b8 14 00 00
00       mov     r8d, 20 // a default argument
00346   f3 44 0f 10 05
00 00 00 00  movss   xmm8, DWORD PTR __real@420c3333 // this is 35.05
0034f   f3 44 0f 11 44
24 28        movss   DWORD PTR [rsp+40], xmm8
00356   48 c7 44 24 20
1e 00 00 00  mov     QWORD PTR [rsp+32], 30 // a default argument
0035f   45 8d 48 05  lea     r9d, QWORD PTR [r8+5]
00363   b2 0f        mov     dl, 15 // a default argument
00365   ff 90 08 01 00
00       call    QWORD PTR [rax+264]

然后调用初始化JVM。

然后在下一次调用时,再次使用xmm8将值复制到堆栈:

00ce8   48 8b 01     mov     rax, QWORD PTR [rcx]
00ceb   41 b8 14 00 00
00       mov     r8d, 20
00cf1   f3 44 0f 11 44
24 28        movss   DWORD PTR [rsp+40], xmm8
00cf8   48 c7 44 24 20
1e 00 00 00  mov     QWORD PTR [rsp+32], 30
00d01   45 8d 48 05  lea     r9d, QWORD PTR [r8+5]
00d05   b2 0f        mov     dl, 15
00d07   ff 90 08 01 00
00       call    QWORD PTR [rax+264]

但是现在,xmm8已经被覆盖了。

如果我取出初始化 JVM 的调用,那么该值将被保留。

问题是,谁错了? JVM 未保留该值,或者 Microsoft 编译器假设 xmm8 值将被保留是错误的。

Microsoft docs 总结的 Windows x64 调用约定。

RCXRDXR8R9 用作输入整数参数。 XMM0LXMM1LXMM2LXMM3L 是输入浮点参数。 RAXR10R11XMM4XMM5 是易变的。包括 XMM8 在内的所有其他都是非易失性的。

Note that the "Caller/Callee Saved Registers" sub-page is a bit misleading right now because it doesn't include the SSE registers.

更新: 默认情况下,新指令集的任何附加寄存器都是易失性的。这包括 YMM0-15ZMM0-15 以及 ?MM16-31(如果存在)的上半部分。