所以我正在处理这种汇编代码段,但遇到一个奇怪的问题: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
中的值。我没有考虑到我的汇编代码的被调用方在堆栈上压入的返回值(使堆栈未对齐),因此在添加了XMM1
reg的压入和弹出之后,我开始遇到段错误。只需将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