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");