/// <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> 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) { 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> /// Initializes a new instance of the <see cref="ExpressionEmittable"/> class. /// </summary> /// <param name="expression">The expression of the value.</param> /// <param name="size">The size of the result.</param> public ExpressionEmittable(ReferenceOffset expression, DataSize size) { Expression = expression; Size = size; }
/// <summary> /// Emits the immediate value as part of the instruction, if any. /// </summary> /// <param name="writer">The <see cref="BinaryWriter"/> to which the encoded instruction is written.</param> /// <param name="instructionOffset">The offset of the instruction in the stream underlying /// <paramref name="writer"/>.</param> /// <param name="context">The <see cref="Context"/> of the instruction.</param> /// <param name="expression">The <see cref="ReferenceOffset"/> to emit.</param> /// <param name="size">The size of the value to emit.</param> void EmitReferenceOffset(BinaryWriter writer, long instructionOffset, Context context, ReferenceOffset expression, DataSize size) { if (expression == null) { return; } // Number of bytes before the expression. var relocationDiff = (ulong)(writer.BaseStream.Position - instructionOffset); Relocation relocation = null; var actualValue = expression.Evaluate(context); if (expression.Reference != null) { relocation = new Relocation(expression.Reference.Symbol, (long)context.Address, actualValue, RelocationType.Default32); } // Emit the expression's value. EmitConstant(writer, size, actualValue); // Add the relocation to the context. if (relocation != null) { relocation.Offset += (long)relocationDiff; context.RelocationTable.Add(relocation); } }