/// <summary> /// Redirects all calls from method 'from' to method 'to'. This version works /// only if the 'from' method has already been compiled (use GetFunctionPointer to force /// this) but no function calling 'from' have already been compiled. In fact, this /// function forces compilation for 'to' and 'from'. 'to' and 'from' are assumed /// to be normal methods. /// After compilation, this method looks up the MonoJitInfo structs for both methods /// from domain->jit_info_hash and patches sets the pointer to native code to the code /// obtained from compiling 'to'. /// </summary> /// <param name="from"></param> /// <param name="to"></param> private static void RedirectCall(MethodInfo from, MethodInfo to) { /* We assume that we are only dealing with 'normal' functions (in Mono lingua). * This excludes in particular: * - generic functions * - PInvokes * - methods built at runtime */ IntPtr methodPtr1 = from.MethodHandle.Value; IntPtr methodPtr2 = to.MethodHandle.Value; // ensure that both methods are compiled from.MethodHandle.GetFunctionPointer(); to.MethodHandle.GetFunctionPointer(); // get domain->jit_code_hash IntPtr domain = mono_domain_get(); unsafe { byte * jitCodeHash = ((byte *)domain.ToPointer() + 0xE8); long **jitCodeHashTable = *(long ***)(jitCodeHash + 0x20); uint tableSize = *(uint *)(jitCodeHash + 0x18); void *jitInfoFrom = null, jitInfoTo = null; // imitate the behavior of mono_internal_hash_table_lookup to get both MonoJitInfo ptrs long mptr1 = methodPtr1.ToInt64(); uint index1 = ((uint)mptr1) >> 3; for (long *value = jitCodeHashTable[index1 % tableSize]; value != null; value = *(long **)(value + 1)) { if (mptr1 == *value) { jitInfoFrom = value; break; } } long mptr2 = methodPtr2.ToInt64(); uint index2 = ((uint)mptr2) >> 3; for (long *value = jitCodeHashTable[index2 % tableSize]; value != null; value = *(long **)(value + 1)) { if (mptr2 == *value) { jitInfoTo = value; break; } } if (jitInfoFrom == null || jitInfoTo == null) { DebugLog.Log("Could not find methods"); return; } // copy over code_start, used_regs, code_size and ignore the rest for now. // code_start beings at +0x10, code_size goes til +0x20 ulong *fromPtr, toPtr; fromPtr = (ulong *)jitInfoFrom; toPtr = (ulong *)jitInfoTo; *(fromPtr + 2) = *(toPtr + 2); *(fromPtr + 3) = *(toPtr + 3); } }