authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-02 00:03:31+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-03 21:19:41+02:00
log1e710396d4489ce11e70820a95c33ec7463b1c12
tree9e0a75de3b1ab878eb8214f9582ed689bac6ffd3
parent7bba3d330ad90026e8b79cae9940a1e878628119

macho: fix linking in incremental context

Fix incorrect writing of symtab and strtab in dSYM bundle in incremental context. Fix incorrectly navigating unnamed consts (freeing) in incremental context. This is currently hard-coded to require all consts to land in `__TEXT,__const`, which is wrong and needs a rewrite.

2 files changed, 69 insertions(+), 50 deletions(-)

src/link/MachO.zig+29-28
......@@ -511,15 +511,14 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
511511
512512 try self.createMhExecuteHeaderSymbol();
513513 try self.resolveDyldStubBinder();
514 try self.createDyldPrivateAtom();
515 try self.createStubHelperPreambleAtom();
514516 try self.resolveSymbolsInDylibs();
515517
516518 if (self.unresolved.count() > 0) {
517519 return error.UndefinedSymbolReference;
518520 }
519521
520 try self.createDyldPrivateAtom();
521 try self.createStubHelperPreambleAtom();
522
523522 try self.allocateSpecialSymbols();
524523
525524 if (build_options.enable_logging) {
......@@ -589,7 +588,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
589588 } else null;
590589
591590 var headers_buf = std.ArrayList(u8).init(arena);
592 try self.writeSegmentHeaders(0, self.segments.items.len, &ncmds, headers_buf.writer());
591 try self.writeSegmentHeaders(&ncmds, headers_buf.writer());
593592
594593 try self.base.file.?.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));
595594 try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);
......@@ -1203,7 +1202,7 @@ fn linkOneShot(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node)
12031202 } else null;
12041203
12051204 var headers_buf = std.ArrayList(u8).init(arena);
1206 try self.writeSegmentHeaders(0, self.segments.items.len, &ncmds, headers_buf.writer());
1205 try self.writeSegmentHeaders(&ncmds, headers_buf.writer());
12071206
12081207 try self.base.file.?.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));
12091208 try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);
......@@ -3863,7 +3862,9 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
38633862fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void {
38643863 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
38653864 for (unnamed_consts.items) |atom| {
3866 const sect_id = atom.getSymbol(self).n_sect;
3865 // TODO
3866 // const sect_id = atom.getSymbol(self).n_sect;
3867 const sect_id = self.getSectionByName("__TEXT", "__const").?;
38673868 self.freeAtom(atom, sect_id, true);
38683869 self.locals_free_list.append(self.base.allocator, atom.sym_index) catch {};
38693870 self.locals.items[atom.sym_index].n_type = 0;
......@@ -4402,8 +4403,6 @@ fn initSection(
44024403 const index = try self.insertSection(segment_id, .{
44034404 .sectname = makeStaticString(sectname),
44044405 .segname = seg.segname,
4405 .size = if (self.mode == .incremental) @intCast(u32, size) else 0,
4406 .@"align" = alignment,
44074406 .flags = opts.flags,
44084407 .reserved1 = opts.reserved1,
44094408 .reserved2 = opts.reserved2,
......@@ -4413,6 +4412,9 @@ fn initSection(
44134412
44144413 if (self.mode == .incremental) {
44154414 const header = &self.sections.items(.header)[index];
4415 header.size = size;
4416 header.@"align" = alignment;
4417
44164418 const prev_end_off = if (index > 0) blk: {
44174419 const prev_section = self.sections.get(index - 1);
44184420 if (prev_section.segment_index == segment_id) {
......@@ -4421,15 +4423,25 @@ fn initSection(
44214423 } else break :blk seg.fileoff;
44224424 } else 0;
44234425 const alignment_pow_2 = try math.powi(u32, 2, alignment);
4424 const padding: u64 = if (index == 0) try self.calcMinHeaderPad() else 0;
4426 // TODO better prealloc for __text section
4427 // const padding: u64 = if (index == 0) try self.calcMinHeaderPad() else 0;
4428 const padding: u64 = if (index == 0) 0x1000 else 0;
44254429 const off = mem.alignForwardGeneric(u64, padding + prev_end_off, alignment_pow_2);
4426 log.debug("allocating {s},{s} section at 0x{x}", .{ header.segName(), header.sectName(), off });
4427
4428 header.addr = seg.vmaddr + off - seg.fileoff;
44294430
44304431 if (!header.isZerofill()) {
44314432 header.offset = @intCast(u32, off);
44324433 }
4434 header.addr = seg.vmaddr + off - seg.fileoff;
4435
4436 // TODO this will break if we are inserting section that is not the last section
4437 // in a segment.
4438 const max_size = self.allocatedSize(segment_id, off);
4439
4440 if (size > max_size) {
4441 try self.growSection(index, @intCast(u32, size));
4442 }
4443
4444 log.debug("allocating {s},{s} section at 0x{x}", .{ header.segName(), header.sectName(), off });
44334445
44344446 self.updateSectionOrdinals(index + 1);
44354447 }
......@@ -4494,7 +4506,7 @@ fn updateSectionOrdinals(self: *MachO, start: u8) void {
44944506
44954507 const slice = self.sections.slice();
44964508 for (slice.items(.last_atom)[start..]) |last_atom| {
4497 var atom = last_atom.?;
4509 var atom = last_atom orelse continue;
44984510
44994511 while (true) {
45004512 const sym = atom.getSymbolPtr(self);
......@@ -4536,17 +4548,6 @@ fn shiftLocalsByOffset(self: *MachO, sect_id: u8, offset: i64) !void {
45364548 }
45374549}
45384550
4539fn findFreeSpace(self: MachO, segment_id: u8, alignment: u64, start: ?u64) u64 {
4540 const seg = self.segments.items[segment_id];
4541 const indexes = self.getSectionIndexes(segment_id);
4542 if (indexes.end - indexes.start == 0) {
4543 return if (start) |v| v else seg.fileoff;
4544 }
4545 const last_sect = self.sections.items(.header)[indexes.end - 1];
4546 const final_off = last_sect.offset + padToIdeal(last_sect.size);
4547 return mem.alignForwardGeneric(u64, final_off, alignment);
4548}
4549
45504551fn growSegment(self: *MachO, segment_index: u8, new_size: u64) !void {
45514552 const segment = &self.segments.items[segment_index];
45524553 const new_segment_size = mem.alignForwardGeneric(u64, new_size, self.page_size);
......@@ -4885,14 +4886,14 @@ fn getSegmentAllocBase(self: MachO, indices: []const ?u8) struct { vmaddr: u64,
48854886 return .{ .vmaddr = 0, .fileoff = 0 };
48864887}
48874888
4888pub fn writeSegmentHeaders(self: *MachO, start: usize, end: usize, ncmds: *u32, writer: anytype) !void {
4889 for (self.segments.items[start..end]) |seg, i| {
4889fn writeSegmentHeaders(self: *MachO, ncmds: *u32, writer: anytype) !void {
4890 for (self.segments.items) |seg, i| {
48904891 if (seg.nsects == 0 and
48914892 (mem.eql(u8, seg.segName(), "__DATA_CONST") or
48924893 mem.eql(u8, seg.segName(), "__DATA"))) continue;
48934894 try writer.writeStruct(seg);
48944895
4895 const indexes = self.getSectionIndexes(@intCast(u8, start + i));
4896 const indexes = self.getSectionIndexes(@intCast(u8, i));
48964897 for (self.sections.items(.header)[indexes.start..indexes.end]) |header| {
48974898 try writer.writeStruct(header);
48984899 }
......@@ -5718,7 +5719,7 @@ pub fn getSectionByName(self: MachO, segname: []const u8, sectname: []const u8)
57185719 } else return null;
57195720}
57205721
5721fn getSectionIndexes(self: MachO, segment_index: u8) struct { start: u8, end: u8 } {
5722pub fn getSectionIndexes(self: MachO, segment_index: u8) struct { start: u8, end: u8 } {
57225723 var start: u8 = 0;
57235724 const nsects = for (self.segments.items) |seg, i| {
57245725 if (i == segment_index) break @intCast(u8, seg.nsects);
src/link/MachO/DebugSymbols.zig+40-22
......@@ -63,6 +63,10 @@ pub const Reloc = struct {
6363pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {
6464 if (self.linkedit_segment_cmd_index == null) {
6565 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
66 log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{
67 self.base.page_size,
68 self.base.page_size * 2,
69 });
6670 // TODO this needs reworking
6771 try self.segments.append(allocator, .{
6872 .segname = makeStaticString("__LINKEDIT"),
......@@ -79,7 +83,7 @@ pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void
7983 if (self.dwarf_segment_cmd_index == null) {
8084 self.dwarf_segment_cmd_index = @intCast(u8, self.segments.items.len);
8185
82 const linkedit = self.segments.items[self.base.linkedit_segment_cmd_index.?];
86 const linkedit = self.segments.items[self.linkedit_segment_cmd_index.?];
8387 const ideal_size: u16 = 200 + 128 + 160 + 250;
8488 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.base.page_size);
8589 const fileoff = linkedit.fileoff + linkedit.filesize;
......@@ -290,20 +294,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
290294
291295 var headers_buf = std.ArrayList(u8).init(allocator);
292296 defer headers_buf.deinit();
293 try self.base.writeSegmentHeaders(
294 0,
295 self.base.linkedit_segment_cmd_index.?,
296 &ncmds,
297 headers_buf.writer(),
298 );
299
300 for (self.segments.items) |seg| {
301 try headers_buf.writer().writeStruct(seg);
302 ncmds += 2;
303 }
304 for (self.sections.items) |header| {
305 try headers_buf.writer().writeStruct(header);
306 }
297 try self.writeSegmentHeaders(&ncmds, headers_buf.writer());
307298
308299 try self.file.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));
309300 try self.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);
......@@ -349,6 +340,7 @@ fn updateDwarfSegment(self: *DebugSymbols) void {
349340
350341 var max_offset: u64 = 0;
351342 for (self.sections.items) |*sect| {
343 sect.addr += diff;
352344 log.debug(" {s},{s} - 0x{x}-0x{x} - 0x{x}-0x{x}", .{
353345 sect.segName(),
354346 sect.sectName(),
......@@ -360,7 +352,6 @@ fn updateDwarfSegment(self: *DebugSymbols) void {
360352 if (sect.offset + sect.size > max_offset) {
361353 max_offset = sect.offset + sect.size;
362354 }
363 sect.addr += diff;
364355 }
365356
366357 const file_size = max_offset - dwarf_segment.fileoff;
......@@ -372,6 +363,37 @@ fn updateDwarfSegment(self: *DebugSymbols) void {
372363 }
373364}
374365
366fn writeSegmentHeaders(self: *DebugSymbols, ncmds: *u32, writer: anytype) !void {
367 // Write segment/section headers from the binary file first.
368 const end = self.base.linkedit_segment_cmd_index.?;
369 for (self.base.segments.items[0..end]) |seg, i| {
370 if (seg.nsects == 0 and
371 (mem.eql(u8, seg.segName(), "__DATA_CONST") or
372 mem.eql(u8, seg.segName(), "__DATA"))) continue;
373 var out_seg = seg;
374 out_seg.fileoff = 0;
375 out_seg.filesize = 0;
376 try writer.writeStruct(out_seg);
377
378 const indexes = self.base.getSectionIndexes(@intCast(u8, i));
379 for (self.base.sections.items(.header)[indexes.start..indexes.end]) |header| {
380 var out_header = header;
381 out_header.offset = 0;
382 try writer.writeStruct(out_header);
383 }
384
385 ncmds.* += 1;
386 }
387 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
388 for (self.segments.items) |seg| {
389 try writer.writeStruct(seg);
390 ncmds.* += 1;
391 }
392 for (self.sections.items) |header| {
393 try writer.writeStruct(header);
394 }
395}
396
375397fn writeHeader(self: *DebugSymbols, ncmds: u32, sizeofcmds: u32) !void {
376398 var header: macho.mach_header_64 = .{};
377399 header.filetype = macho.MH_DSYM;
......@@ -469,11 +491,7 @@ fn writeSymtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
469491 const nsyms = nlocals + nexports;
470492
471493 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
472 const offset = mem.alignForwardGeneric(
473 u64,
474 seg.fileoff + seg.filesize,
475 @alignOf(macho.nlist_64),
476 );
494 const offset = mem.alignForwardGeneric(u64, seg.fileoff, @alignOf(macho.nlist_64));
477495 const needed_size = nsyms * @sizeOf(macho.nlist_64);
478496
479497 if (needed_size > seg.filesize) {
......@@ -535,7 +553,7 @@ fn writeStrtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
535553 const needed_size = mem.alignForwardGeneric(u64, self.strtab.buffer.items.len, @alignOf(u64));
536554 lc.strsize = @intCast(u32, needed_size);
537555
538 if (offset + needed_size > seg.filesize) {
556 if (symtab_size + needed_size > seg.filesize) {
539557 const aligned_size = mem.alignForwardGeneric(u64, offset + needed_size, self.base.page_size);
540558 const diff = @intCast(u32, aligned_size - seg.filesize);
541559 const dwarf_seg = &self.segments.items[self.dwarf_segment_cmd_index.?];