{"record":{"id":"318b3beca51f3260","repo":"egametang/ET","slug":"address-offset-of-target-and-replace-must-less-tha-318b3b","errorCode":null,"errorMessage":"address offset of target and replace must less than (1 << 26) - 1) * 4","messagePattern":"address offset of target and replace must less than \\(1 << 26\\) - 1\\) \\* 4","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.hybridclr/Scripts/Editor/Share/3rds/UnityHook/CodePatcher.cs","lineNumber":265,"sourceCode":"    /// <summary>\n    /// arm64 下 ±128MB 范围内的跳转\n    /// </summary>\n    public unsafe class CodePatcher_arm64_near : CodePatcher\n    {\n        private static readonly byte[] s_jmpCode = new byte[]    // 4 bytes\n        {\n            /*\n             * from 0x14 to 0x17 is B opcode\n             * offset bits is 26\n             * https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/B--Branch-\n             */\n            0x00, 0x00, 0x00, 0x14,                         //  B $val   ; $val = (($dst - $src)/4) & 7FFFFFF\n        };\n\n        public CodePatcher_arm64_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)\n        {\n            if (Math.Abs((long)target - (long)replace) >= ((1 << 26) - 1) * 4)\n                throw new ArgumentException(\"address offset of target and replace must less than (1 << 26) - 1) * 4\");\n\n#if ENABLE_HOOK_DEBUG\n            Debug.Log($\"CodePatcher_arm64: {PrintAddrs()}\");\n#endif\n        }\n\n        protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)\n        {\n            byte[] ret = new byte[s_jmpCode.Length];\n            int val = (int)((long)jmpTo - (long)jmpFrom) / 4;\n\n            fixed (void* p = &ret[0])\n            {\n                byte* ptr = (byte*)p;\n                *ptr++ = (byte)val;\n                *ptr++ = (byte)(val >> 8);\n                *ptr++ = (byte)(val >> 16);\n","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.hybridclr/Scripts/Editor/Share/3rds/UnityHook/CodePatcher.cs#L247-L283","documentation":"Thrown by CodePatcher_arm64_near's constructor. On ARM64, the B (unconditional branch) instruction encodes a 26-bit signed immediate multiplied by 4, giving a ±128 MiB reach ((2^26 - 1) * 4 bytes). If the absolute difference between target and replacement addresses reaches or exceeds this limit, the near branch cannot encode the jump and the constructor throws ArgumentException.","triggerScenarios":"Constructing a CodePatcher_arm64_near where Math.Abs((long)target - (long)replace) >= (67,108,863 * 4) = ~256 MiB. Occurs on ARM64 when ASLR, shared library loading, or JIT code allocation places the target and replacement functions more than ~128 MiB apart in the 64-bit address space.","commonSituations":"Hooking a method on ARM64 (modern Android, Apple Silicon) where the replacement lives in a separately loaded assembly or dynamically allocated code buffer far from the original; address space randomization (ASLR) on 64-bit placing libraries very far apart.","solutions":["Use CodePatcher_arm64_far (20-byte ADR+LDR+BR sequence) for out-of-range offsets.","Implement distance-based patcher selection: near when offset < ((1<<26)-1)*4, far otherwise.","Investigate whether the replacement function can be allocated closer to the target (e.g. via code allocation near the original).","Verify you are on ARM64 — if the issue is on ARM32, use the arm32 patchers instead."],"exampleFix":"// before\nvar patcher = new CodePatcher_arm64_near(targetPtr, replacePtr, proxy);\n\n// after — choose based on distance\nlong offset = Math.Abs((long)targetPtr - (long)replacePtr);\nCodePatcher patcher = offset < ((1L << 26) - 1) * 4\n    ? new CodePatcher_arm64_near(targetPtr, replacePtr, proxy)\n    : new CodePatcher_arm64_far(targetPtr, replacePtr, proxy, 20);","handlingStrategy":"validation","validationCode":"long offset = Math.Abs((long)targetPtr - (long)replacePtr);\nlong arm64NearLimit = ((1L << 26) - 1) * 4; // ~128 MiB\nif (offset >= arm64NearLimit)\n{\n    Debug.LogWarning($\"ARM64 near branch cannot reach offset {offset} (limit {arm64NearLimit}). Use CodePatcher_arm64_far.\");\n}","typeGuard":"static bool CanUseArm64Near(IntPtr target, IntPtr replace)\n{\n    return Math.Abs((long)target - (long)replace) < ((1L << 26) - 1) * 4;\n}","tryCatchPattern":"try\n{\n    var patcher = new CodePatcher_arm64_near(targetPtr, replacePtr, proxy);\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"1 << 26\"))\n{\n    // Offset exceeds ±128 MiB; fall back to far patcher\n    var patcher = new CodePatcher_arm64_far(targetPtr, replacePtr, proxy, 20);\n}","preventionTips":["Compute the offset before choosing arm64_near vs arm64_far.","Use a patcher factory that selects based on measured distance.","On ARM64 with high ASLR entropy, far patchers may be needed more often.","Test on physical ARM64 devices to validate address layout assumptions."],"tags":["unityhook","arm64","code-patching","address-range","method-hook"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}