Improve this page Github へのログインが必要です。 簡単な修正は、ここから fork、オンライン編集、pull request ができます。 大きな修正については、 通常の clone で行って下さい。 Page wiki 関連するWikiページを参照・編集 English このページの英語版(原文)

Application Binary Interface

ABI(アプリケーション・バイナリインターフェイス) に従ったDの実装は、 他の実装によって生成されたライブラリや DLL などと相互利用することが可能なバイナリを出力します。

C ABI

この仕様で C ABI として参照するのは、対象とするシステムの C言語のアプリケーション・バイナリインターフェイスです。 C と D のコードは制限無くリンクでき、特に、D のコードからは C の ABI を持ったランタイムライブラリには完全にアクセス可能となっています。

エンディアン

データレイアウトの エンディアン (バイトオーダー) は、 対象マシンのエンディアンに従います。 Intel x86 CPU では、 値 0x0A0B0C0D がメモリ上で 0D 0C 0B 0A と表現される リトルエンディアン になります。

基本型

bool8 bit byte。0 が false、1 が true を表す
byte8 bit signed
ubyte8 bit unsigned
short16 bit signed
ushort16 bit unsigned
int32 bit signed
uint32 bit unsigned
long64 bit signed
ulong64 bit unsigned
cent128 bit signed
ucent128 bit unsigned
float32 bit IEEE 754 浮動小数点数
double64 bit IEEE 754 浮動小数点数
real実装定義の浮動小数点数。 x86 では 80 bit IEEE 754 拡張実数

delegate

delegate は2つの部分から構成される fat pointers です:

delegate のレイアウト
オフセット プロパティ 内容
0 .ptr コンテキストポインタ
ptrsize .funcptr 関数ポインタ

コンテキストポインタ は、クラスの this 参照か構造体の this ポインタ、あるいは クロージャ、 または周囲の関数のスタックフレーム(ネスト関数の場合)へのポインタです。

構造体

対象環境の C ABI の構造体レイアウトに従います。

クラス

オブジェクトのメモリ構成は次のようになっています:

クラスオブジェクトのレイアウト
サイズ プロパティ 内容
ptrsize .__vptr vtableへのポインタ
ptrsize .__monitor モニタ
... ... 基底クラスの非staticメンバとinterfaceのvtableへのポインタ。継承のルートから順に。
... named fields 非staticメンバ
ptrsize...   このクラスの実装するinterfaceのvtableへのポインタ。左から右、直近の派生元から遠くの派生元、の順で。

vtableの構成は次の通り:

仮想関数ポインタテーブルのレイアウト
サイズ 内容
ptrsize TypeInfo のインスタンスへのポインタ
ptrsize... 仮想メンバ関数へのポインタ

クラスオブジェクトのインターフェイスへのキャストは、 オブジェクトのベースアドレスに、インターフェイスのvptrへのオフセットを加算することで行われます。 インターフェイスをクラス型へキャストし直すには、 引き算する正しいオフセットを求めるために、vtbl[0] の object.Interface エントリを参照します。 vtbl[] の中には、 thisポインタが正しくオブジェクトのインスタンスを参照するように調整するための サンク が生成され格納されます。

サンクは以下のようなコードになります:

 ADD EAX,offset
  JMP method

継承関係グラフの左端は、全てのインターフェイスが vptr を共有する、 単一継承モデルです。 (インターフェイスの多重継承によって)継承グラフが分岐する度に、 新し vptr が作られクラスのインスタンスに格納されます。 また、virtual メソッドがオーバーライドされるたびに、新しく vtbl[] が作られ新しいメソッドポインタをそこに格納する必要があります。

クラス定義:

class XXXX {
  ....
};

は、以下のコードを生成します:

インターフェイス

インターフェイスは vtbl[] へのポインタです。 vtbl[0] は、object.Interface クラスの対応するインスタンスへのポインタです。 残りのエントリ vtbl[1..$] は、 そのインターフェイスで実装される仮想関数へのポインタが、 宣言された順番に入ります。

COM インターフェイスは、通常のインターフェイスと異なり、 vtbl[0] に object.Interface は入りません。 vtbl[0..$] のエントリ全てが仮想関数ポインタで、 宣言された順番に格納されます。 これは Windows の COM オブジェクトのレイアウトに合わせています。

C++ インターフェイスは通常のインターフェイスと異なり、 ターゲット環境での C++ の単一継承のクラスレイアウトと同じ形式に合わせた実装になります。

配列

動的な配列の構成は:

動的配列のレイアウト
オフセット プロパティ 内容
0 .length 配列のサイズ
size_t .ptr 配列データへのポインタ

動的な配列は次のように宣言され:

type[] array;

静的な配列の宣言は次のようになります:

type[dimension] array;

従って、静的な配列のサイズは常に型の一部として静的に得ることが出来ます。 このため、静的な配列についてはC言語と同様に実装されています。 静的な配列と動的な配列は簡単に相互変換が可能です。

連想配列

連想配列は、 実装ごとに定義される実体へのポインタ一つで構成されます。 現在の実装は rt/aaA.d から参照できます。

参照型

Dには参照型がありますが、明示的に表には出てきません。例えば、クラスは常に 参照によってアクセスされます。これはすなわち、クラスのインスタンスそのものは決して スタックに置かれたり関数のパラメタとして渡したりできないことを意味します。

静的な配列を関数へ渡すと、例え静的な配列として宣言されていても、 結果は実際には静的配列への参照となります。例をあげると:

int[3] abc;

関数へ abc を渡す際には、次のような暗黙の変換が引き起こされます:

void func(int[3] array); // 実際には <intの><サイズ3配列><への参照>
void func(int* p);       // abc は
                         // 先頭要素へのポインタへ変換される
void func(int[] array);	 // abc は動的配列へ変換される

名前マングリング

Dでは、型安全なリンクを実現するために、Dの識別子名を mangling してスコープと型の情報を埋め込んでいます。

MangledName:
    _D QualifiedName Type
    _D QualifiedName M Type

QualifiedName:
    SymbolName
    SymbolName QualifiedName

SymbolName:
    LName
    TemplateInstanceName

M は、そのシンボルが this ポインタを必要とする関数であることを表しています。

テンプレートのインスタンス名は、 そのパラメタ型と値をエンコードして保持します:

TemplateInstanceName:
     __T LName TemplateArgs Z

TemplateArgs:
    TemplateArg
    TemplateArg TemplateArgs

TemplateArg:
    T Type
    V Type Value
    S LName

Value:
    n
    Number
    i Number
    N Number
    e HexFloat
    c HexFloat c HexFloat
    A Number Value...
    S Number Value...

HexFloat:
    NAN
    INF
    NINF
    N HexDigits P Exponent
    HexDigits P Exponent

Exponent:
    N Number
    Number

HexDigits:
    HexDigit
    HexDigit HexDigits

HexDigit:
    Digit
    A
    B
    C
    D
    E
    F
n
null 引数を表します
Number
は正の数値リテラルです (文字リテラルを含みます)
N Number
は負の数値リテラルです
e HexFloat
は実数および虚数の浮動小数点数リテラルです。
c HexFloat c HexFloat
は複素数の浮動小数点数リテラルです。
Width Number _ HexDigits
Width は文字列中の文字が 1 byte (a), 2 bytes (w), 4 bytes (d) のいずれであるかを示します。 Number は文字列中の文字の数です。 HexDigits は文字列データの16進表現です。
A Number Value...
配列リテラル。 Number が配列の長さを表します。 通常の配列では ValueNumber 回繰り返し、 連想配列では 2 * Number 回並びます。
S Number Value...
構造体リテラル。ValueNumber 個並びます。
Name:
    Namestart
    Namestart Namechars

Namestart:
    _
    Alpha

Namechar:
    Namestart
    Digit

Namechars:
    Namechar
    Namechar Namechars

Name は標準的なDの識別子です。

LName:
    Number Name

Number:
    Digit
    Digit Number

Digit:
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9

LName は、先頭に文字数を表す Number のついた Name です。

型名のマングリング

型の名前は以下のように単純な一列の文字列になります:

Type:
    Shared
    Const
    Immutable
    Wild
    TypeArray
    TypeNewArray
    TypeStaticArray
    TypeAssocArray
    TypePointer
    TypeFunction
    TypeIdent
    TypeClass
    TypeStruct
    TypeEnum
    TypeTypedef
    TypeDelegate
    TypeNone
    TypeVoid
    TypeByte
    TypeUbyte
    TypeShort
    TypeUshort
    TypeInt
    TypeUint
    TypeLong
    TypeUlong
    TypeFloat
    TypeDouble
    TypeReal
    TypeIfloat
    TypeIdouble
    TypeIreal
    TypeCfloat
    TypeCdouble
    TypeCreal
    TypeBool
    TypeChar
    TypeWchar
    TypeDchar
    TypeTuple

Shared:
    O Type

Const:
    x Type

Immutable:
    y Type

Wild:
    Ng Type

TypeArray:
    A Type

TypeNewArray:
    Ne Type

TypeStaticArray:
    G Number Type

TypeAssocArray:
    H Type Type

TypePointer:
    P Type

TypeFunction:
    CallConvention FuncAttrs Arguments ArgClose Type

CallConvention:
    F       // D
    U       // C
    W       // Windows
    V       // Pascal
    R       // C++

FuncAttrs:
    FuncAttr
    FuncAttr FuncAttrs

FuncAttr:
    empty
    FuncAttrPure
    FuncAttrNothrow
    FuncAttrProperty
    FuncAttrRef
    FuncAttrTrusted
    FuncAttrSafe

FuncAttrPure:
    Na

FuncAttrNothrow:
    Nb

FuncAttrRef:
    Nc

FuncAttrProperty:
    Nd

FuncAttrTrusted:
    Ne

FuncAttrSafe:
    Nf


Arguments:
    Argument
    Argument Arguments

Argument:
   Argument2
    M Argument2     // scope

Argument2:
    Type
    J Type     // out
    K Type     // ref
    L Type     // lazy

ArgClose
    X     // 可変長引数 (T t,...) 形式
    Y     // 可変長引数 (T t...) 形式
    Z     // 可変長引数でない

TypeIdent:
    I QualifiedName

TypeClass:
    C QualifiedName

TypeStruct:
    S QualifiedName

TypeEnum:
    E QualifiedName

TypeTypedef:
    T QualifiedName

TypeDelegate:
    D TypeFunction

TypeNone:
    n

TypeVoid:
    v

TypeByte:
    g

TypeUbyte:
    h

TypeShort:
    s

TypeUshort:
    t

TypeInt:
    i

TypeUint:
    k

TypeLong:
    l

TypeUlong:
    m

TypeFloat:
    f

TypeDouble:
    d

TypeReal:
    e

TypeIfloat:
    o

TypeIdouble:
    p

TypeIreal:
    j

TypeCfloat:
    q

TypeCdouble:
    r

TypeCreal:
    c

TypeBool:
    b

TypeChar:
    a

TypeWchar:
    u

TypeDchar:
    w

TypeTuple:
    B Number Arguments

関数呼び出し規約

extern (C)extern (D) と宣言された関数の呼び出し規約は、 基本的に、ホスト環境で対応するCコンパイラの関数呼び出し規約と一致します。 例外として、Windows x86 では extern (D) の呼び出し規約は以下のようになっています。

レジスター使用規約

返値

引数

可変個引数でない関数の引数:

	foo(a1, a2, ..., an);

は、以下のように渡されます:

a1
a2
...
an
hidden
this

hidden は、構造体を返す必要があるときに現れます。 this は、 メンバ関数に使うthisポインタや、 ネストした関数で使うコンテキストポインタを渡すときに現れます。

次の条件が満たされているときには、最後の引数は、 スタックではなくEAXレジスタで渡されます:

引数は、 常に4バイト境界に切り上げてスタックに push されます。 上位ワードが先にpushされます。 out 引数と ref 引数はポインタが渡されます。 静的配列は先頭へのポインタが渡されます。 Windowsでは、real型は10バイトの量として、 creal型は20バイトの量としてpushされます。 Linuxでは、realは12バイト、 crealは二つの12バイトの量としてpushされます。 パディングの2バイトは ‘most significant’ 側に埋められます。

呼び出された関数側が、スタックを復元します。

以下の形式の可変個引数関数の場合は、

	void foo(int p1, int p2, int[] p3...)
	foo(a1, a2, ..., an);

このように引数が渡されます:

p1
p2
a3
hidden
this

可変個部分は動的配列に変換され、 あとは通常の関数と全く同様です。

以下の形式の可変個引数関数の場合は、

	void foo(int p1, int p2, ...)
	foo(a1, a2, a3, ..., an);

このように引数が渡されます:

an
...
a3
a2
a1
_arguments
hidden
this

呼び出し側がスタックを復元します。 _argptr は直接は渡されません。 呼び出された関数側が計算します。

例外処理

Windows

Microsoft Windows の構造化例外処理の規約に従います。

Linux, FreeBSD, OS X

静的な範囲/ハンドラ対応表を用います。 これはELFの例外ハンドラテーブルとは互換性がありません。 EBP/RBPでスタックフレームを保持しているとの仮定の下で、 スタックをたどります。例外ハンドラテーブル(EHテーブル)を持つ全ての関数で、 このEBP/RBPの規約が満たされている必要があります。

例外ハンドラのあるそれぞれの関数に対して、 EHテーブルのエントリが生成されます。

EHテーブルエントリ
フィールド 説明
void* 関数の開始アドレス
DHandlerTable* 対応するEHデータへのポインタ
uint 関数のサイズ。バイト単位

EHテーブルは、以下の特別なセグメントに配置され、 リンカによって一つに結合されます。

EHテーブルセグメント
OS セグメント名
Windows FI
Linux .deh_eh
FreeBSD.deh_eh
OS X __deh_eh, __DATA

例外ハンドラのそのほかのデータは任意の箇所に配置されます。 書き換えは不可能です。

DHandlerTable
フィールド 説明
void* 関数の開始アドレス
uint ESP/RSPのEBP/RBPからのオフセット
uint 関数の開始アドレスからreturn codeまでのオフセット
uint DHandlerInfo[] の要素数
DHandlerInfo[] ハンドラ情報の配列

DHandlerInfo
フィールド 説明
uint 関数の開始アドレスからtry区間の先頭までのオフセット
uint 同、tryの終端までのオフセット
int 一つ前のテーブルのインデックス
uint 0でない場合、テーブルの先頭から DCatchInfo までのオフセット
void* nullでない場合、finallyのコード

DCatchInfo
フィールド 説明
uint DCatchBlock[] の要素数<
DCatchBlock[] catch 情報の配列

DCatchBlock
フィールド 説明
ClassInfo catchする例外の型
uint catch変数の EBP/RBP からのオフセット
void* catch ハンドラのコード

ガベージコレクション

インターフェイスが phobos/internal/gc に存在します

実行時補助関数

phobos/internal に存在します

モジュール初期化と終了

モジュール内の静的コンストラクタは1つの関数へとまとめられます。 その関数へのポインタが、そのモジュールの ModuleInfo インスタンスの ctor メンバに格納されます。

モジュール内の静的コンストラクタは1つの関数へとまとめられます。 その関数へのポインタが、そのモジュールの ModuleInfo インスタンスの dtor メンバに格納されます。

単体テスト

モジュール内の静的コンストラクタは1つの関数へとまとめられます。 その関数へのポインタが、そのモジュールの ModuleInfo インスタンスの unitTest メンバに格納されます。

シンボリック・デバッグ

D には、既存のC/C++用デバッガでは表現できない型があります。 動的配列、連想配列、delegate がそれにあたります。 しかし、一般には関数呼び出し規約が構造体とは異なるために、 これらを構造体として表現すると C/C++ デバッガの動作ミスを引き起こしてしまいます。 これらデバッガへの対策として、現状では、 呼び出し規約がマッチするような型を選んでそれで置き換えて表現するようになっています。 -gc スイッチを指定した場合、 dmd コンパイラはこのような C 形式シンボル情報のみを出力します。

Cデバッガ向け型情報
D の型 C 表現
動的配列 unsigned long long
連想配列 void*
delegate long long
dchar unsigned long

新しい型を追加できるようなタイプのデバッガでは、 Dの型を完全サポートするために以下の情報を利用してください。

Codeview デバッガ拡張

D の dchar 型は 特別な組み込み型 0x78 として表現されます。

D は、LF_OEM (0x0015) で示される Codeview OEM 汎用型情報レコードを使います。 形式は以下の通りです:

D の Codeview OEM 拡張
フィールドサイズ 2 2 2 2 2 2
D の型 Leaf Index OEM Identifier recOEM num indices type index type index
動的配列 LF_OEM OEM 1 2 @index @element
連想配列 LF_OEM OEM 2 2 @key @element
delegate LF_OEM OEM 3 2 @this @function

OEM 0x42
index 配列の添え字のtype index
key 連想配列のkeyのtype index
element 連想配列のelementのtype index
this コンテキストポインタのtype index
function 関数のtype index

Tこれらの拡張は obj2asm を使うと綺麗に表示できます。

Ddbg デバッガがこの拡張に対応しています。

Dwarf デバッガ拡張

以下のleaf typeが追加されます:

D の Dwarf 拡張
D の型 Identifier Value Format
動的配列 DW_TAG_darray_type 0x41 DW_AT_type が要素の型
associative array DW_TAG_aarray_type 0x42 DW_AT_type が要素の型, DW_AT_containing_type が key の型
delegate DW_TAG_delegate_type 0x43 DW_AT_type が関数の型, DW_AT_containing_type が ‘this’ の型

これらの拡張は dumpobj を使うと綺麗に表示できます。

ZeroBUGS デバッガがこの拡張に対応しています。

これらの Dwarf 拡張は最近の gcc の追加機能と衝突するため取り除かれています。