/// <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> public override void Construct(Context context, EncodedInstruction instruction) { // Determine the size of the immediate operand. Otherwise the length is not calculated correctly. DataSize size = PreferredSize; if (size == DataSize.None) { size = context.AddressingMode; } if (size >= DataSize.Bit64) { var bit = ((int)size) << 3; throw new AssemblerException($"{bit}-bit operands cannot be encoded."); } else if (size == DataSize.None) { throw new AssemblerException("The operand size is not specified."); } instruction.SetOperandSize(context.AddressingMode, size); instruction.ImmediateSize = size; // Let's evaluate the expression. var result = Expression?.Compile()(context); result = new ReferenceOffset(result.Reference, result.Constant - ((long)context.Address + instruction.Length)); instruction.Immediate = result; }
/// <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> /// 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> public override void Construct(Context context, EncodedInstruction instruction) { if (context.AddressingMode != DataSize.Bit64 && Register.Size == DataSize.Bit64) { throw new AssemblerException($"The 64-bit register {Register} cannot be used with non-64-bit operand sizes."); } // Encode the register as part of the opcode or ModRM byte. switch (Encoding) { case OperandEncoding.Default: instruction.SetModRMByte(); instruction.ModRM.Reg = Register.Value; break; case OperandEncoding.AddToOpcode: instruction.OpcodeReg = (byte)(Register.Value & 0xF); break; case OperandEncoding.ModRm: instruction.SetModRMByte(); instruction.ModRM.Mod = 0x03; instruction.ModRM.RM = Register.Value; break; case OperandEncoding.Ignore: // The operand is ignored. break; } // Set the operand size to the size of the register. instruction.SetOperandSize(context.AddressingMode, Register.Size); }
/// <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> public override void Construct(Context context, EncodedInstruction instruction) { ReferenceOffset offsetResult = Offset.Compile()(context); ReferenceOffset selectorResult = Selector?.Compile()(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 (offsetResult.Reference != null) // When the result has a reference, use the architecture's operand size. size = context.AddressingMode; else // Otherwise, use the most efficient word size. size = Extensions.GetSizeOfValue(offsetResult.Constant); } if (size <= DataSize.Bit8) size = DataSize.Bit16; if (size > DataSize.Bit64) throw new AssemblerException("The operand cannot be encoded."); // Set the parameters. instruction.Immediate = offsetResult; instruction.ImmediateSize = size; instruction.ExtraImmediate = selectorResult; instruction.ExtraImmediateSize = (DataSize)2; instruction.SetOperandSize(context.AddressingMode, size); }
/// <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> void EncodeDisplacement(Context context, EncodedInstruction instr, DataSize addressSize) { DataSize displacementSize = DataSize.None; ReferenceOffset displacementExpression = null; if (Displacement != null) { // Let's evaluate the displacement expression. displacementExpression = Displacement.Compile()(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.AddressingMode; } else { // Otherwise, use the most efficient word size. displacementSize = Extensions.GetSizeOfValue(displacementExpression.Evaluate(context)); } } } instr.DisplacementSize = displacementSize; instr.Displacement = displacementExpression; }
/// <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> public override void Construct(Context context, EncodedInstruction instruction) { if (context.AddressingMode != DataSize.Bit64 && Register.Size == DataSize.Bit64) throw new AssemblerException($"The 64-bit register {Register} cannot be used with non-64-bit operand sizes."); // Encode the register as part of the opcode or ModRM byte. switch (Encoding) { case OperandEncoding.Default: instruction.SetModRMByte(); instruction.ModRM.Reg = Register.Value; break; case OperandEncoding.AddToOpcode: instruction.OpcodeReg = (byte)(Register.Value & 0xF); break; case OperandEncoding.ModRm: instruction.SetModRMByte(); instruction.ModRM.Mod = 0x03; instruction.ModRM.RM = Register.Value; break; case OperandEncoding.Ignore: // The operand is ignored. break; } // Set the operand size to the size of the register. instruction.SetOperandSize(context.AddressingMode, Register.Size); }
/// <summary> /// Constructs the operand's representation. /// </summary> /// <param name="context">The <see cref="X86Context"/> in which the /// operand is used.</param> /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the /// operand.</param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="context"/> is <see langword="null"/>.</para> /// -or- /// <para><paramref name="instr"/> is <see langword="null"/>.</para> /// </exception> internal override void Construct(X86Context context, EncodedInstruction instr) { #region Contract if (context == null) { throw new ArgumentNullException("context"); } if (instr == null) { throw new ArgumentNullException("instr"); } #endregion // Let's evaluate the expression. ExpressionResult result = new BinaryExpression( expression, BinaryOperation.Subtract, new BinaryExpression( new CurrentPosition(), BinaryOperation.Add, new Constant((long)instr.GetLength()))).Evaluate(context); // Determine the size of the immediate operand. DataSize size = RequestedSize; if (size == DataSize.None) { // Does the result have a (resolved or not resolved) reference? if (result.HasReference) { // 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 = result.Constant.GetSize(); } } if (size >= DataSize.Bit64) { throw new AssemblerException(ExceptionStrings.OperandSizeNotEncodable); } else if (size == DataSize.None) { throw new AssemblerException(ExceptionStrings.OperandSizeNotSpecified); } // Set the parameters. instr.Immediate = result; instr.ImmediateSize = size; instr.SetOperandSize(context.Representation.Architecture.OperandSize, size); }
/// <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 SimpleExpression offsetResult = offset(context); SimpleExpression selectorResult = selector(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 (offsetResult.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(offsetResult.Constant); } } if (size <= DataSize.Bit8) { size = DataSize.Bit16; } if (size > DataSize.Bit64) { throw new AssemblerException("The operand cannot be encoded."); } else if (size == DataSize.None) { throw new AssemblerException("The operand size is not specified."); } // Set the parameters. instr.Immediate = offsetResult; instr.ImmediateSize = size; instr.ExtraImmediate = selectorResult; instr.ExtraImmediateSize = (DataSize)2; instr.SetOperandSize(context.Representation.Architecture.OperandSize, size); }
/// <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> public override void Construct(Context context, EncodedInstruction instruction) { // Let's evaluate the expression. var result = Expression?.Compile()(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.AddressingMode; } else { // Otherwise, use the most efficient word size. size = Extensions.GetSizeOfValue(result.Constant); } } if (size > DataSize.Bit64) { throw new AssemblerException("Operands with more than 64 bits cannot be encoded."); } else if (size == DataSize.None) { throw new AssemblerException("The operand size is not specified."); } // Set the parameters. if (!asExtraImmediate) { instruction.Immediate = result; instruction.ImmediateSize = size; } else { instruction.ExtraImmediate = result; instruction.ExtraImmediateSize = size; } instruction.SetOperandSize(context.AddressingMode, size); }
/// <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); result = new SimpleExpression(result.Reference, result.Constant - (context.Address + instr.GetLength())); // 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(String.Format(CultureInfo.InvariantCulture, "{0}-bit operands cannot be encoded.", ((int)size) << 3)); } else if (size == DataSize.None) { throw new AssemblerException("The operand size is not specified."); } // Set the parameters. instr.Immediate = result; instr.ImmediateSize = size; instr.SetOperandSize(context.Representation.Architecture.OperandSize, size); }
/// <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> public override void Construct(Context context, EncodedInstruction instruction) { DataSize addressSize = GetAddressSize(context); instruction.SetOperandSize(context.AddressingMode, Size); if (context.AddressingMode != DataSize.Bit64 && Size == DataSize.Bit64) { throw new AssemblerException("A 64-bit operand cannot be used with non-64-bit operand sizes."); } if (context.AddressingMode != DataSize.Bit64 && addressSize == DataSize.Bit64) { throw new AssemblerException("A 64-bit effective address cannot be used with non-64-bit address sizes."); } EncodeDisplacement(context, instruction, addressSize); switch (addressSize) { case DataSize.Bit16: Encode16BitEffectiveAddress(instruction); break; case DataSize.Bit32: Encode32BitEffectiveAddress(instruction); break; case DataSize.Bit64: Encode64BitEffectiveAddress(context, instruction); 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. instruction.SetAddressSize(context.AddressingMode, 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> public override void Construct(Context context, EncodedInstruction instruction) { ReferenceOffset offsetResult = Offset.Compile()(context); ReferenceOffset selectorResult = Selector?.Compile()(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 (offsetResult.Reference != null) { // When the result has a reference, use the architecture's operand size. size = context.AddressingMode; } else { // Otherwise, use the most efficient word size. size = Extensions.GetSizeOfValue(offsetResult.Constant); } } if (size <= DataSize.Bit8) { size = DataSize.Bit16; } if (size > DataSize.Bit64) { throw new AssemblerException("The operand cannot be encoded."); } // Set the parameters. instruction.Immediate = offsetResult; instruction.ImmediateSize = size; instruction.ExtraImmediate = selectorResult; instruction.ExtraImmediateSize = (DataSize)2; instruction.SetOperandSize(context.AddressingMode, size); }
/// <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> /// Constructs the operand's representation. /// </summary> /// <param name="context">The <see cref="X86Context"/> in which the /// operand is used.</param> /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the /// operand.</param> /// <exception cref="ArgumentNullException"> /// <para><paramref name="context"/> is <see langword="null"/>.</para> /// -or- /// <para><paramref name="instr"/> is <see langword="null"/>.</para> /// </exception> internal override void Construct(X86Context context, EncodedInstruction instr) { #region Contract if (context == null) throw new ArgumentNullException("context"); if (instr == null) throw new ArgumentNullException("instr"); #endregion // Let's evaluate the expression. ExpressionResult result = new BinaryExpression( expression, BinaryOperation.Subtract, new BinaryExpression( new CurrentPosition(), BinaryOperation.Add, new Constant((long)instr.GetLength()))).Evaluate(context); // Determine the size of the immediate operand. DataSize size = RequestedSize; if (size == DataSize.None) { // Does the result have a (resolved or not resolved) reference? if (result.HasReference) // 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 = result.Constant.GetSize(); } if (size >= DataSize.Bit64) throw new AssemblerException(ExceptionStrings.OperandSizeNotEncodable); else if (size == DataSize.None) throw new AssemblerException(ExceptionStrings.OperandSizeNotSpecified); // Set the parameters. instr.Immediate = result; instr.ImmediateSize = size; instr.SetOperandSize(context.Representation.Architecture.OperandSize, size); }
/// <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> /// 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> /// <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> /// 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> /// 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> void Encode64BitEffectiveAddress(Context context, EncodedInstruction instr) { instr.SetModRMByte(); bool ripRelative = RelativeAddress ?? context.UseRIPRelativeAddressing; bool forceRipRelative = RelativeAddress.HasValue && RelativeAddress == true; if (BaseRegister.IsNone && IndexRegister.IsNone) { 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 ReferenceOffset(0); } } else { if (forceRipRelative) { throw new AssemblerException("The effective address cannot be encoded with RIP-relative addressing."); } if (BaseRegister != Register.RSP && IndexRegister.IsNone) { // [REG+...] instr.ModRM.RM = BaseRegister.Value; } else { // [REG+REG*s+...] // Encode the SIB byte too. instr.SetSIBByte(); // R/M instr.ModRM.RM = 0x04; // Base if (!BaseRegister.IsNone) { instr.Sib.Base = BaseRegister.Value; } else { instr.Sib.Base = 0x05; } // Index if (!IndexRegister.IsNone) { instr.Sib.Index = IndexRegister.Value; } 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 ReferenceOffset(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> /// Encodes a 16-bit effective address. /// </summary> /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the operand.</param> void Encode16BitEffectiveAddress(EncodedInstruction instr) { instr.SetModRMByte(); // We order the registers in such way that reg1 has the register with the highest number, // and reg2 has the register with the lowest number. When a register is not provided, it is put in reg2. // This simplifies the following tests, for which the order does not matter. var baseReg = BaseRegister; var indexReg = (Scale == 1 ? IndexRegister : Register.None); var reg1 = (baseReg.Value >= indexReg.Value ? baseReg : indexReg); var reg2 = (baseReg.Value < indexReg.Value ? baseReg : indexReg); if (Scale != 1 && Scale != 0) throw new AssemblerException("The specified scaling factor is not supported in a 16-bit effective address."); // Two cases together deviate from the standard MOD encoding. if (reg1 == Register.BP && reg2.IsNone) { // [BP+...] instr.ModRM.RM = 0x06; instr.ModRM.Mod = (byte)(instr.DisplacementSize == DataSize.Bit8 ? 0x01 : 0x02); } else if (reg1.IsNone && reg2.IsNone) { // [...] instr.ModRM.RM = 0x06; instr.ModRM.Mod = 0x00; } else { // The other cases are straight forward. if (reg1 == Register.DI && reg2 == Register.BP) // [BP+DI+...] instr.ModRM.RM = 0x03; else if (reg1 == Register.DI && reg2 == Register.BX) // [BX+DI+...] instr.ModRM.RM = 0x01; else if (reg1 == Register.DI && reg2.IsNone) // [DI+...] instr.ModRM.RM = 0x05; else if (reg1 == Register.SI && reg2 == Register.BP) // [BP+SI+...] instr.ModRM.RM = 0x02; else if (reg1 == Register.SI && reg2 == Register.BX) // [BX+SI+...] instr.ModRM.RM = 0x00; else if (reg1 == Register.SI && reg2.IsNone) // [SI+...] instr.ModRM.RM = 0x04; else if (reg1 == Register.BX && reg2.IsNone) // [BX+...] instr.ModRM.RM = 0x06; else throw new AssemblerException("The effective address cannot be encoded"); switch (instr.DisplacementSize) { case DataSize.None: instr.ModRM.Mod = 0x00; break; case DataSize.Bit8: instr.ModRM.Mod = 0x01; break; default: // The default is 16-bit, so larger values get truncated. instr.ModRM.Mod = 0x02; break; } } }
/// <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> void EncodeDisplacement(Context context, EncodedInstruction instr, DataSize addressSize) { DataSize displacementSize = DataSize.None; ReferenceOffset displacementExpression = null; if (Displacement != null) { // Let's evaluate the displacement expression. displacementExpression = Displacement.Compile()(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.AddressingMode; else // Otherwise, use the most efficient word size. displacementSize = Extensions.GetSizeOfValue(displacementExpression.Evaluate(context)); } } instr.DisplacementSize = displacementSize; instr.Displacement = displacementExpression; }
/// <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> public abstract void Construct(Context context, EncodedInstruction 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 a 32-bit effective address. /// </summary> /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the operand.</param> private void Encode32BitEffectiveAddress(EncodedInstruction instr) { instr.SetModRMByte(); if (baseRegister == Register.None && indexRegister == Register.None) { // R/M instr.ModRM.RM = 0x05; // Mod instr.ModRM.Mod = 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 (baseRegister != Register.ESP && indexRegister == Register.None) { // R/M instr.ModRM.RM = (byte)((int)baseRegister & 0x07); // Displacement. if (instr.Displacement == null && baseRegister == Register.EBP) { // [EBP] will be represented as [EBP+disp8]. instr.DisplacementSize = DataSize.Bit8; instr.Displacement = new SimpleExpression(0); } // Mod if (instr.DisplacementSize == DataSize.None) { instr.ModRM.Mod = 0x00; } else if (instr.DisplacementSize == DataSize.Bit8) { instr.ModRM.Mod = 0x01; } else if (instr.DisplacementSize <= DataSize.Bit32) { instr.ModRM.Mod = 0x02; } } else { // Encode the SIB byte too. instr.SetSIBByte(); // R/M instr.ModRM.RM = 0x04; // Displacement if (instr.Displacement == null && baseRegister == Register.EBP) { // [EBP+REG*s] will be represented as [EBP+REG*s+disp8]. instr.DisplacementSize = DataSize.Bit8; instr.Displacement = new SimpleExpression(0); } // Mod if (instr.DisplacementSize == DataSize.None) { instr.ModRM.Mod = 0x00; } else if (instr.DisplacementSize == DataSize.Bit8) { instr.ModRM.Mod = 0x01; } else if (instr.DisplacementSize <= DataSize.Bit32) { instr.ModRM.Mod = 0x02; } // Base instr.Sib.Base = (byte)((int)baseRegister & 0x07); if (baseRegister == Register.None) { instr.Sib.Base = 0x05; } // Index instr.Sib.Index = (byte)((int)indexRegister & 0x07); if (indexRegister == Register.None) { instr.Sib.Index = 0x20; } // Scale instr.Sib.Scale = (byte)((int)Math.Log(scale, 2)); } }
/// <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> public override void Construct(Context context, EncodedInstruction instruction) { throw new NotImplementedException(); }
/// <summary> /// Encodes a 32-bit effective address. /// </summary> /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the operand.</param> void Encode32BitEffectiveAddress(EncodedInstruction instr) { instr.SetModRMByte(); if (BaseRegister.IsNone && IndexRegister.IsNone) { // R/M instr.ModRM.RM = 0x05; // Mod instr.ModRM.Mod = 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 ReferenceOffset(0); } else if (BaseRegister != Register.ESP && IndexRegister.IsNone) { // R/M instr.ModRM.RM = (byte)(BaseRegister.Full & 0x07); // Displacement. if (instr.Displacement == null && BaseRegister == Register.EBP) { // [EBP] will be represented as [EBP+disp8]. instr.DisplacementSize = DataSize.Bit8; instr.Displacement = new ReferenceOffset(0); } // Mod if (instr.DisplacementSize == DataSize.None) instr.ModRM.Mod = 0x00; else if (instr.DisplacementSize == DataSize.Bit8) instr.ModRM.Mod = 0x01; else if (instr.DisplacementSize <= DataSize.Bit32) instr.ModRM.Mod = 0x02; } else { // Encode the SIB byte too. instr.SetSIBByte(); // R/M instr.ModRM.RM = 0x04; // Displacement if (instr.Displacement == null && BaseRegister == Register.EBP) { // [EBP+REG*s] will be represented as [EBP+REG*s+disp8]. instr.DisplacementSize = DataSize.Bit8; instr.Displacement = new ReferenceOffset(0); } // Mod if (instr.DisplacementSize == DataSize.None) instr.ModRM.Mod = 0x00; else if (instr.DisplacementSize == DataSize.Bit8) instr.ModRM.Mod = 0x01; else if (instr.DisplacementSize <= DataSize.Bit32) instr.ModRM.Mod = 0x02; // Base instr.Sib.Base = (byte)(BaseRegister.Full & 0x07); if (BaseRegister.IsNone) instr.Sib.Base = 0x05; // Index instr.Sib.Index = (byte)(IndexRegister.Full & 0x07); if (IndexRegister.IsNone) instr.Sib.Index = 0x20; // Scale instr.Sib.Scale = (byte)((int)Math.Log(Scale, 2)); } }
/// <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> public override void Construct(Context context, EncodedInstruction instruction) { // Let's evaluate the expression. var result = Expression?.Compile()(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.AddressingMode; else // Otherwise, use the most efficient word size. size = Extensions.GetSizeOfValue(result.Constant); } if (size > DataSize.Bit64) throw new AssemblerException("Operands with more than 64 bits cannot be encoded."); else if (size == DataSize.None) throw new AssemblerException("The operand size is not specified."); // Set the parameters. if (!asExtraImmediate) { instruction.Immediate = result; instruction.ImmediateSize = size; } else { instruction.ExtraImmediate = result; instruction.ExtraImmediateSize = size; } instruction.SetOperandSize(context.AddressingMode, size); }
/// <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> void Encode64BitEffectiveAddress(Context context, EncodedInstruction instr) { instr.SetModRMByte(); bool ripRelative = RelativeAddress ?? context.UseRIPRelativeAddressing; bool forceRipRelative = RelativeAddress.HasValue && RelativeAddress == true; if (BaseRegister.IsNone && IndexRegister.IsNone) { 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 ReferenceOffset(0); } else { if (forceRipRelative) throw new AssemblerException("The effective address cannot be encoded with RIP-relative addressing."); if (BaseRegister != Register.RSP && IndexRegister.IsNone) { // [REG+...] instr.ModRM.RM = BaseRegister.Value; } else { // [REG+REG*s+...] // Encode the SIB byte too. instr.SetSIBByte(); // R/M instr.ModRM.RM = 0x04; // Base if (!BaseRegister.IsNone) instr.Sib.Base = BaseRegister.Value; else instr.Sib.Base = 0x05; // Index if (!IndexRegister.IsNone) instr.Sib.Index = IndexRegister.Value; 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 ReferenceOffset(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(); } } }
public void Construct(Context context, EncodedInstruction instruction) { Contract.Requires <ArgumentNullException>(context != null); Contract.Requires <ArgumentNullException>(instruction != null); }
/// <summary> /// Encodes a 16-bit effective address. /// </summary> /// <param name="instr">The <see cref="EncodedInstruction"/> encoding the operand.</param> void Encode16BitEffectiveAddress(EncodedInstruction instr) { instr.SetModRMByte(); // We order the registers in such way that reg1 has the register with the highest number, // and reg2 has the register with the lowest number. When a register is not provided, it is put in reg2. // This simplifies the following tests, for which the order does not matter. var baseReg = BaseRegister; var indexReg = (Scale == 1 ? IndexRegister : Register.None); var reg1 = (baseReg.Value >= indexReg.Value ? baseReg : indexReg); var reg2 = (baseReg.Value < indexReg.Value ? baseReg : indexReg); if (Scale != 1 && Scale != 0) { throw new AssemblerException("The specified scaling factor is not supported in a 16-bit effective address."); } // Two cases together deviate from the standard MOD encoding. if (reg1 == Register.BP && reg2.IsNone) { // [BP+...] instr.ModRM.RM = 0x06; instr.ModRM.Mod = (byte)(instr.DisplacementSize == DataSize.Bit8 ? 0x01 : 0x02); } else if (reg1.IsNone && reg2.IsNone) { // [...] instr.ModRM.RM = 0x06; instr.ModRM.Mod = 0x00; } else { // The other cases are straight forward. if (reg1 == Register.DI && reg2 == Register.BP) { // [BP+DI+...] instr.ModRM.RM = 0x03; } else if (reg1 == Register.DI && reg2 == Register.BX) { // [BX+DI+...] instr.ModRM.RM = 0x01; } else if (reg1 == Register.DI && reg2.IsNone) { // [DI+...] instr.ModRM.RM = 0x05; } else if (reg1 == Register.SI && reg2 == Register.BP) { // [BP+SI+...] instr.ModRM.RM = 0x02; } else if (reg1 == Register.SI && reg2 == Register.BX) { // [BX+SI+...] instr.ModRM.RM = 0x00; } else if (reg1 == Register.SI && reg2.IsNone) { // [SI+...] instr.ModRM.RM = 0x04; } else if (reg1 == Register.BX && reg2.IsNone) { // [BX+...] instr.ModRM.RM = 0x06; } else { throw new AssemblerException("The effective address cannot be encoded"); } switch (instr.DisplacementSize) { case DataSize.None: instr.ModRM.Mod = 0x00; break; case DataSize.Bit8: instr.ModRM.Mod = 0x01; break; default: // The default is 16-bit, so larger values get truncated. instr.ModRM.Mod = 0x02; break; } } }