diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Module.zig | 6 | ||||
| -rw-r--r-- | src/link/MachO.zig | 86 | ||||
| -rw-r--r-- | src/link/MachO/DebugSymbols.zig | 6 |
3 files changed, 59 insertions, 39 deletions
diff --git a/src/Module.zig b/src/Module.zig index 7a6dc12967..fa9722814e 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1617,8 +1617,10 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void // in `Decl` to notice that the line number did not change. self.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); }, - .macho => { - // TODO Implement for MachO + .macho => if (decl.fn_link.macho.len != 0) { + // TODO Look into detecting when this would be unnecessary by storing enough state + // in `Decl` to notice that the line number did not change. + self.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); }, .c, .wasm => {}, } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 16e06e9a82..93072f69a2 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2232,6 +2232,7 @@ pub fn makeStaticString(comptime bytes: []const u8) [16]u8 { fn makeString(self: *MachO, bytes: []const u8) !u32 { try self.string_table.ensureCapacity(self.base.allocator, self.string_table.items.len + bytes.len + 1); const offset = @intCast(u32, self.string_table.items.len); + log.debug("writing '{s}' into the string table at offset 0x{x}", .{ bytes, offset }); self.string_table.appendSliceAssumeCapacity(bytes); self.string_table.appendAssumeCapacity(0); self.string_table_dirty = true; @@ -2257,6 +2258,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { const index = @intCast(u32, self.extern_lazy_symbols.items().len); const offset = try self.makeString(name); const sym_name = try self.base.allocator.dupe(u8, name); + const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem. try self.extern_lazy_symbols.putNoClobber(self.base.allocator, sym_name, .{ .inner = .{ .n_strx = offset, @@ -2265,8 +2267,9 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER, .n_value = 0, }, - .dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem. + .dylib_ordinal = dylib_ordinal, }); + log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal }); return index; } @@ -2639,6 +2642,11 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { } fn writeIndirectSymbolTable(self: *MachO) !void { + // TODO figure out a way not to rewrite the table every time if + // no new undefs are not added. + const tracy = trace(@src()); + defer tracy.end(); + const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; const stubs = &text_segment.sections.items[self.stubs_section_index.?]; const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; @@ -2646,42 +2654,53 @@ fn writeIndirectSymbolTable(self: *MachO) !void { const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; - dysymtab.nindirectsyms = 0; - // TODO check if we have allocated enough size. - var buf: [@sizeOf(u32)]u8 = undefined; - var off = dysymtab.indirectsymoff; + const lazy = self.extern_lazy_symbols.items(); + const nonlazy = self.extern_nonlazy_symbols.items(); + const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff); + const nindirectsyms = @intCast(u32, lazy.len * 2 + nonlazy.len); + const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32)); + + if (needed_size > allocated_size) { + dysymtab.nindirectsyms = 0; + dysymtab.indirectsymoff = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, @sizeOf(u32), null)); + } + dysymtab.nindirectsyms = nindirectsyms; + log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{ + dysymtab.indirectsymoff, + dysymtab.indirectsymoff + needed_size, + }); + + var buf = try self.base.allocator.alloc(u8, needed_size); + defer self.base.allocator.free(buf); + var stream = std.io.fixedBufferStream(buf); + var writer = stream.writer(); stubs.reserved1 = 0; for (self.extern_lazy_symbols.items()) |_, i| { const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); - mem.writeIntLittle(u32, &buf, symtab_idx); - try self.base.file.?.pwriteAll(&buf, off); - off += @sizeOf(u32); - dysymtab.nindirectsyms += 1; + try writer.writeIntLittle(u32, symtab_idx); } - const base_id = @intCast(u32, self.extern_lazy_symbols.items().len); + const base_id = @intCast(u32, lazy.len); got.reserved1 = base_id; for (self.extern_nonlazy_symbols.items()) |_, i| { const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id); - mem.writeIntLittle(u32, &buf, symtab_idx); - try self.base.file.?.pwriteAll(&buf, off); - off += @sizeOf(u32); - dysymtab.nindirectsyms += 1; + try writer.writeIntLittle(u32, symtab_idx); } - la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, self.extern_nonlazy_symbols.items().len); + la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len); for (self.extern_lazy_symbols.items()) |_, i| { const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); - mem.writeIntLittle(u32, &buf, symtab_idx); - try self.base.file.?.pwriteAll(&buf, off); - off += @sizeOf(u32); - dysymtab.nindirectsyms += 1; + try writer.writeIntLittle(u32, symtab_idx); } + + try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff); + self.load_commands_dirty = true; } fn writeCodeSignaturePadding(self: *MachO) !void { + // TODO figure out how not to rewrite padding every single time. const tracy = trace(@src()); defer tracy.end(); @@ -2693,22 +2712,19 @@ fn writeCodeSignaturePadding(self: *MachO) !void { fileoff, self.page_size, ); - - if (code_sig_cmd.datasize < needed_size) { - code_sig_cmd.dataoff = @intCast(u32, fileoff); - code_sig_cmd.datasize = needed_size; - - // Advance size of __LINKEDIT segment - linkedit_segment.inner.filesize += needed_size; - if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) { - linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size); - } - log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size }); - // Pad out the space. We need to do this to calculate valid hashes for everything in the file - // except for code signature data. - try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1); - self.load_commands_dirty = true; - } + code_sig_cmd.dataoff = @intCast(u32, fileoff); + code_sig_cmd.datasize = needed_size; + + // Advance size of __LINKEDIT segment + linkedit_segment.inner.filesize += needed_size; + if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) { + linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size); + } + log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size }); + // Pad out the space. We need to do this to calculate valid hashes for everything in the file + // except for code signature data. + try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1); + self.load_commands_dirty = true; } fn writeCodeSignature(self: *MachO) !void { diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index fb7488a12c..fc58c1e552 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -1079,7 +1079,8 @@ pub fn commitDeclDebugInfo( const debug_line_sect = &dwarf_segment.sections.items[self.debug_line_section_index.?]; const src_fn = &decl.fn_link.macho; src_fn.len = @intCast(u32, dbg_line_buffer.items.len); - if (self.dbg_line_fn_last) |last| { + if (self.dbg_line_fn_last) |last| blk: { + if (src_fn == last) break :blk; if (src_fn.next) |next| { // Update existing function - non-last item. if (src_fn.off + src_fn.len + min_nop_size > next.off) { @@ -1238,7 +1239,8 @@ fn updateDeclDebugInfoAllocation( const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; const debug_info_sect = &dwarf_segment.sections.items[self.debug_info_section_index.?]; text_block.dbg_info_len = len; - if (self.dbg_info_decl_last) |last| { + if (self.dbg_info_decl_last) |last| blk: { + if (text_block == last) break :blk; if (text_block.dbg_info_next) |next| { // Update existing Decl - non-last item. if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { |
