我使用Visual Studio 2017编译的Windows程序执行以下操作:
在第一次调用中,默认参数获得正确的35.05。在第二个调用中,该值是垃圾。
我查看了生成的程序集,并在第一次调用时将默认参数35.05从内存位置复制到xmm8
并将其复制到堆栈(这是第5个参数),并进行了调用: / p>
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
的值将被保留。
答案 0 :(得分:3)
根据Microsoft docs总结的Windows x64调用约定。
RCX
,RDX
,R8
和R9
用作输入整数参数。 XMM0L
,XMM1L
,XMM2L
和XMM3L
是输入浮点参数。 RAX
,R10
,R11
,XMM4
和XMM5
是易失的。包括XMM8
在内的所有其他非易失性存储器。
请注意,“呼叫者/被呼叫者保存的寄存器”子页面目前有点误导,因为它不包括SSE寄存器。
更新:默认情况下,用于较新指令集的所有其他寄存器都是易失性的。这包括YMM0-15
和ZMM0-15
的上半部分,以及?MM16-31
(如果有)的上半部分。