CPU brand stringを、C++から自身で開発したアセンブリ関数を呼び出し、表示してみた。
arques.hatenablog.com
のアゼンブラーバージョンです。
C++ソースリスト
#include <iostream> extern "C" void asmCode(char*); // assembler function int main() { char CPUBrandString[4 * 4 * 3 + 1]{}; asmCode(CPUBrandString); CPUBrandString[sizeof CPUBrandString -1] = '\0'; std::cout << "CPU Brand String: " << CPUBrandString << std::endl; }
アセンブリ関数ソースリスト
asmCode の rcx には stringの先頭アドレスが格納されているので、そこへ読みだしたデータを書き込むが、 rcx は途中で利用するので、volatile な r9 をかわりに利用する。
rbx は非volatile だが、途中で破壊されるので、volatile な r10 を使って保存・復旧する。
_TEXT segment public asmCode align 16 asmCode proc mov r10, rbx ; save reg mov r9, rcx ; addr mov eax, 80000002h cpuid mov [r9+0], eax mov [r9+4], ebx mov [r9+8], ecx mov [r9+12], edx mov eax, 80000003h cpuid mov [r9+16], eax mov [r9+20], ebx mov [r9+24], ecx mov [r9+28], edx mov eax, 80000004h cpuid mov [r9+32], eax mov [r9+36], ebx mov [r9+40], ecx mov [r9+44], edx mov rbx, r10 ; restore ret asmCode endp _TEXT ends end
prolog、epilogを持つアセンブリ関数ソースリスト
先のアセンブリ関数を書き換えて、少しスマートにする。
rbx は非volatile なので保護する必要がある。上の例は、たまたま空いてた r10 を使って保存・復旧したが、本例ではスタックに保存・復旧する。C++のコードは、先の例と同じものを使用する。
include ksamd64.inc _TEXT segment public asmCode align 16 asmCode proc frame ; prologを使う時はproc frame ; prolog rex_push_reg rbx ; マクロでrbxをpush .endprolog ; end of prolog mov r9, rcx ; addr mov eax, 80000002h cpuid mov [r9+0], eax mov [r9+4], ebx mov [r9+8], ecx mov [r9+12], edx mov eax, 80000003h cpuid mov [r9+16], eax mov [r9+20], ebx mov [r9+24], ecx mov [r9+28], edx mov eax, 80000004h cpuid mov [r9+32], eax mov [r9+36], ebx mov [r9+40], ecx mov [r9+44], edx ; epilog pop rbx ; restore ret asmCode endp _TEXT ends end
実行例: