1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
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");
|