authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-09 19:52:44+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-18 09:13:08+02:00
logb96339f6f6ed368d04639c1d6c67eb85c5eb3c7b
tree980fb6e348635ea69e32cebb921788432bf013cf
parent58997363d3c94aaa66960f0e87b40d5f98f0471b

macho: migrate Relocation struct


2 files changed, 60 insertions(+), 40 deletions(-)

src/link/MachO/Relocation.zig+23-11
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1tag: enum { @"extern", local },1tag: Tag,
2offset: u32,2offset: u32,
3target: u32,3target: u32,
4addend: i64,4addend: i64,
...@@ -10,34 +10,44 @@ meta: packed struct {...@@ -10,34 +10,44 @@ meta: packed struct {
10 symbolnum: u24,10 symbolnum: u24,
11},11},
1212
13pub fn getTargetSymbol(rel: Relocation, macho_file: *MachO) *Symbol {13pub fn getTargetSymbolRef(rel: Relocation, atom: Atom, macho_file: *MachO) MachO.Ref {
14 assert(rel.tag == .@"extern");14 assert(rel.tag == .@"extern");
15 return macho_file.getSymbol(rel.target);15 return atom.getFile(macho_file).getSymbolRef(rel.target, macho_file);
16}16}
1717
18pub fn getTargetAtom(rel: Relocation, macho_file: *MachO) *Atom {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 {
19 assert(rel.tag == .local);25 assert(rel.tag == .local);
20 return macho_file.getAtom(rel.target).?;26 return atom.getFile(macho_file).getAtom(rel.target).?;
21}27}
2228
23pub fn getTargetAddress(rel: Relocation, macho_file: *MachO) u64 {29pub fn getTargetAddress(rel: Relocation, atom: Atom, macho_file: *MachO) u64 {
24 return switch (rel.tag) {30 return switch (rel.tag) {
25 .local => rel.getTargetAtom(macho_file).getAddress(macho_file),31 .local => rel.getTargetAtom(atom, macho_file).getAddress(macho_file),
26 .@"extern" => rel.getTargetSymbol(macho_file).getAddress(.{}, macho_file),32 .@"extern" => rel.getTargetSymbol(atom, macho_file).getAddress(.{}, macho_file),
27 };33 };
28}34}
2935
30pub fn getGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 {36pub fn getGotTargetAddress(rel: Relocation, atom: Atom, macho_file: *MachO) u64 {
31 return switch (rel.tag) {37 return switch (rel.tag) {
32 .local => 0,38 .local => 0,
33 .@"extern" => rel.getTargetSymbol(macho_file).getGotAddress(macho_file),39 .@"extern" => rel.getTargetSymbol(atom, macho_file).getGotAddress(macho_file),
34 };40 };
35}41}
3642
37pub fn getZigGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 {43pub fn getZigGotTargetAddress(rel: Relocation, macho_file: *MachO) u64 {
44 const zo = macho_file.getZigObject().?;
38 return switch (rel.tag) {45 return switch (rel.tag) {
39 .local => 0,46 .local => 0,
40 .@"extern" => rel.getTargetSymbol(macho_file).getZigGotAddress(macho_file),47 .@"extern" => {
48 const ref = zo.getSymbolRef(rel.target, macho_file);
49 return ref.getSymbol(macho_file).?.getZigGotAddress(macho_file);
50 },
41 };51 };
42}52}
4353
...@@ -155,6 +165,8 @@ pub const Type = enum {...@@ -155,6 +165,8 @@ pub const Type = enum {
155 unsigned,165 unsigned,
156};166};
157167
168const Tag = enum { local, @"extern" };
169
158const assert = std.debug.assert;170const assert = std.debug.assert;
159const macho = std.macho;171const macho = std.macho;
160const math = std.math;172const math = std.math;
src/link/MachO/thunks.zig+37-29
...@@ -5,55 +5,45 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void {...@@ -5,55 +5,45 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void {
5 const gpa = macho_file.base.comp.gpa;5 const gpa = macho_file.base.comp.gpa;
6 const slice = macho_file.sections.slice();6 const slice = macho_file.sections.slice();
7 const header = &slice.items(.header)[sect_id];7 const header = &slice.items(.header)[sect_id];
8 const thnks = &slice.items(.thunks)[sect_id];
8 const atoms = slice.items(.atoms)[sect_id].items;9 const atoms = slice.items(.atoms)[sect_id].items;
9 assert(atoms.len > 0);10 assert(atoms.len > 0);
1011
11 for (atoms) |atom_index| {12 for (atoms) |ref| {
12 macho_file.getAtom(atom_index).?.value = @bitCast(@as(i64, -1));13 ref.getAtom(macho_file).?.value = @bitCast(@as(i64, -1));
13 }14 }
1415
15 var i: usize = 0;16 var i: usize = 0;
16 while (i < atoms.len) {17 while (i < atoms.len) {
17 const start = i;18 const start = i;
18 const start_atom = macho_file.getAtom(atoms[start]).?;19 const start_atom = atoms[start].getAtom(macho_file).?;
19 assert(start_atom.flags.alive);20 assert(start_atom.flags.alive);
20 start_atom.value = try advance(header, start_atom.size, start_atom.alignment);21 start_atom.value = advance(header, start_atom.size, start_atom.alignment);
21 i += 1;22 i += 1;
2223
23 while (i < atoms.len and24 while (i < atoms.len and
24 header.size - start_atom.value < max_allowed_distance) : (i += 1)25 header.size - start_atom.value < max_allowed_distance) : (i += 1)
25 {26 {
26 const atom_index = atoms[i];27 const atom = atoms[i].getAtom(macho_file).?;
27 const atom = macho_file.getAtom(atom_index).?;
28 assert(atom.flags.alive);28 assert(atom.flags.alive);
29 atom.value = try advance(header, atom.size, atom.alignment);29 atom.value = advance(header, atom.size, atom.alignment);
30 }30 }
3131
32 // Insert a thunk at the group end32 // Insert a thunk at the group end
33 const thunk_index = try macho_file.addThunk();33 const thunk_index = try macho_file.addThunk();
34 const thunk = macho_file.getThunk(thunk_index);34 const thunk = macho_file.getThunk(thunk_index);
35 thunk.out_n_sect = sect_id;35 thunk.out_n_sect = sect_id;
36 try thnks.append(gpa, thunk_index);
3637
37 // Scan relocs in the group and create trampolines for any unreachable callsite38 // Scan relocs in the group and create trampolines for any unreachable callsite
38 for (atoms[start..i]) |atom_index| {39 try scanRelocs(thunk_index, gpa, atoms[start..i], macho_file);
39 const atom = macho_file.getAtom(atom_index).?;
40 log.debug("atom({d}) {s}", .{ atom_index, atom.getName(macho_file) });
41 for (atom.getRelocs(macho_file)) |rel| {
42 if (rel.type != .branch) continue;
43 if (isReachable(atom, rel, macho_file)) continue;
44 try thunk.symbols.put(gpa, rel.target, {});
45 }
46 try atom.addExtra(.{ .thunk = thunk_index }, macho_file);
47 atom.flags.thunk = true;
48 }
49
50 thunk.value = try advance(header, thunk.size(), .@"4");40 thunk.value = try advance(header, thunk.size(), .@"4");
5141
52 log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) });42 log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) });
53 }43 }
54}44}
5545
56fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 {46fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) u64 {
57 const offset = alignment.forward(sect.size);47 const offset = alignment.forward(sect.size);
58 const padding = offset - sect.size;48 const padding = offset - sect.size;
59 sect.size += padding + size;49 sect.size += padding + size;
...@@ -61,14 +51,32 @@ fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 {...@@ -61,14 +51,32 @@ fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) !u64 {
61 return offset;51 return offset;
62}52}
6353
54fn scanRelocs(thunk_index: Thunk.Index, gpa: Allocator, atoms: []const MachO.Ref, macho_file: *MachO) !void {
55 const tracy = trace(@src());
56 defer tracy.end();
57
58 const thunk = macho_file.getThunk(thunk_index);
59
60 for (atoms) |ref| {
61 const atom = ref.getAtom(macho_file).?;
62 log.debug("atom({d}) {s}", .{ atom.atom_index, atom.getName(macho_file) });
63 for (atom.getRelocs(macho_file)) |rel| {
64 if (rel.type != .branch) continue;
65 if (isReachable(atom, rel, macho_file)) continue;
66 try thunk.symbols.put(gpa, rel.getTargetSymbolRef(atom.*, macho_file), {});
67 }
68 atom.addExtra(.{ .thunk = thunk_index }, macho_file);
69 }
70}
71
64fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {72fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
65 const target = rel.getTargetSymbol(macho_file);73 const target = rel.getTargetSymbol(atom.*, macho_file);
66 if (target.flags.stubs or target.flags.objc_stubs) return false;74 if (target.flags.stubs or target.flags.objc_stubs) return false;
67 if (atom.out_n_sect != target.out_n_sect) return false;75 if (atom.out_n_sect != target.getOutputSectionIndex(macho_file)) return false;
68 const target_atom = target.getAtom(macho_file).?;76 const target_atom = target.getAtom(macho_file).?;
69 if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false;77 if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false;
70 const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off));78 const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off));
71 const taddr: i64 = @intCast(rel.getTargetAddress(macho_file));79 const taddr: i64 = @intCast(rel.getTargetAddress(atom.*, macho_file));
72 _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false;80 _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false;
73 return true;81 return true;
74}82}
...@@ -76,7 +84,7 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {...@@ -76,7 +84,7 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
76pub const Thunk = struct {84pub const Thunk = struct {
77 value: u64 = 0,85 value: u64 = 0,
78 out_n_sect: u8 = 0,86 out_n_sect: u8 = 0,
79 symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},87 symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{},
8088
81 pub fn deinit(thunk: *Thunk, allocator: Allocator) void {89 pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
82 thunk.symbols.deinit(allocator);90 thunk.symbols.deinit(allocator);
...@@ -96,8 +104,8 @@ pub const Thunk = struct {...@@ -96,8 +104,8 @@ pub const Thunk = struct {
96 }104 }
97105
98 pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {106 pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
99 for (thunk.symbols.keys(), 0..) |sym_index, i| {107 for (thunk.symbols.keys(), 0..) |ref, i| {
100 const sym = macho_file.getSymbol(sym_index);108 const sym = ref.getSymbol(macho_file).?;
101 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;109 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
102 const taddr = sym.getAddress(.{}, macho_file);110 const taddr = sym.getAddress(.{}, macho_file);
103 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));111 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
...@@ -144,9 +152,9 @@ pub const Thunk = struct {...@@ -144,9 +152,9 @@ pub const Thunk = struct {
144 const thunk = ctx.thunk;152 const thunk = ctx.thunk;
145 const macho_file = ctx.macho_file;153 const macho_file = ctx.macho_file;
146 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });154 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
147 for (thunk.symbols.keys()) |index| {155 for (thunk.symbols.keys()) |ref| {
148 const sym = macho_file.getSymbol(index);156 const sym = ref.getSymbol(macho_file).?;
149 try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.getName(macho_file), sym.value });157 try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
150 }158 }
151 }159 }
152160