| ... | ... | @@ -1597,7 +1597,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1597 | 1597 | }; |
| 1598 | 1598 | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { |
| 1599 | 1599 | .x86_64 => 6, |
| 1600 | | .aarch64 => 2 * @sizeOf(u32), |
| 1600 | .aarch64 => 3 * @sizeOf(u32), |
| 1601 | 1601 | else => unreachable, // unhandled architecture type |
| 1602 | 1602 | }; |
| 1603 | 1603 | const flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| ... | ... | @@ -2525,9 +2525,12 @@ fn writeStub(self: *MachO, index: u32) !void { |
| 2525 | 2525 | const stub_off = stubs.offset + index * stubs.reserved2; |
| 2526 | 2526 | const stub_addr = stubs.addr + index * stubs.reserved2; |
| 2527 | 2527 | const la_ptr_addr = la_symbol_ptr.addr + index * @sizeOf(u64); |
| 2528 | |
| 2528 | 2529 | log.debug("writing stub at 0x{x}", .{stub_off}); |
| 2530 | |
| 2529 | 2531 | var code = try self.base.allocator.alloc(u8, stubs.reserved2); |
| 2530 | 2532 | defer self.base.allocator.free(code); |
| 2533 | |
| 2531 | 2534 | switch (self.base.options.target.cpu.arch) { |
| 2532 | 2535 | .x86_64 => { |
| 2533 | 2536 | assert(la_ptr_addr >= stub_addr + stubs.reserved2); |
| ... | ... | @@ -2539,12 +2542,50 @@ fn writeStub(self: *MachO, index: u32) !void { |
| 2539 | 2542 | }, |
| 2540 | 2543 | .aarch64 => { |
| 2541 | 2544 | assert(la_ptr_addr >= stub_addr); |
| 2542 | | const displacement = try math.divExact(u64, la_ptr_addr - stub_addr, 4); |
| 2543 | | const literal = try math.cast(u19, displacement); |
| 2544 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ |
| 2545 | | .literal = literal, |
| 2546 | | }).toU32()); |
| 2547 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.br(.x16).toU32()); |
| 2545 | outer: { |
| 2546 | const this_addr = stub_addr; |
| 2547 | const target_addr = la_ptr_addr; |
| 2548 | inner: { |
| 2549 | const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :inner; |
| 2550 | const literal = math.cast(u18, displacement) catch |_| break :inner; |
| 2551 | // ldr x16, literal |
| 2552 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{ |
| 2553 | .literal = literal, |
| 2554 | }).toU32()); |
| 2555 | // nop |
| 2556 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| 2557 | break :outer; |
| 2558 | } |
| 2559 | inner: { |
| 2560 | const new_this_addr = this_addr + @sizeOf(u32); |
| 2561 | const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :inner; |
| 2562 | const literal = math.cast(u18, displacement) catch |_| break :inner; |
| 2563 | // nop |
| 2564 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| 2565 | // ldr x16, literal |
| 2566 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{ |
| 2567 | .literal = literal, |
| 2568 | }).toU32()); |
| 2569 | break :outer; |
| 2570 | } |
| 2571 | // Use adrp followed by ldr(register). |
| 2572 | const this_page = @intCast(i32, this_addr >> 12); |
| 2573 | const target_page = @intCast(i32, target_addr >> 12); |
| 2574 | const pages = @intCast(i21, target_page - this_page); |
| 2575 | // adrp x16, pages |
| 2576 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x16, pages).toU32()); |
| 2577 | const narrowed = @truncate(u12, target_addr); |
| 2578 | const offset = try math.divExact(u12, narrowed, 8); |
| 2579 | // ldr x16, x16, offset |
| 2580 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{ |
| 2581 | .register = .{ |
| 2582 | .rn = .x16, |
| 2583 | .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), |
| 2584 | }, |
| 2585 | }).toU32()); |
| 2586 | } |
| 2587 | // br x16 |
| 2588 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32()); |
| 2548 | 2589 | }, |
| 2549 | 2590 | else => unreachable, |
| 2550 | 2591 | } |