|
11 | 11 | #include <dlfcn.h> // dladdr()
|
12 | 12 |
|
13 | 13 | #include "TargetConditionals.h"
|
14 |
| -#if defined(__i386__) || defined(__x86_64__) |
| 14 | +#if defined(__i386__) || defined(__x86_64__) || defined(__arm64__) |
15 | 15 | #if !(TARGET_IPHONE_SIMULATOR)
|
16 | 16 | #include <mach/mach_vm.h> // mach_vm_*
|
17 | 17 | #else
|
|
38 | 38 | #define RDErrorLog(format, ...) fprintf(stderr, "%s:%d:\n\terror: "format"\n", \
|
39 | 39 | __FILE__, __LINE__, ##__VA_ARGS__)
|
40 | 40 |
|
41 |
| -#if defined(__x86_64__) |
| 41 | +#if defined(__x86_64__) || defined(__arm64__) |
42 | 42 | typedef struct mach_header_64 mach_header_t;
|
43 | 43 | typedef struct segment_command_64 segment_command_t;
|
44 | 44 | #define LC_SEGMENT_ARCH_INDEPENDENT LC_SEGMENT_64
|
@@ -288,7 +288,7 @@ static mach_vm_size_t _image_size(void *image, mach_vm_size_t image_slide, mach_
|
288 | 288 | return (image_end - image_addr);
|
289 | 289 | }
|
290 | 290 |
|
291 |
| - |
| 291 | +#if defined(__x86_64__) || defined(__i386__) |
292 | 292 | static kern_return_t _insert_jmp(void* where, void* to)
|
293 | 293 | {
|
294 | 294 | assert(where);
|
@@ -320,6 +320,75 @@ static kern_return_t _insert_jmp(void* where, void* to)
|
320 | 320 |
|
321 | 321 | return (err);
|
322 | 322 | }
|
| 323 | +#elif defined(__arm64__) |
| 324 | +#include <sys/mman.h> |
| 325 | + |
| 326 | +// Function to create an executable trampoline pointing to the target address |
| 327 | +static void* create_trampoline(void* to) { |
| 328 | + assert(to); |
| 329 | + |
| 330 | + // Allocate an executable memory page |
| 331 | + void* trampoline = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE | MAP_JIT, -1, 0); |
| 332 | + if (trampoline == MAP_FAILED) { |
| 333 | + perror("mmap"); |
| 334 | + return NULL; |
| 335 | + } |
| 336 | + |
| 337 | + // ARM64 absolute jump sequence: |
| 338 | + // - Load 64-bit address into x16 |
| 339 | + // - Branch to x16 |
| 340 | + uint32_t trampoline_code[] = { |
| 341 | + 0x58000050, // LDR x16, #8 (load address of target function into x16) |
| 342 | + 0xD61F0200, // BR x16 (branch to address in x16) |
| 343 | + (uint32_t)((uintptr_t)to), // Address of the target function (low 32 bits) |
| 344 | + (uint32_t)((uintptr_t)to >> 32) // Address of the target function (high 32 bits) |
| 345 | + }; |
| 346 | + |
| 347 | + // Copy the code into the trampoline |
| 348 | + memcpy(trampoline, trampoline_code, sizeof(trampoline_code)); |
| 349 | + |
| 350 | + // Make the trampoline read-execute only |
| 351 | + if (mprotect(trampoline, 4096, PROT_READ | PROT_EXEC) != 0) { |
| 352 | + perror("mprotect"); |
| 353 | + munmap(trampoline, 4096); |
| 354 | + return NULL; |
| 355 | + } |
| 356 | + |
| 357 | + return trampoline; |
| 358 | +} |
| 359 | + |
| 360 | +static kern_return_t _insert_jmp(void* where, void* to) |
| 361 | +{ |
| 362 | + // ARM64 branch (B) instruction format: 4 bytes with a 26-bit signed offset |
| 363 | + uint32_t* patch_location = (uint32_t*)where; |
| 364 | + int64_t offset = (int64_t)to - (int64_t)where; |
| 365 | + |
| 366 | + // Check if the offset is within ARM64 branch limits (+/-128MB) |
| 367 | + /*if (offset < -33554432 || offset > 33554428) { |
| 368 | + // Target address is out of range, create a trampoline |
| 369 | + void* trampoline = create_trampoline(to); |
| 370 | + if (!trampoline) { |
| 371 | + fprintf(stderr, "Failed to create trampoline\n"); |
| 372 | + return KERN_FAILURE; |
| 373 | + } |
| 374 | +
|
| 375 | + // Update `to` to point to the trampoline |
| 376 | + to = trampoline; |
| 377 | + offset = (int64_t)to - (int64_t)where; |
| 378 | + }*/ |
| 379 | + |
| 380 | + // Calculate the signed 26-bit offset (in words) and encode in a branch instruction |
| 381 | + uint32_t branch_instruction = 0x14000000 | ((offset >> 2) & 0x03FFFFFF); |
| 382 | + |
| 383 | + kern_return_t err = _patch_memory(patch_location, sizeof(branch_instruction), (uint8_t*)&branch_instruction); |
| 384 | + if (err != KERN_SUCCESS) { |
| 385 | + fprintf(stderr, "_patch_memory failed with error 0x%x\n", err); |
| 386 | + } |
| 387 | + return err; |
| 388 | +} |
| 389 | +#else |
| 390 | + #error rd_route doesn't work on iOS |
| 391 | +#endif |
323 | 392 |
|
324 | 393 |
|
325 | 394 | static kern_return_t _patch_memory(void *address, mach_msg_type_number_t count, uint8_t *new_bytes)
|
|
0 commit comments