D x86 内联汇编

D,作为一种系统程序设计语言,提供了内联汇编的功能。对于同一个处理器家族来说,D 的内联汇编的实现是标准化了的,例如,Intel Pentium 上的 Win32 D 编译器的内联汇编的语法同 Intel Pentium 上的 Linux D 编译器的语法是一样的。
但是,不同的 D 实现,可以依内存模型、函数调用/返回约定,参数传递约定等的不同而自由实现内联汇编。
本文描述了内联汇编的 x86 实现。
Asm指令:
标志符 : Asm指令
align 整数表达式
even
naked
db 多个操作数
ds 多个操作数
di 多个操作数
dl 多个操作数
df 多个操作数
dd 多个操作数
de 多个操作数
操作码
操作码 多个操作数
多个操作数
操作数
操作数 , 多个操作数
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
标号
汇编指令可以向其他语句一样带有标号。它们可以作为 goto 语句的目标。例如:
void *pc;
asm
{
call L1 ;
L1: ;
pop EBX ;
mov pc[EBP],EBX ; // pc 现在指向 L1 处的代码
}
align 整数表达式
汇编器使用 NOP 指令进行填充,使下一条指令对齐到
整数表达式 边界上。
整数表达式 的值必须是 2 的幂。
使循环代码对齐可以使得执行速度得到可观的提升。
even
汇编器使用 NOP 指令进行填充,使下一条指令对齐到偶数边界上。
naked
禁止编译器生成函数的建帧和退帧指令。这就意味着责任落到了使用内联汇编的程序员的头上,因此这种用法主要用于那些全部用内联汇编编写的函数。
db, ds, di, dl, df, dd, de
这些伪操作用于直接向代码中插入原始数据。
db 用于字节,
ds 用于 16 位字,
di 用于 32 位字,
dl 用于 64 位字,
df 用于 32 位浮点型,
dd 用于 64 位双精度型,
de 用于 80 位扩展实数型。它们都可应用于多个操作数。如果有操作数为字符串文字量,汇编器就认为存在一个隐含的
length 操作数,
length 表示字符串中有多少了字符。每个操作数会额外使用一个字符。例如:
asm
{
db 5,6,0x83; // 插入 byte 0x05、0x06 和 0x83
ds 0x1234; // 插入 byte 0x34、0x12
di 0x1234; // 插入 byte 0x34、0x12、0x00、0x00
dl 0x1234; // 插入 byte 0x34、0x12、0x00、0x00、0x00、0x00、0x00、0x00
df 1.234; // 插入 float 1.234
dd 1.234; // 插入 double 1.234
de 1.234; // 插入 extended 1.234
db "abc"; // 插入 byte 0x61、0x62、and 0x63
ds "abc"; // 插入 byte 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
特殊情况
- lock, rep, repe, repne, repnz, repz
- 这些前缀指令不能同它们修饰的指令位于同一语句,它们必须单独写成一条指令。例如:
asm
{
rep ;
movsb ;
}
- pause
- 内联汇编不支持该操作码,使用
{
rep ;
nop ;
}
代替,效果是相同的。 - 浮点运算
- 使用指令的两操作数形式:
fdiv ST(1); // 错误
fmul ST; // 错误
fdiv ST,ST(1); // 正确
fmul ST,ST(0); // 正确
操作
操作数:
Asm表达式
Asm表达式:
Asm逻辑或表达式
Asm逻辑或表达式 ? Asm表达式 : Asm表达式
Asm逻辑或表达式:
Asm逻辑与表达式
Asm逻辑与表达式 || Asm逻辑与表达式
Asm逻辑与表达式:
Asm或表达式
Asm或表达式 && Asm或表达式
Asm或表达式:
Asm异或表达式
Asm异或表达式 | Asm异或表达式
Asm异或表达式:
Asm与表达式
Asm与表达式 ^ Asm与表达式
Asm与表达式:
Asm相等表达式
Asm相等表达式 & Asm相等表达式
Asm相等表达式:
Asm关系表达式
Asm关系表达式 == Asm关系表达式
Asm关系表达式 != Asm关系表达式
Asm关系表达式:
Asm移位表达式
Asm移位表达式 < Asm移位表达式
Asm移位表达式 <= Asm移位表达式
Asm移位表达式 > Asm移位表达式
Asm移位表达式 >= Asm移位表达式
Asm移位表达式:
Asm和表达式
Asm和表达式 << Asm和表达式
Asm和表达式 >> Asm和表达式
Asm和表达式 >>> Asm和表达式
Asm和表达式:
Asm积表达式
Asm积表达式 + Asm积表达式
Asm积表达式 - Asm积表达式
Asm积表达式:
Asm括号表达式
Asm括号表达式 * Asm括号表达式
Asm括号表达式 / Asm括号表达式
Asm括号表达式 % Asm括号表达式
Asm括号表达式:
Asm一元表达式
Asm括号表达式 [ Asm表达式 ]
Asm一元表达式:
Asm类型前缀 Asm表达式
offset Asm表达式
seg Asm表达式
+ Asm一元表达式
- Asm一元表达式
! Asm一元表达式
~ Asm一元表达式
Asm基本表达式
Asm基本表达式
整数常量
浮点数常量
__LOCAL_SIZE
$
寄存器
点标志符
点标志符
Identifier
标志符 . 点标志符
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
offset AsmExp
seg AsmExp
+ AsmUnaExp
- AsmUnaExp
! AsmUnaExp
~ AsmUnaExp
AsmPrimaryExp
AsmPrimaryExp
IntegerConstant
FloatConstant
__LOCAL_SIZE
$
Register
DotIdentifier
DotIdentifier
Identifier
Identifier . DotIdentifier
操作数的语法基本遵从了 Intel CPU 文档的约定。具体来说,就是右边的操作数是源操作数,左边的操作数是目的操作数。同 Intel 存在不同之处主要是为了同 D 语言的记号识别器和简单解析的目标兼容。
操作类型
Asm类型前缀:
near ptr
far ptr
byte ptr
short ptr
int ptr
word ptr
dword ptr
float ptr
double ptr
extended ptr
AsmTypePrefix:
near ptr
far ptr
byte ptr
short ptr
int ptr
word ptr
dword ptr
float ptr
double ptr
extended ptr
对于操作数大小模棱两可的情况,如同:
add [EAX],3 ;
可以使用
Asm类型前缀 消除歧义:
add byte ptr [EAX],3 ;
add int ptr [EAX],7 ;
结构/联合/类 成员偏移量
假设指向聚集的指针位于一个寄存器中,如果要访问聚集的成员,应使用成员的限定名:
struct Foo { int a,b,c; }
int bar(Foo *f)
{
asm
{ mov EBX,f ;
mov EAX,Foo.b[EBX] ;
}
}
特殊符号
- $
- 代表下一条指令的开始地址。所以,
jmp $ ;
会跳转到 jmp 后的那条指令处。 - __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 | | | |
支持的 AMD 操作码
| pavgusb | pf2id | pfacc | pfadd | pfcmpeq |
| pfcmpge | pfcmpgt | pfmax | pfmin | pfmul |
| pfnacc | pfpnacc | pfrcp | pfrcpit1 | pfrcpit2 |
| pfrsqit1 | pfrsqrt | pfsub | pfsubr | pi2fd |
| pmulhrw | pswapd |