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"); } }
protected override void Compile(CodeContext c) { c.Push(c.Ebp); c.Mov(c.Ebp, c.Esp); c.Sub(c.Esp, 192); c.Push(c.Ebx); c.Push(c.Esi); c.Push(c.Edi); c.Lea(c.Edi, Memory.DWord(c.Ebp, -192)); c.Mov(c.Ecx, 48); c.Mov(c.Eax, -858993460); c.RepStosd(); c.Mov(c.Eax, Memory.DWord(c.Ebp, 8)); c.Add(c.Eax, Memory.DWord(c.Ebp, 12)); c.Pop(c.Edi); c.Pop(c.Esi); c.Pop(c.Ebx); c.Mov(c.Esp, c.Ebp); c.Pop(c.Ebp); c.Ret(8); }
protected override void Compile(CodeContext c) { var dst = c.IntPtr("dst"); var src = c.IntPtr("src"); var i = c.IntPtr("i"); var j = c.IntPtr("j"); var t = c.IntPtr("t"); var cZero = c.Xmm("cZero"); var cMul255A = c.Xmm("cMul255A"); var cMul255M = c.Xmm("cMul255M"); var x0 = c.Xmm("x0"); var x1 = c.Xmm("x1"); var y0 = c.Xmm("y0"); var a0 = c.Xmm("a0"); var a1 = c.Xmm("a1"); var smallLoop = c.Label(); var smallEnd = c.Label(); var largeLoop = c.Label(); var largeEnd = c.Label(); var data = c.Label(); c.SetArgument(0, dst); c.SetArgument(1, src); c.SetArgument(2, i); c.Allocate(dst); c.Allocate(src); c.Allocate(i); // How many pixels have to be processed to make the loop aligned. c.Lea(t, Memory.Ptr(data)); c.Xor(j, j); c.Xorps(cZero, cZero); c.Sub(j, dst); c.Movaps(cMul255A, Memory.Ptr(t, 0)); c.And(j, 15); c.Movaps(cMul255M, Memory.Ptr(t, 16)); c.Shr(j, 2); c.Jz(smallEnd); // j = min(i, j). c.Cmp(j, i); c.Cmovg(j, i); // i -= j. c.Sub(i, j); // Small loop. c.Bind(smallLoop); c.Pcmpeqb(a0, a0); c.Movd(y0, Memory.Ptr(src)); c.Pxor(a0, y0); c.Movd(x0, Memory.Ptr(dst)); c.Psrlw(a0, 8); c.Punpcklbw(x0, cZero); c.Pshuflw(a0, a0, AsmJit.Common.Utils.Shuffle(1, 1, 1, 1)); c.Punpcklbw(y0, cZero); c.Pmullw(x0, a0); c.Paddsw(x0, cMul255A); c.Pmulhuw(x0, cMul255M); c.Paddw(x0, y0); c.Packuswb(x0, x0); c.Movd(Memory.Ptr(dst), x0); c.Add(dst, 4); c.Add(src, 4); c.Dec(j); c.Jnz(smallLoop); // Second section, prepare for an aligned loop. c.Bind(smallEnd); c.Test(i, i); c.Mov(j, i); c.Jz(c.Exit); c.And(j, 3); c.Shr(i, 2); c.Jz(largeEnd); // Aligned loop. c.Bind(largeLoop); c.Movups(y0, Memory.Ptr(src)); c.Pcmpeqb(a0, a0); c.Movaps(x0, Memory.Ptr(dst)); c.Xorps(a0, y0); c.Movaps(x1, x0); c.Psrlw(a0, 8); c.Punpcklbw(x0, cZero); c.Movaps(a1, a0); c.Punpcklwd(a0, a0); c.Punpckhbw(x1, cZero); c.Punpckhwd(a1, a1); c.Pshufd(a0, a0, AsmJit.Common.Utils.Shuffle(3, 3, 1, 1)); c.Pshufd(a1, a1, AsmJit.Common.Utils.Shuffle(3, 3, 1, 1)); c.Pmullw(x0, a0); c.Pmullw(x1, a1); c.Paddsw(x0, cMul255A); c.Paddsw(x1, cMul255A); c.Pmulhuw(x0, cMul255M); c.Pmulhuw(x1, cMul255M); c.Add(src, 16); c.Packuswb(x0, x1); c.Paddw(x0, y0); c.Movaps(Memory.Ptr(dst), x0); c.Add(dst, 16); c.Dec(i); c.Jnz(largeLoop); c.Bind(largeEnd); c.Test(j, j); c.Jnz(smallLoop); // Data c.Data(data, 16, Data.Of(0x0080008000800080, 0x0080008000800080), Data.Of(0x0101010101010101, 0x0080008000800080)); }
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); }