インラインアセンブラ
D はシステムプログラミングのできる言語ですから、 インラインアセンブラを備えています。同一のCPUファミリ上では、 Dのインラインアセンブラは標準化されています。例えば、Win32版の D Compiler の Intel Pentium 向けインラインアセンブラは、 Linux版のIntel Pentium 向けのものと同じ構文が使用できます。
しかし、 異なるアーキテクチャでのDの実装の違いによって、 メモリモデルや関数呼び出し規約の違いが存在する可能性はあります。
このドキュメントでは、 インラインアセンブラのx86での実装について記述します。
AsmInstruction:
Identifier : AsmInstruction
align IntegerExpression
even
naked
db Operands
ds Operands
di Operands
dl Operands
df Operands
dd Operands
de Operands
Opcode
Opcode Operands
Operands:
Operand
Operand , Operands
ラベル
他のDの文同様、 アセンブラの命令にもラベル付けできます。 goto文の飛び先とすることも可能です。例えば:
void *pc;
asm
{
call L1 ;
L1: ;
pop EBX ;
mov pc[EBP],EBX ; // pcはL1のコードを指すようになる
}
align IntegerExpression
IntegerExpression:
IntegerLiteral
Identifier
必要ならばアセンブラにNOP命令を出力させ、 次の命令をメモリの IntegerExpression 境界へ整列します。 IntegerExpression はコンパイル時に2の累乗へ評価される定数です。
ループ先頭を整列すると、 しばしば劇的に実行速度が改善されます。
even
必要ならばアセンブラにNOP命令を出力させ、 次の命令をメモリの偶数番地へ配置します。
naked
コンパイラに、関数のprolog,epilogコードを生成しないように指示します。 これはつまり、そのような処理はインラインアセンブラコードの書き手が 自分で全て書く責任を負うことを意味します。 関数全体をインラインアセンブラで書くときによく使われます。
db, ds, di, dl, df, dd, de
これらの疑似命令は、 生のデータを直接コードに埋め込むときに使います。 db で byte, ds で 16bit word, di で 32bit word, dl で 64bit word, df で 32bit float, dd で 64bit double, de で 80bit extended real を埋め込みます. それぞれ複数のオペランドを指定できます。 オペランドが文字列リテラルだった場合、 文字数個のオペランドが指定されたとみなします。 一文字一文字が一オペランドになります。例えば:asm
{
db 5,6,0x83; // insert bytes 0x05, 0x06, and 0x83 into code
ds 0x1234; // insert bytes 0x34, 0x12
di 0x1234; // insert bytes 0x34, 0x12, 0x00, 0x00
dl 0x1234; // insert bytes 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
df 1.234; // insert float 1.234
dd 1.234; // insert double 1.234
de 1.234; // insert real 1.234
db "abc"; // insert bytes 0x61, 0x62, and 0x63
ds "abc"; // insert bytes 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
特殊な場合
- lock, rep, repe, repne, repnz, repz
- これら接頭命令は、修飾する命令と同じ文には入れません。
これらの命令一つで一つの文になります。
例:
asm { rep ; movsb ; }
- pause
- アセンブラはこのオペコードをサポートしません。代わりに次のように:
asm { rep ; nop ; }
書くと、同じ効果が得られます。 - 浮動小数点演算命令
- 命令形式として、2オペランド形を使います:
fdiv ST(1); // 間違い fmul ST; // 間違い fdiv ST,ST(1); // 正しい fmul ST,ST(0); // 正しい
オペランド
Operand:
AsmExp
AsmExp:
AsmLogOrExp
AsmLogOrExp ? AsmExp : AsmExp
AsmLogOrExp:
AsmLogAndExp
AsmLogAndExp || AsmLogAndExp
AsmLogAndExp:
AsmOrExp
AsmOrExp && AsmOrExp
AsmOrExp:
AsmXorExp
AsmXorExp | AsmXorExp
AsmXorExp:
AsmAndExp
AsmAndExp ^ AsmAndExp
AsmAndExp:
AsmEqualExp
AsmEqualExp & AsmEqualExp
AsmEqualExp:
AsmRelExp
AsmRelExp == AsmRelExp
AsmRelExp != AsmRelExp
AsmRelExp:
AsmShiftExp
AsmShiftExp < AsmShiftExp
AsmShiftExp <= AsmShiftExp
AsmShiftExp > AsmShiftExp
AsmShiftExp >= AsmShiftExp
AsmShiftExp:
AsmAddExp
AsmAddExp << AsmAddExp
AsmAddExp >> AsmAddExp
AsmAddExp >>> AsmAddExp
AsmAddExp:
AsmMulExp
AsmMulExp + AsmMulExp
AsmMulExp - AsmMulExp
AsmMulExp:
AsmBrExp
AsmBrExp * AsmBrExp
AsmBrExp / AsmBrExp
AsmBrExp % AsmBrExp
AsmBrExp:
AsmUnaExp
AsmBrExp [ AsmExp ]
AsmUnaExp:
AsmTypePrefix AsmExp
offsetof AsmExp
seg AsmExp
+ AsmUnaExp
- AsmUnaExp
! AsmUnaExp
~ AsmUnaExp
AsmPrimaryExp
AsmPrimaryExp:
IntegerLiteral
FloatLiteral
__LOCAL_SIZE
$
Register
DotIdentifier
DotIdentifier:
Identifier
Identifier . DotIdentifier
オペランドの構文は、 おおよそのところIntelのCPUドキュメントの規約に従っています。 特に、2オペランド命令では、 ソースが右オペランドでデスディネーションが 左オペランドです。Intelと違うのは、 D言語の字句解析器との互換性を重視し、 パーズを簡単にした部分です。
seg は、シンボルが存在するセグメントの番号を意味します。 これはフラットモデルのコードには無関係です。 代わりに、対応するセグメントレジスタから move します。
オペランド型
AsmTypePrefix:
near ptr
far ptr
byte ptr
short ptr
int ptr
word ptr
dword ptr
qword ptr
float ptr
double ptr
real ptr
オペランドのサイズが曖昧な場合、例えば:
add [EAX],3 ;
iには、AsmTypePrefix を書いて曖昧性を解消します:
add byte ptr [EAX],3 ;
add int ptr [EAX],7 ;
far ptr はフラットモデルのコードには無関係です。
構造体/共用体/クラス メンバのオフセット
集成体へのポインタがレジスタにあってそのメンバへアクセスしたいときは、 メンバの修飾名を使います:
struct Foo { int a,b,c; }
int bar(Foo *f) {
asm {
mov EBX,f ;
mov EAX,Foo.b[EBX] ;
}
}
スタック変数
スタック変数 (関数ローカルの変数で、スタックに割り当てられる) は、 EBP で添え字付けされた変数名でアクセスできます:
int foo(int x) {
asm {
mov EAX,x[EBP] ; // 引数xの値をEAXにロード
mov EAX,x ; // 同上
}
}
[EBP] が省略された場合、ローカル変数への参照と仮定されます。 naked が使われていた場合はその限りではありません。
特殊シンボル
- $
- 直後の命令の先頭のプログラムカウンタを表します。
従って
jmp $ ;
はjmpの直後の命令へと分岐します。 $ は 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 | cmpxch8b | cmpxchg | 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 |
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 | sysenter |
sysexit | test | ucomisd | ucomiss | ud2 |
unpckhpd | unpckhps | unpcklpd | unpcklps | verr |
verw | wait | wbinvd | wrmsr | xadd |
xchg | xlat | xlatb | xor | xorpd |
xorps |
対応している Pentium 4 (Prescott) オペコード
addsubpd | addsubps | fisttp | haddpd | haddps |
hsubpd | hsubps | lddqu | monitor | movddup |
movshdup | movsldup | mwait |
対応しているAMDのオペコード
pavgusb | pf2id | pfacc | pfadd | pfcmpeq |
pfcmpge | pfcmpgt | pfmax | pfmin | pfmul |
pfnacc | pfpnacc | pfrcp | pfrcpit1 | pfrcpit2 |
pfrsqit1 | pfrsqrt | pfsub | pfsubr | pi2fd |
pmulhrw | pswapd |