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 {...@@ -2232,6 +2232,7 @@ pub fn makeStaticString(comptime bytes: []const u8) [16]u8 {
2232fn makeString(self: *MachO, bytes: []const u8) !u32 {2232fn makeString(self: *MachO, bytes: []const u8) !u32 {
2233 try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1);2233 try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1);
2234 const offset = @intCast(u32, self.string_table.items.len);2234 const offset = @intCast(u32, self.string_table.items.len);
2235 log.debug("writing '{s}' into the string table at offset 0x{x}", .{ bytes, offset });
2235 self.string_table.appendSliceAssumeCapacity(bytes);2236 self.string_table.appendSliceAssumeCapacity(bytes);
2236 self.string_table.appendAssumeCapacity(0);2237 self.string_table.appendAssumeCapacity(0);
2237 self.string_table_dirty = true;2238 self.string_table_dirty = true;
...@@ -2257,6 +2258,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {...@@ -2257,6 +2258,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {
2257 const index = @intCast(u32, self.extern_lazy_symbols.items().len);2258 const index = @intCast(u32, self.extern_lazy_symbols.items().len);
2258 const offset = try self.makeString(name);2259 const offset = try self.makeString(name);
2259 const sym_name = try self.base.allocator.dupe(u8, name);2260 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.
2260 try self.extern_lazy_symbols.putNoClobber(self.base.allocator, sym_name, .{2262 try self.extern_lazy_symbols.putNoClobber(self.base.allocator, sym_name, .{
2261 .inner = .{2263 .inner = .{
2262 .n_strx = offset,2264 .n_strx = offset,
...@@ -2265,8 +2267,9 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {...@@ -2265,8 +2267,9 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 {
2265 .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER,2267 .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER,
2266 .n_value = 0,2268 .n_value = 0,
2267 },2269 },
2268 .dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem.2270 .dylib_ordinal = dylib_ordinal,
2269 });2271 });
2272 log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal });
2270 return index;2273 return index;
2271}2274}
22722275
...@@ -2639,6 +2642,11 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {...@@ -2639,6 +2642,11 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
2639}2642}
26402643
2641fn writeIndirectSymbolTable(self: *MachO) !void {2644fn 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
2642 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;2650 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2643 const stubs = &text_segment.sections.items[self.stubs_section_index.?];2651 const stubs = &text_segment.sections.items[self.stubs_section_index.?];
2644 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;2652 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
...@@ -2646,42 +2654,53 @@ fn writeIndirectSymbolTable(self: *MachO) !void {...@@ -2646,42 +2654,53 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
2646 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;2654 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2647 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];2655 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
2648 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;2656 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;2658 const lazy = self.extern_lazy_symbols.items();
2653 var off = dysymtab.indirectsymoff;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
2655 stubs.reserved1 = 0;2679 stubs.reserved1 = 0;
2656 for (self.extern_lazy_symbols.items()) |_, i| {2680 for (self.extern_lazy_symbols.items()) |_, i| {
2657 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);2681 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
2658 mem.writeIntLittle(u32, &buf, symtab_idx);2682 try writer.writeIntLittle(u32, symtab_idx);
2659 try self.base.file.?.pwriteAll(&buf, off);
2660 off += @sizeOf(u32);
2661 dysymtab.nindirectsyms += 1;
2662 }2683 }
26632684
2664 const base_id = @intCast(u32, self.extern_lazy_symbols.items().len);2685 const base_id = @intCast(u32, lazy.len);
2665 got.reserved1 = base_id;2686 got.reserved1 = base_id;
2666 for (self.extern_nonlazy_symbols.items()) |_, i| {2687 for (self.extern_nonlazy_symbols.items()) |_, i| {
2667 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id);2688 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id);
2668 mem.writeIntLittle(u32, &buf, symtab_idx);2689 try writer.writeIntLittle(u32, symtab_idx);
2669 try self.base.file.?.pwriteAll(&buf, off);
2670 off += @sizeOf(u32);
2671 dysymtab.nindirectsyms += 1;
2672 }2690 }
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);
2675 for (self.extern_lazy_symbols.items()) |_, i| {2693 for (self.extern_lazy_symbols.items()) |_, i| {
2676 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);2694 const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
2677 mem.writeIntLittle(u32, &buf, symtab_idx);2695 try writer.writeIntLittle(u32, symtab_idx);
2678 try self.base.file.?.pwriteAll(&buf, off);
2679 off += @sizeOf(u32);
2680 dysymtab.nindirectsyms += 1;
2681 }2696 }
2697
2698 try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
2699 self.load_commands_dirty = true;
2682}2700}
26832701
2684fn writeCodeSignaturePadding(self: *MachO) !void {2702fn writeCodeSignaturePadding(self: *MachO) !void {
2703 // TODO figure out how not to rewrite padding every single time.
2685 const tracy = trace(@src());2704 const tracy = trace(@src());
2686 defer tracy.end();2705 defer tracy.end();
26872706
...@@ -2693,22 +2712,19 @@ fn writeCodeSignaturePadding(self: *MachO) !void {...@@ -2693,22 +2712,19 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
2693 fileoff,2712 fileoff,
2694 self.page_size,2713 self.page_size,
2695 );2714 );
26962715 code_sig_cmd.dataoff = @intCast(u32, fileoff);
2697 if (code_sig_cmd.datasize < needed_size) {2716 code_sig_cmd.datasize = needed_size;
2698 code_sig_cmd.dataoff = @intCast(u32, fileoff);2717
2699 code_sig_cmd.datasize = needed_size;2718 // Advance size of __LINKEDIT segment
27002719 linkedit_segment.inner.filesize += needed_size;
2701 // Advance size of __LINKEDIT segment2720 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
2702 linkedit_segment.inner.filesize += needed_size;2721 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
2703 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {2722 }
2704 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);2723 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
2705 }2724 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
2706 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });2725 // except for code signature data.
2707 // Pad out the space. We need to do this to calculate valid hashes for everything in the file2726 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1);
2708 // except for code signature data.2727 self.load_commands_dirty = true;
2709 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1);
2710 self.load_commands_dirty = true;
2711 }
2712}2728}
27132729
2714fn writeCodeSignature(self: *MachO) !void {2730fn writeCodeSignature(self: *MachO) !void {
src/link/MachO/DebugSymbols.zig+4-2
...@@ -1079,7 +1079,8 @@ pub fn commitDeclDebugInfo(...@@ -1079,7 +1079,8 @@ pub fn commitDeclDebugInfo(
1079 const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];1079 const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?];
1080 const src_fn = &decl.fn_link.macho;1080 const src_fn = &decl.fn_link.macho;
1081 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);1081 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;
1083 if (src_fn.next) |next| {1084 if (src_fn.next) |next| {
1084 // Update existing function - non-last item.1085 // Update existing function - non-last item.
1085 if (src_fn.off + src_fn.len + min_nop_size > next.off) {1086 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
...@@ -1238,7 +1239,8 @@ fn updateDeclDebugInfoAllocation(...@@ -1238,7 +1239,8 @@ fn updateDeclDebugInfoAllocation(
1238 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;1239 const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment;
1239 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];1240 const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?];
1240 text_block.dbg_info_len = len;1241 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;
1242 if (text_block.dbg_info_next) |next| {1244 if (text_block.dbg_info_next) |next| {
1243 // Update existing Decl - non-last item.1245 // Update existing Decl - non-last item.
1244 if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {1246 if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {