D x86 インラインアセンブラ
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
必要ならばアセンブラに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; // バイト列 0x05, 0x06, 0x83 をコードへ挿入 ds 0x1234; // バイト列 0x34, 0x12 di 0x1234; // バイト列 0x34, 0x12, 0x00, 0x00 dl 0x1234; // バイト列 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"; // バイト列 0x61, 0x62, and 0x63 ds "abc"; // バイト列 0x61, 0x00, 0x62, 0x00, 0x63, 0x00 }
オペコード
対応しているオペコードの一覧はこの文書の末尾にあります。以下のレジスタをサポートします。 レジスタ名は常に大文字を用います。
- 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
- BL, BH, BX, EBX
特殊な場合
- lock, rep, repe, repne, repnz, repz
- これら接頭命令は、修飾する命令と同じ文には入れません。
これらの命令一つで一つの文になります。
例:
asm { rep ; movsb ; } - pause
- アセンブラはこのオペコードをサポートしません。代わりに次のように:
{ rep ; nop ; }
書くと、同じ効果が得られます。
- floating point ops
- 命令形式として、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 IntegerConstant FloatConstant __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 ;
には、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 |
