人生にはインラインアセンブラが必要なことがありますよね。
D言語にはインラインアセンブラが実装されておりIntelスタイルでアセンブリを書くことが出来ます。
はじめに
この記事はD言語 Advent Calenderの12日目の記事です。
遅れての投稿で申し訳ありません。
ここに書いてあることは殆ど公式かLLVM公式に書いてあるのでそちらを読んだほうが多分正確な情報が手に入ります。
基本構文
import std.stdio: writeln;
void main() {
int a = 5;
writeln(a);
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;
}
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{}ではx86、x86_64までしかサポートされていませんがLDCを使うとLLVMのインラインアセンブラを使えるモジュールがあるのでARM、PPC、MIPSなどのインラインアセンブラも書くことが出来ます。
D言語Adc遅れて申し訳ないです。
編集
Twitterでshitsyndromeさんにご指摘頂きアーキテクチャ名をamd64 -> x86、x86_64に、EAXを一部RAXにしました。