英語版
このページの英語版を見る

インラインアセンブラ

Some Assembly Required

D言語はシステム・プログラミング言語であり、インライン・アセンブラを提供する。 アセンブラを提供している。 インライン・アセンブラは、同じCPUファミリーのD実装で標準化されている。 インライン・アセンブラは、同じCPUファミリーのD実装で標準化されている。 インライン・アセンブラは、Win32 Dコンパイラ用のインライン・アセンブラと構文互換性がある。 インライン・アセンブラと構文互換性がある。

しかし、異なるアーキテクチャー上のD実装は、メモリモデル、関数のコール/リターン規則、アセンブラを自由に変更することができる。 メモリモデル、関数の呼び出し/戻り値の規則、引数の受け渡し規則などを自由に変更することができる、 引数の受け渡し規則などを自由に変更することができる。

この文書では、x86 およびx86_64 のインライン・アセンブラの実装について説明する。 インライン・アセンブラの実装について説明する。コンパイラが提供するインライン・アセンブラ・プラットフォームのサポートは、 および で示される。 が提供するインライン・アセンブラのプラットフォーム・サポートは、それぞれD_InlineAsm_X86D_InlineAsm_X86_64 バージョン識別子で示される。

Asmステートメント

AsmStatement:
    asm FunctionAttributesopt { AsmInstructionListopt }
AsmInstructionList: AsmInstruction ; AsmInstruction ; AsmInstructionList

アセンブラ命令は、asm ブロック内に配置されなければならない。 関数と同様に、asm ステートメントは、呼び出し元と互換性があるように、適切な関数属性でアノテーションされなければならない。 asm文の属性は明示的に定義されなければならない。

void func1() pure nothrow @safe @nogc
{
    asm pure nothrow @trusted @nogc
    {}
}

void func2() @safe @nogc
{
    asm @nogc // エラー: asm文は@systemであると仮定される - そうでない場合は'@trusted'でマークする
    {}
}

asm命令

AsmInstruction:
    Identifier : AsmInstruction
    align IntegerExpression
    even
    naked
    db Operands
    ds Operands
    di Operands
    dl Operands
    df Operands
    dd Operands
    de Operands
    db StringLiteral
    ds StringLiteral
    di StringLiteral
    dl StringLiteral
    dw StringLiteral
    dq StringLiteral
    Opcode
    Opcode Operands
Opcode: Identifier int in out
Operands: Operand Operand , Operands

ラベル

アセンブラ命令には、他の文と同様にラベルを付けることができる。 これらはgoto文のターゲットになることができる。 例えば、次のようになる:

void *pc;
asm
{
    call L1          ;
  L1:                ;
    pop  EBX         ;
    mov  pc[EBP],EBX ; // pcは現在L1のコードを指している
}

整列IntegerExpression

IntegerExpression:
    IntegerLiteral
    Identifier

アセンブラに NOP 命令を発行させ、次のアセンブラ命令を IntegerExpression 境界に揃える。 アセンブラに NOP 命令を発行させる。 IntegerExpressionは、コンパイル時に 2 のべき乗である整数に評価されなければならない。 でなければならない。

ループ本体の開始位置を揃えることは、実行速度に劇的な影響を与えることがある。 実行速度に劇的な影響を与えることがある。

でさえある。

アセンブラにNOP命令を発行させ、次のアセンブラ命令を偶数境界に揃える。 アセンブラが次のアセンブラ命令を偶数境界に揃えるようにする。

naked

コンパイラが関数のプロログとエピログを生成しないようにする。 シーケンスを生成しないようにする。これは、インライン アセンブラ・プログラマーの責任であり、通常、関数全体をアセンブラで記述する場合に使用される。 をアセンブラで記述する場合に使用される。

db, ds, di, dl, df, dd, de

これらの擬似オペランドは、生データをコードに直接挿入するためのものである。 コードに直接挿入するためのものである。 db はバイトである、 ds は16ビットワード di は32ビット・ワード用である、 dl は64ビットワードである、 df は32ビット浮動小数点数である、 dd は64ビット倍精度である、 そしてde は80ビット拡張リアルである。 それぞれ複数のオペランドを持つことができる。 オペランドが文字列リテラルの場合、あたかも長さ オペランドがあるのと同じで、さは文字列の文字数である。 1つのオペランドにつき1文字が使用される。 例:

asm
{
    db 5,6,0x83;   // コードにバイト0x05、0x06、0x83を挿入する
    ds 0x1234;     // バイト0x34、0x12を挿入する
    di 0x1234;     // バイト0x34, 0x12, 0x00, 0x00を挿入する
    dl 0x1234;     // バイト0x34, 0x12, 0x00, 0x00, 0x00, 0x00を挿入する
    df 1.234;      // float 1.234を挿入する
    dd 1.234;      // 1.234を挿入する
    de 1.234;      // 1.234を挿入する
    db "abc";      // バイト0x61、0x62、0x63を挿入する
    ds "abc";      // バイト0x61、0x00、0x62、0x00、0x63、0x00を挿入する
}

オペコード

サポートされているオペコードのリストは最後にある。

以下のレジスタがサポートされている。レジスタ名 は常に大文字である。

Register:
    AL
    AH
    AX
    EAX
BL BH BX EBX
CL CH CX ECX
DL DH DX EDX
BP EBP
SP ESP
DI EDI
SI ESI
ES CS SS DS GS FS
CR0 CR2 CR3 CR4
DR0 DR1 DR2 DR3 DR6 DR7
TR3 TR4 TR5 TR6 TR7
ST
ST(0) ST(1) ST(2) ST(3) ST(4) ST(5) ST(6) ST(7)
MM0 MM1 MM2 MM3 MM4 MM5 MM6 MM7
XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7

x86_64 はこれらのレジスタを追加する。

Register64:
    RAX
    RBX
    RCX
    RDX
BPL RBP
SPL RSP
DIL RDI
SIL RSI
R8B R8W R8D R8
R9B R9W R9D R9
R10B R10W R10D R10
R11B R11W R11D R11
R12B R12W R12D R12
R13B R13W R13D R13
R14B R14W R14D R14
R15B R15W R15D R15
XMM8 XMM9 XMM10 XMM11 XMM12 XMM13 XMM14 XMM15
YMM0 YMM1 YMM2 YMM3 YMM4 YMM5 YMM6 YMM7
YMM8 YMM9 YMM10 YMM11 YMM12 YMM13 YMM14 YMM15

特別なケース

lock rep, , , 、repe repne repnz repz
これらのプレフィックス命令は、プレフィックス命令と同じ文には現れない。 これらのプレフィックス命令は、プレフィックス命令と同じステートメントには現れない。 例えば次のようになる:
asm
{
    rep   ;
    movsb ;
}
pause
このオペコードはアセンブラではサポートされていない。
asm
{
    rep  ;
    nop  ;
}
を使う。
floating point ops
命令形式の2オペランド形式を使用する;
fdiv ST(1);     // wrong
fmul ST;        // wrong
fdiv ST,ST(1);  // right
fmul ST,ST(0);  // right

オペランド

Operand:
    AsmExp
AsmExp: AsmLogOrExp AsmLogOrExp ? AsmExp : AsmExp
AsmLogOrExp: AsmLogAndExp AsmLogOrExp || AsmLogAndExp
AsmLogAndExp: AsmOrExp AsmLogAndExp && AsmOrExp
AsmOrExp: AsmXorExp AsmOrExp | AsmXorExp
AsmXorExp: AsmAndExp AsmXorExp ^ AsmAndExp
AsmAndExp: AsmEqualExp AsmAndExp & AsmEqualExp
AsmEqualExp: AsmRelExp AsmEqualExp == AsmRelExp AsmEqualExp != AsmRelExp
AsmRelExp: AsmShiftExp AsmRelExp < AsmShiftExp AsmRelExp <= AsmShiftExp AsmRelExp > AsmShiftExp AsmRelExp >= AsmShiftExp
AsmShiftExp: AsmAddExp AsmShiftExp << AsmAddExp AsmShiftExp >> AsmAddExp AsmShiftExp >>> AsmAddExp
AsmAddExp: AsmMulExp AsmAddExp + AsmMulExp AsmAddExp - AsmMulExp
AsmMulExp: AsmBrExp AsmMulExp * AsmBrExp AsmMulExp / AsmBrExp AsmMulExp % AsmBrExp
AsmBrExp: AsmUnaExp AsmBrExp [ AsmExp ]
AsmUnaExp: AsmTypePrefix AsmExp offsetof AsmExp seg AsmExp + AsmUnaExp - AsmUnaExp ! AsmUnaExp ~ AsmUnaExp AsmPrimaryExp
AsmPrimaryExp: IntegerLiteral FloatLiteral __LOCAL_SIZE $ Register Register : AsmExp Register64 Register64 : AsmExp DotIdentifier this
DotIdentifier: Identifier Identifier . DotIdentifier FundamentalType . Identifier

オペランドの構文は、多かれ少なかれ、インテルCPUのドキュメントに従ったものである。 の規則に従っている。 特に、2オペランド命令では、次のような慣例がある。 ソースは右オペランド、デスティネーションは左オペランドである。 オペランドである。 構文がインテルのものと異なるのは、D言語のトークナイザーと互換性を保つためである。 D言語のトークナイザーと互換性があり、構文解析を簡単にするためである。

seg は、シンボルが含まれるセグメント番号をロードすることを意味する。 をロードすることを意味する。これはフラット・モデル・コードには関係ない。 代わりに、関連するセグメント・レジスタからムーブを行う。

点線式はコンパイル時に評価され、定数を与えるか、上位の変数を示さなければならない。 定数を与えるか、ターゲット・レジスタまたは変数に適合する を示さなければならない。

オペランド型

AsmTypePrefix:
    near ptr
    far ptr
    word ptr
    dword ptr
    qword ptr
    FundamentalType ptr

のように、オペランド・サイズがあいまいな場合である:

add [EAX],3     ;
のようにオペランドサイズが曖昧な場合は、AsmTypePrefixを使うことで曖昧さをなくすことができる:
add  byte ptr [EAX],3 ;
add  int ptr [EAX],7  ;

far ptr はフラットモデル・コードには関係ない。

構造体/共用体/クラス・メンバー・オフセット

集合体のメンバにアクセスするには、集合体へのポインタがレジスタにある場合、修飾名 .offsetof へのポインタがレジスタにある場合、メンバの修飾名の"@property" プロパティを使用する。 プロパティを使用する:

struct Foo { int a,b,c; }
int bar(Foo *f)
{
    asm
    {
        mov EBX,f                   ;
        mov EAX,Foo.b.offsetof[EBX] ;
    }
}
void main()
{
    Foo f = Foo(0, 2, 0);
    assert(bar(&f) == 2);
}

あるいは、集約のスコープ内では、メンバー名だけが必要となる:

struct Foo   // またはクラス
{
    int a,b,c;
    int bar()
    {
        asm
        {
            mov EBX, this   ;
            mov EAX, b[EBX] ;
        }
    }
}
void main()
{
    Foo f = Foo(0, 2, 0);
    assert(f.bar() == 2);
}

スタック変数

スタック変数("関数"のローカル変数で、スタック上に確保された変数)は、インデックス付けされた変数名でアクセスされる。 スタック上に確保されたローカル変数)には、EBPでインデックス付けされた変数名でアクセスする。 を介してアクセスされる:

int foo(int x)
{
    asm
    {
        mov EAX,x[EBP] ; // パラメータxの値をEAXにロードする
        mov EAX,x      ; // 同じことを行う
    }
}

EBP]が省略された場合、ローカル変数とみなされる。 naked を使用した場合は、この限りではない。

特殊記号

ドル;
次の命令の開始のプログラムカウンタを表す。つまり
jmp  $  ;
はjmp命令の次の命令に分岐する。 dollar;は、jmp命令またはcall命令のターゲットとしてのみ使用できる。 命令のターゲットとしてのみ現れる。
__LOCAL_SIZE
これは、ローカルスタックフレームのローカルバイト数に置き換えられる。 スタックフレームのローカルバイト数に置き換えられる。naked 。 が呼び出され、カスタム・スタック・フレームがプログラムされている場合に最も便利である。

サポートされるオペコード

オペコード
aaa aad aam aas adc
add addpd addps addsd addss
and andnpd andnps andpd andps
arpl bound bsf bsr bswap
bt btc btr bts call
cbw cdq clc cld clflush
cli clts cmc cmova cmovae
cmovb cmovbe cmovc cmove cmovg
cmovge cmovl cmovle cmovna cmovnae
cmovnb cmovnbe cmovnc cmovne cmovng
cmovnge cmovnl cmovnle cmovno cmovnp
cmovns cmovnz cmovo cmovp cmovpe
cmovpo cmovs cmovz cmp cmppd
cmpps cmps cmpsb cmpsd cmpss
cmpsw cmpxchg cmpxchg8b cmpxchg16b
comisd comiss
cpuid cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi
cvtpd2ps cvtpi2pd cvtpi2ps cvtps2dq cvtps2pd
cvtps2pi cvtsd2si cvtsd2ss cvtsi2sd cvtsi2ss
cvtss2sd cvtss2si cvttpd2dq cvttpd2pi cvttps2dq
cvttps2pi cvttsd2si cvttss2si cwd cwde
da daa das db dd
de dec df di div
divpd divps divsd divss dl
dq ds dt dw emms
enter f2xm1 fabs fadd faddp
fbld fbstp fchs fclex fcmovb
fcmovbe fcmove fcmovnb fcmovnbe fcmovne
fcmovnu fcmovu fcom fcomi fcomip
fcomp fcompp fcos fdecstp fdisi
fdiv fdivp fdivr fdivrp feni
ffree fiadd ficom ficomp fidiv
fidivr fild fimul fincstp finit
fist fistp fisub fisubr fld
fld1 fldcw fldenv fldl2e fldl2t
fldlg2 fldln2 fldpi fldz fmul
fmulp fnclex fndisi fneni fninit
fnop fnsave fnstcw fnstenv fnstsw
fpatan fprem fprem1 fptan frndint
frstor fsave fscale fsetpm fsin
fsincos fsqrt fst fstcw fstenv
fstp fstsw fsub fsubp fsubr
fsubrp ftst fucom fucomi fucomip
fucomp fucompp fwait fxam fxch
fxrstor fxsave fxtract fyl2x fyl2xp1
hlt idiv imul in inc
ins insb insd insw int
into invd invlpg iret iretd
iretq ja jae jb jbe
jc jcxz je jecxz jg
jge jl jle jmp jna
jnae jnb jnbe jnc jne
jng jnge jnl jnle jno
jnp jns jnz jo jp
jpe jpo js jz lahf
lar ldmxcsr lds lea leave
les lfence lfs lgdt lgs
lidt lldt lmsw lock lods
lodsb lodsd lodsw loop loope
loopne loopnz loopz lsl lss
ltr maskmovdqu maskmovq maxpd maxps
maxsd maxss mfence minpd minps
minsd minss mov movapd movaps
movd movdq2q movdqa movdqu movhlps
movhpd movhps movlhps movlpd movlps
movmskpd movmskps movntdq movnti movntpd
movntps movntq movq movq2dq movs
movsb movsd movss movsw movsx
movupd movups movzx mul mulpd
mulps mulsd mulss neg nop
not or orpd orps out
outs outsb outsd outsw packssdw
packsswb packuswb paddb paddd paddq
paddsb paddsw paddusb paddusw paddw
pand pandn pavgb pavgw pcmpeqb
pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw
pextrw pinsrw pmaddwd pmaxsw pmaxub
pminsw pminub pmovmskb pmulhuw pmulhw
pmullw pmuludq pop popa popad
popf popfd por prefetchnta prefetcht0
prefetcht1 prefetcht2 psadbw pshufd pshufhw
pshuflw pshufw pslld pslldq psllq
psllw psrad psraw psrld psrldq
psrlq psrlw psubb psubd psubq
psubsb psubsw psubusb psubusw psubw
punpckhbw punpckhdq punpckhqdq punpckhwd punpcklbw
punpckldq punpcklqdq punpcklwd push pusha
pushad pushf pushfd pxor rcl
rcpps rcpss rcr rdmsr rdpmc
rdtsc rep repe repne repnz
repz ret retf rol ror
rsm rsqrtps rsqrtss sahf sal
sar sbb scas scasb scasd
scasw seta setae setb setbe
setc sete setg setge setl
setle setna setnae setnb setnbe
setnc setne setng setnge setnl
setnle setno setnp setns setnz
seto setp setpe setpo sets
setz sfence sgdt shl shld
shr shrd shufpd shufps sidt
sldt smsw sqrtpd sqrtps sqrtsd
sqrtss stc std sti stmxcsr
stos stosb stosd stosw str
sub subpd subps subsd subss
syscall sysenter sysexit sysret test
ucomisd ucomiss ud2 unpckhpd unpckhps
unpcklpd unpcklps verr verw wait
wbinvd wrmsr xadd xchg xlat
xlatb xor xorpd xorps

ペンティアム4(プレスコット)対応オペコード

ペンティアム4オペコード
addsubpd addsubps fisttp haddpd haddps
hsubpd hsubps lddqu monitor movddup
movshdup movsldup mwait

AMDがサポートするオペコード

AMDオペコード
pavgusb pf2id pfacc pfadd pfcmpeq
pfcmpge pfcmpgt pfmax pfmin pfmul
pfnacc pfpnacc pfrcp pfrcpit1 pfrcpit2
pfrsqit1 pfrsqrt pfsub pfsubr pi2fd
pmulhrw pswapd

SIMD

SSE、SSE2、SSE3、SSSE3、SSE4.1、SSE4.2、AVXがサポートされている。

GCCの構文

GNU Dコンパイラは、インライン・アセンブラにGCCベースの代替構文を使う:

GccAsmStatement:
    asm FunctionAttributesopt { GccAsmInstructionList }
GccAsmInstructionList: GccAsmInstruction ; GccAsmInstruction ; GccAsmInstructionList
GccAsmInstruction: GccBasicAsmInstruction GccExtAsmInstruction GccGotoAsmInstruction
GccBasicAsmInstruction: AssignExpression
GccExtAsmInstruction: AssignExpression : GccAsmOperandsopt AssignExpression : GccAsmOperandsopt : GccAsmOperandsopt AssignExpression : GccAsmOperandsopt : GccAsmOperandsopt : GccAsmClobbersopt
GccGotoAsmInstruction: AssignExpression : : GccAsmOperandsopt : GccAsmClobbersopt : GccAsmGotoLabelsopt
GccAsmOperands: GccSymbolicNameopt StringLiteral ( AssignExpression ) GccSymbolicNameopt StringLiteral ( AssignExpression ) , GccAsmOperands
GccSymbolicName: [ Identifier ]
GccAsmClobbers: StringLiteral StringLiteral , GccAsmClobbers
GccAsmGotoLabels: Identifier Identifier , GccAsmGotoLabels