private ParsedOperand ParsePtrOperand(PrimitiveType width) { Expect(Token.PTR); ParsedOperand op = ParseOperand(); op.Operand.Width = width; return(op); }
public ParsedOperand [] ParseOperandList(int min, int max) { OperandParser opp = asm.CreateOperandParser(lexer); List <ParsedOperand> ops = new List <ParsedOperand>(); asm.SegmentOverride = RegisterStorage.None; asm.AddressWidth = asm.SegmentAddressWidth; if (lexer.PeekToken() != Token.EOL) { ops.Add(opp.ParseOperand()); if (opp.SegmentOverride != RegisterStorage.None) { asm.SegmentOverride = opp.SegmentOverride; } if (opp.AddressWidth != null) { asm.AddressWidth = opp.AddressWidth; } while (lexer.PeekToken() == Token.COMMA) { lexer.DiscardToken(); opp.DataWidth = ops[0].Operand.Width; ops.Add(opp.ParseOperand()); if (opp.SegmentOverride != RegisterStorage.None) { if (asm.SegmentOverride != RegisterStorage.None) { Error("Can't have two segment overrides in one instruction"); } asm.SegmentOverride = opp.SegmentOverride; } if (opp.AddressWidth != null) { asm.AddressWidth = opp.AddressWidth; } } } if (min <= ops.Count && ops.Count <= max) { ParsedOperand [] o = new ParsedOperand[ops.Count]; ops.CopyTo(o); return(o); } else { if (min == max) { Error(string.Format("Instruction expects {0} operand(s).", min)); } else { Error(string.Format("Instruction expects between {0} and {1} operand(s).", min, max)); } return(null); } }
internal void ProcessBitScan(byte opCode, ParsedOperand dst, ParsedOperand src) { PrimitiveType dataWidth = EnsureValidOperandSize(src); RegisterOperand regDst = dst.Operand as RegisterOperand; if (regDst == null) Error("First operand of bit scan instruction must be a register"); EmitOpcode(0x0F, dataWidth); emitter.EmitByte(opCode); EmitModRM(RegisterEncoding(regDst.Register), src); }
internal void EmitModRM(int reg, ParsedOperand op) { RegisterOperand regOp = op.Operand as RegisterOperand; if (regOp != null) { modRm.EmitModRM(reg, regOp); return; } FpuOperand fpuOp = op.Operand as FpuOperand; if (fpuOp != null) { modRm.EmitModRM(reg, fpuOp); } else { EmitModRM(reg, (MemoryOperand) op.Operand, op.Symbol); } }
private PrimitiveType EnsureValidOperandSizes(ParsedOperand[] ops, int count) { if (count == 0) return null; PrimitiveType w = ops[0].Operand.Width; if (count == 1 && ops[0].Operand.Width == null) Error("Width of the first operand is unknown"); if (count == 2) { if (w == null) { w = ops[1].Operand.Width; if (w == null) Error("Width of the first operand is unknown"); else ops[0].Operand.Width = w; } else { if (ops[1].Operand.Width == null) ops[1].Operand.Width = w; else if (ops[0].Operand.Width != ops[0].Operand.Width) Error("Operand widths don't match"); } } return w; }
internal void ProcessPushPop(bool fPop, ParsedOperand op) { int imm; ImmediateOperand immOp = op.Operand as ImmediateOperand; if (immOp != null) { if (fPop) throw new ApplicationException("Can't pop an immediate value"); imm = immOp.Value.ToInt32(); if (IsSignedByte(imm)) { EmitOpcode(0x6A, PrimitiveType.Byte); emitter.EmitByte(imm); } else { EmitOpcode(0x68, SegmentDataWidth); emitter.EmitLe(SegmentDataWidth, imm); } return; } PrimitiveType dataWidth = EnsureValidOperandSize(op); RegisterOperand regOp = op.Operand as RegisterOperand; if (regOp != null) { var rrr = regOp.Register; if (IsBaseRegister(rrr)) { EmitOpcode(0x50 | (fPop ? 8 : 0) | RegisterEncoding(regOp.Register), dataWidth); } else { int mask = (fPop ? 1 : 0); if (regOp.Register == Registers.es) emitter.EmitByte(0x06 | mask); else if (regOp.Register == Registers.cs) emitter.EmitByte(0x0E | mask); else if (regOp.Register == Registers.ss) emitter.EmitByte(0x16 | mask); else if (regOp.Register == Registers.ds) emitter.EmitByte(0x1E | mask); else if (regOp.Register == Registers.fs) { emitter.EmitByte(0x0F); emitter.EmitByte(0xA0 | mask); } else if (regOp.Register == Registers.gs) { emitter.EmitByte(0x0F); emitter.EmitByte(0xA8 | mask); } } return; } EmitOpcode(fPop ? 0x8F : 0xFF, dataWidth); EmitModRM(fPop ? 0 : 6, op); }
internal void ProcessShiftRotation(byte bits, ParsedOperand dst, ParsedOperand count) { PrimitiveType dataWidth = EnsureValidOperandSize(dst); ImmediateOperand immOp = count.Operand as ImmediateOperand; if (immOp != null) { int imm = immOp.Value.ToInt32(); if (imm == 1) { EmitOpcode(0xD0 | IsWordWidth(dataWidth), dataWidth); EmitModRM(bits, dst); } else { EmitOpcode(0xC0 | IsWordWidth(dataWidth), dataWidth); EmitModRM(bits, dst, (byte) immOp.Value.ToInt32()); } return; } RegisterOperand regOp = count.Operand as RegisterOperand; if (regOp != null && regOp.Register == Registers.cl) { EmitOpcode(0xD2 | IsWordWidth(dataWidth), dataWidth); EmitModRM(bits, dst); return; } throw new ApplicationException("Shift/rotate instructions must be followed by a constant or CL"); }
internal void ProcessIncDec(bool fDec, ParsedOperand op) { PrimitiveType dataWidth = EnsureValidOperandSize(op); RegisterOperand regOp = op.Operand as RegisterOperand; if (regOp != null) { if (IsWordWidth(dataWidth) != 0) { EmitOpcode((fDec ? 0x48 : 0x40) | RegisterEncoding(regOp.Register), dataWidth); } else { EmitOpcode(0xFE | IsWordWidth(dataWidth), dataWidth); EmitModRM(fDec ? 1 : 0, op); } return; } MemoryOperand memOp = op.Operand as MemoryOperand; if (memOp != null) { EmitOpcode(0xFE | IsWordWidth(dataWidth), dataWidth); EmitModRM(fDec ? 1 : 0, op); } else { throw new ApplicationException("constant operator illegal"); } }
internal void ProcessMovx(int opcode, ParsedOperand[] ops) { PrimitiveType dataWidth = EnsureValidOperandSize(ops[1]); RegisterOperand regDst = ops[0].Operand as RegisterOperand; if (regDst == null) Error("First operand must be a register"); EmitOpcode(0x0F, regDst.Width); emitter.EmitByte(opcode | IsWordWidth(dataWidth)); EmitModRM(RegisterEncoding(regDst.Register), ops[1]); }
public void Cmp(ParsedOperand src, int dst) { ProcessBinop(0x7, src, Imm(dst)); }
public void Sub(ParsedOperand op, int constant) { Sub(op, Imm(op.Operand.Width, constant)); }
public void Shrd(ParsedOperand op1, ParsedOperand op2, byte count) { ProcessDoubleShift(8, op1, op2, new ParsedOperand(ImmediateOperand.Byte(count))); }
public void Bsr(ParsedOperand dst, ParsedOperand src) { ProcessBitScan(0xBD, dst, src); }
public void Shld(ParsedOperand op1, ParsedOperand op2, ParsedOperand op3) { ProcessDoubleShift(0, op1, op2, op3); }
internal void ProcessDoubleShift(byte bits, ParsedOperand op0, ParsedOperand op1, ParsedOperand count) { PrimitiveType dataWidth = EnsureValidOperandSize(op0); RegisterOperand regSrc = op1.Operand as RegisterOperand; if (regSrc == null) Error("Second operand of SHLD/SHRD must be a register"); ImmediateOperand immShift = count.Operand as ImmediateOperand; RegisterOperand regShift = count.Operand as RegisterOperand; if (regShift != null && regShift.Register == Registers.cl) { bits |= 0x01; } else if (immShift == null) { Error("SHLD/SHRD instruction must be followed by a constant or CL"); } EmitOpcode(0x0F, dataWidth); emitter.EmitByte(0xA4 | bits); EmitModRM(RegisterEncoding(regSrc.Register), op0); if (immShift != null) emitter.EmitByte((byte) immShift.Value.ToUInt32()); }
internal void ProcessCallJmp(bool far, int indirect, ParsedOperand op) { if (far) indirect |= 1; EmitOpcode(0xFF, SegmentDataWidth); EmitModRM(indirect, op); }
internal void ProcessFpuCommon(int opcodeFreg, int opcodeMem, int fpuOperation, bool isPop, bool fixedOrder, params ParsedOperand[] ops) { if (ops.Length == 0) { ops = new ParsedOperand[] { new ParsedOperand(new FpuOperand(0)), new ParsedOperand(new FpuOperand(1)) }; } else if (ops.Length == 1 && ops[0].Operand is FpuOperand) { ops = new ParsedOperand[] { new ParsedOperand(new FpuOperand(0)), ops[0] }; } FpuOperand fop1 = ops[0].Operand as FpuOperand; FpuOperand fop2 = ops.Length > 1 ? ops[1].Operand as FpuOperand : null; MemoryOperand mop = ops[0].Operand as MemoryOperand; if (mop == null && ops.Length > 1) mop = ops[1].Operand as MemoryOperand; if (mop != null) { EmitOpcode(opcodeMem | (mop.Width == PrimitiveType.Word64 ? 4 : 0), null); EmitModRM(fpuOperation, mop, null); return; } if (isPop) { if (fop1 == null) Error("First operand must be of type ST(n)"); EmitOpcode(opcodeFreg, null); if (fixedOrder) fpuOperation ^= 1; if (fop1.StNumber == 0) EmitModRM(fpuOperation, new ParsedOperand(fop2, null)); else EmitModRM(fpuOperation, new ParsedOperand(fop1, null)); return; } if (fop1 != null) { fop2 = (FpuOperand) ops[1].Operand; if (fop1.StNumber != 0) { if (fop2.StNumber != 0) Error("at least one of the floating point stack arguments must be ST(0)"); if (fixedOrder) fpuOperation ^= 1; fop2 = fop1; } EmitOpcode(opcodeFreg, null); EmitModRM(fpuOperation, new ParsedOperand(fop2, null)); return; } throw new NotImplementedException("NYI"); }
public void Les(ParsedOperand dst, ParsedOperand src) { ProcessLxs(-1, 0xC4, dst, src); }
internal void ProcessFst(bool pop, ParsedOperand operand) { FpuOperand fop = operand.Operand as FpuOperand; MemoryOperand mop = operand.Operand as MemoryOperand; int regBits = pop ? 3 : 2; if (mop != null) { switch (mop.Width.Size) { case 4: EmitOpcode(0xD9, null); break; case 8: EmitOpcode(0xDD, null); break; default: Error("Unexpected operator width"); break; } EmitModRM(regBits, operand); } else if (fop != null) { EmitOpcode(0xDD, null); EmitModRM(regBits, new ParsedOperand(fop, null)); } else Error("Unexpected operator type"); }
public void Sub(ParsedOperand minuend, ParsedOperand subtrahend) { ProcessBinop(0x05, minuend, subtrahend); }
internal void ProcessInt(ParsedOperand vector) { ImmediateOperand op = (ImmediateOperand) vector.Operand; EmitOpcode(0xCD, null); emitter.EmitByte(op.Value.ToInt32()); }
public void Test(ParsedOperand op1, ParsedOperand op2) { ProcessTest( op1, op2 ); }
public void Mul(ParsedOperand op) { PrimitiveType dataWidth = EnsureValidOperandSize(op); // Single operand doesn't accept immediate values. if (op.Operand is ImmediateOperand) Error("Immediate operand not allowed for single-argument multiplication"); EmitOpcode(0xF6 | IsWordWidth(dataWidth), dataWidth); EmitModRM(4, op); }
internal void Xchg(ParsedOperand[] ops) { PrimitiveType dataWidth = EnsureValidOperandSizes(ops, 2); RegisterOperand regOp = ops[0].Operand as RegisterOperand; ParsedOperand otherOp = ops[1]; if (regOp == null) { regOp = ops[1].Operand as RegisterOperand; if (regOp == null) { Error("One operand must be a register."); } otherOp = ops[0]; } EmitOpcode(0x86 | IsWordWidth(regOp), dataWidth); EmitModRM(RegisterEncoding(regOp.Register), otherOp); }
internal void ProcessSetCc(byte bits, ParsedOperand op) { PrimitiveType dataWidth = EnsureValidOperandSize(op); if (dataWidth != PrimitiveType.Byte) Error("Instruction takes only a byte operand"); EmitOpcode(0x0F, dataWidth); emitter.EmitByte(0x90 | (bits & 0xF)); EmitModRM(0, op); }
public void Xor(ParsedOperand dst, ParsedOperand src) { ProcessBinop(0x06, dst, src); }
internal void ProcessUnary(int operation, ParsedOperand op) { PrimitiveType dataWidth = EnsureValidOperandSize(op); EmitOpcode(0xF6 | IsWordWidth(dataWidth), dataWidth); EmitModRM(operation, op); }
internal void ProcessBitOp(ParsedOperand[] ops) { PrimitiveType dataWidth = EnsureValidOperandSize(ops[0]); ImmediateOperand imm2 = ops[1].Operand as ImmediateOperand; if (imm2 != null) { EmitOpcode(0x0F, dataWidth); emitter.EmitByte(0xBA); EmitModRM(0x04, ops[0]); emitter.EmitByte(imm2.Value.ToInt32()); } else { EmitOpcode(0x0F, dataWidth); emitter.EmitByte(0xA3); EmitModRM(RegisterEncoding(((RegisterOperand) ops[1].Operand).Register), ops[0]); } }
internal void EmitModRM(int reg, ParsedOperand op, byte b) { RegisterOperand regOp = op.Operand as RegisterOperand; if (regOp != null) { modRm.EmitModRM(reg, regOp); emitter.EmitByte(b); } else { EmitModRM(reg, (MemoryOperand) op.Operand, b, op.Symbol); } }
internal PrimitiveType EnsureValidOperandSize(ParsedOperand op) { PrimitiveType w = op.Operand.Width; if (w == null) Error("Width of the operand is unknown"); return w; }
public void Test(ParsedOperand op1, int imm) { ProcessTest(op1, Imm(imm)); }
public void Shr(ParsedOperand dst, byte c) { ProcessShiftRotation(0x05, dst, new ParsedOperand(new ImmediateOperand(Constant.Byte(c)))); }