egametang/ET · error · ArgumentException

address offset of target and replace must larger than ((1 <<

Error message

address offset of target and replace must larger than ((1 << 25) - 1), please use InstructionModifier_arm32_near instead

What it means

Thrown by CodePatcher_arm32_far's constructor. The far branch variant (8-byte LDR PC, [PC, #-4]) works at any distance but is needlessly large when a near branch would suffice. As a guard against using the wrong patcher, the constructor rejects the case where the offset is actually small enough (< 32 MiB) for the near variant, directing you to use CodePatcher_arm32_near instead.

Source

Thrown at Packages/cn.etetet.hybridclr/Scripts/Editor/Share/3rds/UnityHook/CodePatcher.cs:226

                *ptr++ = (byte)(val >> 16);
                *ptr++ = 0xEA;
            }
            return ret;
        }
    }

    public unsafe class CodePatcher_arm32_far : CodePatcher
    {
        private static readonly byte[] s_jmpCode = new byte[]    // 8 bytes
        {
            0x04, 0xF0, 0x1F, 0xE5,                         // LDR PC, [PC, #-4]
            0x00, 0x00, 0x00, 0x00,                         // $val
        };

        public CodePatcher_arm32_far(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 larger than ((1 << 25) - 1), please use InstructionModifier_arm32_near instead");

#if ENABLE_HOOK_DEBUG
            Debug.Log($"CodePatcher_arm32_far: {PrintAddrs()}");
#endif
        }

        protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
        {
            byte[] ret = new byte[s_jmpCode.Length];

            fixed (void* p = &ret[0])
            {
                uint* ptr = (uint*)p;
                *ptr++ = 0xE51FF004;
                *ptr = (uint)jmpTo;
            }
            return ret;
        }

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Switch to CodePatcher_arm32_near for this target/replace pair since the offset is within range.
  2. Implement distance-based patcher selection so near is used when offset < (1<<25)-1 and far only when it exceeds that.
  3. If you intentionally want the far patcher for uniformity, you must fork the class and remove the guard.

Example fix

// before
var patcher = new CodePatcher_arm32_far(targetPtr, replacePtr, proxyPtr);

// after — select based on distance
long offset = Math.Abs((long)targetPtr - (long)replacePtr);
CodePatcher patcher = offset < ((1 << 25) - 1)
    ? (CodePatcher)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;
if (offset < ARM32_NEAR_LIMIT)
{
    // Use near patcher instead — far patcher will reject this offset
    Debug.LogWarning($"Offset {offset} is within near range. Use CodePatcher_arm32_near.");
}

Type guard

static bool ShouldUseArm32Near(IntPtr target, IntPtr replace)
{
    return Math.Abs((long)target - (long)replace) < ((1 << 25) - 1);
}

Try / catch

try
{
    var patcher = new CodePatcher_arm32_far(targetPtr, replacePtr, proxyPtr);
}
catch (ArgumentException ex) when (ex.Message.Contains("must larger than ((1 << 25)"))
{
    // Switch to near patcher since offset is small enough
    var patcher = new CodePatcher_arm32_near(targetPtr, replacePtr, proxyPtr);
}

Prevention

When it happens

Trigger: Constructing a CodePatcher_arm32_far where Math.Abs((long)target - (long)replace) < 33,554,431 bytes. This means a near patcher would work, so the far patcher considers this a misconfiguration and throws ArgumentException.

Common situations: Hardcoding the far patcher class without distance-based selection; copying example code that used the far patcher for a different scenario; the hook framework's selection logic incorrectly choosing far when near applies.

Related errors


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/63d1fbaa2a97328c. Report an issue: GitHub.