예제 #1
0
파일: ModRmBuilder.cs 프로젝트: mmyydd/reko
 private Constant EmitDirectAddress(int reg, MemoryOperand memOp)
 {
     Debug.Assert(memOp.Offset.IsValid);
     if (defaultWordSize == PrimitiveType.Word16)
     {
         reg |= 0x6;
         emitter.EmitByte(reg);
         return(Constant.Create(PrimitiveType.Word16, memOp.Offset.ToUInt32()));
     }
     else
     {
         reg |= 0x5;
         emitter.EmitByte(reg);
         return(Constant.Word32(memOp.Offset.ToUInt32()));
     }
 }
예제 #2
0
        public void DisEdiTimes2()
        {
            X86TextAssembler asm = new X86TextAssembler(sc, new X86ArchitectureFlat32("x86-protected-32"));
            var program          = asm.AssembleFragment(Address.SegPtr(0x0B00, 0),
                                                        @"	.i386
	mov ebx,[edi*2]
");

            CreateDisassembler32(program.SegmentMap.Segments.Values.First().MemoryArea);
            var           instr = dasm.First();
            MemoryOperand mem   = (MemoryOperand)instr.op2;

            Assert.AreEqual(2, mem.Scale);
            Assert.AreEqual(RegisterStorage.None, mem.Base);
            Assert.AreEqual(Registers.edi, mem.Index);
        }
예제 #3
0
        private void RenderObjdumpMemoryOperand(MemoryOperand mem, StringBuilder sb)
        {
            switch (mem.Width.Size)
            {
            case 1: sb.Append("BYTE PTR"); break;

            case 2: sb.Append("WORD PTR"); break;

            case 4: sb.Append("DWORD PTR"); break;

            case 8: sb.Append("QWORD PTR"); break;

            case 10: sb.Append("TBYTE PTR"); break;

            case 16: sb.Append("XMMWORD PTR"); break;

            case 32: sb.Append("YMMWORD PTR"); break;

            default: sb.AppendFormat("[SIZE {0} PTR]", mem.Width.Size); break;
            }
            sb.AppendFormat(" {0}[", mem.SegOverride != null && mem.SegOverride != RegisterStorage.None
                ? $"{mem.SegOverride}:"
                : "");
            if (mem.Base != null && mem.Base != RegisterStorage.None)
            {
                sb.Append(mem.Base.Name);
                if (mem.Index != null && mem.Index != RegisterStorage.None)
                {
                    sb.Append("+");
                    sb.Append(mem.Index.Name);
                    if (mem.Scale >= 1)
                    {
                        sb.AppendFormat("*{0}", mem.Scale);
                    }
                }
                if (mem.Offset != null && mem.Offset.IsValid)
                {
                    RenderObjdumpConstant(mem.Offset, true, sb);
                }
            }
            else
            {
                sb.Append(mem.Offset);
            }
            sb.Append("]");
        }
예제 #4
0
        protected virtual Address ResolveFlowInstructionTarget(MemoryOperand operand)
        {
#if false
            // TODO: handle symbolic target.
            MemoryOperand opr = (MemoryOperand)instruction.Operands[0];

            // Handle static near jump table. We recognize a jump table
            // heuristically if the instruction looks like the following:
            //
            //   jmpn word ptr cs:[bx+3782h]
            //
            // That is, it meets the requirements that
            //   - the instruction is JMPN
            //   - the jump target is a word-ptr memory location
            //   - the memory location has CS prefix
            //   - a base register (e.g. bx) specifies the entry index
            //
            // Note that a malformed executable may create a jump table
            // not conforming to the above rules, or create a non-jump
            // table that conforms to the above rules. We do not deal with
            // these cases for the moment.
            if (instruction.Operation == Operation.JMP &&
                opr.Size == CpuSize.Use16Bit &&
                opr.Segment == Register.CS &&
                opr.Base != Register.None &&
                opr.Index == Register.None)
            {
#if false
                return(new XRef(
                           type: XRefType.NearIndexedJump,
                           source: start,
                           target: Pointer.Invalid,
                           dataLocation: new Pointer(start.Segment, (UInt16)opr.Displacement.Value)
                           ));
#else
                return(new XRef(
                           type: XRefType.NearJump,
                           source: start,
                           target: Address.Invalid
                           ));
#endif
            }
#endif
            return(Address.Invalid);
        }
예제 #5
0
        private ParsedOperand ParseMemoryOperand(RegisterStorage segOver)
        {
            MemoryOperand memOp = new MemoryOperand(null);

            memOp.SegOverride = segOver;
            this.segOverride  = segOver;

            ParseMemoryFactor(memOp);
            for (;;)
            {
                Token token = lexer.GetToken();
                switch (token)
                {
                default:
                    OnError("Unexpected token: " + token);
                    return(null);

                case Token.KET:
                    if (totalInt != 0 || sym != null)
                    {
                        if (addrWidth == null || sym != null)
                        {
                            memOp.Offset = Constant.Create(defaultAddressWidth, totalInt);
                        }
                        else
                        {
                            memOp.Offset = X86Assembler.IntegralConstant(totalInt, addrWidth);
                        }
                    }
                    return(new ParsedOperand(memOp, sym));

                case Token.PLUS:
                    break;

                case Token.MINUS:
                    Expect(Token.INTEGER);
                    totalInt -= lexer.Integer;
                    continue;

                case Token.ID:
                    break;
                }
                ParseMemoryFactor(memOp);
            }
        }
예제 #6
0
            public static Operand MemoryOp(
                OperandType type,
                Operand baseAddress,
                Operand index    = default,
                Multiplier scale = Multiplier.x1,
                int displacement = 0)
            {
                Operand result = Make(OperandKind.Memory, type, 0);

                MemoryOperand memory = result.GetMemory();

                memory.BaseAddress  = baseAddress;
                memory.Index        = index;
                memory.Scale        = scale;
                memory.Displacement = displacement;

                return(result);
            }
예제 #7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="emitter"></param>
        protected override void Emit(Context ctx, MachineCodeEmitter emitter)
        {
            RegisterOperand rop = (RegisterOperand)ctx.Result;
            MemoryOperand   mop = (MemoryOperand)ctx.Operand1;

            byte[] code;

            if (mop.Base != null)
            {
                code     = new byte[] { 0x8D, 0x84, (4 << 3) };
                code[1] |= (byte)((rop.Register.RegisterCode & 0x07));
                code[2] |= (byte)((mop.Base.RegisterCode & 0x07));
            }
            else
            {
                code = new byte[] { 0xB8 };
            }

            emitter.Write(code, 0, code.Length);
            emitter.EmitImmediate(mop);
        }
예제 #8
0
        protected override void HandleCallInstance(CompilationData compilationData, Instruction instruction, int index)
        {
            var classType = instruction.ClassType;
            var signature = this.virtualMachine.Binder.MemberFunctionSignature(
                classType,
                instruction.StringValue,
                instruction.Parameters);

            var funcToCall = this.virtualMachine.Binder.GetFunction(signature);

            var firstArgOffset = new MemoryOperand(
                Register.BP,
                compilationData.OperandStack.GetStackOperandOffset(
                    compilationData.OperandStack.TopIndex - (int)funcToCall.Parameters.Count + 1));

            //Add null check
            compilationData.Assembler.Move(Register.AX, firstArgOffset);
            this.exceptionHandling.AddNullCheck(compilationData, Register.AX);

            this.GenerateCallInstruction(compilationData, funcToCall, index);
        }
예제 #9
0
        /// <summary>
        /// Moves the return value to 64 bit.
        /// </summary>
        /// <param name="resultOperand">The result operand.</param>
        /// <param name="ctx">The context.</param>
        private static void MoveReturnValueTo64Bit(Operand resultOperand, Context ctx)
        {
            SigType       I4            = new SigType(CilElementType.I4);
            SigType       U4            = new SigType(CilElementType.U4);
            MemoryOperand memoryOperand = resultOperand as MemoryOperand;

            if (memoryOperand == null)
            {
                return;
            }
            Operand opL, opH;

            LongOperandTransformationStage.SplitLongOperand(memoryOperand, out opL, out opH);
            //MemoryOperand opL = new MemoryOperand(U4, memoryOperand.Base, memoryOperand.Offset);
            //MemoryOperand opH = new MemoryOperand(I4, memoryOperand.Base, new IntPtr(memoryOperand.Offset.ToInt64() + 4));
            RegisterOperand eax = new RegisterOperand(U4, GeneralPurposeRegister.EAX);
            RegisterOperand edx = new RegisterOperand(I4, GeneralPurposeRegister.EDX);

            ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, opL, eax);
            ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, opH, edx);
        }
예제 #10
0
        /// <summary>
        /// Emits the given code.
        /// </summary>
        /// <param name="code">The opcode bytes.</param>
        /// <param name="regField">The modR/M regfield.</param>
        /// <param name="dest">The destination operand.</param>
        /// <param name="src">The source operand.</param>
        public void Emit(byte[] code, byte?regField, Operand dest, Operand src)
        {
            byte?         sib = null, modRM = null;
            MemoryOperand displacement = null;

            // Write the opcode
            _codeStream.Write(code, 0, code.Length);

            if (null == dest && null == src)
            {
                return;
            }

            // Write the mod R/M byte
            modRM = CalculateModRM(regField, dest, src, out sib, out displacement);
            if (null != modRM)
            {
                _codeStream.WriteByte(modRM.Value);
                if (sib.HasValue)
                {
                    _codeStream.WriteByte(sib.Value);
                }
            }

            // Add displacement to the code
            if (null != displacement)
            {
                EmitDisplacement(displacement);
            }

            // Add immediate bytes
            if (dest is ConstantOperand)
            {
                EmitImmediate(dest);
            }
            if (src is ConstantOperand)
            {
                EmitImmediate(src);
            }
        }
예제 #11
0
파일: AssemblerBasic.cs 프로젝트: qcyb/reko
        public void ModRm16Memop()
        {
            MemoryOperand m;
            PrimitiveType w   = PrimitiveType.Word16;
            ModRmBuilder  mrm = new ModRmBuilder(w, null);

            m = new MemoryOperand(w, Registers.bx, Registers.si, 1, Constant.Invalid);
            Assert.AreEqual(0, mrm.Get16AddressingModeMask(m));
            m = new MemoryOperand(w, Registers.bx, Registers.di, 1, Constant.Invalid);
            Assert.AreEqual(1, mrm.Get16AddressingModeMask(m));
            m = new MemoryOperand(w, Registers.bp, Registers.si, 1, Constant.Invalid);
            Assert.AreEqual(2, mrm.Get16AddressingModeMask(m));
            m = new MemoryOperand(w, Registers.bp, Registers.di, 1, Constant.Invalid);
            Assert.AreEqual(3, mrm.Get16AddressingModeMask(m));
            m = new MemoryOperand(w, Registers.si, Constant.Invalid);
            Assert.AreEqual(4, mrm.Get16AddressingModeMask(m));
            m = new MemoryOperand(w, Registers.di, Constant.Invalid);
            Assert.AreEqual(5, mrm.Get16AddressingModeMask(m));
            m = new MemoryOperand(w, Registers.bp, Constant.Invalid);
            Assert.AreEqual(0x46, mrm.Get16AddressingModeMask(m));
            m = new MemoryOperand(w, Registers.bx, Constant.Invalid);
            Assert.AreEqual(7, mrm.Get16AddressingModeMask(m));
        }
예제 #12
0
        /// <summary>
        /// Emits the given code.
        /// </summary>
        /// <param name="opCode">The op code.</param>
        /// <param name="result">The destination operand.</param>
        /// <param name="leftOperand">The source operand.</param>
        /// <param name="rightOperand">The third operand.</param>
        public void Emit(OpCode opCode, Operand result, Operand leftOperand, Operand rightOperand)
        {
            byte?         sib = null, modRM = null;
            MemoryOperand displacement = null;

            // Write the opcode
            _codeStream.Write(opCode.Code, 0, opCode.Code.Length);

            if (null == result && null == leftOperand)
            {
                return;
            }

            // Write the mod R/M byte
            modRM = CalculateModRM(opCode.RegField, result, leftOperand, out sib, out displacement);
            if (null != modRM)
            {
                _codeStream.WriteByte(modRM.Value);
                if (sib.HasValue)
                {
                    _codeStream.WriteByte(sib.Value);
                }
            }

            // Add displacement to the code
            if (null != displacement)
            {
                WriteDisplacement(displacement);
            }

            // Add immediate bytes
            if (rightOperand is ConstantOperand)
            {
                WriteImmediate(rightOperand);
            }
        }
예제 #13
0
        protected override void HandleStoreElement(CompilationData compilationData, Instruction instruction, int index)
        {
            var elementType = this.virtualMachine.TypeProvider.FindType(instruction.StringValue);

            //Pop the operands
            compilationData.OperandStack.PopRegister(Register.DX);  //The value to store
            compilationData.OperandStack.PopRegister(Register.R10); //The index of the element
            compilationData.OperandStack.PopRegister(Register.AX);  //The address of the array

            //Error checks
            this.exceptionHandling.AddNullCheck(compilationData);
            this.exceptionHandling.AddArrayBoundsCheck(compilationData);

            //Compute the address of the element
            this.GenerateComputeAddress(compilationData, elementType);

            //Store the element
            var elementSize = TypeSystem.SizeOf(elementType);
            var dataSize    = this.SizeOf(elementSize);

            var elementOffset = new MemoryOperand(Register.AX);

            if (dataSize != DataSize.Size8)
            {
                compilationData.Assembler.Move(elementOffset, Register.DX, dataSize);
            }
            else
            {
                compilationData.Assembler.Move(elementOffset, Register8Bit.DL);
            }

            //if (elementType.IsReference())
            //{
            //    addCardMarking(vmState, assembler, Registers::AX);
            //}
        }
예제 #14
0
        /// <summary>
        /// Replaces the instrinsic call site
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="typeSystem">The type system.</param>
        public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem)
        {
            MemoryOperand operand = new MemoryOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.Ptr), GeneralPurposeRegister.EAX, new System.IntPtr(0));

            context.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.Ptr), GeneralPurposeRegister.EAX), context.Operand1);
            context.AppendInstruction(CPUx86.Instruction.LgdtInstruction, null, operand);

            RegisterOperand ax = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), GeneralPurposeRegister.EAX);
            RegisterOperand ds = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.DS);
            RegisterOperand es = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.ES);
            RegisterOperand fs = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.FS);
            RegisterOperand gs = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.GS);
            RegisterOperand ss = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.SS);

            context.AppendInstruction(CPUx86.Instruction.MovInstruction, ax, new ConstantOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I4), (int)0x00000010));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, ds, ax);
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, es, ax);
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, fs, ax);
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, gs, ax);
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, ss, ax);
            context.AppendInstruction(CPUx86.Instruction.FarJmpInstruction);
            context.AppendInstruction(CPUx86.Instruction.NopInstruction);
            context.Previous.SetBranch(context.Offset);
        }
예제 #15
0
        /// <summary>
        /// Emits the displacement operand.
        /// </summary>
        /// <param name="displacement">The displacement operand.</param>
        private void EmitDisplacement(MemoryOperand displacement)
        {
            byte[] disp;

            MemberOperand member = displacement as MemberOperand;
            LabelOperand  label  = displacement as LabelOperand;

            if (null != label)
            {
                int pos = (int)(_codeStream.Position - _codeStreamBasePosition);
                disp = LittleEndianBitConverter.GetBytes((uint)_linker.Link(LinkType.AbsoluteAddress | LinkType.I4, _compiler.Method, pos, 0, label.Name, IntPtr.Zero));
            }
            else if (null != member)
            {
                int pos = (int)(_codeStream.Position - _codeStreamBasePosition);
                disp = LittleEndianBitConverter.GetBytes((uint)_linker.Link(LinkType.AbsoluteAddress | LinkType.I4, _compiler.Method, pos, 0, member.Member, member.Offset));
            }
            else
            {
                disp = LittleEndianBitConverter.GetBytes(displacement.Offset.ToInt32());
            }

            _codeStream.Write(disp, 0, disp.Length);
        }
예제 #16
0
        public static void RunPass(ControlFlowGraph cfg)
        {
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
            {
                Node nextNode;

                for (Node node = block.Operations.First; node != null; node = nextNode)
                {
                    nextNode = node.ListNext;

                    if (!(node is Operation operation))
                    {
                        continue;
                    }

                    // Insert copies for constants that can't fit on a 32-bits immediate.
                    // Doing this early unblocks a few optimizations.
                    if (operation.Instruction == Instruction.Add)
                    {
                        Operand src1 = operation.GetSource(0);
                        Operand src2 = operation.GetSource(1);

                        if (src1.Kind == OperandKind.Constant && (src1.Relocatable || CodeGenCommon.IsLongConst(src1)))
                        {
                            Operand temp = Local(src1.Type);

                            Operation copyOp = Operation(Instruction.Copy, temp, src1);

                            block.Operations.AddBefore(operation, copyOp);

                            operation.SetSource(0, temp);
                        }

                        if (src2.Kind == OperandKind.Constant && (src2.Relocatable || CodeGenCommon.IsLongConst(src2)))
                        {
                            Operand temp = Local(src2.Type);

                            Operation copyOp = Operation(Instruction.Copy, temp, src2);

                            block.Operations.AddBefore(operation, copyOp);

                            operation.SetSource(1, temp);
                        }
                    }

                    // Try to fold something like:
                    //  shl rbx, 2
                    //  add rax, rbx
                    //  add rax, 0xcafe
                    //  mov rax, [rax]
                    // Into:
                    //  mov rax, [rax+rbx*4+0xcafe]
                    if (IsMemoryLoadOrStore(operation.Instruction))
                    {
                        OperandType type;

                        if (operation.Destination != null)
                        {
                            type = operation.Destination.Type;
                        }
                        else
                        {
                            type = operation.GetSource(1).Type;
                        }

                        MemoryOperand memOp = GetMemoryOperandOrNull(operation.GetSource(0), type);

                        if (memOp != null)
                        {
                            operation.SetSource(0, memOp);
                        }
                    }
                }
            }

            Optimizer.RemoveUnusedNodes(cfg);
        }
예제 #17
0
        /// <summary>
        /// Emits the ModRM byte (and SIB byte if applicable)
        /// </summary>
        /// <param name="reg"></param>
        /// <param name="memOp"></param>
        /// <returns>The offset value to be emitted as the last piece of the instruction</returns>
        public Constant?EmitModRMPrefix(int reg, MemoryOperand memOp)
        {
            offset = null;
            reg  <<= 3;
            if (memOp.Base != RegisterStorage.None || memOp.Index != RegisterStorage.None)
            {
                PrimitiveType baseWidth  = memOp.Base.DataType;
                PrimitiveType indexWidth = memOp.Index.DataType;
                if (memOp.Base != RegisterStorage.None && memOp.Index != RegisterStorage.None)
                {
                    if (baseWidth != indexWidth)
                    {
                        OnError("mismatched base and index registers");
                        return(null);
                    }
                }

                // Add the 'mod' bits

                if (memOp.Offset != null)
                {
                    Debug.Assert(memOp.Offset.IsValid);
                    if (memOp.Offset.DataType == PrimitiveType.SByte)
                    {
                        reg   |= 0x40;
                        offset = memOp.Offset;
                    }
                    else
                    {
                        reg   |= 0x80;
                        offset = Constant.Create(defaultWordSize, memOp.Offset.ToInt32());
                    }
                }

                bool fNeedsSib = false;
                int  sib       = 0;
                if (baseWidth == PrimitiveType.Word16)
                {
                    reg |= Get16AddressingModeMask(memOp);
                }
                else if (baseWidth == PrimitiveType.Word32 || indexWidth == PrimitiveType.Word32)
                {
                    if (memOp.Index == RegisterStorage.None)
                    {
                        if (memOp.Base != Registers.esp)
                        {
                            reg |= X86Assembler.RegisterEncoding(memOp.Base);
                            if (memOp.Offset == null && memOp.Base == Registers.ebp)
                            {
                                reg   |= 0x40;
                                offset = Constant.Byte(0);
                            }
                        }
                        else
                        {
                            reg      |= 0x04;
                            fNeedsSib = true;
                            sib       = 0x24;
                        }
                    }
                    else
                    {
                        reg      |= 0x04;
                        fNeedsSib = true;
                        switch (memOp.Scale)
                        {
                        case 1: sib = 0; break;

                        case 2: sib = 0x40; break;

                        case 4: sib = 0x80; break;

                        case 8: sib = 0xC0; break;

                        default: OnError("Scale factor must be 1, 2, 4, or 8"); return(Constant.Invalid);
                        }

                        if (memOp.Base == RegisterStorage.None)
                        {
                            sib |= 0x05;
                            reg &= ~0xC0;                                               // clear mod part of modRM.

                            if (memOp.Offset == null)
                            {
                                offset = Constant.Word32(0);
                            }
                        }
                        else
                        {
                            sib |= X86Assembler.RegisterEncoding(memOp.Base);
                        }

                        if (memOp.Index != Registers.esp)
                        {
                            sib |= X86Assembler.RegisterEncoding(memOp.Index) << 3;
                        }
                        else
                        {
                            throw new ApplicationException("ESP register can't be used as an index register");
                        }
                    }
                }
                else
                {
                    throw new ApplicationException("unexpected address width");
                }

                emitter.EmitByte(reg);
                if (fNeedsSib)
                {
                    emitter.EmitByte(sib);
                }
                return(offset);
            }
            else
            {
                return(EmitDirectAddress(reg, memOp));
            }
        }
예제 #18
0
 void Verify_MemoryOperand_ctors()
 {
     {
         var op = new MemoryOperand(Register.RCX, Register.RSI, 4, 0x12345678, 8, true, Register.FS);
         Assert.Equal(Register.RCX, op.Base);
         Assert.Equal(Register.RSI, op.Index);
         Assert.Equal(4, op.Scale);
         Assert.Equal(0x12345678, op.Displacement);
         Assert.Equal(8, op.DisplSize);
         Assert.True(op.IsBroadcast);
         Assert.Equal(Register.FS, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RCX, Register.RSI, 4, true, Register.FS);
         Assert.Equal(Register.RCX, op.Base);
         Assert.Equal(Register.RSI, op.Index);
         Assert.Equal(4, op.Scale);
         Assert.Equal(0, op.Displacement);
         Assert.Equal(0, op.DisplSize);
         Assert.True(op.IsBroadcast);
         Assert.Equal(Register.FS, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RCX, 0x12345678, 8, true, Register.FS);
         Assert.Equal(Register.RCX, op.Base);
         Assert.Equal(Register.None, op.Index);
         Assert.Equal(1, op.Scale);
         Assert.Equal(0x12345678, op.Displacement);
         Assert.Equal(8, op.DisplSize);
         Assert.True(op.IsBroadcast);
         Assert.Equal(Register.FS, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RSI, 4, 0x12345678, 8, true, Register.FS);
         Assert.Equal(Register.None, op.Base);
         Assert.Equal(Register.RSI, op.Index);
         Assert.Equal(4, op.Scale);
         Assert.Equal(0x12345678, op.Displacement);
         Assert.Equal(8, op.DisplSize);
         Assert.True(op.IsBroadcast);
         Assert.Equal(Register.FS, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RCX, 0x12345678, true, Register.FS);
         Assert.Equal(Register.RCX, op.Base);
         Assert.Equal(Register.None, op.Index);
         Assert.Equal(1, op.Scale);
         Assert.Equal(0x12345678, op.Displacement);
         Assert.Equal(1, op.DisplSize);
         Assert.True(op.IsBroadcast);
         Assert.Equal(Register.FS, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RCX, Register.RSI, 4, 0x12345678, 8);
         Assert.Equal(Register.RCX, op.Base);
         Assert.Equal(Register.RSI, op.Index);
         Assert.Equal(4, op.Scale);
         Assert.Equal(0x12345678, op.Displacement);
         Assert.Equal(8, op.DisplSize);
         Assert.False(op.IsBroadcast);
         Assert.Equal(Register.None, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RCX, Register.RSI, 4);
         Assert.Equal(Register.RCX, op.Base);
         Assert.Equal(Register.RSI, op.Index);
         Assert.Equal(4, op.Scale);
         Assert.Equal(0, op.Displacement);
         Assert.Equal(0, op.DisplSize);
         Assert.False(op.IsBroadcast);
         Assert.Equal(Register.None, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RCX, Register.RSI);
         Assert.Equal(Register.RCX, op.Base);
         Assert.Equal(Register.RSI, op.Index);
         Assert.Equal(1, op.Scale);
         Assert.Equal(0, op.Displacement);
         Assert.Equal(0, op.DisplSize);
         Assert.False(op.IsBroadcast);
         Assert.Equal(Register.None, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RCX, 0x12345678, 8);
         Assert.Equal(Register.RCX, op.Base);
         Assert.Equal(Register.None, op.Index);
         Assert.Equal(1, op.Scale);
         Assert.Equal(0x12345678, op.Displacement);
         Assert.Equal(8, op.DisplSize);
         Assert.False(op.IsBroadcast);
         Assert.Equal(Register.None, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RSI, 4, 0x12345678, 8);
         Assert.Equal(Register.None, op.Base);
         Assert.Equal(Register.RSI, op.Index);
         Assert.Equal(4, op.Scale);
         Assert.Equal(0x12345678, op.Displacement);
         Assert.Equal(8, op.DisplSize);
         Assert.False(op.IsBroadcast);
         Assert.Equal(Register.None, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RCX, 0x12345678);
         Assert.Equal(Register.RCX, op.Base);
         Assert.Equal(Register.None, op.Index);
         Assert.Equal(1, op.Scale);
         Assert.Equal(0x12345678, op.Displacement);
         Assert.Equal(1, op.DisplSize);
         Assert.False(op.IsBroadcast);
         Assert.Equal(Register.None, op.SegmentPrefix);
     }
     {
         var op = new MemoryOperand(Register.RCX);
         Assert.Equal(Register.RCX, op.Base);
         Assert.Equal(Register.None, op.Index);
         Assert.Equal(1, op.Scale);
         Assert.Equal(0, op.Displacement);
         Assert.Equal(0, op.DisplSize);
         Assert.False(op.IsBroadcast);
         Assert.Equal(Register.None, op.SegmentPrefix);
     }
 }
예제 #19
0
        public static IEnumerable <object[]> ParseMovFromMemoryOffsetTestCases()
        {
            var registers = new[]
            {
                "rax",
                "rbx",
                "rcx",
                "rdx",
                "rsi",
                "rdi",
                "rbp",
                "rsp",
                "r8",
                "r9",
                "r10",
                "r11",
                "r12",
                "r13",
                "r14",
                "r15",
            };

            var values = new[]
            {
                -122232425,
                -71819202,
                -1314151,
                -101112,
                -56789,
                -1234,
                -300,
                -255,
                -128,
                -127,
                -126,
                -1,
                0,
                1,
                126,
                127,
                128,
                255,
                300,
                1234,
                56789,
                101112,
                1314151,
                71819202,
                122232425,
            };

            foreach (var value in values)
            {
                var imm           = new Imm32Operand(value);
                var memoryOperand = new MemoryOperand(imm);

                foreach (var reg1 in registers)
                {
                    var register64Operand = new Register64Operand(reg1);

                    // mov [offset], reg2
                    yield return(new object[]
                    {
                        new Instruction(64, "mov", new Operand[] { memoryOperand, register64Operand }),
                        $"mov [{value}], {reg1}"
                    });

                    // mov reg1, [offset]
                    yield return(new object[]
                    {
                        new Instruction(64, "mov", new Operand[] { register64Operand, memoryOperand }),
                        $"mov {reg1}, [{value}]"
                    });
                }
            }
        }
        /// <summary>
        /// Generates code for an one virtual register operand instruction with an int value
        /// </summary>
        /// <param name="destinationRegister">The destination register</param>
        /// <param name="value">The value</param>
        public void GenerateOneRegisterWithValueInstruction(VirtualRegister destinationRegister, int value,
            Action<IList<byte>, IntRegister, int> inst1,
            Action<IList<byte>, MemoryOperand, int> inst2)
        {
            var generatedCode = compilationData.Function.GeneratedCode;
            var regAlloc = compilationData.RegisterAllocation;

            var opStack = regAlloc.GetStackIndex(destinationRegister);

            if (!opStack.HasValue)
            {
                var opReg = this.GetIntRegisterForVirtual(destinationRegister).Value;
                inst1(generatedCode, opReg, value);
            }
            else
            {
                var stackOp = new MemoryOperand(
                    Register.BP,
                    CalculateStackOffset(opStack.Value));
                inst2(generatedCode, stackOp, value);
            }
        }
예제 #21
0
        public AllocationResult RunPass(
            ControlFlowGraph cfg,
            StackAllocator stackAlloc,
            RegisterMasks regMasks)
        {
            int intUsedRegisters = 0;
            int vecUsedRegisters = 0;

            int intFreeRegisters = regMasks.IntAvailableRegisters;
            int vecFreeRegisters = regMasks.VecAvailableRegisters;

            var blockInfo = new BlockInfo[cfg.Blocks.Count];

            var locInfo    = new List <LocalInfo>();
            var locVisited = new HashSet <Operand>();

            for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
            {
                BasicBlock block = cfg.PostOrderBlocks[index];

                int intFixedRegisters = 0;
                int vecFixedRegisters = 0;

                bool hasCall = false;

                for (Node node = block.Operations.First; node != null; node = node.ListNext)
                {
                    if (node is Operation operation && operation.Instruction == Instruction.Call)
                    {
                        hasCall = true;
                    }

                    for (int srcIndex = 0; srcIndex < node.SourcesCount; srcIndex++)
                    {
                        Operand source = node.GetSource(srcIndex);

                        if (source.Kind == OperandKind.LocalVariable)
                        {
                            locInfo[source.GetLocalNumber() - 1].SetBlockIndex(block.Index);
                        }
                        else if (source.Kind == OperandKind.Memory)
                        {
                            MemoryOperand memOp = (MemoryOperand)source;

                            if (memOp.BaseAddress != null)
                            {
                                locInfo[memOp.BaseAddress.GetLocalNumber() - 1].SetBlockIndex(block.Index);
                            }

                            if (memOp.Index != null)
                            {
                                locInfo[memOp.Index.GetLocalNumber() - 1].SetBlockIndex(block.Index);
                            }
                        }
                    }

                    for (int dstIndex = 0; dstIndex < node.DestinationsCount; dstIndex++)
                    {
                        Operand dest = node.GetDestination(dstIndex);

                        if (dest.Kind == OperandKind.LocalVariable)
                        {
                            LocalInfo info;

                            if (!locVisited.Add(dest))
                            {
                                info = locInfo[dest.GetLocalNumber() - 1];
                            }
                            else
                            {
                                dest.NumberLocal(locInfo.Count + 1);

                                info = new LocalInfo(dest.Type, UsesCount(dest));

                                locInfo.Add(info);
                            }

                            info.SetBlockIndex(block.Index);
                        }
                        else if (dest.Kind == OperandKind.Register)
                        {
                            if (dest.Type.IsInteger())
                            {
                                intFixedRegisters |= 1 << dest.GetRegister().Index;
                            }
                            else
                            {
                                vecFixedRegisters |= 1 << dest.GetRegister().Index;
                            }
                        }
                    }
                }

                blockInfo[block.Index] = new BlockInfo(hasCall, intFixedRegisters, vecFixedRegisters);
            }

            int sequence = 0;

            for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
            {
                BasicBlock block = cfg.PostOrderBlocks[index];

                BlockInfo blkInfo = blockInfo[block.Index];

                int intLocalFreeRegisters = intFreeRegisters & ~blkInfo.IntFixedRegisters;
                int vecLocalFreeRegisters = vecFreeRegisters & ~blkInfo.VecFixedRegisters;

                int intCallerSavedRegisters = blkInfo.HasCall ? regMasks.IntCallerSavedRegisters : 0;
                int vecCallerSavedRegisters = blkInfo.HasCall ? regMasks.VecCallerSavedRegisters : 0;

                int intSpillTempRegisters = SelectSpillTemps(
                    intCallerSavedRegisters & ~blkInfo.IntFixedRegisters,
                    intLocalFreeRegisters);
                int vecSpillTempRegisters = SelectSpillTemps(
                    vecCallerSavedRegisters & ~blkInfo.VecFixedRegisters,
                    vecLocalFreeRegisters);

                intLocalFreeRegisters &= ~(intSpillTempRegisters | intCallerSavedRegisters);
                vecLocalFreeRegisters &= ~(vecSpillTempRegisters | vecCallerSavedRegisters);

                for (Node node = block.Operations.First; node != null; node = node.ListNext)
                {
                    int intLocalUse = 0;
                    int vecLocalUse = 0;

                    void AllocateRegister(Operand source, MemoryOperand memOp, int srcIndex)
                    {
                        LocalInfo info = locInfo[source.GetLocalNumber() - 1];

                        info.UseCount++;

                        Debug.Assert(info.UseCount <= info.Uses);

                        if (info.Register != -1)
                        {
                            Operand reg = Register(info.Register, source.Type.ToRegisterType(), source.Type);

                            if (memOp != null)
                            {
                                if (srcIndex == 0)
                                {
                                    memOp.BaseAddress = reg;
                                }
                                else /* if (srcIndex == 1) */
                                {
                                    memOp.Index = reg;
                                }
                            }
                            else
                            {
                                node.SetSource(srcIndex, reg);
                            }

                            if (info.UseCount == info.Uses && !info.PreAllocated)
                            {
                                if (source.Type.IsInteger())
                                {
                                    intLocalFreeRegisters |= 1 << info.Register;
                                }
                                else
                                {
                                    vecLocalFreeRegisters |= 1 << info.Register;
                                }
                            }
                        }
                        else if (node is Operation operation && operation.Instruction == Instruction.Copy)
                        {
                            Operation fillOp = Operation(Instruction.Fill, node.Destination, Const(info.SpillOffset));

                            block.Operations.AddBefore(node, fillOp);
                            block.Operations.Remove(node);

                            node = fillOp;
                        }
        /// <summary>
        /// Generates code for an instruction with virtual register destination and memory source
        /// </summary>
        /// <param name="destinationRegister">The destination</param>
        /// <param name="source">The source</param>
        /// <param name="memoryRewrite">Determines how an instruction with two memory operands will be rewritten into one memory operand.</param>
        public void GenerateOneRegisterMemorySourceInstruction(VirtualRegister destinationRegister, MemoryOperand source,
            Action<IList<byte>, IntRegister, MemoryOperand> inst1,
            Action<IList<byte>, MemoryOperand, IntRegister> inst2,
            MemoryRewrite memoryRewrite = MemoryRewrite.MemoryOnLeft)
        {
            var generatedCode = compilationData.Function.GeneratedCode;
            var regAlloc = compilationData.RegisterAllocation;
            int? opStack = compilationData.RegisterAllocation.GetStackIndex(destinationRegister);

            if (!opStack.HasValue)
            {
                var destinationReg = this.GetIntRegisterForVirtual(destinationRegister).Value;
                inst1(generatedCode, destinationReg, source);
            }
            else
            {
                var opStackOffset = CalculateStackOffset(opStack.Value);
                RewriteMemory(memoryRewrite, new MemoryOperand(Register.BP, opStackOffset), source, inst1, inst2);
            }
        }
예제 #23
0
        public AllocationResult RunPass(
            ControlFlowGraph cfg,
            StackAllocator stackAlloc,
            RegisterMasks regMasks)
        {
            int intUsedRegisters = 0;
            int vecUsedRegisters = 0;

            int intFreeRegisters = regMasks.IntAvailableRegisters;
            int vecFreeRegisters = regMasks.VecAvailableRegisters;

            BlockInfo[] blockInfo = new BlockInfo[cfg.Blocks.Count];

            List <LocalInfo> locInfo = new List <LocalInfo>();

            for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
            {
                BasicBlock block = cfg.PostOrderBlocks[index];

                int intFixedRegisters = 0;
                int vecFixedRegisters = 0;

                bool hasCall = false;

                for (Node node = block.Operations.First; node != null; node = node.ListNext)
                {
                    if (node is Operation operation && operation.Instruction == Instruction.Call)
                    {
                        hasCall = true;
                    }

                    for (int srcIndex = 0; srcIndex < node.SourcesCount; srcIndex++)
                    {
                        Operand source = node.GetSource(srcIndex);

                        if (source.Kind == OperandKind.LocalVariable)
                        {
                            locInfo[source.AsInt32() - 1].SetBlockIndex(block.Index);
                        }
                        else if (source.Kind == OperandKind.Memory)
                        {
                            MemoryOperand memOp = (MemoryOperand)source;

                            if (memOp.BaseAddress != null)
                            {
                                locInfo[memOp.BaseAddress.AsInt32() - 1].SetBlockIndex(block.Index);
                            }

                            if (memOp.Index != null)
                            {
                                locInfo[memOp.Index.AsInt32() - 1].SetBlockIndex(block.Index);
                            }
                        }
                    }

                    for (int dstIndex = 0; dstIndex < node.DestinationsCount; dstIndex++)
                    {
                        Operand dest = node.GetDestination(dstIndex);

                        if (dest.Kind == OperandKind.LocalVariable)
                        {
                            LocalInfo info;

                            if (dest.Value != 0)
                            {
                                info = locInfo[dest.AsInt32() - 1];
                            }
                            else
                            {
                                dest.NumberLocal(locInfo.Count + 1);

                                info = new LocalInfo(dest.Type, UsesCount(dest));

                                locInfo.Add(info);
                            }

                            info.SetBlockIndex(block.Index);
                        }
                        else if (dest.Kind == OperandKind.Register)
                        {
                            if (dest.Type.IsInteger())
                            {
                                intFixedRegisters |= 1 << dest.GetRegister().Index;
                            }
                            else
                            {
                                vecFixedRegisters |= 1 << dest.GetRegister().Index;
                            }
                        }
                    }
                }

                blockInfo[block.Index] = new BlockInfo(hasCall, intFixedRegisters, vecFixedRegisters);
            }

            int sequence = 0;

            for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
            {
                BasicBlock block = cfg.PostOrderBlocks[index];

                BlockInfo blkInfo = blockInfo[block.Index];

                int intLocalFreeRegisters = intFreeRegisters & ~blkInfo.IntFixedRegisters;
                int vecLocalFreeRegisters = vecFreeRegisters & ~blkInfo.VecFixedRegisters;

                int intCallerSavedRegisters = blkInfo.HasCall ? regMasks.IntCallerSavedRegisters : 0;
                int vecCallerSavedRegisters = blkInfo.HasCall ? regMasks.VecCallerSavedRegisters : 0;

                int intSpillTempRegisters = SelectSpillTemps(
                    intCallerSavedRegisters & ~blkInfo.IntFixedRegisters,
                    intLocalFreeRegisters);
                int vecSpillTempRegisters = SelectSpillTemps(
                    vecCallerSavedRegisters & ~blkInfo.VecFixedRegisters,
                    vecLocalFreeRegisters);

                intLocalFreeRegisters &= ~(intSpillTempRegisters | intCallerSavedRegisters);
                vecLocalFreeRegisters &= ~(vecSpillTempRegisters | vecCallerSavedRegisters);

                for (Node node = block.Operations.First; node != null; node = node.ListNext)
                {
                    int intLocalUse = 0;
                    int vecLocalUse = 0;

                    void AllocateRegister(Operand source, MemoryOperand memOp, int srcIndex)
                    {
                        LocalInfo info = locInfo[source.AsInt32() - 1];

                        info.UseCount++;

                        Debug.Assert(info.UseCount <= info.Uses);

                        if (info.Register != -1)
                        {
                            Operand reg = Register(info.Register, source.Type.ToRegisterType(), source.Type);

                            if (memOp != null)
                            {
                                if (srcIndex == 0)
                                {
                                    memOp.BaseAddress = reg;
                                }
                                else /* if (srcIndex == 1) */
                                {
                                    memOp.Index = reg;
                                }
                            }
                            else
                            {
                                node.SetSource(srcIndex, reg);
                            }

                            if (info.UseCount == info.Uses && !info.PreAllocated)
                            {
                                if (source.Type.IsInteger())
                                {
                                    intLocalFreeRegisters |= 1 << info.Register;
                                }
                                else
                                {
                                    vecLocalFreeRegisters |= 1 << info.Register;
                                }
                            }
                        }
                        else
                        {
                            Operand temp = info.Temp;

                            if (temp == null || info.Sequence != sequence)
                            {
                                temp = source.Type.IsInteger()
                                    ? GetSpillTemp(source, intSpillTempRegisters, ref intLocalUse)
                                    : GetSpillTemp(source, vecSpillTempRegisters, ref vecLocalUse);

                                info.Sequence = sequence;
                                info.Temp     = temp;
                            }

                            if (memOp != null)
                            {
                                if (srcIndex == 0)
                                {
                                    memOp.BaseAddress = temp;
                                }
                                else /* if (srcIndex == 1) */
                                {
                                    memOp.Index = temp;
                                }
                            }
                            else
                            {
                                node.SetSource(srcIndex, temp);
                            }

                            Operation fillOp = new Operation(Instruction.Fill, temp, Const(info.SpillOffset));

                            block.Operations.AddBefore(node, fillOp);
                        }
                    }

                    for (int srcIndex = 0; srcIndex < node.SourcesCount; srcIndex++)
                    {
                        Operand source = node.GetSource(srcIndex);

                        if (source.Kind == OperandKind.LocalVariable)
                        {
                            AllocateRegister(source, null, srcIndex);
                        }
                        else if (source.Kind == OperandKind.Memory)
                        {
                            MemoryOperand memOp = (MemoryOperand)source;

                            if (memOp.BaseAddress != null)
                            {
                                AllocateRegister(memOp.BaseAddress, memOp, 0);
                            }

                            if (memOp.Index != null)
                            {
                                AllocateRegister(memOp.Index, memOp, 1);
                            }
                        }
                    }

                    int intLocalAsg = 0;
                    int vecLocalAsg = 0;

                    for (int dstIndex = 0; dstIndex < node.DestinationsCount; dstIndex++)
                    {
                        Operand dest = node.GetDestination(dstIndex);

                        if (dest.Kind != OperandKind.LocalVariable)
                        {
                            continue;
                        }

                        LocalInfo info = locInfo[dest.AsInt32() - 1];

                        if (info.UseCount == 0 && !info.PreAllocated)
                        {
                            int mask = dest.Type.IsInteger()
                                ? intLocalFreeRegisters
                                : vecLocalFreeRegisters;

                            if (info.IsBlockLocal && mask != 0)
                            {
                                int selectedReg = BitUtils.LowestBitSet(mask);

                                info.Register = selectedReg;

                                if (dest.Type.IsInteger())
                                {
                                    intLocalFreeRegisters &= ~(1 << selectedReg);
                                    intUsedRegisters      |= 1 << selectedReg;
                                }
                                else
                                {
                                    vecLocalFreeRegisters &= ~(1 << selectedReg);
                                    vecUsedRegisters      |= 1 << selectedReg;
                                }
                            }
                            else
                            {
                                info.Register    = -1;
                                info.SpillOffset = stackAlloc.Allocate(dest.Type.GetSizeInBytes());
                            }
                        }

                        info.UseCount++;

                        Debug.Assert(info.UseCount <= info.Uses);

                        if (info.Register != -1)
                        {
                            node.SetDestination(dstIndex, Register(info.Register, dest.Type.ToRegisterType(), dest.Type));
                        }
                        else
                        {
                            Operand temp = info.Temp;

                            if (temp == null || info.Sequence != sequence)
                            {
                                temp = dest.Type.IsInteger()
                                    ? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg)
                                    : GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);

                                info.Sequence = sequence;
                                info.Temp     = temp;
                            }

                            node.SetDestination(dstIndex, temp);

                            Operation spillOp = new Operation(Instruction.Spill, null, Const(info.SpillOffset), temp);

                            block.Operations.AddAfter(node, spillOp);

                            node = spillOp;
                        }
                    }

                    sequence++;

                    intUsedRegisters |= intLocalAsg | intLocalUse;
                    vecUsedRegisters |= vecLocalAsg | vecLocalUse;
                }
            }

            return(new AllocationResult(intUsedRegisters, vecUsedRegisters, stackAlloc.TotalSize));
        }
        /// <summary>
        /// Analyzes an instruction and returns a xref if the instruction is
        /// one of the branch/call/jump instructions. Note that the 'no-jump'
        /// branch of a conditional jump instruction is not returned. The
        /// caller must manually create such a xref if needed.
        /// </summary>
        /// <param name="instruction">The instruction to analyze.</param>
        /// <returns>XRef if the instruction is a b/c/j instruction;
        /// null otherwise.</returns>
        /// TBD: address wrapping if IP is above 0xFFFF is not handled. It should be.
        private XRef AnalyzeFlowInstruction(Pointer start, Instruction instruction)
        {
            Operation op = instruction.Operation;

            // Find the type of branch/call/jump instruction being processed.
            //
            // Note: If the instruction is a conditional jump, we assume that
            // the condition may be true or false, so that both "jump" and
            // "no jump" is a reachable branch. If the code is malformed such
            // that either branch will never be executed, the analysis may not
            // work correctly.
            //
            // Note: If the instruction is a function call, we assume that the
            // subroutine being called will return. If the subroutine never
            // returns the analysis may not work correctly.
            XRefType bcjType;

            switch (op)
            {
            case Operation.JO:
            case Operation.JNO:
            case Operation.JB:
            case Operation.JAE:
            case Operation.JE:
            case Operation.JNE:
            case Operation.JBE:
            case Operation.JA:
            case Operation.JS:
            case Operation.JNS:
            case Operation.JP:
            case Operation.JNP:
            case Operation.JL:
            case Operation.JGE:
            case Operation.JLE:
            case Operation.JG:
            case Operation.JCXZ:
            case Operation.LOOP:
            case Operation.LOOPZ:
            case Operation.LOOPNZ:
                bcjType = XRefType.ConditionalJump;
                break;

            case Operation.JMP:
                bcjType = XRefType.NearJump;
                break;

            case Operation.JMPF:
                bcjType = XRefType.FarJump;
                break;

            case Operation.CALL:
                bcjType = XRefType.NearCall;
                break;

            case Operation.CALLF:
                bcjType = XRefType.FarCall;
                break;

            default:
                // Not a b/c/j instruction; do nothing.
                return(null);
            }

            // Create a cross-reference depending on the type of operand.
            if (instruction.Operands[0] is RelativeOperand) // near jump/call to relative address
            {
                RelativeOperand opr = (RelativeOperand)instruction.Operands[0];
                return(new XRef(
                           type: bcjType,
                           source: start,
                           target: start.IncrementWithWrapping(instruction.EncodedLength + opr.Offset.Value)
                           ));
            }

            if (instruction.Operands[0] is PointerOperand) // far jump/call to absolute address
            {
                PointerOperand opr = (PointerOperand)instruction.Operands[0];
                return(new XRef(
                           type: bcjType,
                           source: start,
                           target: new Pointer(opr.Segment.Value, (UInt16)opr.Offset.Value)
                           ));
            }

            if (instruction.Operands[0] is MemoryOperand) // indirect jump/call
            {
                MemoryOperand opr = (MemoryOperand)instruction.Operands[0];

                // Handle static near jump table. We recognize a jump table
                // heuristically if the instruction looks like the following:
                //
                //   jmpn word ptr cs:[bx+3782h]
                //
                // That is, it meets the requirements that
                //   - the instruction is JMPN
                //   - the jump target is a word-ptr memory location
                //   - the memory location has CS prefix
                //   - a base register (e.g. bx) specifies the entry index
                //
                // Note that a malformed executable may create a jump table
                // not conforming to the above rules, or create a non-jump
                // table that conforms to the above rules. We do not deal with
                // these cases for the moment.
                if (op == Operation.JMP &&
                    opr.Size == CpuSize.Use16Bit &&
                    opr.Segment == Register.CS &&
                    opr.Base != Register.None &&
                    opr.Index == Register.None)
                {
                    return(new XRef(
                               type: XRefType.NearIndexedJump,
                               source: start,
                               target: Pointer.Invalid,
                               dataLocation: new Pointer(start.Segment, (UInt16)opr.Displacement.Value)
                               ));
                }
            }

            // Other jump/call targets that we cannot recognize.
            AddError(start, ErrorCategory.Message,
                     "Cannot determine target of {0} instruction.", op);

            return(new XRef(
                       type: bcjType,
                       source: start,
                       target: Pointer.Invalid
                       ));
        }
예제 #25
0
        /// <summary>
        /// Emits an immediate operand.
        /// </summary>
        /// <param name="op">The immediate operand to emit.</param>
        public void EmitImmediate(Operand op)
        {
            byte[] imm = null;
            if (op is LocalVariableOperand)
            {
                // Add the displacement
                StackOperand so = (StackOperand)op;
                imm = LittleEndianBitConverter.GetBytes(so.Offset.ToInt32());
            }
            else if (op is LabelOperand)
            {
                _literals.Add(new Patch((op as LabelOperand).Label, _codeStream.Position));
                imm = new byte[4];
            }
            else if (op is MemoryOperand)
            {
                // Add the displacement
                MemoryOperand mo = (MemoryOperand)op;
                imm = LittleEndianBitConverter.GetBytes(mo.Offset.ToInt32());
            }
            else if (op is ConstantOperand)
            {
                // Add the immediate
                ConstantOperand co = (ConstantOperand)op;
                switch (op.Type.Type)
                {
                case CilElementType.I:
                    try
                    {
                        imm = LittleEndianBitConverter.GetBytes(Convert.ToInt32(co.Value));
                    }
                    catch (OverflowException)
                    {
                        imm = LittleEndianBitConverter.GetBytes(Convert.ToUInt32(co.Value));
                    }
                    break;

                case CilElementType.I1:
                    //imm = LittleEndianBitConverter.GetBytes(Convert.ToSByte(co.Value));
                    imm = new byte[1] {
                        Convert.ToByte(co.Value)
                    };
                    break;

                case CilElementType.I2:
                    imm = LittleEndianBitConverter.GetBytes(Convert.ToInt16(co.Value));
                    break;

                case CilElementType.I4: goto case CilElementType.I;

                case CilElementType.U1:
                    //imm = LittleEndianBitConverter.GetBytes(Convert.ToByte(co.Value));
                    imm = new byte[1] {
                        Convert.ToByte(co.Value)
                    };
                    break;

                case CilElementType.Char:
                    goto case CilElementType.U2;

                case CilElementType.U2:
                    imm = LittleEndianBitConverter.GetBytes(Convert.ToUInt16(co.Value));
                    break;

                case CilElementType.U4:
                    imm = LittleEndianBitConverter.GetBytes(Convert.ToUInt32(co.Value));
                    break;

                case CilElementType.I8:
                    imm = LittleEndianBitConverter.GetBytes(Convert.ToInt64(co.Value));
                    break;

                case CilElementType.U8:
                    imm = LittleEndianBitConverter.GetBytes(Convert.ToUInt64(co.Value));
                    break;

                case CilElementType.R4:
                    imm = LittleEndianBitConverter.GetBytes(Convert.ToSingle(co.Value));
                    break;

                case CilElementType.R8: goto default;

                default:
                    throw new NotSupportedException();
                }
            }
            else if (op is RegisterOperand)
            {
                // Nothing to do...
            }
            else
            {
                throw new NotImplementedException();
            }

            // Emit the immediate constant to the code
            if (null != imm)
            {
                _codeStream.Write(imm, 0, imm.Length);
            }
        }
        /// <summary>
        /// Handles the given function call argument
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        /// <param name="argumentIndex">The index of the argument</param>
        /// <param name="argumentType">The type of the argument</param>
        /// <param name="argumentRegisters">The virtual registers for the arguments</param>
        /// <param name="aliveRegistersStack">The alive registers stack</param>
        /// <param name="toCall">The function to call</param>
        public void CallFunctionArgument(
            CompilationData compilationData,
            int argumentIndex, VMType argumentType,
            IReadOnlyList<VirtualRegister> argumentRegisters,
            IDictionary<HardwareRegister, int> aliveRegistersStack,
            FunctionDefinition toCall)
        {
            var virtualAssembler = compilationData.VirtualAssembler;
            var regAlloc = compilationData.RegisterAllocation;
            var generatedCode = compilationData.Function.GeneratedCode;
            int thisNumArgs = compilationData.Function.Definition.Parameters.Count;
            int numArgs = toCall.Parameters.Count;

            int argsStart = 1 + compilationData.StackSize / Assembler.RegisterSize;

            if (virtualAssembler.NeedSpillRegister)
            {
                argsStart += 1;
            }

            int alignment = this.CalculateStackAlignment(compilationData, toCall.Parameters, aliveRegistersStack.Count);

            var virtualReg = argumentRegisters[numArgs - 1 - argumentIndex];
            var virtualRegStack = regAlloc.GetStackIndex(virtualReg);

            //Check if to pass argument by via the stack
            if (argumentIndex >= numRegisterArguments)
            {
                //Move arguments to the stack
                HardwareRegister spillReg;
                int stackOffset = 0;

                if (argumentType.IsPrimitiveType(PrimitiveTypes.Float))
                {
                    spillReg = virtualAssembler.GetFloatSpillRegister();

                    if (!virtualRegStack.HasValue)
                    {
                        stackOffset = aliveRegistersStack[virtualAssembler.GetFloatRegisterForVirtual(virtualReg).Value];
                    }
                }
                else
                {
                    spillReg = virtualAssembler.GetIntSpillRegister();

                    if (!virtualRegStack.HasValue)
                    {
                        stackOffset = aliveRegistersStack[virtualAssembler.GetIntRegisterForVirtual(virtualReg).Value];
                    }
                }

                var argMemory = new MemoryOperand();

                if (virtualRegStack.HasValue)
                {
                    argMemory = new MemoryOperand(
                        Register.BP,
                        virtualAssembler.CalculateStackOffset(virtualRegStack.Value));
                }
                else
                {
                    argMemory = new MemoryOperand(
                        Register.BP,
                        -(argsStart + stackOffset)
                        * Assembler.RegisterSize);
                }

                Assembler.Move(generatedCode, spillReg, argMemory);
                Assembler.Push(generatedCode, spillReg);
            }
            else
            {
                HardwareRegister argReg;
                int stackOffset = 0;

                if (argumentType.IsPrimitiveType(PrimitiveTypes.Float))
                {
                    argReg = floatArgumentRegisters[argumentIndex];

                    if (!virtualRegStack.HasValue)
                    {
                        stackOffset = aliveRegistersStack[virtualAssembler.GetFloatRegisterForVirtual(virtualReg).Value];
                    }
                }
                else
                {
                    argReg = intArgumentRegisters[argumentIndex];

                    if (!virtualRegStack.HasValue)
                    {
                        stackOffset = aliveRegistersStack[virtualAssembler.GetIntRegisterForVirtual(virtualReg).Value];
                    }
                }

                var argMemory = new MemoryOperand();

                if (virtualRegStack.HasValue)
                {
                    argMemory = new MemoryOperand(
                        Register.BP,
                        virtualAssembler.CalculateStackOffset(virtualRegStack.Value));
                }
                else
                {
                    argMemory = new MemoryOperand(
                        Register.BP,
                        -(argsStart + stackOffset)
                        * Assembler.RegisterSize);
                }

                Assembler.Move(generatedCode, argReg, argMemory);
            }
        }
예제 #27
0
        /// <summary>
        /// Calculates the value of the modR/M byte and SIB bytes.
        /// </summary>
        /// <param name="regField">The modR/M regfield value.</param>
        /// <param name="op1">The destination operand.</param>
        /// <param name="op2">The source operand.</param>
        /// <param name="sib">A potential SIB byte to emit.</param>
        /// <param name="displacement">An immediate displacement to emit.</param>
        /// <returns>The value of the modR/M byte.</returns>
        private static byte?CalculateModRM(byte?regField, Operand op1, Operand op2, out byte?sib, out Operand displacement)
        {
            byte?modRM = null;

            displacement = null;

            // FIXME: Handle the SIB byte
            sib = null;

            RegisterOperand rop1 = op1 as RegisterOperand, rop2 = op2 as RegisterOperand;
            MemoryOperand   mop1 = op1 as MemoryOperand, mop2 = op2 as MemoryOperand;

            // Normalize the operand order
            if (rop1 == null && rop2 != null)
            {
                // Swap the memory operands
                rop1 = rop2; rop2 = null;
                mop2 = mop1; mop1 = null;
            }

            if (regField != null)
            {
                modRM = (byte)(regField.Value << 3);
            }

            if (rop1 != null && rop2 != null)
            {
                // mod = 11b, reg = rop1, r/m = rop2
                modRM = (byte)((3 << 6) | (rop1.Register.RegisterCode << 3) | rop2.Register.RegisterCode);
            }
            // Check for register/memory combinations
            else if (mop2 != null && mop2.Base != null)
            {
                // mod = 10b, reg = rop1, r/m = mop2
                modRM = (byte)(modRM.GetValueOrDefault() | (2 << 6) | (byte)mop2.Base.RegisterCode);
                if (rop1 != null)
                {
                    modRM |= (byte)(rop1.Register.RegisterCode << 3);
                }
                displacement = mop2;
                if (mop2.Base.RegisterCode == 4)
                {
                    sib = 0xA4;
                }
            }
            else if (mop2 != null)
            {
                // mod = 10b, r/m = mop1, reg = rop2
                modRM = (byte)(modRM.GetValueOrDefault() | 5);
                if (rop1 != null)
                {
                    modRM |= (byte)(rop1.Register.RegisterCode << 3);
                }
                displacement = mop2;
            }
            else if (mop1 != null && mop1.Base != null)
            {
                // mod = 10b, r/m = mop1, reg = rop2
                modRM = (byte)(modRM.GetValueOrDefault() | (2 << 6) | mop1.Base.RegisterCode);
                if (rop2 != null)
                {
                    modRM |= (byte)(rop2.Register.RegisterCode << 3);
                }
                displacement = mop1;
                if (mop1.Base.RegisterCode == 4)
                {
                    sib = 0xA4;
                }
            }
            else if (mop1 != null)
            {
                // mod = 10b, r/m = mop1, reg = rop2
                modRM = (byte)(modRM.GetValueOrDefault() | 5);
                if (rop2 != null)
                {
                    modRM |= (byte)(rop2.Register.RegisterCode << 3);
                }
                displacement = mop1;
            }
            else if (rop1 != null)
            {
                modRM = (byte)(modRM.GetValueOrDefault() | (3 << 6) | rop1.Register.RegisterCode);
                //if (op2 is SymbolOperand)
                //    displacement = op2;
            }

            return(modRM);
        }
예제 #28
0
 private MemoryAccess RewriteMemoryAccess(MemoryOperand mem, PrimitiveType dataWidth, Address addrInstr)
 {
     Expression ea;
     if (mem.Base == Registers.pc)
     {
         ea = addrInstr + mem.Offset.ToInt32();
     }
     else
     {
         var bReg = frame.EnsureRegister(mem.Base);
         ea = bReg;
         if (mem.Offset != null)
         {
             ea = m.IAdd(bReg, Constant.Int32(mem.Offset.ToInt32()));
         }
     }
     return m.Load(dataWidth, ea);
 }
예제 #29
0
        /// <summary>
        /// Pushes the specified instructions.
        /// </summary>
        /// <param name="ctx">The context.</param>
        /// <param name="op">The op.</param>
        /// <param name="stackSize">Size of the stack.</param>
        private void Push(Context ctx, Operand op, int stackSize)
        {
            if (op is MemoryOperand)
            {
                RegisterOperand rop;
                switch (op.StackType)
                {
                case StackTypeCode.O:
                    goto case StackTypeCode.N;

                case StackTypeCode.Ptr:
                    goto case StackTypeCode.N;

                case StackTypeCode.Int32:
                    goto case StackTypeCode.N;

                case StackTypeCode.N:
                    rop = new RegisterOperand(op.Type, GeneralPurposeRegister.EAX);
                    break;

                case StackTypeCode.F:
                    rop = new RegisterOperand(op.Type, SSE2Register.XMM0);
                    break;

                case StackTypeCode.Int64:
                {
                    SigType       I4  = new SigType(CilElementType.I4);
                    MemoryOperand mop = op as MemoryOperand;
                    Debug.Assert(null != mop, "I8/U8 arg is not in a memory operand.");
                    RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX);
                    Operand         opL, opH;
                    LongOperandTransformationStage.SplitLongOperand(mop, out opL, out opH);
                    //MemoryOperand opL = new MemoryOperand(I4, mop.Base, mop.Offset);
                    //MemoryOperand opH = new MemoryOperand(I4, mop.Base, new IntPtr(mop.Offset.ToInt64() + 4));

                    ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opL);
                    ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(op.Type, GeneralPurposeRegister.EDX, new IntPtr(stackSize)), eax);
                    ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opH);
                    ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(op.Type, GeneralPurposeRegister.EDX, new IntPtr(stackSize + 4)), eax);
                }
                    return;

                default:

                    throw new NotSupportedException();
                }

                ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, rop, op);
                op = rop;
            }
            else if (op is ConstantOperand && op.StackType == StackTypeCode.Int64)
            {
                Operand         opL, opH;
                SigType         I4  = new SigType(CilElementType.I4);
                RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX);
                LongOperandTransformationStage.SplitLongOperand(op, out opL, out opH);

                ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opL);
                ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(I4, GeneralPurposeRegister.EDX, new IntPtr(stackSize)), eax);
                ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, opH);
                ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(I4, GeneralPurposeRegister.EDX, new IntPtr(stackSize + 4)), eax);

                return;
            }

            ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(op.Type, GeneralPurposeRegister.EDX, new IntPtr(stackSize)), op);
        }
예제 #30
0
        protected virtual Address ResolveFlowInstructionTarget(MemoryOperand operand)
        {
            #if false
            // TODO: handle symbolic target.
                MemoryOperand opr = (MemoryOperand)instruction.Operands[0];

                // Handle static near jump table. We recognize a jump table
                // heuristically if the instruction looks like the following:
                //
                //   jmpn word ptr cs:[bx+3782h]
                //
                // That is, it meets the requirements that
                //   - the instruction is JMPN
                //   - the jump target is a word-ptr memory location
                //   - the memory location has CS prefix
                //   - a base register (e.g. bx) specifies the entry index
                //
                // Note that a malformed executable may create a jump table
                // not conforming to the above rules, or create a non-jump
                // table that conforms to the above rules. We do not deal with
                // these cases for the moment.
                if (instruction.Operation == Operation.JMP &&
                    opr.Size == CpuSize.Use16Bit &&
                    opr.Segment == Register.CS &&
                    opr.Base != Register.None &&
                    opr.Index == Register.None)
                {
            #if false
                    return new XRef(
                        type: XRefType.NearIndexedJump,
                        source: start,
                        target: Pointer.Invalid,
                        dataLocation: new Pointer(start.Segment, (UInt16)opr.Displacement.Value)
                    );
            #else
                    return new XRef(
                        type: XRefType.NearJump,
                        source: start,
                        target: Address.Invalid
                        );
            #endif
                }
            #endif
            return Address.Invalid;
        }
        /// <summary>
        /// Moves an argument to the stack
        /// </summary>
        /// <param name="compilationData">The compilation data</param>
        /// <param name="argumentIndex">The argument index</param>
        /// <param name="argumentType">The type of the argument</param>
        private void MoveArgumentToStack(CompilationData compilationData, int argumentIndex, VMType argumentType)
        {
            var generatedCode = compilationData.Function.GeneratedCode;
            int argStackOffset = -(1 + argumentIndex) * Assembler.RegisterSize;

            if (argumentIndex >= numRegisterArguments)
            {
                int stackArgumentIndex = this.GetStackArgumentIndex(compilationData, argumentIndex);

                var argStackSource = new MemoryOperand(
                    Register.BP,
                    Assembler.RegisterSize * (6 + stackArgumentIndex));

                HardwareRegister tmpReg;

                if (argumentType.IsPrimitiveType(PrimitiveTypes.Float))
                {
                    tmpReg = compilationData.VirtualAssembler.GetFloatSpillRegister();
                }
                else
                {
                    tmpReg = new IntRegister(Register.AX);
                }

                Assembler.Move(generatedCode, tmpReg, argStackSource);
                Assembler.Move(generatedCode, new MemoryOperand(Register.BP, argStackOffset), tmpReg);
            }
            else
            {
                //var argReg = floatArgumentRegisters[argumentIndex];
                HardwareRegister argReg;

                if (argumentType.IsPrimitiveType(PrimitiveTypes.Float))
                {
                    argReg = floatArgumentRegisters[argumentIndex];
                }
                else
                {
                    argReg = intArgumentRegisters[argumentIndex];
                }

                Assembler.Move(generatedCode, new MemoryOperand(Register.BP, argStackOffset), argReg);
            }
        }
예제 #32
0
        public SymbolicMemoryOperand(MemoryOperand opr, SymbolicTarget target)
        {
            base.Base = opr.Base;
            base.Displacement = opr.Displacement;
            base.Index = opr.Index;
            base.Scaling = opr.Scaling;
            base.Segment = opr.Segment;
            base.Size = opr.Size;

            this.Target = target;
        }
예제 #33
0
        private void ParseMemoryFactor(MemoryOperand memOp)
        {
            Token           token = lexer.GetToken();
            RegisterStorage reg   = RegisterStorage.None;

            switch (token)
            {
            default:
                OnError("unexpected token: " + token);
                return;

            case Token.INTEGER:
                totalInt += lexer.Integer;
                break;

            case Token.REGISTER:
            {
                reg = lexer.Register !;
                PrimitiveType width = reg.DataType;
                if (addrWidth == null)
                {
                    addrWidth = width;
                }
                else if (addrWidth != width)
                {
                    throw new ApplicationException("Conflicting address widths");
                }
                break;
            }

            case Token.ID:
            {
                if (symtab.Equates.TryGetValue(lexer.StringLiteral.ToLower(), out int v))
                {
                    totalInt += v;
                }
                else
                {
                    sym       = symtab.CreateSymbol(lexer.StringLiteral);
                    totalInt += unchecked ((int)addrBase.Offset);
                }
                break;
            }
            }

            if (lexer.PeekToken() == Token.TIMES)
            {
                if (reg == RegisterStorage.None)
                {
                    throw new ApplicationException("Scale factor must be preceded by a register");
                }
                lexer.GetToken();
                if (memOp.Index != RegisterStorage.None)
                {
                    throw new ApplicationException("Scale can only be used once in an addressing form");
                }
                Expect(Token.INTEGER, "Expected an integer scale");
                if (lexer.Integer != 1 && lexer.Integer != 2 && lexer.Integer != 4 && lexer.Integer != 8)
                {
                    throw new ApplicationException("Only scales 1, 2, 4, and 8 are supported");
                }
                memOp.Scale = (byte)lexer.Integer;
                memOp.Index = reg;
            }
            else if (reg != RegisterStorage.None)
            {
                if (memOp.Base == RegisterStorage.None)
                {
                    memOp.Base = reg;
                }
                else if (memOp.Index == RegisterStorage.None)
                {
                    memOp.Index = reg;
                    memOp.Scale = 1;
                }
                else
                {
                    throw new ApplicationException("Can't have more than two registers in an addressing form");
                }
            }
        }
        /// <summary>
        /// Rewrites two memory operand instructions
        /// </summary>
        /// <param name="memoryRewrite">The memory rewrite rule</param>
        /// <param name="destination">The destination</param>
        /// <param name="source">The source</param>
        private void RewriteMemory(MemoryRewrite memoryRewrite, MemoryOperand destination, MemoryOperand source,
            Action<IList<byte>, FloatRegister, MemoryOperand> inst1,
            Action<IList<byte>, MemoryOperand, FloatRegister> inst2)
        {
            var generatedCode = compilationData.Function.GeneratedCode;
            var spillReg = this.GetFloatSpillRegister();

            if (memoryRewrite == MemoryRewrite.MemoryOnLeft)
            {
                Assembler.Move(generatedCode, spillReg, source);
                inst2(generatedCode, destination, spillReg);
            }
            else
            {
                Assembler.Move(generatedCode, spillReg, destination);
                inst1(generatedCode, spillReg, source);
                Assembler.Move(generatedCode, destination, spillReg);
            }
        }
        public virtual string FormatOperand(MemoryOperand operand)
        {
            CpuSize size = operand.Size;
            string prefix =
                (size == CpuSize.Use8Bit) ? "byte" :
                (size == CpuSize.Use16Bit) ? "word" :
                (size == CpuSize.Use32Bit) ? "dword" :
                (size == CpuSize.Use64Bit) ? "qword" :
                (size == CpuSize.Use128Bit) ? "dqword" : "";

            StringBuilder sb = new StringBuilder();
            if (prefix != "")
            {
                sb.Append(prefix);
                sb.Append(" ptr ");
            }

            if (operand.Segment != Register.None)
            {
                FormatRegister(sb, operand.Segment);
                sb.Append(':');
            }

            string strDisplacement = FormatFixableLocation(operand);

            sb.Append('[');
            if (operand.Base == Register.None) // only displacement
            {
                if (strDisplacement != null)
                    sb.Append(strDisplacement);
                else
                    FormatNumber(sb, (UInt16)operand.Displacement.Value);
            }
            else // base+index*scale+displacement
            {
                FormatRegister(sb, operand.Base);
                if (operand.Index != Register.None)
                {
                    sb.Append('+');
                    FormatRegister(sb, operand.Index);
                    if (operand.Scaling != 1)
                    {
                        sb.Append('*');
                        sb.Append(operand.Scaling);
                    }
                }

                if (strDisplacement != null)
                {
                    sb.Append('+');
                    sb.Append(strDisplacement);
                }
                else
                {
                    int displacement = operand.Displacement.Value;
                    if (displacement > 0) // e.g. [BX+1]
                    {
                        sb.Append('+');
                        FormatNumber(sb, (uint)displacement);
                    }
                    else if (displacement < 0)
                    {
                        sb.Append('-');
                        FormatNumber(sb, (uint)-displacement);
                    }
                }
            }
            sb.Append(']');
            return sb.ToString();
        }
예제 #36
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;
        }