authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-19 20:28:05+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:41+01:00
loga112241f6454b3dd5b93703337339d38c2707be7
tree33f82f99d268e4066a7d51638a17ceaaaa5603ad
parent7647db327328bffea7dc8d7286cb6be9265080be

macho: re-read atom code from ZigObject when resolving relocs


4 files changed, 90 insertions(+), 16 deletions(-)

src/link/MachO.zig+71-2
...@@ -596,6 +596,47 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node...@@ -596,6 +596,47 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
596 state_log.debug("{}", .{self.dumpState()});596 state_log.debug("{}", .{self.dumpState()});
597597
598 try self.initDyldInfoSections();598 try self.initDyldInfoSections();
599
600 // Beyond this point, everything has been allocated a virtual address and we can resolve
601 // the relocations, and commit objects to file.
602 if (self.getZigObject()) |zo| {
603 var has_resolve_error = false;
604
605 for (zo.atoms.items) |atom_index| {
606 const atom = self.getAtom(atom_index) orelse continue;
607 if (!atom.flags.alive) continue;
608 const sect = &self.sections.items(.header)[atom.out_n_sect];
609 if (sect.isZerofill()) continue;
610 const code = zo.getAtomDataAlloc(self, atom.*) catch |err| switch (err) {
611 error.InputOutput => {
612 try self.reportUnexpectedError("fetching code for '{s}' failed", .{
613 atom.getName(self),
614 });
615 return error.FlushFailure;
616 },
617 else => |e| {
618 try self.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{
619 atom.getName(self),
620 @errorName(e),
621 });
622 return error.FlushFailure;
623 },
624 };
625 defer gpa.free(code);
626 const file_offset = sect.offset + atom.value - sect.addr;
627 atom.resolveRelocs(self, code) catch |err| switch (err) {
628 error.ResolveFailed => has_resolve_error = true,
629 else => |e| {
630 try self.reportUnexpectedError("unexpected error while resolving relocations", .{});
631 return e;
632 },
633 };
634 try self.base.file.?.pwriteAll(code, file_offset);
635 }
636
637 if (has_resolve_error) return error.FlushFailure;
638 }
639
599 self.writeAtoms() catch |err| switch (err) {640 self.writeAtoms() catch |err| switch (err) {
600 error.ResolveFailed => return error.FlushFailure,641 error.ResolveFailed => return error.FlushFailure,
601 else => |e| {642 else => |e| {
...@@ -1955,6 +1996,28 @@ pub fn sortSections(self: *MachO) !void {...@@ -1955,6 +1996,28 @@ pub fn sortSections(self: *MachO) !void {
1955 self.sections.appendAssumeCapacity(slice.get(sorted.index));1996 self.sections.appendAssumeCapacity(slice.get(sorted.index));
1956 }1997 }
19571998
1999 if (self.getZigObject()) |zo| {
2000 for (zo.atoms.items) |atom_index| {
2001 const atom = self.getAtom(atom_index) orelse continue;
2002 if (!atom.flags.alive) continue;
2003 atom.out_n_sect = backlinks[atom.out_n_sect];
2004 }
2005
2006 for (zo.symtab.items(.nlist)) |*sym| {
2007 if (sym.sect()) {
2008 sym.n_sect = backlinks[sym.n_sect];
2009 }
2010 }
2011
2012 for (zo.symbols.items) |sym_index| {
2013 const sym = self.getSymbol(sym_index);
2014 const atom = sym.getAtom(self) orelse continue;
2015 if (!atom.flags.alive) continue;
2016 if (sym.getFile(self).?.getIndex() != zo.index) continue;
2017 sym.out_n_sect = backlinks[sym.out_n_sect];
2018 }
2019 }
2020
1958 for (self.objects.items) |index| {2021 for (self.objects.items) |index| {
1959 for (self.getFile(index).?.object.atoms.items) |atom_index| {2022 for (self.getFile(index).?.object.atoms.items) |atom_index| {
1960 const atom = self.getAtom(atom_index) orelse continue;2023 const atom = self.getAtom(atom_index) orelse continue;
...@@ -1962,6 +2025,7 @@ pub fn sortSections(self: *MachO) !void {...@@ -1962,6 +2025,7 @@ pub fn sortSections(self: *MachO) !void {
1962 atom.out_n_sect = backlinks[atom.out_n_sect];2025 atom.out_n_sect = backlinks[atom.out_n_sect];
1963 }2026 }
1964 }2027 }
2028
1965 if (self.getInternalObject()) |object| {2029 if (self.getInternalObject()) |object| {
1966 for (object.atoms.items) |atom_index| {2030 for (object.atoms.items) |atom_index| {
1967 const atom = self.getAtom(atom_index) orelse continue;2031 const atom = self.getAtom(atom_index) orelse continue;
...@@ -2517,6 +2581,7 @@ fn writeAtoms(self: *MachO) !void {...@@ -2517,6 +2581,7 @@ fn writeAtoms(self: *MachO) !void {
2517 const atom = self.getAtom(atom_index).?;2581 const atom = self.getAtom(atom_index).?;
2518 assert(atom.flags.alive);2582 assert(atom.flags.alive);
2519 const off = atom.value - header.addr;2583 const off = atom.value - header.addr;
2584 @memcpy(buffer[off..][0..atom.size], atom.getFile(self).object.getAtomData(atom.*));
2520 atom.resolveRelocs(self, buffer[off..][0..atom.size]) catch |err| switch (err) {2585 atom.resolveRelocs(self, buffer[off..][0..atom.size]) catch |err| switch (err) {
2521 error.ResolveFailed => has_resolve_error = true,2586 error.ResolveFailed => has_resolve_error = true,
2522 else => |e| return e,2587 else => |e| return e,
...@@ -2757,7 +2822,8 @@ pub fn calcSymtabSize(self: *MachO) !void {...@@ -2757,7 +2822,8 @@ pub fn calcSymtabSize(self: *MachO) !void {
27572822
2758 var files = std.ArrayList(File.Index).init(gpa);2823 var files = std.ArrayList(File.Index).init(gpa);
2759 defer files.deinit();2824 defer files.deinit();
2760 try files.ensureTotalCapacityPrecise(self.objects.items.len + self.dylibs.items.len + 1);2825 try files.ensureTotalCapacityPrecise(self.objects.items.len + self.dylibs.items.len + 2);
2826 if (self.zig_object) |index| files.appendAssumeCapacity(index);
2761 for (self.objects.items) |index| files.appendAssumeCapacity(index);2827 for (self.objects.items) |index| files.appendAssumeCapacity(index);
2762 for (self.dylibs.items) |index| files.appendAssumeCapacity(index);2828 for (self.dylibs.items) |index| files.appendAssumeCapacity(index);
2763 if (self.internal_object) |index| files.appendAssumeCapacity(index);2829 if (self.internal_object) |index| files.appendAssumeCapacity(index);
...@@ -2816,6 +2882,9 @@ pub fn writeSymtab(self: *MachO, off: u32) !u32 {...@@ -2816,6 +2882,9 @@ pub fn writeSymtab(self: *MachO, off: u32) !u32 {
2816 try self.symtab.resize(gpa, cmd.nsyms);2882 try self.symtab.resize(gpa, cmd.nsyms);
2817 try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1);2883 try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1);
28182884
2885 if (self.getZigObject()) |zo| {
2886 zo.writeSymtab(self);
2887 }
2819 for (self.objects.items) |index| {2888 for (self.objects.items) |index| {
2820 self.getFile(index).?.writeSymtab(self);2889 self.getFile(index).?.writeSymtab(self);
2821 }2890 }
...@@ -3752,7 +3821,7 @@ fn reportDependencyError(...@@ -3752,7 +3821,7 @@ fn reportDependencyError(
3752 try err.addNote(self, "a dependency of {}", .{self.getFile(parent).?.fmtPath()});3821 try err.addNote(self, "a dependency of {}", .{self.getFile(parent).?.fmtPath()});
3753}3822}
37543823
3755fn reportUnexpectedError(self: *MachO, comptime format: []const u8, args: anytype) error{OutOfMemory}!void {3824pub fn reportUnexpectedError(self: *MachO, comptime format: []const u8, args: anytype) error{OutOfMemory}!void {
3756 var err = try self.addErrorWithNotes(1);3825 var err = try self.addErrorWithNotes(1);
3757 try err.addMsg(self, format, args);3826 try err.addMsg(self, format, args);
3758 try err.addNote(self, "please report this as a linker bug on https://github.com/ziglang/zig/issues/new/choose", .{});3827 try err.addNote(self, "please report this as a linker bug on https://github.com/ziglang/zig/issues/new/choose", .{});
src/link/MachO/Atom.zig+1-10
...@@ -50,14 +50,6 @@ pub fn getFile(self: Atom, macho_file: *MachO) File {...@@ -50,14 +50,6 @@ pub fn getFile(self: Atom, macho_file: *MachO) File {
50 return macho_file.getFile(self.file).?;50 return macho_file.getFile(self.file).?;
51}51}
5252
53pub fn getData(self: Atom, macho_file: *MachO) []const u8 {
54 return switch (self.getFile(macho_file)) {
55 .zig_object => @panic("TODO Atom.getData"),
56 .object => |x| x.getAtomData(self),
57 else => unreachable,
58 };
59}
60
61pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {53pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {
62 return switch (self.getFile(macho_file)) {54 return switch (self.getFile(macho_file)) {
63 .zig_object => |x| x.getAtomRelocs(self),55 .zig_object => |x| x.getAtomRelocs(self),
...@@ -538,7 +530,6 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {...@@ -538,7 +530,6 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
538 const file = self.getFile(macho_file);530 const file = self.getFile(macho_file);
539 const name = self.getName(macho_file);531 const name = self.getName(macho_file);
540 const relocs = self.getRelocs(macho_file);532 const relocs = self.getRelocs(macho_file);
541 @memcpy(buffer, self.getData(macho_file));
542533
543 relocs_log.debug("{x}: {s}", .{ self.value, name });534 relocs_log.debug("{x}: {s}", .{ self.value, name });
544535
...@@ -1153,7 +1144,7 @@ const macho = std.macho;...@@ -1153,7 +1144,7 @@ const macho = std.macho;
1153const math = std.math;1144const math = std.math;
1154const mem = std.mem;1145const mem = std.mem;
1155const log = std.log.scoped(.link);1146const log = std.log.scoped(.link);
1156const relocs_log = std.log.scoped(.relocs);1147const relocs_log = std.log.scoped(.link_relocs);
1157const std = @import("std");1148const std = @import("std");
1158const trace = @import("../../tracy.zig").trace;1149const trace = @import("../../tracy.zig").trace;
11591150
src/link/MachO/ZigObject.zig+17-3
...@@ -128,6 +128,20 @@ pub fn addAtom(self: *ZigObject, macho_file: *MachO) !Symbol.Index {...@@ -128,6 +128,20 @@ pub fn addAtom(self: *ZigObject, macho_file: *MachO) !Symbol.Index {
128 return symbol_index;128 return symbol_index;
129}129}
130130
131/// Caller owns the memory.
132pub fn getAtomDataAlloc(self: ZigObject, macho_file: *MachO, atom: Atom) ![]u8 {
133 const gpa = macho_file.base.comp.gpa;
134 assert(atom.file == self.index);
135 const sect = macho_file.sections.items(.header)[atom.out_n_sect];
136 const file_offset = sect.offset + atom.value - sect.addr;
137 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
138 const code = try gpa.alloc(u8, size);
139 errdefer gpa.free(code);
140 const amt = try macho_file.base.file.?.preadAll(code, file_offset);
141 if (amt != code.len) return error.InputOutput;
142 return code;
143}
144
131pub fn getAtomRelocs(self: *ZigObject, atom: Atom) []const Relocation {145pub fn getAtomRelocs(self: *ZigObject, atom: Atom) []const Relocation {
132 const relocs = self.relocs.items[atom.relocs.pos];146 const relocs = self.relocs.items[atom.relocs.pos];
133 return relocs.items[0..atom.relocs.len];147 return relocs.items[0..atom.relocs.len];
...@@ -659,7 +673,7 @@ fn updateDeclCode(...@@ -659,7 +673,7 @@ fn updateDeclCode(
659673
660 if (old_size > 0) {674 if (old_size > 0) {
661 const capacity = atom.capacity(macho_file);675 const capacity = atom.capacity(macho_file);
662 const need_realloc = code.len > capacity or !required_alignment.check(sym.getAddress(.{}, macho_file));676 const need_realloc = code.len > capacity or !required_alignment.check(atom.value);
663677
664 if (need_realloc) {678 if (need_realloc) {
665 try atom.grow(macho_file);679 try atom.grow(macho_file);
...@@ -678,7 +692,7 @@ fn updateDeclCode(...@@ -678,7 +692,7 @@ fn updateDeclCode(
678 } else if (code.len < old_size) {692 } else if (code.len < old_size) {
679 atom.shrink(macho_file);693 atom.shrink(macho_file);
680 } else if (macho_file.getAtom(atom.next_index) == null) {694 } else if (macho_file.getAtom(atom.next_index) == null) {
681 const needed_size = (sym.getAddress(.{}, macho_file) + code.len) - sect.addr;695 const needed_size = atom.value + code.len - sect.addr;
682 sect.size = needed_size;696 sect.size = needed_size;
683 }697 }
684 } else {698 } else {
...@@ -696,7 +710,7 @@ fn updateDeclCode(...@@ -696,7 +710,7 @@ fn updateDeclCode(
696 }710 }
697711
698 if (!sect.isZerofill()) {712 if (!sect.isZerofill()) {
699 const file_offset = sect.offset + sym.getAddress(.{}, macho_file) - sect.addr;713 const file_offset = sect.offset + atom.value - sect.addr;
700 try macho_file.base.file.?.pwriteAll(code, file_offset);714 try macho_file.base.file.?.pwriteAll(code, file_offset);
701 }715 }
702}716}
src/link/MachO/relocatable.zig+1-1
...@@ -274,7 +274,7 @@ fn writeAtoms(macho_file: *MachO) !void {...@@ -274,7 +274,7 @@ fn writeAtoms(macho_file: *MachO) !void {
274 const atom = macho_file.getAtom(atom_index).?;274 const atom = macho_file.getAtom(atom_index).?;
275 assert(atom.flags.alive);275 assert(atom.flags.alive);
276 const off = atom.value - header.addr;276 const off = atom.value - header.addr;
277 @memcpy(code[off..][0..atom.size], atom.getData(macho_file));277 @memcpy(code[off..][0..atom.size], atom.getFile(macho_file).object.getAtomData(atom.*));
278 try atom.writeRelocs(macho_file, code[off..][0..atom.size], &relocs);278 try atom.writeRelocs(macho_file, code[off..][0..atom.size], &relocs);
279 }279 }
280280