| ... | @@ -422,7 +422,7 @@ const Reloc = struct { | ... | @@ -422,7 +422,7 @@ const Reloc = struct { |
| 422 | /// | 422 | /// |
| 423 | /// This function does not perform length checks on `dest_overlong`; the caller guarantees | 423 | /// This function does not perform length checks on `dest_overlong`; the caller guarantees |
| 424 | /// that it will be at least long enough to support this relocation type. | 424 | /// that it will be at least long enough to support this relocation type. |
| 425 | fn validateInst(t: Type, macho: *const MachO, dest_overlong: []const u8) bool { | 425 | fn validateInst(t: Type, dest_overlong: []const u8) bool { |
| 426 | switch (t) { | 426 | switch (t) { |
| 427 | .abs8, | 427 | .abs8, |
| 428 | .abs16, | 428 | .abs16, |
| ... | @@ -432,8 +432,8 @@ const Reloc = struct { | ... | @@ -432,8 +432,8 @@ const Reloc = struct { |
| 432 | => return true, | 432 | => return true, |
| 433 | | 433 | |
| 434 | .arm64_branchrel26 => { | 434 | .arm64_branchrel26 => { |
| 435 | const inst: *align(1) const aarch64.encoding.Instruction = @ptrCast(dest_overlong[0..4]); | 435 | const inst: aarch64.encoding.Instruction = .read(dest_overlong[0..4]); |
| 436 | return switch (macho.targetLoad(inst).decode()) { | 436 | return switch (inst.decode()) { |
| 437 | .branch_exception_generating_system => |begs| switch (begs.decode()) { | 437 | .branch_exception_generating_system => |begs| switch (begs.decode()) { |
| 438 | .unconditional_branch_immediate => true, | 438 | .unconditional_branch_immediate => true, |
| 439 | else => false, | 439 | else => false, |
| ... | @@ -442,8 +442,8 @@ const Reloc = struct { | ... | @@ -442,8 +442,8 @@ const Reloc = struct { |
| 442 | }; | 442 | }; |
| 443 | }, | 443 | }, |
| 444 | .arm64_pagerel21 => { | 444 | .arm64_pagerel21 => { |
| 445 | const inst: *align(1) const aarch64.encoding.Instruction = @ptrCast(dest_overlong[0..4]); | 445 | const inst: aarch64.encoding.Instruction = .read(dest_overlong[0..4]); |
| 446 | return switch (macho.targetLoad(inst).decode()) { | 446 | return switch (inst.decode()) { |
| 447 | .data_processing_immediate => |dpi| switch (dpi.decode()) { | 447 | .data_processing_immediate => |dpi| switch (dpi.decode()) { |
| 448 | .pc_relative_addressing => |pra| switch (pra.decode()) { | 448 | .pc_relative_addressing => |pra| switch (pra.decode()) { |
| 449 | .adrp => true, | 449 | .adrp => true, |
| ... | @@ -455,8 +455,8 @@ const Reloc = struct { | ... | @@ -455,8 +455,8 @@ const Reloc = struct { |
| 455 | }; | 455 | }; |
| 456 | }, | 456 | }, |
| 457 | .arm64_pageoff12 => { | 457 | .arm64_pageoff12 => { |
| 458 | const inst: *align(1) const aarch64.encoding.Instruction = @ptrCast(dest_overlong[0..4]); | 458 | const inst: aarch64.encoding.Instruction = .read(dest_overlong[0..4]); |
| 459 | return switch (macho.targetLoad(inst).decode()) { | 459 | return switch (inst.decode()) { |
| 460 | .data_processing_immediate => |dpi| switch (dpi.decode()) { | 460 | .data_processing_immediate => |dpi| switch (dpi.decode()) { |
| 461 | .add_subtract_immediate => true, | 461 | .add_subtract_immediate => true, |
| 462 | else => false, | 462 | else => false, |
| ... | @@ -602,10 +602,9 @@ const Reloc = struct { | ... | @@ -602,10 +602,9 @@ const Reloc = struct { |
| 602 | } | 602 | } |
| 603 | const casted = std.math.cast(i26, shifted) orelse return error.RelocationOverflow; | 603 | const casted = std.math.cast(i26, shifted) orelse return error.RelocationOverflow; |
| 604 | | 604 | |
| 605 | const inst: *align(1) aarch64.encoding.Instruction = @ptrCast(dest_slice[0..4]); | 605 | var inst: aarch64.encoding.Instruction = .read(dest_slice[0..4]); |
| 606 | var x = macho.targetLoad(inst); | 606 | inst.branch_exception_generating_system.unconditional_branch_immediate.group.imm26 = casted; |
| 607 | x.branch_exception_generating_system.unconditional_branch_immediate.group.imm26 = casted; | 607 | inst.write(dest_slice[0..4]); |
| 608 | macho.targetStore(inst, x); | | |
| 609 | }, | 608 | }, |
| 610 | .arm64_pagerel21 => { | 609 | .arm64_pagerel21 => { |
| 611 | const cur_page: u53 = @intCast(dest_vaddr >> 12); | 610 | const cur_page: u53 = @intCast(dest_vaddr >> 12); |
| ... | @@ -615,25 +614,21 @@ const Reloc = struct { | ... | @@ -615,25 +614,21 @@ const Reloc = struct { |
| 615 | std.math.cast(i21, page_off) orelse return error.RelocationOverflow, | 614 | std.math.cast(i21, page_off) orelse return error.RelocationOverflow, |
| 616 | ); | 615 | ); |
| 617 | | 616 | |
| 618 | const inst: *align(1) aarch64.encoding.Instruction = @ptrCast(dest_slice[0..4]); | 617 | var inst: aarch64.encoding.Instruction = .read(dest_slice[0..4]); |
| 619 | var x = macho.targetLoad(inst); | 618 | inst.data_processing_immediate.pc_relative_addressing.adrp.immhi = split.hi; |
| 620 | x.data_processing_immediate.pc_relative_addressing.adrp.immhi = split.hi; | 619 | inst.data_processing_immediate.pc_relative_addressing.adrp.immlo = split.lo; |
| 621 | x.data_processing_immediate.pc_relative_addressing.adrp.immlo = split.lo; | 620 | inst.write(dest_slice[0..4]); |
| 622 | macho.targetStore(inst, x); | | |
| 623 | }, | 621 | }, |
| 624 | .arm64_pageoff12 => { | 622 | .arm64_pageoff12 => { |
| 625 | const page_off: u12 = @truncate(target_val); | 623 | const page_off: u12 = @truncate(target_val); |
| 626 | | 624 | |
| 627 | // This could be one of several instructions: an `ADD`, an `LDR`, or an `STR`. The | 625 | // This could be one of several instructions: an `ADD`, an `LDR`, or an `STR`. The |
| 628 | // `LDR` and `STR` instructions have scale factors which we need to compensate for | 626 | // `LDR` and `STR` instructions have scale factors which we need to compensate for, |
| 629 | // by dividing the value we store. Therefore, we need to figure out which case we're | 627 | // so we need to decode the instruction to figure out which case we're in. |
| 630 | // in by looking at the instruction encoding. | 628 | var inst: aarch64.encoding.Instruction = .read(dest_slice[0..4]); |
| 631 | const inst: *align(1) aarch64.encoding.Instruction = @ptrCast(dest_slice[0..4]); | 629 | switch (inst.decode()) { |
| 632 | switch (macho.targetLoad(inst).decode()) { | | |
| 633 | .data_processing_immediate => { | 630 | .data_processing_immediate => { |
| 634 | var x = macho.targetLoad(inst); | 631 | inst.data_processing_immediate.add_subtract_immediate.group.imm12 = page_off; |
| 635 | x.data_processing_immediate.add_subtract_immediate.group.imm12 = page_off; | | |
| 636 | macho.targetStore(inst, x); | | |
| 637 | }, | 632 | }, |
| 638 | .load_store => |ls| { | 633 | .load_store => |ls| { |
| 639 | const scale: u3 = switch (ls.register_unsigned_immediate.decode()) { | 634 | const scale: u3 = switch (ls.register_unsigned_immediate.decode()) { |
| ... | @@ -644,12 +639,11 @@ const Reloc = struct { | ... | @@ -644,12 +639,11 @@ const Reloc = struct { |
| 644 | if (shifted << scale != page_off) { | 639 | if (shifted << scale != page_off) { |
| 645 | return error.RelocationMisaligned; | 640 | return error.RelocationMisaligned; |
| 646 | } | 641 | } |
| 647 | var x = macho.targetLoad(inst); | 642 | inst.load_store.register_unsigned_immediate.group.imm12 = shifted; |
| 648 | x.load_store.register_unsigned_immediate.group.imm12 = shifted; | | |
| 649 | macho.targetStore(inst, x); | | |
| 650 | }, | 643 | }, |
| 651 | else => unreachable, | 644 | else => unreachable, |
| 652 | } | 645 | } |
| | 646 | inst.write(dest_slice[0..4]); |
| 653 | }, | 647 | }, |
| 654 | } | 648 | } |
| 655 | } | 649 | } |
| ... | @@ -3033,7 +3027,7 @@ fn loadObject( | ... | @@ -3033,7 +3027,7 @@ fn loadObject( |
| 3033 | }; | 3027 | }; |
| 3034 | | 3028 | |
| 3035 | const dest_slice = atoms.items[atom_index].index.node(macho).sliceConst(&macho.mf)[offset_in_atom..]; | 3029 | const dest_slice = atoms.items[atom_index].index.node(macho).sliceConst(&macho.mf)[offset_in_atom..]; |
| 3036 | if (!internal_type.validateInst(macho, dest_slice)) { | 3030 | if (!internal_type.validateInst(dest_slice)) { |
| 3037 | return diags.failParse(path, "relocation '{s}' against invalid instruction", .{ | 3031 | return diags.failParse(path, "relocation '{s}' against invalid instruction", .{ |
| 3038 | reloc_type_str, | 3032 | reloc_type_str, |
| 3039 | }); | 3033 | }); |
| ... | @@ -3719,57 +3713,23 @@ fn writeStubEntry(macho: *MachO, stub_index: u64, got_index: u64) void { | ... | @@ -3719,57 +3713,23 @@ fn writeStubEntry(macho: *MachO, stub_index: u64, got_index: u64) void { |
| 3719 | .aarch64 => { | 3713 | .aarch64 => { |
| 3720 | // The first instruction of the stub will be an ADRP for which we need to compute the | 3714 | // The first instruction of the stub will be an ADRP for which we need to compute the |
| 3721 | // offset from that instruction's 4k page to the GOT entry's 4k page. | 3715 | // offset from that instruction's 4k page to the GOT entry's 4k page. |
| 3722 | const Imm21 = packed union { | 3716 | const cur_page_base = (new_stub_vaddr >> 12) << 12; |
| 3723 | raw: i21, | 3717 | const target_page_base = (got_entry_vaddr >> 12) << 12; |
| 3724 | split: packed struct(u21) { lo: u2, hi: u19 }, | 3718 | const cur_page_to_target_page: i64 = @bitCast(target_page_base - cur_page_base); |
| 3725 | }; | | |
| 3726 | const page_off: Imm21 = page_off: { | | |
| 3727 | const cur_page: u53 = @intCast((new_stub_vaddr + 4) >> 12); // first instruction, so pc = stub addr + 4 | | |
| 3728 | const target_page: u53 = @intCast(got_entry_vaddr >> 12); | | |
| 3729 | const off: i53 = @bitCast(target_page -% cur_page); | | |
| 3730 | break :page_off .{ .raw = @intCast(off) }; | | |
| 3731 | }; | | |
| 3732 | | 3719 | |
| 3733 | const Inst = packed union(u32) { | 3720 | // Then we will use an LDR to reference the GOT entry on that page. |
| 3734 | raw: u32, | 3721 | const target_page_off: u12 = @truncate(got_entry_vaddr); |
| 3735 | adrp: packed struct(u32) { | 3722 | |
| 3736 | reg: u5, | 3723 | const insts: []align(4) aarch64.encoding.Instruction = @ptrCast(@alignCast( |
| 3737 | immhi: u19, | | |
| 3738 | other0: u5, | | |
| 3739 | immlo: u2, | | |
| 3740 | other1: u1, | | |
| 3741 | }, | | |
| 3742 | ldr: packed struct(u32) { | | |
| 3743 | reg_t: u5, | | |
| 3744 | reg_n: u5, | | |
| 3745 | imm12: u12, | | |
| 3746 | other0: u10, | | |
| 3747 | }, | | |
| 3748 | }; | | |
| 3749 | const insts: []align(4) Inst = @ptrCast(@alignCast( | | |
| 3750 | macho.known_sections.stubs.node(macho).slice(&macho.mf)[@intCast(stub_offset)..][0..entry_size], | 3724 | macho.known_sections.stubs.node(macho).slice(&macho.mf)[@intCast(stub_offset)..][0..entry_size], |
| 3751 | )); | 3725 | )); |
| 3752 | @memcpy(insts, @as([]const Inst, &.{ | 3726 | @memcpy(insts, @as([]const aarch64.encoding.Instruction, &.{ |
| 3753 | // adrp x16, got_entry@page | 3727 | .adrp(.x16, @intCast(cur_page_to_target_page)), |
| 3754 | .{ .adrp = .{ | 3728 | .ldr(.x16, .{ .unsigned_offset = .{ .base = .x16, .offset = target_page_off } }), |
| 3755 | .reg = 0b10000, | 3729 | .br(.x16), |
| 3756 | .immhi = page_off.split.hi, | | |
| 3757 | .other0 = 0b100_00, | | |
| 3758 | .immlo = page_off.split.lo, | | |
| 3759 | .other1 = 0b1, | | |
| 3760 | } }, | | |
| 3761 | // ldr x16, [x16, got_entry@pageoff] | | |
| 3762 | .{ .ldr = .{ | | |
| 3763 | .reg_t = 0b10000, | | |
| 3764 | .reg_n = 0b10000, | | |
| 3765 | .imm12 = @divExact(@as(u12, @truncate(got_entry_vaddr)), 8), | | |
| 3766 | .other0 = 0b11_111_0_01_01, | | |
| 3767 | } }, | | |
| 3768 | // br x16 | | |
| 3769 | .{ .raw = 0xd61f0200 }, | | |
| 3770 | })); | 3730 | })); |
| 3771 | if (macho.targetEndian() != std.lang.Endian.native) { | 3731 | if (.little != std.lang.Endian.native) { // aarch64 instructions are little-endian |
| 3772 | std.mem.byteSwapAllElements(Inst, insts); | 3732 | std.mem.byteSwapAllElements(aarch64.encoding.Instruction, insts); |
| 3773 | } | 3733 | } |
| 3774 | }, | 3734 | }, |
| 3775 | .x86_64 => { | 3735 | .x86_64 => { |