2017-04-12 182 views
0

我有點驚訝,我找不到這方面的很多信息。保存xmm寄存器的值

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

有沒有類似的方法來保存/恢復所有的xmm寄存器?

+1

這不像它沒有被寫入指令集引用...請參閱'FXSAVE'。 PS:'pusha/popa'在64位模式下不再可用。 – Jester

+1

嘗試'fxsave'或更新的'xsave'。 – fuz

+0

@fuz寫道,['XSAVE'](http://www.felixcloutier.com/x86/XSAVE.html)可能對您有所幫助,因爲它確實可以將幾乎所有寄存器保存到內存區域 - 非常類似於' PUSHA',但更廣泛。 – zx485

回答

3

如果你想保存XMM/YMM寄存器來存儲你有2種選擇:

答:使用(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] 

B:手動的REG保存到存儲器

另一種選擇是簡單地將寄存器的內容保存在存儲器中。 假設您想要將數據存儲在堆棧中。
這種方法可以在任何CPU上工作,並且更加便攜,在未來的十年中,至少這將是我最喜歡的方法。

快速和骯髒的對齊保存

;push xmm0 
lea rsp,[rsp-16*numOfRegsToSave]   ;reserve space on the stack 
vmovdqu [rsp+16*0],xmm0     ;push a register (note unaligned! 

寫) vmovdqu [RSP + 16 * 1],XMM0;繼續推動

;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. 

如果你有大量的寄存器保存,你需要在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 

始終推第一任何ymm寄存器和任何其它寄存器以後(按遞減的尺寸的順序),這樣,在堆棧將總是被最佳比對。請注意0​​不再支持x64。

+0

您遺漏了找出XSAVE緩衝區大小的部分,給它64字節對齊並初始化XSAVE標題。還有,爲什麼在問題只問如何保存XMM寄存器時保存所有內容?只保存SSE狀態意味着您可以使用固定大小的緩衝區,因爲您只使用XSAVE緩衝區的傳統部分,因此不需要在運行時計算其大小。 –

+0

@Johan 嘿。要麼我填補了剩餘的抵消錯誤,要麼在您的實施中存在一些小錯誤。在我的例子中,我想存儲xmm0,xmm1,xmm2,xmm3。我sub rsp 16 * 4。現在,如果我從vmovdqu [rsp + 16 * 1]開始將寄存器內容移動到堆棧上,xmm0,那麼我最終將執行覆蓋以前堆棧內容的rsp + 16 * 4。我相信這應該是vmovdqu [rsp + 16 * 0],xmm0 vmovdqu [rsp + 16 * 1],xmm1等 –