master
  1tag: Tag,
  2offset: u32,
  3target: u32,
  4addend: i64,
  5type: Type,
  6meta: packed struct {
  7    pcrel: bool,
  8    has_subtractor: bool,
  9    length: u2,
 10    symbolnum: u24,
 11},
 12
 13pub fn getTargetSymbolRef(rel: Relocation, atom: Atom, macho_file: *MachO) MachO.Ref {
 14    assert(rel.tag == .@"extern");
 15    return atom.getFile(macho_file).getSymbolRef(rel.target, macho_file);
 16}
 17
 18pub fn getTargetSymbol(rel: Relocation, atom: Atom, macho_file: *MachO) *Symbol {
 19    assert(rel.tag == .@"extern");
 20    const ref = atom.getFile(macho_file).getSymbolRef(rel.target, macho_file);
 21    return ref.getSymbol(macho_file).?;
 22}
 23
 24pub fn getTargetAtom(rel: Relocation, atom: Atom, macho_file: *MachO) *Atom {
 25    assert(rel.tag == .local);
 26    return atom.getFile(macho_file).getAtom(rel.target).?;
 27}
 28
 29pub fn getTargetAddress(rel: Relocation, atom: Atom, macho_file: *MachO) u64 {
 30    return switch (rel.tag) {
 31        .local => rel.getTargetAtom(atom, macho_file).getAddress(macho_file),
 32        .@"extern" => rel.getTargetSymbol(atom, macho_file).getAddress(.{}, macho_file),
 33    };
 34}
 35
 36pub fn getGotTargetAddress(rel: Relocation, atom: Atom, macho_file: *MachO) u64 {
 37    return switch (rel.tag) {
 38        .local => 0,
 39        .@"extern" => rel.getTargetSymbol(atom, macho_file).getGotAddress(macho_file),
 40    };
 41}
 42
 43pub fn getZigGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 {
 44    const zo = macho_file.getZigObject() orelse return 0;
 45    return switch (rel.tag) {
 46        .local => 0,
 47        .@"extern" => {
 48            const ref = zo.getSymbolRef(rel.target, macho_file);
 49            return ref.getSymbol(macho_file).?.getZigGotAddress(macho_file);
 50        },
 51    };
 52}
 53
 54pub fn getRelocAddend(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) i64 {
 55    const addend: i64 = switch (rel.type) {
 56        .signed => 0,
 57        .signed1 => -1,
 58        .signed2 => -2,
 59        .signed4 => -4,
 60        else => 0,
 61    };
 62    return switch (cpu_arch) {
 63        .x86_64 => if (rel.meta.pcrel) addend - 4 else addend,
 64        else => addend,
 65    };
 66}
 67
 68pub fn lessThan(ctx: void, lhs: Relocation, rhs: Relocation) bool {
 69    _ = ctx;
 70    return lhs.offset < rhs.offset;
 71}
 72
 73pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Alt(Format, Format.pretty) {
 74    return .{ .data = .{ .relocation = rel, .arch = cpu_arch } };
 75}
 76
 77const Format = struct {
 78    relocation: Relocation,
 79    arch: std.Target.Cpu.Arch,
 80
 81    fn pretty(f: Format, w: *Writer) Writer.Error!void {
 82        try w.writeAll(switch (f.relocation.type) {
 83            .signed => "X86_64_RELOC_SIGNED",
 84            .signed1 => "X86_64_RELOC_SIGNED_1",
 85            .signed2 => "X86_64_RELOC_SIGNED_2",
 86            .signed4 => "X86_64_RELOC_SIGNED_4",
 87            .got_load => "X86_64_RELOC_GOT_LOAD",
 88            .tlv => "X86_64_RELOC_TLV",
 89            .page => "ARM64_RELOC_PAGE21",
 90            .pageoff => "ARM64_RELOC_PAGEOFF12",
 91            .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21",
 92            .got_load_pageoff => "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
 93            .tlvp_page => "ARM64_RELOC_TLVP_LOAD_PAGE21",
 94            .tlvp_pageoff => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
 95            .branch => switch (f.arch) {
 96                .x86_64 => "X86_64_RELOC_BRANCH",
 97                .aarch64 => "ARM64_RELOC_BRANCH26",
 98                else => unreachable,
 99            },
100            .got => switch (f.arch) {
101                .x86_64 => "X86_64_RELOC_GOT",
102                .aarch64 => "ARM64_RELOC_POINTER_TO_GOT",
103                else => unreachable,
104            },
105            .subtractor => switch (f.arch) {
106                .x86_64 => "X86_64_RELOC_SUBTRACTOR",
107                .aarch64 => "ARM64_RELOC_SUBTRACTOR",
108                else => unreachable,
109            },
110            .unsigned => switch (f.arch) {
111                .x86_64 => "X86_64_RELOC_UNSIGNED",
112                .aarch64 => "ARM64_RELOC_UNSIGNED",
113                else => unreachable,
114            },
115        });
116    }
117};
118
119pub const Type = enum {
120    // x86_64
121    /// RIP-relative displacement (X86_64_RELOC_SIGNED)
122    signed,
123    /// RIP-relative displacement (X86_64_RELOC_SIGNED_1)
124    signed1,
125    /// RIP-relative displacement (X86_64_RELOC_SIGNED_2)
126    signed2,
127    /// RIP-relative displacement (X86_64_RELOC_SIGNED_4)
128    signed4,
129    /// RIP-relative GOT load (X86_64_RELOC_GOT_LOAD)
130    got_load,
131    /// RIP-relative TLV load (X86_64_RELOC_TLV)
132    tlv,
133
134    // arm64
135    /// PC-relative load (distance to page, ARM64_RELOC_PAGE21)
136    page,
137    /// Non-PC-relative offset to symbol (ARM64_RELOC_PAGEOFF12)
138    pageoff,
139    /// PC-relative GOT load (distance to page, ARM64_RELOC_GOT_LOAD_PAGE21)
140    got_load_page,
141    /// Non-PC-relative offset to GOT slot (ARM64_RELOC_GOT_LOAD_PAGEOFF12)
142    got_load_pageoff,
143    /// PC-relative TLV load (distance to page, ARM64_RELOC_TLVP_LOAD_PAGE21)
144    tlvp_page,
145    /// Non-PC-relative offset to TLV slot (ARM64_RELOC_TLVP_LOAD_PAGEOFF12)
146    tlvp_pageoff,
147
148    // common
149    /// PC-relative call/bl/b (X86_64_RELOC_BRANCH or ARM64_RELOC_BRANCH26)
150    branch,
151    /// PC-relative displacement to GOT pointer (X86_64_RELOC_GOT or ARM64_RELOC_POINTER_TO_GOT)
152    got,
153    /// Absolute subtractor value (X86_64_RELOC_SUBTRACTOR or ARM64_RELOC_SUBTRACTOR)
154    subtractor,
155    /// Absolute relocation (X86_64_RELOC_UNSIGNED or ARM64_RELOC_UNSIGNED)
156    unsigned,
157};
158
159const Tag = enum { local, @"extern" };
160
161const std = @import("std");
162const assert = std.debug.assert;
163const macho = std.macho;
164const math = std.math;
165const Writer = std.Io.Writer;
166
167const Atom = @import("Atom.zig");
168const MachO = @import("../MachO.zig");
169const Relocation = @This();
170const Symbol = @import("Symbol.zig");