/// <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);
/// <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; }
/// <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); }
/// <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); }
/// <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); } } }
/// <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; }
/// <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); }
/// <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);
/// <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; }
/// <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(); } } }
/// <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()); }
/// <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; }