diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-09-17 16:37:26 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2022-09-17 18:42:47 +0200 |
| commit | 5391541f11570dc444bfb79e5cf0e89aa872d0b8 (patch) | |
| tree | cb52d2a38af4581be8ef16f099e570bd5c538741 /src | |
| parent | dfcadd22bb71f1137aae532b78c1785d1c35e894 (diff) | |
| download | zig-5391541f11570dc444bfb79e5cf0e89aa872d0b8.tar.gz zig-5391541f11570dc444bfb79e5cf0e89aa872d0b8.zip | |
macho: do not assume every object has a symtab
For example, building stage2 requires an empty `empty.cc` source file
compiling which generates a valid translation unit with no symtab/strtab.
In this case, we cannot simply assume that every translation unit will
have a valid symtab; instead, we cautiously default the input symtab
and strtab fields to optional `null` to signal symtab's presence or its lack of.
In case the symtab is not present, we catch this fact when splitting
input sections into subsections and create a synthetic symbol per every
suitable section.
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO/Object.zig | 69 | ||||
| -rw-r--r-- | src/link/MachO/dead_strip.zig | 4 |
2 files changed, 63 insertions, 10 deletions
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index d99cfae3b7..b65c9ccfd1 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -24,8 +24,11 @@ mtime: u64, contents: []align(@alignOf(u64)) const u8, header: macho.mach_header_64 = undefined, -in_symtab: []align(1) const macho.nlist_64 = undefined, -in_strtab: []const u8 = undefined, + +/// Symtab and strtab might not exist for empty object files so we use an optional +/// to signal this. +in_symtab: ?[]align(1) const macho.nlist_64 = null, +in_strtab: ?[]const u8 = null, symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, sections: std.ArrayListUnmanaged(macho.section_64) = .{}, @@ -105,7 +108,7 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch) self.contents.ptr + symtab.symoff, )[0..symtab.nsyms]; self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize]; - try self.symtab.appendUnalignedSlice(allocator, self.in_symtab); + try self.symtab.appendUnalignedSlice(allocator, self.in_symtab.?); }, else => {}, } @@ -243,6 +246,50 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) log.debug("splitting object({d}, {s}) into atoms: one-shot mode", .{ object_id, self.name }); + const in_symtab = self.in_symtab orelse { + for (self.sections.items) |sect, id| { + if (sect.isDebug()) continue; + const match = (try macho_file.getOutputSection(sect)) orelse { + log.debug(" unhandled section", .{}); + continue; + }; + if (sect.size == 0) continue; + + const sect_id = @intCast(u8, id); + const sym_index = self.sections_as_symbols.get(sect_id) orelse blk: { + const sym_index = @intCast(u32, self.symtab.items.len); + try self.symtab.append(gpa, .{ + .n_strx = 0, + .n_type = macho.N_SECT, + .n_sect = match + 1, + .n_desc = 0, + .n_value = sect.addr, + }); + try self.sections_as_symbols.putNoClobber(gpa, sect_id, sym_index); + break :blk sym_index; + }; + const code: ?[]const u8 = if (!sect.isZerofill()) try self.getSectionContents(sect) else null; + const relocs = @ptrCast( + [*]align(1) const macho.relocation_info, + self.contents.ptr + sect.reloff, + )[0..sect.nreloc]; + const atom = try self.createAtomFromSubsection( + macho_file, + object_id, + sym_index, + sect.size, + sect.@"align", + code, + relocs, + &.{}, + match, + sect, + ); + try macho_file.addAtomToSection(atom, match); + } + return; + }; + // You would expect that the symbol table is at least pre-sorted based on symbol's type: // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance, // the GO compiler does not necessarily respect that therefore we sort immediately by type @@ -250,10 +297,10 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) const context = Context{ .object = self, }; - var sorted_all_syms = try std.ArrayList(SymbolAtIndex).initCapacity(gpa, self.in_symtab.len); + var sorted_all_syms = try std.ArrayList(SymbolAtIndex).initCapacity(gpa, in_symtab.len); defer sorted_all_syms.deinit(); - for (self.in_symtab) |_, index| { + for (in_symtab) |_, index| { sorted_all_syms.appendAssumeCapacity(.{ .index = @intCast(u32, index) }); } @@ -282,6 +329,8 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32) const subsections_via_symbols = self.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; for (self.sections.items) |sect, id| { + if (sect.isDebug()) continue; + const sect_id = @intCast(u8, id); log.debug("splitting section '{s},{s}' into atoms", .{ sect.segName(), sect.sectName() }); @@ -530,8 +579,9 @@ fn createAtomFromSubsection( } pub fn getSourceSymbol(self: Object, index: u32) ?macho.nlist_64 { - if (index >= self.in_symtab.len) return null; - return self.in_symtab[index]; + const symtab = self.in_symtab.?; + if (index >= symtab.len) return null; + return symtab[index]; } pub fn getSourceSection(self: Object, index: u16) macho.section_64 { @@ -636,8 +686,9 @@ pub fn getSectionContents(self: Object, sect: macho.section_64) error{Overflow}! } pub fn getString(self: Object, off: u32) []const u8 { - assert(off < self.in_strtab.len); - return mem.sliceTo(@ptrCast([*:0]const u8, self.in_strtab.ptr + off), 0); + const strtab = self.in_strtab.?; + assert(off < strtab.len); + return mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + off), 0); } pub fn getAtomForSymbol(self: Object, sym_index: u32) ?*Atom { diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig index c8c4950730..e4ca890bbb 100644 --- a/src/link/MachO/dead_strip.zig +++ b/src/link/MachO/dead_strip.zig @@ -179,7 +179,9 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac loop = false; for (macho_file.objects.items) |object| { - for (object.in_symtab) |_, source_index| { + const in_symtab = object.in_symtab orelse continue; + + for (in_symtab) |_, source_index| { const atom = object.getAtomForSymbol(@intCast(u32, source_index)) orelse continue; if (alive.contains(atom)) continue; |
