Ejemplo n.º 1
0
 /// <summary>
 /// Constructs the operand's representation.
 /// </summary>
 /// <param name="context">The <see cref="Context"/> in which the operand is used.</param>
 /// <param name="instruction">The <see cref="EncodedInstruction"/> encoding the operand.</param>
 internal abstract void Construct(Context context, EncodedInstruction instruction);
Ejemplo n.º 2
0
        /// <summary>
        /// Determines the address size used by this instruction.
        /// </summary>
        /// <param name="context">The <see cref="Context"/> in which the register width is determined.</param>
        /// <returns>The width of the registers as a <see cref="DataSize"/>.</returns>
        private DataSize GetAddressSize(Context context)
        {
            #region Contract
            Contract.Requires<ArgumentNullException>(context != null);
            Contract.Ensures(Enum.IsDefined(typeof(DataSize), Contract.Result<DataSize>()));
            Contract.Ensures(Contract.Result<DataSize>() != DataSize.None);
            #endregion

            DataSize addressSize = this.addressSize;
            DataSize baseWidth = baseRegister.GetSize();
            DataSize indexWidth = indexRegister.GetSize();
            DataSize contextAddressSize = context.Representation.Architecture.AddressSize;

            if (addressSize == DataSize.None)
                addressSize = baseWidth;
            if (addressSize == DataSize.None)
                addressSize = indexWidth;
            if (addressSize == DataSize.None)
                addressSize = contextAddressSize;

            if (baseWidth != DataSize.None && baseWidth != addressSize)
                throw new AssemblerException(String.Format(CultureInfo.InvariantCulture,
                    "BASE register {0} has a different width than the determined address size.",
                    Enum.GetName(typeof(Register), baseRegister)));

            if (baseWidth != DataSize.None && indexWidth != DataSize.None && baseWidth != indexWidth)
                throw new AssemblerException(String.Format(CultureInfo.InvariantCulture,
                    "BASE register {0} and INDEX register {1} have different widths.",
                    Enum.GetName(typeof(Register), baseRegister),
                    Enum.GetName(typeof(Register), indexRegister)));

            if (!IsValidRegisterWidthForMode(baseWidth, contextAddressSize))
                throw new AssemblerException(String.Format(CultureInfo.InvariantCulture,
                    "The {0} BASE register is not valid for the {1}-bit address size.",
                    Enum.GetName(typeof(Register), baseRegister),
                    ((int)contextAddressSize) << 3));

            if (!IsValidRegisterWidthForMode(indexWidth, contextAddressSize))
                throw new AssemblerException(String.Format(CultureInfo.InvariantCulture,
                    "The {0} INDEX register is not valid for the {1}-bit address size.",
                    Enum.GetName(typeof(Register), indexRegister),
                    ((int)contextAddressSize) << 3));

            if (indexWidth != DataSize.None && indexWidth != addressSize)
                throw new AssemblerException(String.Format(CultureInfo.InvariantCulture,
                    "INDEX register {0} has a different width than the determined address size.",
                    Enum.GetName(typeof(Register), indexRegister)));

            return addressSize;
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Constructs the operand's representation.
 /// </summary>
 /// <param name="context">The <see cref="Context"/> in which the operand is used.</param>
 /// <param name="instruction">The <see cref="EncodedInstruction"/> encoding the operand.</param>
 void IConstructableOperand.Construct(Context context, EncodedInstruction instruction)
 {
     this.Construct(context, instruction);
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Constructs the operand's representation.
        /// </summary>
        /// <param name="context">The <see cref="Context"/> in which the operand is used.</param>
        /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the operand.</param>
        internal override void Construct(Context context, EncodedInstruction instr)
        {
            // CONTRACT: Operand

            DataSize addressSize = GetAddressSize(context);

            instr.SetOperandSize(context.Representation.Architecture.OperandSize, Size);

            if (context.Representation.Architecture.OperandSize != DataSize.Bit64 &&
                this.Size == DataSize.Bit64)
                throw new AssemblerException("A 64-bit operand cannot be used with non-64-bit operand sizes.");
            if (context.Representation.Architecture.AddressSize != DataSize.Bit64 &&
                addressSize == DataSize.Bit64)
                throw new AssemblerException("A 64-bit effective address cannot be used with non-64-bit address sizes.");

            EncodeDisplacement(context, instr, addressSize);

            switch(addressSize)
            {
                case DataSize.Bit16:
                    Encode16BitEffectiveAddress(instr);
                    break;
                case DataSize.Bit32:
                    Encode32BitEffectiveAddress(instr);
                    break;
                case DataSize.Bit64:
                    Encode64BitEffectiveAddress(context, instr);
                    break;
                default:
                    throw new NotSupportedException();
            }

            // Address size prefix.
            // When the registers have a width different from the current
            // operating mode width, then we have to add an address size prefix.
            // At this point, we know that the widths are valid.
            instr.SetAddressSize(context.Representation.Architecture.AddressSize, addressSize);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Encodes the displacement in the <see cref="EncodedInstruction"/>.
        /// </summary>
        /// <param name="context">The <see cref="Context"/> in which the operand is used.</param>
        /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the operand.</param>
        /// <param name="addressSize">The address size used by the effective address.</param>
        private void EncodeDisplacement(Context context, EncodedInstruction instr, DataSize addressSize)
        {
            #region Contract
            Contract.Requires<ArgumentNullException>(context != null);
            Contract.Requires<ArgumentNullException>(instr != null);
            #endregion

            DataSize displacementSize = DataSize.None;
            SimpleExpression displacementExpression = null;

            if (displacement != null)
            {
                // Let's evaluate the displacement expression.
                displacementExpression = displacement(context);

                // Determine the size of the displacement.
                displacementSize = addressSize;
                if (displacementSize == DataSize.None)
                {
                    // Does the result have a (resolved or not resolved) reference?
                    if (displacementExpression.Reference != null && !displacementExpression.Reference.Resolved)
                        // When the result has a reference, use the architecture's address size.
                        displacementSize = context.Representation.Architecture.AddressSize;
                    else
                        // Otherwise, use the most efficient word size.
                        displacementSize = MathExt.GetSizeOfValue(displacementExpression.Evaluate(context));	//.Constant);
                }
            }

            instr.DisplacementSize = displacementSize;
            instr.Displacement = displacementExpression;
        }
            /// <summary>
            /// Encodes this instruction variant into its binary representation
            /// using the specified operands.
            /// </summary>
            /// <param name="context">The <see cref="Context"/> used.</param>
            /// <param name="operands">The <see cref="Operand"/> objects to
            /// encode.</param>
            /// <remarks>This method assumes that a call to <see
            /// cref="Match(IList{Operand})"/>
            /// with <paramref name="operands"/> would return
            /// <see langword="true"/>. Otherwise, exceptions may be thrown or
            /// the results may yield unexpected values.</remarks>
            internal void Encode(Context context, IList<Operand> operands)
            {
                InstructionEncoder encoder = context.Encoder;

                encoder.Opcode = opcode;
                encoder.Reg = fixedReg;

                for (int i = 0; i < operands.Count; i++)
                {
                if (descriptors[i].OperandType != OperandType.None &&
                    descriptors[i].OperandType != OperandType.FixedRegister)
                {
                    descriptors[i].Adjust(operands[i]);
                    operands[i].Encode(context);
                }
                }
            }
Ejemplo n.º 7
0
        /// <summary>
        /// Constructs the operand's representation.
        /// </summary>
        /// <param name="context">The <see cref="Context"/> in which the operand is used.</param>
        /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the operand.</param>
        internal override void Construct(Context context, EncodedInstruction instr)
        {
            // CONTRACT: Operand

            // Let's evaluate the expression.
            SimpleExpression result = expression(context);

            // Determine the size of the immediate operand.
            DataSize size = PreferredSize;
            if (size == DataSize.None)
            {
                // Does the result have a (resolved or not resolved) reference?
                if (result.Reference != null)
                    // When the result has a reference, use the architecture's operand size.
                    size = context.Representation.Architecture.OperandSize;
                else
                    // Otherwise, use the most efficient word size.
                    size = MathExt.GetSizeOfValue(result.Constant);
            }
            if (size >= DataSize.Bit64)
                throw new AssemblerException("64-bit operands cannot be encoded.");
            else if (size == DataSize.None)
                throw new AssemblerException("The operand size is not specified.");

            // Set the parameters.
            if (!asExtraImmediate)
            {
                instr.Immediate = result;
                instr.ImmediateSize = size;
            }
            else
            {
                instr.ExtraImmediate = result;
                instr.ExtraImmediateSize = size;
            }
            instr.SetOperandSize(context.Representation.Architecture.OperandSize, size);
        }
            /// <summary>
            /// Constructs the representation of this instruction variant using the specified operands.
            /// </summary>
            /// <param name="context">The <see cref="Context"/> used.</param>
            /// <param name="operands">The <see cref="Operand"/> objects to encode.</param>
            /// <returns>The encoded instruction.</returns>
            public EncodedInstruction Construct(Context context, IEnumerable<Operand> operands)
            {
                #region Contract
                Contract.Requires<ArgumentNullException>(context != null);
                Contract.Requires<ArgumentNullException>(operands != null);
                Contract.Ensures(Contract.Result<EncodedInstruction>() != null);
                #endregion

                return Construct(context, operands, false);
            }
            /// <summary>
            /// Constructs the representation of this instruction variant using the specified operands.
            /// </summary>
            /// <param name="context">The <see cref="Context"/> used.</param>
            /// <param name="operands">The <see cref="Operand"/> objects to encode.</param>
            /// <param name="lockPrefix">Whether to use a lock prefix.</param>
            /// <returns>The encoded instruction.</returns>
            public EncodedInstruction Construct(Context context, IEnumerable<IConstructableOperand> operands, bool lockPrefix)
            {
                #region Contract
                Contract.Requires<ArgumentNullException>(context != null);
                Contract.Requires<ArgumentNullException>(operands != null);
                Contract.Ensures(Contract.Result<EncodedInstruction>() != null);
                #endregion

                EncodedInstruction instr = new EncodedInstruction();

                // Set the lock prefix.
                instr.SetLock(lockPrefix);

                // Set the opcode.
                instr.Opcode = opcode;

                // Set the fixed REG value, if any.
                instr.FixedReg = fixedReg;

                int i = 0;
                foreach(var operand in operands)
                {
                    if (operand == null)
                        // No operand. Nothing to do.
                        continue;
                    if (i >= descriptors.Length)
                        // No descriptors left. Nothing to be done.
                        break;

                    operand.Adjust(descriptors[i]);
                    operand.Construct(context, instr);
                    i++;
                }

                // When the operand size has been explicitly set, set it on the encoded instruction.
                if (operandSize != DataSize.None)
                    instr.SetOperandSize(context.Representation.Architecture.OperandSize, operandSize);

                // We are done.
                return instr;
            }
Ejemplo n.º 10
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="addressingMode"></param>
 /// <param name="offset"></param>
 /// <param name="useRipRelative"></param>
 public Assembler(DataSize addressingMode, ulong offset, bool useRipRelative)
 {
     Context = new Context(addressingMode, offset, useRipRelative);
 }
Ejemplo n.º 11
0
 /// <summary>
 /// Modifies the context and constructs an emittable representing this constructable.
 /// </summary>
 /// <param name="context">The mutable <see cref="Context"/> in which the emittable will be constructed.</param>
 /// <returns>A list of constructed emittables; or an empty list.</returns>
 public abstract IEnumerable<IEmittable> Construct(Context context);
Ejemplo n.º 12
0
        /// <summary>
        /// Resolves any unresolved symbol references and returns the actual value of the expression.
        /// </summary>
        /// <param name="context">The <see cref="Context"/> in which the unresolved symbol references are
        /// resolved.</param>
        /// <returns>The result of the expression.</returns>
        /// <exception cref="InvalidOperationException">
        /// The symbol referenced could not be resolved.
        /// </exception>
        public long Evaluate(Context context)
        {
            // Attempts to resolve any unresolved symbol references.
            if (Reference != null && !Reference.Resolve(context))
                throw new InvalidOperationException("The expression still contains an unresolved symbol reference.");

            long value = Constant;
            if (Reference != null)
                value += Reference.Symbol.Value;

            return value;
        }
Ejemplo n.º 13
0
 /// <summary>
 /// Constructs the operand's representation.
 /// </summary>
 /// <param name="context">The <see cref="Context"/> in which the operand is used.</param>
 /// <param name="instruction">The <see cref="EncodedInstruction"/> encoding the operand.</param>
 internal override void Construct(Context context, EncodedInstruction instruction)
 {
     throw new NotImplementedException();
 }
        /// <summary>
        /// Encodes a 64-bit effective address.
        /// </summary>
        /// <param name="context">The <see cref="Context"/> in which the operand is used.</param>
        /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the operand.</param>
        private void Encode64BitEffectiveAddress(Context context, EncodedInstruction instr)
        {
            instr.SetModRMByte();

            bool ripRelative =
                this.relativeAddress ?? ((X86Architecture)context.Representation.Architecture).UseRIPRelativeAddressing;
            bool forceRipRelative = this.relativeAddress.HasValue && this.relativeAddress == true;

            if (baseRegister == Register.None && indexRegister == Register.None)
            {
                if (ripRelative)
                {
                    // [RIP+disp32]

                    instr.ModRM.RM = 0x05;
                    instr.ModRM.Mod = 0x00;
                }
                else
                {
                    // [disp32]

                    instr.ModRM.RM = 0x04;
                    instr.ModRM.Mod = 0x00;

                    instr.SetSIBByte();
                    instr.Sib.Base = 0x05;
                    instr.Sib.Index = 0x04;
                    instr.Sib.Scale = 0x00;
                }

                // Only 32-bit displacements can be encoded without a base and index register.
                instr.DisplacementSize = DataSize.Bit32;
                if (instr.Displacement == null)
                    instr.Displacement = new SimpleExpression(0);
            }
            else
            {
                if (forceRipRelative)
                    throw new AssemblerException("The effective address cannot be encoded with RIP-relative addressing.");

                if (baseRegister != Register.RSP && indexRegister == Register.None)
                {
                    // [REG+...]

                    instr.ModRM.RM = baseRegister.GetValue();
                }
                else
                {
                    // [REG+REG*s+...]

                    // Encode the SIB byte too.
                    instr.SetSIBByte();

                    // R/M
                    instr.ModRM.RM = 0x04;

                    // Base
                    if (baseRegister != Register.None)
                        instr.Sib.Base = baseRegister.GetValue();
                    else
                        instr.Sib.Base = 0x05;

                    // Index
                    if (indexRegister != Register.None)
                        instr.Sib.Index = indexRegister.GetValue();
                    else
                        instr.Sib.Index = 0x20;

                    // Scale
                    instr.Sib.Scale = (byte)((int)Math.Log(scale, 2));
                }

                if (instr.Displacement == null && baseRegister == Register.RBP)
                {
                    // [RBP] will be represented as [RBP+disp8].
                    // [RBP+REG*s] will be represented as [RBP+REG*s+disp8].
                    instr.DisplacementSize = DataSize.Bit8;
                    instr.Displacement = new SimpleExpression(0);
                }

                switch (instr.DisplacementSize)
                {
                    case DataSize.None:
                        instr.ModRM.Mod = 0x00;
                        break;
                    case DataSize.Bit8:
                        instr.ModRM.Mod = 0x01;
                        break;
                    case DataSize.Bit16:
                    case DataSize.Bit32:
                        instr.ModRM.Mod = 0x02;
                        break;
                    default:
                        throw new NotSupportedException();
                }
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Constructs the operand's representation.
        /// </summary>
        /// <param name="context">The <see cref="Context"/> in which the operand is used.</param>
        /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the operand.</param>
        internal override void Construct(Context context, EncodedInstruction instr)
        {
            // CONTRACT: Operand

            if (context.Representation.Architecture.OperandSize != DataSize.Bit64 &&
                register.GetSize() == DataSize.Bit64)
            {
                throw new AssemblerException(String.Format(
                    "The 64-bit register {0} cannot be used with non-64-bit operand sizes.",
                    Enum.GetName(typeof(Register), register)));
            }

            // Encode the register as part of the opcode or ModRM byte.
            switch (encoding)
            {
                case OperandEncoding.Default:
                    instr.SetModRMByte();
                    instr.ModRM.Reg = Register.GetValue();
                    break;
                case OperandEncoding.AddToOpcode:
                    instr.OpcodeReg = Register.GetValue();
                    break;
                case OperandEncoding.ModRm:
                    instr.SetModRMByte();
                    instr.ModRM.Mod = 0x03;
                    instr.ModRM.RM = Register.GetValue();
                    break;
                case OperandEncoding.Ignore:
                    // The operand is ignored.
                    break;
            }

            // Set the operand size to the size of the register.
            instr.SetOperandSize(context.Representation.Architecture.OperandSize, Register.GetSize());
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Resolves any unresolved symbol references and returns the actual value of the expression.
        /// </summary>
        /// <param name="context">The <see cref="Context"/> in which the unresolved symbol references are
        /// resolved.</param>
        /// <returns>The result of the expression.</returns>
        /// <exception cref="InvalidOperationException">
        /// The symbol referenced could not be resolved.
        /// </exception>
        public Int128 Evaluate(Context context)
        {
            #region Contract
            Contract.Requires<ArgumentNullException>(context != null);
            #endregion

            // Attempts to resolve any unresolved symbol references.
            if (this.reference != null && !this.reference.Resolve(context))
                throw new InvalidOperationException("The expression still contains an unresolved symbol reference.");

            Int128 value = this.constant;
            if (this.reference != null)
                value += this.reference.Symbol.Value;

            return value;
        }