egametang/ET · error · ArgumentException
address offset of target and replace must less than ((1 << 2
Error message
address offset of target and replace must less than ((1 << 25) - 1)
What it means
Thrown by CodePatcher_arm32_near's constructor. On ARM32, a near branch (B instruction) encodes a 24-bit signed offset multiplied by 4, giving a ±32 MiB reach (2^25 - 1 bytes). If the absolute difference between the target function address and the replacement function address reaches or exceeds this limit, the single-instruction branch cannot reach and the constructor rejects the patch with ArgumentException.
Source
Thrown at Packages/cn.etetet.hybridclr/Scripts/Editor/Share/3rds/UnityHook/CodePatcher.cs:191
ptr += 8;
*ptr++ = 0x50;
*ptr++ = 0xC3;
}
return ret;
}
}
public unsafe class CodePatcher_arm32_near : CodePatcher
{
private static readonly byte[] s_jmpCode = new byte[] // 4 bytes
{
0x00, 0x00, 0x00, 0xEA, // B $val ; $val = (($dst - $src) / 4 - 2) & 0x1FFFFFF
};
public CodePatcher_arm32_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)
{
if (Math.Abs((long)target - (long)replace) >= ((1 << 25) - 1))
throw new ArgumentException("address offset of target and replace must less than ((1 << 25) - 1)");
#if ENABLE_HOOK_DEBUG
Debug.Log($"CodePatcher_arm32_near: {PrintAddrs()}");
#endif
}
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
{
byte[] ret = new byte[s_jmpCode.Length];
int val = ((int)jmpTo - (int)jmpFrom) / 4 - 2;
fixed (void* p = &ret[0])
{
byte* ptr = (byte*)p;
*ptr++ = (byte)val;
*ptr++ = (byte)(val >> 8);
*ptr++ = (byte)(val >> 16);
*ptr++ = 0xEA;View on GitHub (pinned to 5cab01f7a8)
Solutions
- Use the far branch variant CodePatcher_arm32_far instead, which uses an 8-byte LDR PC sequence with no distance limit.
- If you control patcher selection, compute the offset first and choose near vs. far dynamically.
- On 32-bit ARM, consider whether the hook is necessary at all — prefer higher-level interception if address layout is uncontrollable.
- Check if the target runtime is actually 32-bit ARM; if it is 64-bit, use the arm64 patchers.
Example fix
// before
var patcher = new CodePatcher_arm32_near(targetPtr, replacePtr, proxyPtr);
// after — choose patcher based on distance
long offset = Math.Abs((long)targetPtr - (long)replacePtr);
CodePatcher patcher = offset < ((1 << 25) - 1)
? new CodePatcher_arm32_near(targetPtr, replacePtr, proxyPtr)
: new CodePatcher_arm32_far(targetPtr, replacePtr, proxyPtr); Defensive patterns
Strategy: validation
Validate before calling
long offset = Math.Abs((long)targetPtr - (long)replacePtr);
const long ARM32_NEAR_LIMIT = (1 << 25) - 1; // ~32 MiB
if (offset >= ARM32_NEAR_LIMIT)
{
// Use far patcher instead, or abort with a clear message
Debug.LogWarning($"ARM32 near branch cannot reach offset {offset}. Use CodePatcher_arm32_far.");
} Type guard
static bool CanUseArm32Near(IntPtr target, IntPtr replace)
{
return Math.Abs((long)target - (long)replace) < ((1 << 25) - 1);
} Try / catch
try
{
var patcher = new CodePatcher_arm32_near(targetPtr, replacePtr, proxyPtr);
}
catch (ArgumentException ex) when (ex.Message.Contains("must less than ((1 << 25)"))
{
// Fall back to far patcher
var patcher = new CodePatcher_arm32_far(targetPtr, replacePtr, proxyPtr);
} Prevention
- Always compute the address offset before selecting a patcher class.
- Implement a factory method that chooses near vs. far based on actual distance.
- On ARM32, prefer far patcher as a safe default if you cannot predict address layout.
- Test hooks on real ARM32 devices, not just emulators, to catch distance issues.
When it happens
Trigger: Constructing a CodePatcher_arm32_near where Math.Abs((long)target - (long)replace) >= 33,554,431 bytes. This occurs when ASLR or memory layout places the target method and its replacement in memory regions more than ~32 MiB apart — common when the replacement is in a separately loaded assembly or a JIT-allocated code region far from the original.
Common situations: Hooking a method on ARM32 (older Android devices, 32-bit iOS) where the hot-reload replacement function is loaded far from the original; using the near patcher unconditionally instead of letting the framework choose near vs. far based on actual distance; address space fragmentation on 32-bit systems.
Related errors
- address offset of target and replace must larger than ((1 <<
- address offset of target and replace must less than (1 << 26
- none of methods targetMethod or replacementMethod can be nul
- MethodHook:targetMethod and replacementMethod and proxyMetho
- WRANING: you can not hook abstract method [{methodName}]
AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13).
Data as JSON: /api/errors/4147fb2dda6ab85d.
Report an issue: GitHub.