Пример #1
0
        /// <summary>
        /// Decodes an instruction.
        /// </summary>
        /// <param name="code">X86 binary code.</param>
        /// <param name="startIndex">Index of the first byte to start
        /// decoding.</param>
        /// <param name="context">Decoding context.</param>
        /// <returns>The decoded instruction.</returns>
        /// <exception cref="InvalidInstructionException">If decoding failed.
        /// </exception>
        public Instruction Decode(
            byte[] code, 
            int startIndex,
            int count,
            DecoderContext context)
        {
            Instruction instruction = new Instruction();

            // Create an instruction reader.
            InstructionReader reader = new InstructionReader(code, startIndex, count);

            // Reset the context.
            context.AddressSize = CpuSize.Use16Bit;
            context.OperandSize = CpuSize.Use16Bit;
            context.SegmentOverride = Register.None;

            // Decode prefixes.
            Prefixes prefix = DecodeLegacyPrefixes(reader);
            if ((prefix & Prefixes.OperandSizeOverride) != 0)
            {
                context.OperandSize = CpuSize.Use32Bit;
            }
            if ((prefix & Prefixes.AddressSizeOverride) != 0)
            {
                context.AddressSize = CpuSize.Use32Bit;
            }
            if ((prefix & Prefixes.Group2) != 0)
            {
                Register seg = Register.None;
                switch (prefix & Prefixes.Group2)
                {
                    case Prefixes.ES: seg = Register.ES; break;
                    case Prefixes.CS: seg = Register.CS; break;
                    case Prefixes.SS: seg = Register.SS; break;
                    case Prefixes.DS: seg = Register.DS; break;
                    case Prefixes.FS: seg = Register.FS; break;
                    case Prefixes.GS: seg = Register.GS; break;
                }
                context.SegmentOverride = seg;
            }
            instruction.Prefix = prefix;

            // Decode the opcode to retrieve opcode specification.
            Op spec = DecodeOpcode(reader);
            instruction.Operation = spec.Operation;

            // Decode operands.
            instruction.Operands = new Operand[spec.Operands.Length];
            for (int i = 0; i < spec.Operands.Length; i++)
            {
                instruction.Operands[i] =
                    DecodeOperand(spec.Operands[i], reader, context);
            }

            // Update the encoded length of the instruction.
            instruction.EncodedLength = reader.Position;
            //instruction.Location = location;
            return instruction;
        }
Пример #2
0
        static Operand DecodeOperand(O spec,
            InstructionReader reader, DecoderContext context)
        {
            int number;
            CpuSize size;

            switch (spec)
            {
                case O.Imm0:
                case O.Imm1:
                case O.Imm2:
                case O.Imm3:
                    return new ImmediateOperand(spec - O.Imm0, CpuSize.Use8Bit);

                case O.ES:
                case O.CS:
                case O.SS:
                case O.DS:
                    return CreateRegisterOperand(
                        RegisterType.Segment,
                        spec - O.ES,
                        CpuSize.Use16Bit);

                case O.AL:
                case O.CL:
                case O.DL:
                case O.BL:
                    return CreateRegisterOperand(
                        RegisterType.General,
                        spec - O.AL,
                        CpuSize.Use8Bit);

                case O.AH:
                case O.CH:
                case O.DH:
                case O.BH:
                    return CreateRegisterOperand(
                        RegisterType.HighByte,
                        spec - O.AH,
                        CpuSize.Use8Bit);

                case O.AX:
                case O.CX:
                case O.DX:
                case O.BX:
                case O.SP:
                case O.BP:
                case O.SI:
                case O.DI:
                    return CreateRegisterOperand(
                        RegisterType.General,
                        spec - O.AX,
                        CpuSize.Use16Bit);

                case O.eAX:
                case O.eCX:
                case O.eDX:
                case O.eBX:
                case O.eSP:
                case O.eBP:
                case O.eSI:
                case O.eDI:
                    number = spec - O.eAX;
                    size = (context.OperandSize == CpuSize.Use16Bit) ?
                        CpuSize.Use16Bit : CpuSize.Use32Bit;
                    return CreateRegisterOperand(RegisterType.General, number, size);

                case O.rAX:
                case O.rCX:
                case O.rDX:
                case O.rBX:
                case O.rSP:
                case O.rBP:
                case O.rSI:
                case O.rDI:
                    number = spec - O.rAX;
                    return CreateRegisterOperand(RegisterType.General, number, context.OperandSize);

                case O.ST0:
                    return new RegisterOperand(Register.ST0);

                case O.Ap: // off:seg encoded in the instruction
                    if (context.OperandSize != CpuSize.Use16Bit)
                    {
                        throw new NotSupportedException();
                    }
                    else
                    {
                        var off = reader.ReadImmediate(CpuSize.Use16Bit);
                        var seg = reader.ReadImmediate(CpuSize.Use16Bit);
                        return new PointerOperand(
                            new Operand.LocationAware<UInt16>(seg.Location, (UInt16)seg.Value),
                            new Operand.LocationAware<UInt32>(off.Location, (UInt16)off.Value));
                    }

                case O.Eb: // r/m; 8-bit
                    return DecodeMemoryOperand(reader, RegisterType.General, CpuSize.Use8Bit, context);

                case O.Ep: // r/m; contains far ptr
                    if (context.OperandSize != CpuSize.Use16Bit)
                        throw new NotSupportedException();
                    // TBD: operand size? address size?
                    return DecodeMemoryOperand(reader, RegisterType.General, CpuSize.Use16Bit, context);

                case O.Ev: // r/m; 16, 32, or 64 bit
                    return DecodeMemoryOperand(reader, RegisterType.General, context.OperandSize, context);

                case O.Ew: // r/m; 16-bit
                    return DecodeMemoryOperand(reader, RegisterType.General, CpuSize.Use16Bit, context);

                case O.Fv: // FLAGS/EFLAGS/RFLAGS
                    return new RegisterOperand(Register.FLAGS.Resize(context.OperandSize));

                case O.Gb: // general-purpose register; byte
                    return DecodeRegisterOperand(reader, RegisterType.General, CpuSize.Use8Bit, context);

                case O.Gv: // general-purpose register; 16, 32, or 64 bit
                    return DecodeRegisterOperand(reader, RegisterType.General, context.OperandSize, context);

                case O.Gw: // general-purpose register; 16-bit
                    return DecodeRegisterOperand(reader, RegisterType.General, CpuSize.Use16Bit, context);

                case O.Gz: // general-purpose register; 16 or 32 bit
                    return DecodeRegisterOperand(
                        reader,
                        RegisterType.General,
                        context.OperandSize == CpuSize.Use16Bit ? CpuSize.Use16Bit : CpuSize.Use32Bit,
                        context);

                case O.Ib: // immediate; byte
                    return DecodeImmediateOperand(reader, CpuSize.Use8Bit);

                case O.Iw: // immediate; 16 bit
                    return DecodeImmediateOperand(reader, CpuSize.Use16Bit);

                case O.Iv: // immediate, 16, 32, or 64 bit
                    return DecodeImmediateOperand(reader, context.OperandSize);

                case O.Iz: // immediate, 16 or 32 bit
                    return DecodeImmediateOperand(reader,
                        (context.OperandSize == CpuSize.Use16Bit) ?
                        CpuSize.Use16Bit : CpuSize.Use32Bit);

                case O.Jb: // immediate encodes relative offset; byte
                    return DecodeRelativeOperand(reader, CpuSize.Use8Bit);

                case O.Jz: // immediate encodes relative offset; 16 or 32 bit
                    return DecodeRelativeOperand(reader,
                        (context.OperandSize == CpuSize.Use16Bit) ?
                        CpuSize.Use16Bit : CpuSize.Use32Bit);

                case O.M_: // r/m must refer to memory; contains void pointer
                    return DecodeMemoryOperand(reader, RegisterType.None, CpuSize.Default, context);

                case O.Ma: // r/m must refer to memory; contains a pair of words or dwords
                    // TODO: handle 32-bit
                    return DecodeMemoryOperand(reader, RegisterType.None, CpuSize.Use32Bit, context);

                case O.Mp: // r/m must refer to memory; contains far pointer
                    // seg:ptr of 32, 48, or 80 bits.
                    if (context.OperandSize != CpuSize.Use16Bit)
                        throw new NotSupportedException();
                    return DecodeMemoryOperand(reader, RegisterType.None, CpuSize.Use32Bit, context);

                case O.Mb: // r/m refers to memory; byte
                    return DecodeMemoryOperand(reader, RegisterType.None, CpuSize.Use8Bit, context);

                case O.Mw: // r/m refers to memory; word
                    return DecodeMemoryOperand(reader, RegisterType.None, CpuSize.Use16Bit, context);

                case O.Md: // r/m refers to memory; dword
                    return DecodeMemoryOperand(reader, RegisterType.None, CpuSize.Use32Bit, context);

                case O.Mq:
                    return DecodeMemoryOperand(reader, RegisterType.None, CpuSize.Use64Bit, context);

                case O.M14or28b: // r/m refers to memory; 14 or 28 bytes
                    // TODO: we actually need to check the CPU operation mode,
                    // not the operand-size attribute.
                    return DecodeMemoryOperand(
                        reader,
                        RegisterType.None,
                        (context.OperandSize == CpuSize.Use16Bit) ? 
                            CpuSize.Use14Bytes : CpuSize.Use28Bytes,
                        context);

                case O.M32fp: // r/m refers to memory; single-precision float
                    return DecodeMemoryOperand(reader, RegisterType.None, CpuSize.Use32Bit, context);

                case O.M64fp: // r/m refers to memory; double-precision float
                    return DecodeMemoryOperand(reader, RegisterType.None, CpuSize.Use64Bit, context);

                case O.M80fp: // r/m refers to memory; extended-precision float
                    return DecodeMemoryOperand(reader, RegisterType.None, CpuSize.Use80Bit, context);

                case O.Ob: // absolute address (w/o segment); byte
                    // TODO: check 64-bit mode behavior
                    return new MemoryOperand
                    {
                        Size = CpuSize.Use8Bit,
                        Displacement = reader.ReadImmediate(context.AddressSize),
                        // Segment = Register.DS,
                    };

                case O.Ov: // absolute address (w/o segment); 16, 32, or 64 bit
                    // TODO: check 64-bit mode behavior
                    return new MemoryOperand
                    {
                        Size = context.OperandSize,
                        Displacement = reader.ReadImmediate(context.AddressSize),
                        // Segment = Register.DS,
                    };

                case O.Sw: // REG(modrm) selects segment register
                    return DecodeRegisterOperand(reader, RegisterType.Segment, CpuSize.Use16Bit, context);

                case O.T80fp: // r/m selects x87 FPU register ST0-ST7
                    return CreateRegisterOperand(RegisterType.Fpu, reader.GetModRM().RM, CpuSize.Use80Bit);

                case O.Xb: // memory addressed by DS:rSI; byte
                    return new MemoryOperand
                    {
                        Size = CpuSize.Use8Bit,
                        Segment = Register.DS,
                        Base = Register.SI.Resize(context.AddressSize)
                    };

                case O.Xv: // memory addressed by DS:rSI; 16, 32, or 64 bit
                    return new MemoryOperand
                    {
                        Size = context.OperandSize,
                        Segment = Register.DS,
                        Base = Register.SI.Resize(context.AddressSize)
                    };

                case O.Xz: // memory addressed by DS:rSI; 16 or 32 bit
                    return new MemoryOperand
                    {
                        Size = CpuSize.Use16Bit, // TODO: handle 32 bit
                        Segment = Register.DS,
                        Base = Register.SI.Resize(context.AddressSize)
                    };

                case O.Yb: // memory addressed by ES:rDI; byte
                    return new MemoryOperand
                    {
                        Size = CpuSize.Use8Bit,
                        Segment = Register.ES,
                        Base = Register.DI.Resize(context.AddressSize)
                    };

                case O.Yv: // memory addressed by ES:rDI; 16, 32, or 64 bit
                    return new MemoryOperand
                    {
                        Size = context.OperandSize,
                        Segment = Register.ES,
                        Base = Register.DI.Resize(context.AddressSize)
                    };

                case O.Yz: // memory addressed by ES:rDI; 16 or 32 bit
                    return new MemoryOperand
                    {
                        Size = CpuSize.Use16Bit, // TODO: handle 32 bit
                        Segment = Register.ES,
                        Base = Register.DI.Resize(context.AddressSize)
                    };

                case O._XLAT:
                    return new MemoryOperand
                    {
                        Size = CpuSize.Use8Bit,
                        Segment = context.SegmentOverride,
                        Base = (context.AddressSize == CpuSize.Use16Bit) ?
                            Register.BX : Register.EBX
                    };

                default:
                    throw new NotImplementedException(
                        "DecodeOperand() is not implemented for operand type " + spec.ToString());
            }
        }
Пример #3
0
 static RelativeOperand DecodeRelativeOperand(InstructionReader reader, CpuSize size)
 {
     return new RelativeOperand(reader.ReadImmediate(size));
 }
Пример #4
0
 static ImmediateOperand DecodeImmediateOperand(InstructionReader reader, CpuSize size)
 {
     return new ImmediateOperand(reader.ReadImmediate(size), size);
 }
Пример #5
0
        // Note: we need to take into account OperandSizeOverride and
        // AddressSizeOverride!!!!!!

        /// <summary>
        /// Decodes a memory operand encoded by the ModRM byte, SIB byte, and
        /// Displacement, or a register operand if MOD=3 and registerType is
        /// specified.
        /// </summary>
        /// <param name="reader">Instruction reader.</param>
        /// <param name="registerType">Type of the register to return if the
        /// Mod field of the ModR/M byte is 3. If this parameter is set to
        /// RegisterType.None, an exception is thrown if Mod=3.</param>
        /// <param name="operandSize">Size of the returned operand.</param>
        /// <param name="context">Decoding context.</param>
        /// <returns>The decoded memory or register operand.</returns>
        /// <exception cref="InvalidInstructionException">If registerType is
        /// set to None but the ModR/M byte encodes a register.</exception>
        static Operand DecodeMemoryOperand(
            InstructionReader reader,
            RegisterType registerType,
            CpuSize operandSize,
            DecoderContext context)
        {
            if (context.CpuMode == CpuMode.X64Mode)
                throw new NotSupportedException();
            //if (operandSize == CpuSize.Default)
            //    throw new ArgumentException("operandSize is not specified.");
            if (context.AddressSize != CpuSize.Use16Bit)
                throw new NotSupportedException("32-bit addressing mode is not supported.");

            ModRM modrm = reader.GetModRM();
            int rm = modrm.RM;
            int mod = modrm.MOD;

            // Decode a register if MOD = (11).
            if (mod == 3)
            {
                // If the instruction expects a memory operand, throw an exception.
                if (registerType == RegisterType.None)
                {
                    throw new InvalidInstructionException(
                        "The instruction expects a memory operand, but the ModR/M byte encodes a register.");
                }

                // Treat AH-DH specially.
                if (registerType == RegisterType.General &&
                    operandSize == CpuSize.Use8Bit &&
                    rm >= 4)
                {
                    return new RegisterOperand(new Register(
                        RegisterType.HighByte,
                        rm - 4,
                        CpuSize.Use8Bit));
                }
                else
                {
                    return new RegisterOperand(new Register(registerType, rm, operandSize));
                }
            }

            // Take into account segment override prefix if present.
            Register segment = context.SegmentOverride;

            // Special treatment for MOD = (00) and RM = (110).
            // This encodes a 16-bit sign-extended displacement.
            if (mod == 0 && rm == 6)
            {
                return new MemoryOperand
                {
                    Size = operandSize,
                    Segment = segment,
                    Displacement = reader.ReadImmediate(CpuSize.Use16Bit)
                };
            }

            /* Decode an indirect memory address XX[+YY][+disp]. */
            MemoryOperand mem = new MemoryOperand();
            mem.Size = operandSize;
            mem.Segment = segment;
            switch (rm)
            {
                case 0: /* [BX+SI] */
                    mem.Base = Register.BX;
                    mem.Index = Register.SI;
                    break;
                case 1: /* [BX+DI] */
                    mem.Base = Register.BX;
                    mem.Index = Register.DI;
                    break;
                case 2: /* [BP+SI] */
                    mem.Base = Register.BP;
                    mem.Index = Register.SI;
                    break;
                case 3: /* [BP+DI] */
                    mem.Base = Register.BP;
                    mem.Index = Register.DI;
                    break;
                case 4: /* [SI] */
                    mem.Base = Register.SI;
                    break;
                case 5: /* [DI] */
                    mem.Base = Register.DI;
                    break;
                case 6: /* [BP] */
                    mem.Base = Register.BP;
                    break;
                case 7: /* [BX] */
                    mem.Base = Register.BX;
                    break;
            }
            if (mod == 1) /* disp8, sign-extended */
            {
                mem.Displacement = reader.ReadImmediate(CpuSize.Use8Bit);
            }
            else if (mod == 2) /* disp16, sign-extended */
            {
                mem.Displacement = reader.ReadImmediate(CpuSize.Use16Bit);
            }
            return mem;
        }
Пример #6
0
        /// <summary>
        /// Decodes a register operand from the REG field of the ModR/M byte.
        /// Since the REG field only contains the register number, additional
        /// parameters are used to determine the register's type and size.
        /// </summary>
        /// <param name="reader">Instruction reader.</param>
        /// <param name="registerType">Type of the register to return.</param>
        /// <param name="operandSize">Size of the register to return.</param>
        /// <param name="context">Decoding context.</param>
        /// <returns>The decoded register operand.</returns>
        private static RegisterOperand DecodeRegisterOperand(
            InstructionReader reader,
            RegisterType registerType,
            CpuSize operandSize,
            DecoderContext context)
        {
            if (context.CpuMode == CpuMode.X64Mode)
                throw new NotSupportedException();
            if (operandSize == CpuSize.Default)
                throw new ArgumentException("operandSize is not specified.");

            int reg = reader.GetModRM().REG;
            if (registerType == RegisterType.General &&
                operandSize == CpuSize.Use8Bit &&
                reg >= 4)
            {
                return new RegisterOperand(new Register(
                    RegisterType.HighByte,
                    reg - 4,
                    CpuSize.Use8Bit));
            }
            return new RegisterOperand(new Register(registerType, reg, operandSize));
        }
Пример #7
0
        private Op DecodeFpuOpcode(InstructionReader reader, byte firstByte)
        {
            ModRM modrm = reader.GetModRM();
            int mod = modrm.MOD;
            int reg = modrm.REG;
            int rm = modrm.RM;
            Op x = Op.Empty;

            switch (firstByte)
            {
                case 0xD8:
                    if (mod == 3)
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FADD, O.ST0, O.T80fp); break;
                            case 1: x = new Op(Operation.FMUL, O.ST0, O.T80fp); break;
                            case 2: x = new Op(Operation.FCOM, O.ST0, O.T80fp); break;
                            case 3: x = new Op(Operation.FCOMP, O.ST0, O.T80fp); break;
                            case 4: x = new Op(Operation.FSUB, O.ST0, O.T80fp); break;
                            case 5: x = new Op(Operation.FSUBR, O.ST0, O.T80fp); break;
                            case 6: x = new Op(Operation.FDIV, O.ST0, O.T80fp); break;
                            case 7: x = new Op(Operation.FDIVR, O.ST0, O.T80fp); break;
                        }
                    }
                    else
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FADD, O.ST0, O.M32fp); break;
                            case 1: x = new Op(Operation.FMUL, O.ST0, O.M32fp); break;
                            case 2: x = new Op(Operation.FCOM, O.ST0, O.M32fp); break;
                            case 3: x = new Op(Operation.FCOMP, O.ST0, O.M32fp); break;
                            case 4: x = new Op(Operation.FSUB, O.ST0, O.M32fp); break;
                            case 5: x = new Op(Operation.FSUBR, O.ST0, O.M32fp); break;
                            case 6: x = new Op(Operation.FDIV, O.ST0, O.M32fp); break;
                            case 7: x = new Op(Operation.FDIVR, O.ST0, O.M32fp); break;
                        }
                    }
                    break;

                case 0xD9:
                    if (mod == 3)
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FLD, O.ST0, O.T80fp); break;
                            case 1: x = new Op(Operation.FXCH, O.ST0, O.T80fp); break;
                            case 2:
                                switch (rm)
                                {
                                    case 0: x = new Op(Operation.FNOP); break;
                                }
                                break;
                            case 3: break;
                            case 4:
                                switch (rm)
                                {
                                    case 0: x = new Op(Operation.FCHS); break;
                                    case 1: x = new Op(Operation.FABS); break;
                                    case 4: x = new Op(Operation.FTST); break;
                                    case 5: x = new Op(Operation.FXAM); break;
                                }
                                break;
                            case 5:
                                switch (rm)
                                {
                                    case 0: x = new Op(Operation.FLD1); break;
                                    case 1: x = new Op(Operation.FLDL2T); break;
                                    case 2: x = new Op(Operation.FLDL2E); break;
                                    case 3: x = new Op(Operation.FLDPI); break;
                                    case 4: x = new Op(Operation.FLDLG2); break;
                                    case 5: x = new Op(Operation.FLDLN2); break;
                                    case 6: x = new Op(Operation.FLDZ); break;
                                }
                                break;
                            case 6:
                                switch (rm)
                                {
                                    case 0: x = new Op(Operation.F2XM1); break;
                                    case 1: x = new Op(Operation.FYL2X); break;
                                    case 2: x = new Op(Operation.FPTAN); break;
                                    case 3: x = new Op(Operation.FPATAN); break;
                                    case 4: x = new Op(Operation.FXTRACT); break;
                                    case 5: x = new Op(Operation.FPREM1); break;
                                    case 6: x = new Op(Operation.FDECSTP); break;
                                    case 7: x = new Op(Operation.FINCSTP); break;
                                }
                                break;
                            case 7:
                                switch (rm)
                                {
                                    case 0: x = new Op(Operation.FPREM); break;
                                    case 1: x = new Op(Operation.FYL2XP1); break;
                                    case 2: x = new Op(Operation.FSQRT); break;
                                    case 3: x = new Op(Operation.FSINCOS); break;
                                    case 4: x = new Op(Operation.FRNDINT); break;
                                    case 5: x = new Op(Operation.FSCALE); break;
                                    case 6: x = new Op(Operation.FSIN); break;
                                    case 7: x = new Op(Operation.FCOS); break;
                                }
                                break;
                        }
                    }
                    else
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FLD, O.ST0, O.M32fp); break;
                            case 1: break;
                            case 2: x = new Op(Operation.FST, O.ST0, O.M32fp); break;
                            case 3: x = new Op(Operation.FSTP, O.ST0, O.M32fp); break;
                            case 4: x = new Op(Operation.FLDENV, O.M14or28b); break;
                            case 5: x = new Op(Operation.FLDCW, O.Mw); break;
                            case 6: x = new Op(Operation.FSTENV, O.M14or28b); break;
                            case 7: x = new Op(Operation.FSTCW, O.Mw); break;
                        }
                    }
                    break;

                case 0xDA:
                    if (mod == 3)
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FCMOVB, O.ST0, O.T80fp); break;
                            case 1: x = new Op(Operation.FCMOVE, O.ST0, O.T80fp); break;
                            case 2: x = new Op(Operation.FCMOVBE, O.ST0, O.T80fp); break;
                            case 3: x = new Op(Operation.FCMOVU, O.ST0, O.T80fp); break;
                            case 6:
                                switch (rm)
                                {
                                    case 1: x = new Op(Operation.FUCOMPP); break;
                                }
                                break;
                        }
                    }
                    else
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FIADD, O.ST0, O.Md); break;
                            case 1: x = new Op(Operation.FIMUL, O.ST0, O.Md); break;
                            case 2: x = new Op(Operation.FICOM, O.ST0, O.Md); break;
                            case 3: x = new Op(Operation.FICOMP, O.ST0, O.Md); break;
                            case 4: x = new Op(Operation.FISUB, O.ST0, O.Md); break;
                            case 5: x = new Op(Operation.FISUBR, O.ST0, O.Md); break;
                            case 6: x = new Op(Operation.FIDIV, O.ST0, O.Md); break;
                            case 7: x = new Op(Operation.FIDIVR, O.ST0, O.Md); break;
                        }
                    }
                    break;

                case 0xDB:
                    if (mod == 3)
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FCMOVNB, O.ST0, O.T80fp); break;
                            case 1: x = new Op(Operation.FCMOVNE, O.ST0, O.T80fp); break;
                            case 2: x = new Op(Operation.FCMOVNBE, O.ST0, O.T80fp); break;
                            case 3: x = new Op(Operation.FCMOVNU, O.ST0, O.T80fp); break;
                            case 4:
                                switch (rm)
                                {
                                    case 2: x = new Op(Operation.FCLEX); break;
                                    case 3: x = new Op(Operation.FINIT); break;
                                }
                                break;
                            case 5: x = new Op(Operation.FUCOMI, O.ST0, O.T80fp); break;
                            case 6: x = new Op(Operation.FCOMI, O.ST0, O.T80fp); break;
                            case 7: break;
                        }
                    }
                    else
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FILD, O.Md); break;
                            case 1: x = new Op(Operation.FISTTP, O.Md); break;
                            case 2: x = new Op(Operation.FIST, O.Md); break;
                            case 3: x = new Op(Operation.FISTP, O.Md); break;
                            case 4: break;
                            case 5: x = new Op(Operation.FLD, O.M80fp); break;
                            case 6: break;
                            case 7: x = new Op(Operation.FSTP, O.M80fp); break;
                        }
                    }
                    break;

                case 0xDC:
                    if (mod == 3)
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FADD,O.T80fp, O.ST0); break;
                            case 1: x = new Op(Operation.FMUL, O.T80fp, O.ST0); break;
                            case 2: break;
                            case 3: break;
                            case 4: x = new Op(Operation.FSUBR, O.T80fp, O.ST0); break;
                            case 5: x = new Op(Operation.FSUB, O.T80fp, O.ST0); break;
                            case 6: x = new Op(Operation.FDIVR, O.T80fp, O.ST0); break;
                            case 7: x = new Op(Operation.FDIV, O.T80fp, O.ST0); break;
                        }
                    }
                    else
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FADD, O.ST0, O.M64fp); break;
                            case 1: x = new Op(Operation.FMUL, O.ST0, O.M64fp); break;
                            case 2: x = new Op(Operation.FCOM, O.ST0, O.M64fp); break;
                            case 3: x = new Op(Operation.FCOMP, O.ST0, O.M64fp); break;
                            case 4: x = new Op(Operation.FSUB, O.ST0, O.M64fp); break;
                            case 5: x = new Op(Operation.FSUBR, O.ST0, O.M64fp); break;
                            case 6: x = new Op(Operation.FDIV, O.ST0, O.M64fp); break;
                            case 7: x = new Op(Operation.FDIVR, O.ST0, O.M64fp); break;
                        }
                    }
                    break;

                case 0xDD:
                    if (mod == 3)
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FFREE, O.T80fp); break;
                            case 1: break;
                            case 2: x = new Op(Operation.FST, O.T80fp); break;
                            case 3: x = new Op(Operation.FSTP, O.T80fp); break;
                            case 4: x = new Op(Operation.FUCOM, O.T80fp, O.ST0); break;
                            case 5: x = new Op(Operation.FUCOMP, O.T80fp, O.ST0); break;
                            case 6: break;
                            case 7: break;
                        }
                    }
                    else
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FLD, O.M64fp); break;
                            case 1: x = new Op(Operation.FISTTP, O.Mq); break;
                            case 2: x = new Op(Operation.FST, O.M64fp); break;
                            case 3: x = new Op(Operation.FSTP, O.M64fp); break;
                            case 4: x = new Op(Operation.FRSTOR, O.Mb); break; // TODO: should be 98/108 bytes
                            case 5: break;
                            case 6: x = new Op(Operation.FSAVE, O.Mb); break; // TODO: should be 98/108 bytes
                            case 7: x = new Op(Operation.FSTSW, O.Mw); break;
                        }
                    }
                    break;

                case 0xDE:
                    if (mod == 3)
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FADDP, O.T80fp, O.ST0); break;
                            case 1: x = new Op(Operation.FMULP, O.T80fp, O.ST0); break;
                            case 2: break;
                            case 3:
                                switch (rm)
                                {
                                    case 1: x = new Op(Operation.FCOMPP); break;
                                }
                                break;
                            case 4: x = new Op(Operation.FSUBRP, O.T80fp, O.ST0); break;
                            case 5: x = new Op(Operation.FSUBP, O.T80fp, O.ST0); break;
                            case 6: x = new Op(Operation.FDIVRP, O.T80fp, O.ST0); break;
                            case 7: x = new Op(Operation.FDIVP, O.T80fp, O.ST0); break;
                        }
                    }
                    else
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FIADD, O.ST0, O.Mw); break;
                            case 1: x = new Op(Operation.FIMUL, O.ST0, O.Mw); break;
                            case 2: x = new Op(Operation.FICOM, O.ST0, O.Mw); break;
                            case 3: x = new Op(Operation.FICOMP, O.ST0, O.Mw); break;
                            case 4: x = new Op(Operation.FISUB, O.ST0, O.Mw); break;
                            case 5: x = new Op(Operation.FISUBR, O.ST0, O.Mw); break;
                            case 6: x = new Op(Operation.FIDIV, O.ST0, O.Mw); break;
                            case 7: x = new Op(Operation.FIDIVR, O.ST0, O.Mw); break;
                        }
                    }
                    break;

                case 0xDF:
                    if (mod == 3)
                    {
                        switch (reg)
                        {
                            case 0: break;
                            case 1: break;
                            case 2: break;
                            case 3: break;
                            case 4:
                                switch (rm)
                                {
                                    case 0: x = new Op(Operation.FSTSW, O.AX); break;
                                }
                                break;
                            case 5: x = new Op(Operation.FUCOMIP, O.ST0, O.T80fp); break;
                            case 6: x = new Op(Operation.FCOMIP, O.ST0, O.T80fp); break;
                            case 7: break;
                        }
                    }
                    else
                    {
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.FILD, O.Mw); break;
                            case 1: x = new Op(Operation.FISTTP, O.Mw); break;
                            case 2: x = new Op(Operation.FIST, O.Mw); break;
                            case 3: x = new Op(Operation.FISTP, O.Mw); break;
                            case 4: x = new Op(Operation.FBLD, O.M80fp); break;
                            case 5: x = new Op(Operation.FILD, O.Mq); break;
                            case 6: x = new Op(Operation.FBSTP, O.M80fp); break;
                            case 7: x = new Op(Operation.FISTP, O.Mq); break;
                        }
                    }
                    break;
            }
            if (x.IsEmpty)
            {
                throw new InvalidInstructionException(string.Format(
                    "Invalid opcode: {0:X2} {1:X2}.",
                    firstByte, modrm.Value));
            }
            return x;
        }
Пример #8
0
        private Op DecodeOpcode(InstructionReader reader)
        {
            // Process the first byte of the opcode.
            byte c = reader.PeekByte();
            reader.ConsumeOpcodeByte();

            // Find an opcode entry for this opcode, and return it if it's
            // well-defined.
            Op spec = OneByteOpcodeMap[c];

            // Check opcode extensions.
            if (spec.IsExtension)
            {
                int reg = reader.GetModRM().REG;
                int mod = reader.GetModRM().MOD;
                int rm = reader.GetModRM().RM;
                Op x = new Op();
                switch (spec.Extension)
                {
                    case OpcodeExtension.Ext1:
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.ADD); break;
                            case 1: x = new Op(Operation.OR); break;
                            case 2: x = new Op(Operation.ADC); break;
                            case 3: x = new Op(Operation.SBB); break;
                            case 4: x = new Op(Operation.AND); break;
                            case 5: x = new Op(Operation.SUB); break;
                            case 6: x = new Op(Operation.XOR); break;
                            case 7: x = new Op(Operation.CMP); break;
                        }
                        break;

                    case OpcodeExtension.Ext1A:
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.POP, O.Ev); break;
                        }
                        break;

                    case OpcodeExtension.Ext2:
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.ROL); break;
                            case 1: x = new Op(Operation.ROR); break;
                            case 2: x = new Op(Operation.RCL); break;
                            case 3: x = new Op(Operation.RCR); break;
                            case 4: x = new Op(Operation.SHL); break;
                            case 5: x = new Op(Operation.SHR); break;
                            case 6: break;
                            case 7: x = new Op(Operation.SAR); break;
                        }
                        break;

                    case OpcodeExtension.Ext3:
                        if (c == 0xF6)
                        {
                            switch (reg)
                            {
                                case 0: x = new Op(Operation.TEST, O.Eb, O.Ib); break;
                                case 1: break;
                                case 2: x = new Op(Operation.NOT, O.Eb); break;
                                case 3: x = new Op(Operation.NEG, O.Eb); break;
                                case 4: x = new Op(Operation.MULB, O.Eb, O.AL); break;
                                case 5: x = new Op(Operation.IMULB, O.Eb, O.AL); break;
                                case 6: x = new Op(Operation.DIVB, O.Eb); break;
                                case 7: x = new Op(Operation.IDIVB, O.Eb); break;
                            }
                        }
                        else if (c == 0xF7)
                        {
                            switch (reg)
                            {
                                case 0: x = new Op(Operation.TEST, O.Ev, O.Iz); break;
                                case 1: break;
                                case 2: x = new Op(Operation.NOT, O.Ev); break;
                                case 3: x = new Op(Operation.NEG, O.Ev); break;
                                case 4: x = new Op(Operation.MULW, O.Ev, O.rAX); break;
                                case 5: x = new Op(Operation.IMULW, O.Ev, O.rAX); break;
                                case 6: x = new Op(Operation.DIVW, O.Ev); break;
                                case 7: x = new Op(Operation.IDIVW, O.Ev); break;
                            }
                        }
                        break;

                    case OpcodeExtension.Ext4:
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.INC, O.Eb); break;
                            case 1: x = new Op(Operation.DEC, O.Eb); break;
                        }
                        break;

                    case OpcodeExtension.Ext5:
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.INC, O.Ev); break;
                            case 1: x = new Op(Operation.DEC, O.Ev); break;
                            case 2: x = new Op(Operation.CALL, O.Ev); break;
                            case 3: x = new Op(Operation.CALLF, O.Ep); break;
                            case 4: x = new Op(Operation.JMP, O.Ev); break;
                            case 5: x = new Op(Operation.JMPF, O.Mp); break;
                            case 6: x = new Op(Operation.PUSH, O.Ev); break;
                            case 7: break;
                        }
                        break;

                    case OpcodeExtension.Ext6:
                        switch (reg)
                        {
                            case 0: x = new Op(Operation.SLDT, O.Rv, O.Mw); break;
                            case 1: x = new Op(Operation.STR, O.Rv, O.Mw); break;
                            case 2: x = new Op(Operation.LLDT, O.Ew); break;
                            case 3: x = new Op(Operation.LTR, O.Ew); break;
                            case 4: x = new Op(Operation.VERR, O.Ew); break;
                            case 5: x = new Op(Operation.VERW, O.Ew); break;
                            case 6: break;
                            case 7: break;
                        }
                        break;

                    case OpcodeExtension.Ext11:
                        if (c == 0xC6)
                        {
                            switch (reg)
                            {
                                case 0: x = new Op(Operation.MOV, O.Eb, O.Ib); break;
                                case 7:
                                    if (mod == 3 && rm == 0)
                                        x = new Op(Operation.XABORT, O.Ib);
                                    break;
                            }
                        }
                        else if (c == 0xC7)
                        {
                            switch (reg)
                            {
                                case 0: x = new Op(Operation.MOV, O.Ev, O.Iz); break;
                                case 7:
                                    if (mod == 3 && rm == 0)
                                        x = new Op(Operation.XBEGIN, O.Jz);
                                    break;
                            }
                        }
                        break;

                    case OpcodeExtension.Fpu:
                        return DecodeFpuOpcode(reader, c);

                }
                spec = x.MergeOperandsFrom(spec);
            }

            if (spec.Operation == Operation.None)
                throw new InvalidInstructionException("Invalid opcode.");
            return spec;
        }
Пример #9
0
        /// <summary>
        /// Decodes legacy prefixes of an instruction. There are four groups
        /// of legacy prefixes; at most one prefix from each group may be
        /// present. The encoded prefixes may take zero to four bytes.
        /// </summary>
        /// <exception cref="InvalidInstructionException">
        /// More than one prefix from the same group is present.
        /// </exception>
        /// <returns>The legacy prefixes, which may be None if no prefix is
        /// present.</returns>
        private Prefixes DecodeLegacyPrefixes(InstructionReader reader)
        {
            Prefixes prefix = Prefixes.None;
            while (true)
            {
                Prefixes pfx = Prefixes.None;
                Prefixes grp = Prefixes.None;
                byte c = reader.PeekByte();
                switch (c)
                {
                    case 0xF0: pfx = Prefixes.LOCK; grp = Prefixes.Group1; break;
                    case 0xF2: pfx = Prefixes.REPNZ; grp = Prefixes.Group1; break;
                    case 0xF3: pfx = Prefixes.REP; grp = Prefixes.Group1; break;

                    case 0x2E: pfx = Prefixes.CS; grp = Prefixes.Group2; break;
                    case 0x36: pfx = Prefixes.SS; grp = Prefixes.Group2; break;
                    case 0x3E: pfx = Prefixes.DS; grp = Prefixes.Group2; break;
                    case 0x26: pfx = Prefixes.ES; grp = Prefixes.Group2; break;
                    case 0x64: pfx = Prefixes.FS; grp = Prefixes.Group2; break;
                    case 0x65: pfx = Prefixes.GS; grp = Prefixes.Group2; break;

                    case 0x66:
                        pfx = Prefixes.OperandSizeOverride;
                        grp = Prefixes.Group3;
                        break;

                    case 0x67:
                        pfx = Prefixes.AddressSizeOverride;
                        grp = Prefixes.Group4;
                        break;
                }
                if (pfx == Prefixes.None)
                {
                    break;
                }
                if ((prefix & grp) != Prefixes.None)
                {
                    throw new InvalidInstructionException(string.Format(
                        "The instruction contains multiple prefixes from {0}: {1} and {2}.",
                        grp, prefix & grp, pfx));
                }

                // Consume 1 byte.
                reader.ConsumePrefixByte();
                prefix |= pfx;
            }
            return prefix;
        }