private static void GetBranchTarget(Instruction instruction, CodeContext context, GpRegister target) { var operand = instruction.Operands.First(); switch (operand.Type) { case ud_type.UD_OP_REG: var maybeRegister = SdToAsm.SdToAsmJit(context, operand.Base); if (!maybeRegister.Present) { throw new Exception("could not map register"); } switch (maybeRegister.Type) { case RegisterType.GpRegister: context.Mov(target, (GpRegister)maybeRegister.Register); break; case RegisterType.SegRegister: context.Mov(target, (SegRegister)maybeRegister.Register); break; default: throw new Exception("unsupported register"); } break; case ud_type.UD_OP_MEM: CreateLea(context, target, instruction); break; case ud_type.UD_OP_JIMM: ulong immediate; ulong truncMask = 0xffffffffffffffff >> (64 - instruction.opr_mode); // Console.WriteLine($"opr_mode: {instruction.opr_mode}"); switch (operand.Size) { case 8: immediate = (instruction.PC + (ulong)operand.LvalSByte) & truncMask; break; case 16: immediate = (instruction.PC + (ulong)operand.LvalSWord) & truncMask; break; case 32: immediate = (instruction.PC + (ulong)operand.LvalSDWord) & truncMask; break; default: throw new Exception("invalid relative offset size."); } // in our emulator we are going to keep RIP in target (RAX) context.Lea(target, Memory.QWord(target, (int)immediate)); break; default: throw new Exception("unsupported operand type"); } }
public static void CreateLea(CodeContext context, GpRegister target, Instruction instruction) { var operand = instruction.Operands.First(); Memory memoryReference = null; GpRegister baseRegister = null; bool baseRipRegister = false; MaybeRegister maybeIndexRegister = null; if (operand.Base != ud_type.UD_NONE) { var maybeBaseRegister = SdToAsm.SdToAsmJit(context, operand.Base); if (!maybeBaseRegister.Present) { throw new Exception($"could not map base register for: {instruction}"); } if (maybeBaseRegister.Type != RegisterType.GpRegister) { if (maybeBaseRegister.Type == RegisterType.RipRegister) { baseRipRegister = true; } else { throw new Exception("could not map base register to GpRegister"); } } else { baseRegister = (GpRegister)maybeBaseRegister.Register; } } if (operand.Index != ud_type.UD_NONE) { maybeIndexRegister = SdToAsm.SdToAsmJit(context, operand.Index); if (!maybeIndexRegister.Present) { throw new Exception("could not map base register"); } } var displacement = SdToAsm.GetDisplacement(instruction, operand); var displacementIntPtr = (IntPtr)displacement.Value; var scale = 0; switch (operand.Scale) { case 0: case 1: scale = 0; break; case 2: scale = 1; break; case 4: scale = 2; break; case 8: scale = 3; break; } if (baseRipRegister) { // in our emulator we are going to keep our RIP in target (RAX) baseRegister = target; if (maybeIndexRegister == null) { switch (operand.Size) { case 8: memoryReference = Memory.Byte(baseRegister, (int)displacement.Value); break; case 16: memoryReference = Memory.Word(baseRegister, (int)displacement.Value); break; case 32: memoryReference = Memory.DWord(baseRegister, (int)displacement.Value); break; case 64: memoryReference = Memory.QWord(baseRegister, (int)displacement.Value); break; case 80: memoryReference = Memory.TWord(baseRegister, (int)displacement.Value); break; default: throw new Exception("unsupported operand size"); } } else { throw new Exception("index register not supported when base register is RIP"); } } else { if (baseRegister == null && maybeIndexRegister == null) { switch (operand.Size) { case 8: memoryReference = Memory.ByteAbs(displacementIntPtr); break; case 16: memoryReference = Memory.WordAbs(displacementIntPtr); break; case 32: memoryReference = Memory.DWordAbs(displacementIntPtr); break; case 64: memoryReference = Memory.QWordAbs(displacementIntPtr); break; default: throw new Exception("unsupported operand size"); } } else if (baseRegister != null && maybeIndexRegister == null) { switch (operand.Size) { case 8: memoryReference = Memory.Byte(baseRegister, (int)displacement.Value); break; case 16: memoryReference = Memory.Word(baseRegister, (int)displacement.Value); break; case 32: memoryReference = Memory.DWord(baseRegister, (int)displacement.Value); break; case 64: memoryReference = Memory.QWord(baseRegister, (int)displacement.Value); break; case 80: memoryReference = Memory.TWord(baseRegister, (int)displacement.Value); break; default: throw new Exception("unsupported operand size"); } } else if (baseRegister == null) { switch (operand.Size) { case 8: switch (maybeIndexRegister.Type) { case RegisterType.MmRegister: throw new Exception("mmregister not supported as index by asmjit"); case RegisterType.SegRegister: throw new Exception("segregister not supported as index by asmjit"); case RegisterType.GpRegister: memoryReference = Memory.ByteAbs(displacementIntPtr, (GpRegister)maybeIndexRegister.Register, scale); break; case RegisterType.XmmRegister: memoryReference = Memory.ByteAbs(displacementIntPtr, (XmmRegister)maybeIndexRegister.Register, scale); break; case RegisterType.YmmRegister: memoryReference = Memory.ByteAbs(displacementIntPtr, (YmmRegister)maybeIndexRegister.Register, scale); break; } break; case 16: switch (maybeIndexRegister.Type) { case RegisterType.MmRegister: throw new Exception("mmregister not supported as index by asmjit"); case RegisterType.SegRegister: throw new Exception("segregister not supported as index by asmjit"); case RegisterType.GpRegister: memoryReference = Memory.WordAbs(displacementIntPtr, (GpRegister)maybeIndexRegister.Register, scale); break; case RegisterType.XmmRegister: memoryReference = Memory.WordAbs(displacementIntPtr, (XmmRegister)maybeIndexRegister.Register, scale); break; case RegisterType.YmmRegister: memoryReference = Memory.WordAbs(displacementIntPtr, (YmmRegister)maybeIndexRegister.Register, scale); break; } break; case 32: switch (maybeIndexRegister.Type) { case RegisterType.MmRegister: throw new Exception("mmregister not supported as index by asmjit"); case RegisterType.SegRegister: throw new Exception("segregister not supported as index by asmjit"); case RegisterType.GpRegister: memoryReference = Memory.DWordAbs(displacementIntPtr, (GpRegister)maybeIndexRegister.Register, scale); break; case RegisterType.XmmRegister: memoryReference = Memory.DWordAbs(displacementIntPtr, (XmmRegister)maybeIndexRegister.Register, scale); break; case RegisterType.YmmRegister: memoryReference = Memory.DWordAbs(displacementIntPtr, (YmmRegister)maybeIndexRegister.Register, scale); break; } break; case 64: switch (maybeIndexRegister.Type) { case RegisterType.MmRegister: throw new Exception("mmregister not supported as index by asmjit"); case RegisterType.SegRegister: throw new Exception("segregister not supported as index by asmjit"); case RegisterType.GpRegister: memoryReference = Memory.QWordAbs(displacementIntPtr, (GpRegister)maybeIndexRegister.Register, scale); break; case RegisterType.XmmRegister: memoryReference = Memory.QWordAbs(displacementIntPtr, (XmmRegister)maybeIndexRegister.Register, scale); break; case RegisterType.YmmRegister: memoryReference = Memory.QWordAbs(displacementIntPtr, (YmmRegister)maybeIndexRegister.Register, scale); break; } break; case 80: throw new Exception("unsupported operand size 80"); default: throw new Exception("unsupported operand size"); } } else { switch (operand.Size) { case 8: switch (maybeIndexRegister.Type) { case RegisterType.MmRegister: throw new Exception("mmregister not supported as index by asmjit"); case RegisterType.SegRegister: throw new Exception("segregister not supported as index by asmjit"); case RegisterType.GpRegister: memoryReference = Memory.Byte(baseRegister, (GpRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; case RegisterType.XmmRegister: memoryReference = Memory.Byte(baseRegister, (XmmRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; case RegisterType.YmmRegister: memoryReference = Memory.Byte(baseRegister, (YmmRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; } break; case 16: switch (maybeIndexRegister.Type) { case RegisterType.MmRegister: throw new Exception("mmregister not supported as index by asmjit"); case RegisterType.SegRegister: throw new Exception("segregister not supported as index by asmjit"); case RegisterType.GpRegister: memoryReference = Memory.Word(baseRegister, (GpRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; case RegisterType.XmmRegister: memoryReference = Memory.Word(baseRegister, (XmmRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; case RegisterType.YmmRegister: memoryReference = Memory.Word(baseRegister, (YmmRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; } break; case 32: switch (maybeIndexRegister.Type) { case RegisterType.MmRegister: throw new Exception("mmregister not supported as index by asmjit"); case RegisterType.SegRegister: throw new Exception("segregister not supported as index by asmjit"); case RegisterType.GpRegister: memoryReference = Memory.DWord(baseRegister, (GpRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; case RegisterType.XmmRegister: memoryReference = Memory.DWord(baseRegister, (XmmRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; case RegisterType.YmmRegister: memoryReference = Memory.DWord(baseRegister, (YmmRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; } break; case 64: switch (maybeIndexRegister.Type) { case RegisterType.MmRegister: throw new Exception("mmregister not supported as index by asmjit"); case RegisterType.SegRegister: throw new Exception("segregister not supported as index by asmjit"); case RegisterType.GpRegister: memoryReference = Memory.QWord(baseRegister, (GpRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; case RegisterType.XmmRegister: memoryReference = Memory.QWord(baseRegister, (XmmRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; case RegisterType.YmmRegister: memoryReference = Memory.QWord(baseRegister, (YmmRegister)maybeIndexRegister.Register, scale, (int)displacement.Value); break; } break; case 80: throw new Exception("unsupported operand size 80"); default: throw new Exception("unsupported operand size"); } } } context.Lea(target, memoryReference); }