保存 xmm 寄存器的值

noo*_*der 1 x86 assembly

我有点惊讶我找不到这方面的太多信息。

如果我们想保存/恢复通用寄存器的值,我们可以使用pushad/ popad

是否有类似的方法来保存/恢复所有xmm 寄存器?

Joh*_*ica 5

如果要将 XMM/YMM 寄存器保存到内存中,您有 2 个选项:

A:使用(F) XSAVE / (F) XRSTOR,参见:Intel x86-64 XSAVE/XRSTOR

为此,您将需要最新的 CPU。

;save:
mov     rdx, -1              
mov     rax, -1                 ;save all possible regs
xsave   [location]

...some code that alters the registers
;restore:
mov     rdx, -1
mov     rax, -1
xrstor  [location]
Run Code Online (Sandbox Code Playgroud)

B: 手动将 regs 保存到内存

另一种选择是简单地将寄存器的内容存储在内存中。假设您想将数据存储在堆栈上。
这种方法可以在任何 CPU 上运行,并且更加便携,至少在接下来的十年里,这将是我最喜欢的方法。

快速而肮脏的未对齐保存

;push xmm0
lea rsp,[rsp-16*numOfRegsToSave]          ;reserve space on the stack
vmovdqu [rsp+16*0],xmm0                   ;push a register (note unaligned! write) 
vmovdqu [rsp+16*1],xmm1                   ;keep pushing
.......

;pop xmm0
.......
vmovdqu xmm1,[rsp+16*1]                   ;pop registers in reverse order
vmovdqu xmm0,[rsp+16*0]                   ;first 'pop' the register
lea rsp,[rsp+16*numOfRegsToSave]          ;then update the stack.
Run Code Online (Sandbox Code Playgroud)

如果您有很多寄存器要保存,您需要在 32 字节边界上对齐堆栈:

稍微快一点的代码(以一个损坏的寄存器为代价)

mov rbp,rsp                       ;save the stack pointer
and rsp,-32                       ;align on a 32 byte boundary
;push ymm0
lea rsp,[rsp-32*numOfRegsToSave] ;reserve space on the stack
vmovdqa [rsp+32],ymm0             ;push a register (note aligned! write)
.......

;pop ymm0
....
vmovdqa ymm0,[rsp+32]
mov rsp,rbp
Run Code Online (Sandbox Code Playgroud)

始终先压入任何 ymm 寄存器,然后再压入任何其他寄存器(按大小递减顺序),这样堆栈将始终以最佳方式对齐。

请注意,pushad/popadx64 上不再支持。