authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-18 18:48:52+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-18 22:26:23+01:00
loge32131cfae60859340ea43893fa1d0f70701ec31
treedb2a51cb72d126c4fe08d43facf48217c0d47fe9
parent6c7e66613d57aec2f2949c065ea6431ff6c31f88

stage2 macho: cleanup indirect symbol table writes

Also, force rewriting of code signature padding at every update so that we take into account possible section relocs and expansion of the last preceeding section, e.g., the string table. This commit also tweak the logic responsible for managing debug lines in `DebugSymbols`. In particular, in case we update the same function, we'd previously incorrectly create a cycle adding pointer to the same `SrcFn` to itself.

2 files changed, 55 insertions(+), 37 deletions(-)

src/link/MachO.zig+51-35
......@@ -2232,6 +2232,7 @@ pub fn makeStaticString(comptime bytes: []const u8) [16]u8 {
22322232fn makeString(self: *MachO, bytes: []const u8) !u32 {
22332233 try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1);
22342234 const offset = @intCast(u32, self.string_table.items.len);
2235 log.debug("writing '{s}' into the string table at offset 0x{x}", .{ bytes, offset });
22352236 self.string_table.appendSliceAssumeCapacity(bytes);
22362237 self.string_table.appendAssumeCapacity(0);
22372238 self.string_table_dirty = true;
......@@ -2257,6 +2258,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {
22572258 const index = @intCast(u32, self.extern_lazy_symbols.items().len);
22582259 const offset = try self.makeString(name);
22592260 const sym_name = try self.base.allocator.dupe(u8, name);
2261 const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem.
22602262 try self.extern_lazy_symbols.putNoClobber(self.base.allocator, sym_name, .{
22612263 .inner = .{
22622264 .n_strx = offset,
......@@ -2265,8 +2267,9 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {
22652267 .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER,
22662268 .n_value = 0,
22672269 },
2268 .dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem.
2270 .dylib_ordinal = dylib_ordinal,
22692271 });
2272 log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal });
22702273 return index;
22712274}
22722275
......@@ -2639,6 +2642,11 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
26392642}
26402643
26412644fn writeIndirectSymbolTable(self: *MachO) !void {
2645 // TODO figure out a way not to rewrite the table every time if
2646 // no new undefs are not added.
2647 const tracy = trace(@src());
2648 defer tracy.end();
2649
26422650 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
26432651 const stubs = &text_segment.sections.items[self.stubs_section_index.?];
26442652 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
......@@ -2646,42 +2654,53 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
26462654 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
26472655 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
26482656 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
2649 dysymtab.nindirectsyms = 0;
2650 // TODO check if we have allocated enough size.
26512657
2652 var buf: [@sizeOf(u32)]u8 = undefined;
2653 var off = dysymtab.indirectsymoff;
2658 const lazy = self.extern_lazy_symbols.items();
2659 const nonlazy = self.extern_nonlazy_symbols.items();
2660 const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff);
2661 const nindirectsyms = @intCast(u32, lazy.len * 2 + nonlazy.len);
2662 const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32));
2663
2664 if (needed_size > allocated_size) {
2665 dysymtab.nindirectsyms = 0;
2666 dysymtab.indirectsymoff = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, @sizeOf(u32), null));
2667 }
2668 dysymtab.nindirectsyms = nindirectsyms;
2669 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{
2670 dysymtab.indirectsymoff,
2671 dysymtab.indirectsymoff + needed_size,
2672 });
2673
2674 var buf = try self.base.allocator.alloc(u8, needed_size);
2675 defer self.base.allocator.free(buf);
2676 var stream = std.io.fixedBufferStream(buf);
2677 var writer = stream.writer();
26542678
26552679 stubs.reserved1 = 0;
26562680 for (self.extern_lazy_symbols.items()) |_, i| {
26572681 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
2658 mem.writeIntLittle(u32, &buf, symtab_idx);
2659 try self.base.file.?.pwriteAll(&buf, off);
2660 off += @sizeOf(u32);
2661 dysymtab.nindirectsyms += 1;
2682 try writer.writeIntLittle(u32, symtab_idx);
26622683 }
26632684
2664 const base_id = @intCast(u32, self.extern_lazy_symbols.items().len);
2685 const base_id = @intCast(u32, lazy.len);
26652686 got.reserved1 = base_id;
26662687 for (self.extern_nonlazy_symbols.items()) |_, i| {
26672688 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id);
2668 mem.writeIntLittle(u32, &buf, symtab_idx);
2669 try self.base.file.?.pwriteAll(&buf, off);
2670 off += @sizeOf(u32);
2671 dysymtab.nindirectsyms += 1;
2689 try writer.writeIntLittle(u32, symtab_idx);
26722690 }
26732691
2674 la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, self.extern_nonlazy_symbols.items().len);
2692 la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len);
26752693 for (self.extern_lazy_symbols.items()) |_, i| {
26762694 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
2677 mem.writeIntLittle(u32, &buf, symtab_idx);
2678 try self.base.file.?.pwriteAll(&buf, off);
2679 off += @sizeOf(u32);
2680 dysymtab.nindirectsyms += 1;
2695 try writer.writeIntLittle(u32, symtab_idx);
26812696 }
2697
2698 try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
2699 self.load_commands_dirty = true;
26822700}
26832701
26842702fn writeCodeSignaturePadding(self: *MachO) !void {
2703 // TODO figure out how not to rewrite padding every single time.
26852704 const tracy = trace(@src());
26862705 defer tracy.end();
26872706
......@@ -2693,22 +2712,19 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
26932712 fileoff,
26942713 self.page_size,
26952714 );
2696
2697 if (code_sig_cmd.datasize < needed_size) {
2698 code_sig_cmd.dataoff = @intCast(u32, fileoff);
2699 code_sig_cmd.datasize = needed_size;
2700
2701 // Advance size of __LINKEDIT segment
2702 linkedit_segment.inner.filesize += needed_size;
2703 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
2704 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
2705 }
2706 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
2707 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
2708 // except for code signature data.
2709 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1);
2710 self.load_commands_dirty = true;
2711 }
2715 code_sig_cmd.dataoff = @intCast(u32, fileoff);
2716 code_sig_cmd.datasize = needed_size;
2717
2718 // Advance size of __LINKEDIT segment
2719 linkedit_segment.inner.filesize += needed_size;
2720 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
2721 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
2722 }
2723 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
2724 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
2725 // except for code signature data.
2726 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1);
2727 self.load_commands_dirty = true;
27122728}
27132729
27142730fn writeCodeSignature(self: *MachO) !void {
src/link/MachO/DebugSymbols.zig+4-2
......@@ -1079,7 +1079,8 @@ pub fn commitDeclDebugInfo(
10791079 const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];
10801080 const src_fn = &decl.fn_link.macho;
10811081 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
1082 if (self.dbg_line_fn_last) |last| {
1082 if (self.dbg_line_fn_last) |last| blk: {
1083 if (src_fn == last) break :blk;
10831084 if (src_fn.next) |next| {
10841085 // Update existing function - non-last item.
10851086 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
......@@ -1238,7 +1239,8 @@ fn updateDeclDebugInfoAllocation(
12381239 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
12391240 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
12401241 text_block.dbg_info_len = len;
1241 if (self.dbg_info_decl_last) |last| {
1242 if (self.dbg_info_decl_last) |last| blk: {
1243 if (text_block == last) break :blk;
12421244 if (text_block.dbg_info_next) |next| {
12431245 // Update existing Decl - non-last item.
12441246 if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {