x86-64 程序集 XMM1 寄存器丢失其值

x86-64 assembly XMM1 register loses its value

所以我正在处理这种汇编代码片段,我 运行 遇到了一个奇怪的问题:XMM1 寄存器似乎在执行过程中丢失了它的值,即使我没有'认为我在这里使用任何可能改变其值的指令。下面是有问题的代码片段。

    MOVSD QWORD [RSP], XMM1 ;Copy to stack
    MOV RDI, QWORD [RSP]
    CALL printfcallfloat;Prints floating point value from the RDI register, preserves all registers

    ;Load 10 to the fpu stack
    PUSH 10
    FILD QWORD [RSP]
    POP RDI

    MOVSD QWORD [RSP], XMM0 ;Copy to stack
    FLD QWORD [RSP];Load number float from XMM0 to the x87

    ;Do the math y = xmm0 (2), x=10 X*LOG2(Y)
    FYL2X

    ;We now have the result of x*log2(y) in ST(0)
    FSTP QWORD [RSP];Pop the result from the logarithm to the stack
    MOVSD XMM0, QWORD [RSP];Move the result back to xmm0

    ;print XMM0 and XMM1
    MOVSD QWORD [RSP], XMM0 ;Copy to stack
    MOV RDI, QWORD [RSP]
    CALL printfcallfloat;This preserves all registers

    MOVSD QWORD [RSP], XMM1 ;Copy to stack
    MOV RDI, QWORD [RSP]
    CALL printfcallfloat;This preserves all registers

这给出了以下输出:

10.000000
10.000000
-nan

我对这里发生的事情感到很困惑。

编辑:打印功能的实现如下:

printfcallfloat:

    ;Value is passed here in RDI
    PUSH RDI ;Preserve value of rdi
    PUSH RAX ;Preserve value of RAX
    pushxmm XMM0 ;Preserve XMM0
    ;Double is passed to printf in XMM0
    ;Now we move the value from the reg to the XMM0 using stack
    PUSH RDI
    popxmm XMM0
    MOV AL, 1;We are passing one argument so al should be 1
    MOV RDI, formatStrf ;Format string is passed in RDI
    CALL printf

    ;Restore XMM0
    popxmm XMM0
    POP RAX
    POP RDI
    RET

好吧,这是一个堆栈错位问题,printf 方法实际上覆盖了 XMM1 中的值。我没有考虑我的汇编代码的被调用者压入堆栈的 return 值(使堆栈未对齐),因此在添加 XMM1 的压入和弹出后我开始出现段错误注册。刚刚在我的代码开头添加 SUB RSP, 8 以将堆栈对齐到 16 字节,这似乎是事实上的标准,而且对于我也在代码中使用的 SSE 寄存器来说,它也是足够大的对齐方式。我做了以下更改(在代码注释中)。 打印子程序:

printfcallfloat:

    ;Value is passed here in RDI
    PUSH RDI ;Preserve value of rdi
    PUSH RAX ;Preserve value of RAX
    pushxmm XMM0
    pushxmm XMM1 ;Added this to make sure XMM1 is surely preserved after call

    PUSH RDI
    popxmm XMM0
    MOV AL, 1;We are passing one argument so al should be 1
    MOV RDI, formatStrf ;Format string is passed in RDI

    CALL printf ;Does not necessarily preserve SSE registers

    ;Restore XMM anmd other regs
    popxmm XMM1 ;Pop the XMM1 reg also
    popxmm XMM0
    POP RAX
    POP RDI
    RET

在主代码中刚刚添加了以下内容以在输入后对齐堆栈,尽管我不确定这是否是正确的方法,如果我做错了请告诉我:

    ;Align the stack
    SUB RSP, 8 ;8 bytes return address