C++とアセンブラー④で紹介したように、xmmレジスターを保護しただけでは、ymmレジスターやzmmレジスターの保護が保証されないことが分かった。そこで、ここでは512ビットのSIMDをサポートしたCPUはzmmレジスターを、256ビットのSIMDをサポートしたCPUはymmレジスターを保護する例を示す。併せて、mov命令へ適切なアライメントを保証できるとは限らないので、アライメントを要求しない命令に書き換える。
ymmレジスターの保護
256ビットのSIMDをサポートしたCPUはymmレジスターを搭載している。このような環境でymmレジスターを保護する例を示す。呼び出し側のC++ソースコードを示す。
#include <iostream> using namespace std; extern "C" void myCpuid(int*, int); // assembler function int main() { int regs[4]; char CPUString[(sizeof(int)) * 3 + 1]{}; try { myCpuid(regs, 0); *((int*)(CPUString + 0)) = regs[1]; *((int*)(CPUString + 4)) = regs[3]; *((int*)(CPUString + 8)) = regs[2]; CPUString[sizeof CPUString - 1] = '\0'; cout << "Vender Id: " << CPUString << endl; } catch (...) // その他の例外をキャッチ { cerr << "unknown exeption" << endl; } return 0; }
プロローグ、エピローグ、そして構造体の定義などをincファイルへ分離したので、それを示す。
; prolog PROLOG macro stack alloc_stack(size stack) ; prolog vmovups stack.ymm6sv[rsp], ymm6 vmovups stack.ymm7sv[rsp], ymm7 vmovups stack.ymm8sv[rsp], ymm8 vmovups stack.ymm9sv[rsp], ymm9 vmovups stack.ymm10sv[rsp], ymm10 vmovups stack.ymm11sv[rsp], ymm11 vmovups stack.ymm12sv[rsp], ymm12 vmovups stack.ymm13sv[rsp], ymm13 vmovups stack.ymm14sv[rsp], ymm14 vmovups stack.ymm15sv[rsp], ymm15 mov stack.rbxsv[rsp], rbx mov stack.rsisv[rsp], rsi mov stack.rdisv[rsp], rdi mov stack.rbpsv[rsp], rbp mov stack.r12sv[rsp], r12 mov stack.r13sv[rsp], r13 mov stack.r14sv[rsp], r14 mov stack.r15sv[rsp], r15 .endprolog ; end of prolog endm ; epilog EPILOG macro stack vmovups ymm6, stack.ymm6sv[rsp] ; epilog, restore vmovups ymm7, stack.ymm7sv[rsp] vmovups ymm8, stack.ymm8sv[rsp] vmovups ymm9, stack.ymm9sv[rsp] vmovups ymm10, stack.ymm10sv[rsp] vmovups ymm11, stack.ymm11sv[rsp] vmovups ymm12, stack.ymm12sv[rsp] vmovups ymm13, stack.ymm13sv[rsp] vmovups ymm14, stack.ymm14sv[rsp] vmovups ymm15, stack.ymm15sv[rsp] mov rbx, stack.rbxsv[rsp] mov rsi, stack.rsisv[rsp] mov rdi, stack.rdisv[rsp] mov rbp, stack.rbpsv[rsp] mov r12, stack.r12sv[rsp] mov r13, stack.r13sv[rsp] mov r14, stack.r14sv[rsp] mov r15, stack.r15sv[rsp] add rsp, size stack ; end of epilog ret endm ; data structure to push on the stack stkF struct ymm6sv ymmword ? ymm7sv ymmword ? ymm8sv ymmword ? ymm9sv ymmword ? ymm10sv ymmword ? ymm11sv ymmword ? ymm12sv ymmword ? ymm13sv ymmword ? ymm14sv ymmword ? ymm15sv ymmword ? rbxsv dq ? rsisv dq ? rdisv dq ? rbpsv dq ? r12sv dq ? r13sv dq ? r14sv dq ? r15sv dq ? dq ? ; padding stkF ends ; error, if size is not a 16 multiples and plus 8 .erre (size stkF mod 16) eq 8, <the size of stack structure must be 16n+8>
include ksamd64.inc include reg256.inc _TEXT segment ; ; rcx = stringの先頭アドレス。 ; rdx = function # ; public myCpuid align 16 myCpuid proc frame PROLOG stkF ; prolog mov r9, rcx ; save param addr mov eax, edx cpuid mov [r9+0], eax mov [r9+4], ebx mov [r9+8], ecx mov [r9+12], edx EPILOG stkF ; epilog myCpuid endp _TEXT ends end
実行結果:Vender Id: GenuineIntel
zmmレジスターの保護
512ビットのSIMDをサポートしたCPUはzmmレジスターを搭載している。このような環境でzmmレジスターを保護する例を示す。呼び出し側のC++ソースコードを示す。呼び出し側のC++ソースコードは、「ymmレジスターの保護」と同じなので、incファイルとアセンブリ言語で記述したソースコードを示す。
; prolog PROLOG macro stack alloc_stack(size stack) ; prolog vmovups stack.zmm6sv[rsp], zmm6 vmovups stack.zmm7sv[rsp], zmm7 vmovups stack.zmm8sv[rsp], zmm8 vmovups stack.zmm9sv[rsp], zmm9 vmovups stack.zmm10sv[rsp], zmm10 vmovups stack.zmm11sv[rsp], zmm11 vmovups stack.zmm12sv[rsp], zmm12 vmovups stack.zmm13sv[rsp], zmm13 vmovups stack.zmm14sv[rsp], zmm14 vmovups stack.zmm15sv[rsp], zmm15 ; vmovups stack.zmm16sv[rsp], zmm16 ; vmovups stack.zmm17sv[rsp], zmm17 ; vmovups stack.zmm18sv[rsp], zmm18 ; vmovups stack.zmm19sv[rsp], zmm19 ; vmovups stack.zmm20sv[rsp], zmm20 ; vmovups stack.zmm21sv[rsp], zmm21 ; vmovups stack.zmm22sv[rsp], zmm22 ; vmovups stack.zmm23sv[rsp], zmm23 ; vmovups stack.zmm24sv[rsp], zmm24 ; vmovups stack.zmm25sv[rsp], zmm25 ; vmovups stack.zmm26sv[rsp], zmm26 ; vmovups stack.zmm27sv[rsp], zmm27 ; vmovups stack.zmm28sv[rsp], zmm28 ; vmovups stack.zmm29sv[rsp], zmm29 ; vmovups stack.zmm30sv[rsp], zmm30 ; vmovups stack.zmm31sv[rsp], zmm31 mov stack.rbxsv[rsp], rbx mov stack.rsisv[rsp], rsi mov stack.rdisv[rsp], rdi mov stack.rbpsv[rsp], rbp mov stack.r12sv[rsp], r12 mov stack.r13sv[rsp], r13 mov stack.r14sv[rsp], r14 mov stack.r15sv[rsp], r15 .endprolog ; end of prolog endm ; epilog EPILOG macro stack vmovups zmm6, stack.zmm6sv[rsp] ; epilog, restore vmovups zmm7, stack.zmm7sv[rsp] vmovups zmm8, stack.zmm8sv[rsp] vmovups zmm9, stack.zmm9sv[rsp] vmovups zmm10, stack.zmm10sv[rsp] vmovups zmm11, stack.zmm11sv[rsp] vmovups zmm12, stack.zmm12sv[rsp] vmovups zmm13, stack.zmm13sv[rsp] vmovups zmm14, stack.zmm14sv[rsp] vmovups zmm15, stack.zmm15sv[rsp] ; vmovups zmm16, stack.zmm16sv[rsp] ; vmovups zmm17, stack.zmm17sv[rsp] ; vmovups zmm18, stack.zmm18sv[rsp] ; vmovups zmm19, stack.zmm19sv[rsp] ; vmovups zmm20, stack.zmm20sv[rsp] ; vmovups zmm21, stack.zmm21sv[rsp] ; vmovups zmm22, stack.zmm22sv[rsp] ; vmovups zmm23, stack.zmm23sv[rsp] ; vmovups zmm24, stack.zmm24sv[rsp] ; vmovups zmm25, stack.zmm25sv[rsp] ; vmovups zmm26, stack.zmm26sv[rsp] ; vmovups zmm27, stack.zmm27sv[rsp] ; vmovups zmm28, stack.zmm28sv[rsp] ; vmovups zmm29, stack.zmm29sv[rsp] ; vmovups zmm30, stack.zmm30sv[rsp] ; vmovups zmm31, stack.zmm31sv[rsp] mov rbx, stack.rbxsv[rsp] mov rsi, stack.rsisv[rsp] mov rdi, stack.rdisv[rsp] mov rbp, stack.rbpsv[rsp] mov r12, stack.r12sv[rsp] mov r13, stack.r13sv[rsp] mov r14, stack.r14sv[rsp] mov r15, stack.r15sv[rsp] add rsp, size stack ; end of epilog ret endm ; data structure to push on the stack stkF struct zmm6sv zmmword ? zmm7sv zmmword ? zmm8sv zmmword ? zmm9sv zmmword ? zmm10sv zmmword ? zmm11sv zmmword ? zmm12sv zmmword ? zmm13sv zmmword ? zmm14sv zmmword ? zmm15sv zmmword ? ; zmm16sv zmmword ? ; zmm17sv zmmword ? ; zmm18sv zmmword ? ; zmm19sv zmmword ? ; zmm20sv zmmword ? ; zmm21sv zmmword ? ; zmm22sv zmmword ? ; zmm23sv zmmword ? ; zmm24sv zmmword ? ; zmm25sv zmmword ? ; zmm26sv zmmword ? ; zmm27sv zmmword ? ; zmm28sv zmmword ? ; zmm29sv zmmword ? ; zmm30sv zmmword ? ; zmm31sv zmmword ? rbxsv dq ? rsisv dq ? rdisv dq ? rbpsv dq ? r12sv dq ? r13sv dq ? r14sv dq ? r15sv dq ? dq ? ; padding stkF ends ; error, if size is not a 16 multiples and plus 8 .erre (size stkF mod 16) eq 8, <the size of stack structure must be 16n+8>
include ksamd64.inc include reg512.inc _TEXT segment ; ; rcx = stringの先頭アドレス。 ; rdx = function # ; public myCpuid align 16 myCpuid proc frame PROLOG stkF ; prolog mov r9, rcx ; save param addr mov eax, edx cpuid mov [r9+0], eax mov [r9+4], ebx mov [r9+8], ecx mov [r9+12], edx EPILOG stkF ; epilog myCpuid endp _TEXT ends end