/// <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) { 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="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> /// 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 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> /// 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 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 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 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)); } }