public static void Adr(ArmEmitterContext context) { OpCodeAdr op = (OpCodeAdr)context.CurrOp; ulong address = op.Address + (ulong)op.Immediate; Operand addressOp = !context.HasTtc ? Const(address) : Const(address, new Symbol(SymbolType.DynFunc, context.GetOffset(address))); SetIntOrZR(context, op.Rd, addressOp); }
public static void Bl(ArmEmitterContext context) { OpCodeBImmAl op = (OpCodeBImmAl)context.CurrOp; ulong address = op.Address + 4; Operand addressOp = !context.HasTtc ? Const(address) : Const(address, new Symbol(SymbolType.DynFunc, context.GetOffset(address))); context.Copy(GetIntOrZR(context, RegisterAlias.Lr), addressOp); EmitCall(context, (ulong)op.Immediate); }
public static void Blr(ArmEmitterContext context) { OpCodeBReg op = (OpCodeBReg)context.CurrOp; ulong address = op.Address + 4; Operand addressOp = !context.HasTtc ? Const(address) : Const(address, new Symbol(SymbolType.DynFunc, context.GetOffset(address))); context.Copy(GetIntOrZR(context, RegisterAlias.Lr), addressOp); Operand n = context.Copy(GetIntOrZR(context, op.Rn)); EmitVirtualCall(context, n); }
public static void EmitCall(ArmEmitterContext context, ulong immediate) { bool isRecursive = immediate == context.EntryAddress; if (isRecursive) { context.Branch(context.GetLabel(immediate)); } else { Operand address = !context.HasTtc ? Const(immediate) : Const(immediate, new Symbol(SymbolType.DynFunc, context.GetOffset(immediate))); EmitTableBranch(context, address, isJump: false); } }
public static void Ldr_Literal(ArmEmitterContext context) { IOpCodeLit op = (IOpCodeLit)context.CurrOp; if (op.Prefetch) { return; } Operand address = !context.HasTtc ? Const(op.Immediate) : Const(op.Immediate, new Symbol(SymbolType.DynFunc, context.GetOffset((ulong)op.Immediate))); if (op.Signed) { EmitLoadSx64(context, address, op.Rt, op.Size); } else { EmitLoadZx(context, address, op.Rt, op.Size); } }
public static void Adrp(ArmEmitterContext context) { OpCodeAdr op = (OpCodeAdr)context.CurrOp; Operand addressOp; if (!context.HasTtc) { ulong address = (op.Address & ~0xfffUL) + ((ulong)op.Immediate << 12); addressOp = Const(address); } else { addressOp = Const(op.Address & ~0xfffUL, new Symbol(SymbolType.DynFuncAdrp, context.GetOffset(op.Address))); addressOp = context.Add(addressOp, Const((ulong)op.Immediate << 12)); } SetIntOrZR(context, op.Rd, addressOp); }
private static void EmitTableBranch(ArmEmitterContext context, Operand guestAddress, bool isJump) { context.StoreToContext(); if (guestAddress.Type == OperandType.I32) { guestAddress = context.ZeroExtend32(OperandType.I64, guestAddress); } // Store the target guest address into the native context. The stubs uses this address to dispatch into the // next translation. Operand nativeContext = context.LoadArgument(OperandType.I64, 0); Operand dispAddressAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset())); context.Store(dispAddressAddr, guestAddress); Operand hostAddress; // If address is mapped onto the function table, we can skip the table walk. Otherwise we fallback // onto the dispatch stub. if (guestAddress.Kind == OperandKind.Constant && context.FunctionTable.IsValid(guestAddress.Value)) { Symbol symbol = default; if (context.HasPtc) { symbol = new Symbol(SymbolType.FunctionTable, guestAddress.Value); } else if (context.HasTtc) { symbol = new Symbol(SymbolType.FunctionTable, context.GetOffset(guestAddress.Value)); } Operand hostAddressAddr = Const(ref context.FunctionTable.GetValue(guestAddress.Value), symbol); hostAddress = context.Load(OperandType.I64, hostAddressAddr); } else { hostAddress = !context.HasPtc ? Const((long)context.Stubs.DispatchStub) : Const((long)context.Stubs.DispatchStub, Ptc.DispatchStubSymbol); } if (isJump) { context.Tailcall(hostAddress, nativeContext); } else { OpCode op = context.CurrOp; Operand returnAddress = context.Call(hostAddress, OperandType.I64, nativeContext); context.LoadFromContext(); // Note: The return value of a translated function is always an Int64 with the address execution has // returned to. We expect this address to be immediately after the current instruction, if it isn't we // keep returning until we reach the dispatcher. Operand nextAddr = Const((long)op.Address + op.OpCodeSizeInBytes); // Try to continue within this block. // If the return address isn't to our next instruction, we need to return so the JIT can figure out // what to do. Operand lblContinue = context.GetLabel(nextAddr.Value); context.BranchIf(lblContinue, returnAddress, nextAddr, Comparison.Equal, BasicBlockFrequency.Cold); context.Return(returnAddress); } }