authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-02 22:17:25+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-03 09:28:25+01:00
loge10a2018a7b6a51243589ec95842d2cef2da45ac
treed549caea83d2b3060e5d14c856a2509d977eb951
parentdc222c9ba5865176fde9607d10dd5dca69654894

macho: emit relocs for ZigObject


3 files changed, 83 insertions(+), 10 deletions(-)

src/link/MachO.zig+8-4
......@@ -615,6 +615,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
615615 const sect = &self.sections.items(.header)[atom.out_n_sect];
616616 if (sect.isZerofill()) continue;
617617 if (mem.indexOf(u8, sect.segName(), "ZIG") == null) continue; // Non-Zig sections are handled separately
618 if (atom.getRelocs(self).len == 0) continue;
618619 // TODO: we will resolve and write ZigObject's TLS data twice:
619620 // once here, and once in writeAtoms
620621 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
......@@ -4107,10 +4108,13 @@ fn formatSections(
41074108 _ = unused_fmt_string;
41084109 const slice = self.sections.slice();
41094110 for (slice.items(.header), slice.items(.segment_id), 0..) |header, seg_id, i| {
4110 try writer.print("sect({d}) : seg({d}) : {s},{s} : @{x} ({x}) : align({x}) : size({x})\n", .{
4111 i, seg_id, header.segName(), header.sectName(), header.addr, header.offset,
4112 header.@"align", header.size,
4113 });
4111 try writer.print(
4112 "sect({d}) : seg({d}) : {s},{s} : @{x} ({x}) : align({x}) : size({x}) : relocs({x};{d})\n",
4113 .{
4114 i, seg_id, header.segName(), header.sectName(), header.addr, header.offset,
4115 header.@"align", header.size, header.reloff, header.nreloc,
4116 },
4117 );
41144118 }
41154119}
41164120
src/link/MachO/Atom.zig+4-4
......@@ -1143,10 +1143,10 @@ fn format2(
11431143 _ = unused_fmt_string;
11441144 const atom = ctx.atom;
11451145 const macho_file = ctx.macho_file;
1146 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : thunk({d})", .{
1147 atom.atom_index, atom.getName(macho_file), atom.value,
1148 atom.out_n_sect, atom.alignment, atom.size,
1149 atom.thunk_index,
1146 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{
1147 atom.atom_index, atom.getName(macho_file), atom.value,
1148 atom.out_n_sect, atom.alignment, atom.size,
1149 atom.getRelocs(macho_file).len, atom.thunk_index,
11501150 });
11511151 if (!atom.flags.alive) try writer.writeAll(" : [*]");
11521152 if (atom.unwind_records.len > 0) {
src/link/MachO/relocatable.zig+71-2
......@@ -63,14 +63,15 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u
6363 allocateSegment(macho_file);
6464 macho_file.allocateAtoms();
6565
66 state_log.debug("{}", .{macho_file.dumpState()});
67
6866 var off = off: {
6967 const seg = macho_file.segments.items[0];
7068 const off = math.cast(u32, seg.fileoff + seg.filesize) orelse return error.Overflow;
7169 break :off mem.alignForward(u32, off, @alignOf(macho.relocation_info));
7270 };
7371 off = allocateSectionsRelocs(macho_file, off);
72
73 state_log.debug("{}", .{macho_file.dumpState()});
74
7475 try macho_file.calcSymtabSize();
7576 try writeAtoms(macho_file);
7677 try writeCompactUnwind(macho_file);
......@@ -195,6 +196,16 @@ fn calcSectionSizes(macho_file: *MachO) !void {
195196 sect.@"align" = 3;
196197 sect.nreloc = eh_frame.calcNumRelocs(macho_file);
197198 }
199
200 if (macho_file.getZigObject()) |zo| {
201 for (zo.atoms.items) |atom_index| {
202 const atom = macho_file.getAtom(atom_index) orelse continue;
203 if (!atom.flags.alive) continue;
204 const header = &macho_file.sections.items(.header)[atom.out_n_sect];
205 if (mem.indexOf(u8, header.segName(), "ZIG") == null) continue;
206 header.nreloc += atom.calcNumRelocs(macho_file);
207 }
208 }
198209}
199210
200211fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {
......@@ -303,6 +314,7 @@ fn writeAtoms(macho_file: *MachO) !void {
303314 for (slice.items(.header), slice.items(.atoms)) |header, atoms| {
304315 if (atoms.items.len == 0) continue;
305316 if (header.isZerofill()) continue;
317 if (mem.indexOf(u8, header.segName(), "ZIG") != null) continue;
306318
307319 const size = math.cast(usize, header.size) orelse return error.Overflow;
308320 const code = try gpa.alloc(u8, size);
......@@ -330,6 +342,63 @@ fn writeAtoms(macho_file: *MachO) !void {
330342 try macho_file.base.file.?.pwriteAll(code, header.offset);
331343 try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
332344 }
345
346 if (macho_file.getZigObject()) |zo| {
347 // TODO: this is ugly; perhaps we should aggregrate before?
348 var relocs = std.AutoArrayHashMap(u8, std.ArrayList(macho.relocation_info)).init(gpa);
349 defer {
350 for (relocs.values()) |*list| {
351 list.deinit();
352 }
353 relocs.deinit();
354 }
355
356 for (macho_file.sections.items(.header), 0..) |header, n_sect| {
357 if (header.isZerofill()) continue;
358 if (mem.indexOf(u8, header.segName(), "ZIG") == null) continue;
359 const gop = try relocs.getOrPut(@intCast(n_sect));
360 if (gop.found_existing) continue;
361 gop.value_ptr.* = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);
362 }
363
364 for (zo.atoms.items) |atom_index| {
365 const atom = macho_file.getAtom(atom_index) orelse continue;
366 if (!atom.flags.alive) continue;
367 const header = macho_file.sections.items(.header)[atom.out_n_sect];
368 if (header.isZerofill()) continue;
369 if (mem.indexOf(u8, header.segName(), "ZIG") == null) continue;
370 if (atom.getRelocs(macho_file).len == 0) continue;
371 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
372 const code = try gpa.alloc(u8, atom_size);
373 defer gpa.free(code);
374 atom.getData(macho_file, code) catch |err| switch (err) {
375 error.InputOutput => {
376 try macho_file.reportUnexpectedError("fetching code for '{s}' failed", .{
377 atom.getName(macho_file),
378 });
379 return error.FlushFailure;
380 },
381 else => |e| {
382 try macho_file.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{
383 atom.getName(macho_file),
384 @errorName(e),
385 });
386 return error.FlushFailure;
387 },
388 };
389 const file_offset = header.offset + atom.value - header.addr;
390 const rels = relocs.getPtr(atom.out_n_sect).?;
391 try atom.writeRelocs(macho_file, code, rels);
392 try macho_file.base.file.?.pwriteAll(code, file_offset);
393 }
394
395 for (relocs.keys(), relocs.values()) |sect_id, rels| {
396 const header = macho_file.sections.items(.header)[sect_id];
397 assert(rels.items.len == header.nreloc);
398 mem.sort(macho.relocation_info, rels.items, {}, sortReloc);
399 try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(rels.items), header.reloff);
400 }
401 }
333402}
334403
335404fn writeCompactUnwind(macho_file: *MachO) !void {