tag: Tag, offset: u32, target: u32, addend: i64, type: Type, meta: packed struct { pcrel: bool, has_subtractor: bool, length: u2, symbolnum: u24, }, pub fn getTargetSymbolRef(rel: Relocation, atom: Atom, macho_file: *MachO) MachO.Ref { assert(rel.tag == .@"extern"); return atom.getFile(macho_file).getSymbolRef(rel.target, macho_file); } pub fn getTargetSymbol(rel: Relocation, atom: Atom, macho_file: *MachO) *Symbol { assert(rel.tag == .@"extern"); const ref = atom.getFile(macho_file).getSymbolRef(rel.target, macho_file); return ref.getSymbol(macho_file).?; } pub fn getTargetAtom(rel: Relocation, atom: Atom, macho_file: *MachO) *Atom { assert(rel.tag == .local); return atom.getFile(macho_file).getAtom(rel.target).?; } pub fn getTargetAddress(rel: Relocation, atom: Atom, macho_file: *MachO) u64 { return switch (rel.tag) { .local => rel.getTargetAtom(atom, macho_file).getAddress(macho_file), .@"extern" => rel.getTargetSymbol(atom, macho_file).getAddress(.{}, macho_file), }; } pub fn getGotTargetAddress(rel: Relocation, atom: Atom, macho_file: *MachO) u64 { return switch (rel.tag) { .local => 0, .@"extern" => rel.getTargetSymbol(atom, macho_file).getGotAddress(macho_file), }; } pub fn getZigGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 { const zo = macho_file.getZigObject() orelse return 0; return switch (rel.tag) { .local => 0, .@"extern" => { const ref = zo.getSymbolRef(rel.target, macho_file); return ref.getSymbol(macho_file).?.getZigGotAddress(macho_file); }, }; } pub fn getRelocAddend(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) i64 { const addend: i64 = switch (rel.type) { .signed => 0, .signed1 => -1, .signed2 => -2, .signed4 => -4, else => 0, }; return switch (cpu_arch) { .x86_64 => if (rel.meta.pcrel) addend - 4 else addend, else => addend, }; } pub fn lessThan(ctx: void, lhs: Relocation, rhs: Relocation) bool { _ = ctx; return lhs.offset < rhs.offset; } pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Alt(Format, Format.pretty) { return .{ .data = .{ .relocation = rel, .arch = cpu_arch } }; } const Format = struct { relocation: Relocation, arch: std.Target.Cpu.Arch, fn pretty(f: Format, w: *Writer) Writer.Error!void { try w.writeAll(switch (f.relocation.type) { .signed => "X86_64_RELOC_SIGNED", .signed1 => "X86_64_RELOC_SIGNED_1", .signed2 => "X86_64_RELOC_SIGNED_2", .signed4 => "X86_64_RELOC_SIGNED_4", .got_load => "X86_64_RELOC_GOT_LOAD", .tlv => "X86_64_RELOC_TLV", .page => "ARM64_RELOC_PAGE21", .pageoff => "ARM64_RELOC_PAGEOFF12", .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21", .got_load_pageoff => "ARM64_RELOC_GOT_LOAD_PAGEOFF12", .tlvp_page => "ARM64_RELOC_TLVP_LOAD_PAGE21", .tlvp_pageoff => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12", .branch => switch (f.arch) { .x86_64 => "X86_64_RELOC_BRANCH", .aarch64 => "ARM64_RELOC_BRANCH26", else => unreachable, }, .got => switch (f.arch) { .x86_64 => "X86_64_RELOC_GOT", .aarch64 => "ARM64_RELOC_POINTER_TO_GOT", else => unreachable, }, .subtractor => switch (f.arch) { .x86_64 => "X86_64_RELOC_SUBTRACTOR", .aarch64 => "ARM64_RELOC_SUBTRACTOR", else => unreachable, }, .unsigned => switch (f.arch) { .x86_64 => "X86_64_RELOC_UNSIGNED", .aarch64 => "ARM64_RELOC_UNSIGNED", else => unreachable, }, }); } }; pub const Type = enum { // x86_64 /// RIP-relative displacement (X86_64_RELOC_SIGNED) signed, /// RIP-relative displacement (X86_64_RELOC_SIGNED_1) signed1, /// RIP-relative displacement (X86_64_RELOC_SIGNED_2) signed2, /// RIP-relative displacement (X86_64_RELOC_SIGNED_4) signed4, /// RIP-relative GOT load (X86_64_RELOC_GOT_LOAD) got_load, /// RIP-relative TLV load (X86_64_RELOC_TLV) tlv, // arm64 /// PC-relative load (distance to page, ARM64_RELOC_PAGE21) page, /// Non-PC-relative offset to symbol (ARM64_RELOC_PAGEOFF12) pageoff, /// PC-relative GOT load (distance to page, ARM64_RELOC_GOT_LOAD_PAGE21) got_load_page, /// Non-PC-relative offset to GOT slot (ARM64_RELOC_GOT_LOAD_PAGEOFF12) got_load_pageoff, /// PC-relative TLV load (distance to page, ARM64_RELOC_TLVP_LOAD_PAGE21) tlvp_page, /// Non-PC-relative offset to TLV slot (ARM64_RELOC_TLVP_LOAD_PAGEOFF12) tlvp_pageoff, // common /// PC-relative call/bl/b (X86_64_RELOC_BRANCH or ARM64_RELOC_BRANCH26) branch, /// PC-relative displacement to GOT pointer (X86_64_RELOC_GOT or ARM64_RELOC_POINTER_TO_GOT) got, /// Absolute subtractor value (X86_64_RELOC_SUBTRACTOR or ARM64_RELOC_SUBTRACTOR) subtractor, /// Absolute relocation (X86_64_RELOC_UNSIGNED or ARM64_RELOC_UNSIGNED) unsigned, }; const Tag = enum { local, @"extern" }; const std = @import("std"); const assert = std.debug.assert; const macho = std.macho; const math = std.math; const Writer = std.Io.Writer; const Atom = @import("Atom.zig"); const MachO = @import("../MachO.zig"); const Relocation = @This(); const Symbol = @import("Symbol.zig");