C++とアセンブラー⑥

C++アセンブラーで開発した関数について一通り解説してきた。今回は、スタックへレジスターの保存を行うだけでなく、スタックに作業領域を割り当てて使う方法を紹介する。レジスターの保護と、作業領域確保の両方を行う例を紹介する。

スタックに作業領域を確保

rbxとrsiレジスターを保護し、かつ2つの作業領域を確保する例を紹介する。アセンブリ関数は、レジスターを保護を行うとともに、作業領域を使用する。以降に、呼び出し側の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;
}



プロローグ、エピローグ、そして構造体の定義に加え、スタックに確保した作業領域を使う関数を示す。

include ksamd64.inc

_TEXT       segment

; prolog
PROLOG  macro   stack
        alloc_stack(size stack)         ; prolog
        mov     stack.rbxsv[rsp], rbx
        mov     stack.rsisv[rsp], rsi
        .endprolog                      ; end of prolog
        endm

; epilog
EPILOG  macro   stack
        mov     rbx,   stack.rbxsv[rsp]
        mov     rsi,   stack.rsisv[rsp]
        add     rsp,   size stack       ; end of epilog
        ret
        endm

; data structure to push on the stack
stkF    struct
        rbxsv   dq      ?
        rsisv   dq      ?
        work0   dq      ?
        work1   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>


;
; 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     bl, 'A'
        mov     stkF.work0[rsp], rbx    ; use work
        xor     ebx, ebx                ; clear eax
        mov     rbx, stkF.work0[rsp]    ; restore eax form work

        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: AenuineIntel

コマンドラインでビルド・実行:

C:\Master>ml64 /c asmCode.asm
Microsoft (R) Macro Assembler (x64) Version 14.33.31629.0
Copyright (C) Microsoft Corporation.  All rights reserved.

 Assembling: asmCode.asm

C:\Master>cl /EHsc /Fe:withWork Source.cpp asmCode.obj
Microsoft(R) C/C++ Optimizing Compiler Version 19.33.31629 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

Source.cpp
Microsoft (R) Incremental Linker Version 14.33.31629.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:withWork.exe
Source.obj
asmCode.obj

C:\Master>withWork
Vender Id: AenuineIntel