D言語のインラインアセンブラ

人生にはインラインアセンブラが必要なことがありますよね。 D言語にはインラインアセンブラが実装されておりIntelスタイルでアセンブリを書くことが出来ます。

はじめに

この記事はD言語 Advent Calenderの12日目の記事です。 遅れての投稿で申し訳ありません。 ここに書いてあることは殆ど公式LLVM公式に書いてあるのでそちらを読んだほうが多分正確な情報が手に入ります。

基本構文

import std.stdio: writeln;

void main() {
    int a = 5;
    writeln(a);
    // asmブロックで囲む
    asm {
       // asm外で定義した変数を触れる
       mov RAX, a; // 末尾には「;」が必須
       add RAX, 1;
       mov a, RAX;
   }
    writeln(a);
}

関数からの値の返却

RAXレジスタに入れて抜けます。

int add(int a, int b) {
    asm {
       mov RAX, a;
       mov RBX, b;
       add RAX, RBX;
   }
}

D言語で追加された命令

align

align <Interger Expression>

命令を次の命令までの倍数で整列させるためにアセンブラにNOPを吐かせる命令です。

even

alignのに2が指定されたのと同じ意味です。

naked

D言語インラインアセンブラはデフォルトでprolog(論理型プログラミング言語ではない)とepilogを生成しますがそれをさせない命令です。 関数を全て書く場合などで、prologもepilogもプログラマ自信が書く場合などに使います。 基本は付けておいたほうが良いでしょう。

d.?

コードにデータを直接埋め込むための疑似命令です。 オペランドに文字列を指定すればバイト列で埋め込む事も出来ます。 |疑似命令|データ型| |-------:|-------:| | db | 8bit 整数 | | ds | 16bit 整数 | | di | 32bit 整数 | | dl | 64bit 整数 | | df | 32bit IEEE754浮動小数点数 | | dd | 64bit IEEE754浮動小数点数 | | de | 80bit 浮動小数点数 |

Operand Types

mov [RAX], 3;

上の例では3の型が曖昧です。3の型によって命令の意味が変わってしまいます。

mov int ptr [RAX], 3;

なのでこのようにintのptrとして書き込むとしてしてやります。

構造体等の扱い

struct Foo {
    int a, b, c;
}

// bを返す
int bar(Foo *f) {
    asm {
       mov RBX, f;
       mov EAX, Foo.b.offsetsetof[RBX];
   }
}

offsetsetofを使います。

struct Foo {
    int a, b, c;
    int bar(Foo *f) {
        asm {
           mov RBX, this;
           mov EAX, b[RBX];
       }
    }
}

構造体内だとメンバ名だけで書くことが出来ます。

最後に

D言語インラインアセンブラアセンブリそのままではなくD言語コンパイラによって意味解析まで行われるのでかなり書きやすくなっていると思います。 ただ、全ての命令が使える訳でも無く、例えばshlなどはオペランドを2つ取る形式しか使えません。 SSEもSIMDモジュールと同じでSSE4.2までです。 D言語のasm{}ではx86x86_64までしかサポートされていませんがLDCを使うとLLVMインラインアセンブラを使えるモジュールがあるのでARM、PPCMIPSなどのインラインアセンブラも書くことが出来ます。 D言語Adc遅れて申し訳ないです。

編集

Twitterでshitsyndromeさんにご指摘頂きアーキテクチャ名をamd64 -> x86x86_64に、EAXを一部RAXにしました。