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
所以我正在处理这种汇编代码片段,我 运行 遇到了一个奇怪的问题: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