将XMM寄存器推入堆栈

18

有没有一种方法可以从XMM寄存器中推送一个打包的双字整数到栈中?然后在需要时再将其弹出?

理想情况下,我正在寻找类似于通用寄存器的PUSH或POP命令,我已经查看了英特尔手册,但我可能错过了该命令或者确实没有这样的命令...

还是说我必须将值解包到通用寄存器中,然后将它们推送到栈中?

2个回答

27

不,x86架构下没有这样的汇编指令,但你可以做类似这样的操作:

//Push xmm0
sub     esp, 16
movdqu  dqword [esp], xmm0

//Pop xmm0
movdqu  xmm0, dqword [esp]
add     esp, 16

编辑:

上面的代码示例是直接模拟推入/弹出操作。

如果你在栈上同时使用其他本地变量,那么ebp寄存器必须首先正确设置,例如:

push ebp
mov  ebp, esp
sub  esp, LocaStackVariablesSize
//... your code
mov  esp, ebp
pop  ebp  
ret
在这种情况下,您也可以使用 Daniel 的解决方案!

感谢您的回答。基于此(您的解决方案并没有完全奏效),我想出了一个可行的方案(请参见我的问题)。仍然标记为答案... - Daniel Gruszczyk
@Daniel Gruszczyk:是的,您也可以使用ebp,但请确保ebp寄存器已正确设置。请记住,如果ebp未正确设置,则其他push或call指令可能会覆盖堆栈上的数据。 - GJ.
2
也许值得编辑答案,写下你最终成功的方法,以帮助未来看到这个问题的用户。 - Jason R

0

我建议为此使用单独的、16位对齐的堆栈,以便您可以使用movdqa而不是movdqu。这两个指令之间的执行时间略有不同!


Linux上当前的i386 System V ABI 需要16字节的堆栈对齐。并非所有32位操作系统都要求这样做,例如我认为Windows仍然只需要32位进程的4字节对齐。但是在函数中可以执行and esp, -16;保存/恢复原始ESP可能比单独使用堆栈更便宜。 - Peter Cordes
如果操作系统确保16字节的堆栈对齐,你可以轻松地用 movdqa 代替 movdqu,一切都没问题。 但是,如果操作系统不需要堆栈对齐,那么即使使用 and esp, -16 也不会有太大的帮助,因为在弹出最后一个xmm寄存器之后,你还是必须恢复原始的 esp - Zoltán Bíró
1
是的,你必须保存/恢复旧ESP。但这并不比维护第二个堆栈更昂贵!编译器在溢出__m256时使用and esp,-16-32或它们需要的任何对齐方式,或者如果您使用alignas(16)。https://godbolt.org/g/6856no。`-mpreferred-stack-boundary = 2告诉gcc仅使用4字节堆栈对齐。(在32位模式下,它选择使用rep stos`而不是向量存储,但确实提供所请求的对齐方式。)堆栈对齐开销仅在每个函数中发生一次(它可能会占用额外的寄存器,但手动可以溢出)。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接