authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-17 16:37:26+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-09-17 18:42:47+02:00
log5391541f11570dc444bfb79e5cf0e89aa872d0b8
treecb52d2a38af4581be8ef16f099e570bd5c538741
parentdfcadd22bb71f1137aae532b78c1785d1c35e894

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.

2 files changed, 63 insertions(+), 10 deletions(-)

src/link/MachO/Object.zig+60-9
......@@ -24,8 +24,11 @@ mtime: u64,
2424contents: []align(@alignOf(u64)) const u8,
2525
2626header: macho.mach_header_64 = undefined,
27in_symtab: []align(1) const macho.nlist_64 = undefined,
28in_strtab: []const u8 = undefined,
27
28/// Symtab and strtab might not exist for empty object files so we use an optional
29/// to signal this.
30in_symtab: ?[]align(1) const macho.nlist_64 = null,
31in_strtab: ?[]const u8 = null,
2932
3033symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
3134sections: std.ArrayListUnmanaged(macho.section_64) = .{},
......@@ -105,7 +108,7 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
105108 self.contents.ptr + symtab.symoff,
106109 )[0..symtab.nsyms];
107110 self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize];
108 try self.symtab.appendUnalignedSlice(allocator, self.in_symtab);
111 try self.symtab.appendUnalignedSlice(allocator, self.in_symtab.?);
109112 },
110113 else => {},
111114 }
......@@ -243,6 +246,50 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
243246
244247 log.debug("splitting object({d}, {s}) into atoms: one-shot mode", .{ object_id, self.name });
245248
249 const in_symtab = self.in_symtab orelse {
250 for (self.sections.items) |sect, id| {
251 if (sect.isDebug()) continue;
252 const match = (try macho_file.getOutputSection(sect)) orelse {
253 log.debug(" unhandled section", .{});
254 continue;
255 };
256 if (sect.size == 0) continue;
257
258 const sect_id = @intCast(u8, id);
259 const sym_index = self.sections_as_symbols.get(sect_id) orelse blk: {
260 const sym_index = @intCast(u32, self.symtab.items.len);
261 try self.symtab.append(gpa, .{
262 .n_strx = 0,
263 .n_type = macho.N_SECT,
264 .n_sect = match + 1,
265 .n_desc = 0,
266 .n_value = sect.addr,
267 });
268 try self.sections_as_symbols.putNoClobber(gpa, sect_id, sym_index);
269 break :blk sym_index;
270 };
271 const code: ?[]const u8 = if (!sect.isZerofill()) try self.getSectionContents(sect) else null;
272 const relocs = @ptrCast(
273 [*]align(1) const macho.relocation_info,
274 self.contents.ptr + sect.reloff,
275 )[0..sect.nreloc];
276 const atom = try self.createAtomFromSubsection(
277 macho_file,
278 object_id,
279 sym_index,
280 sect.size,
281 sect.@"align",
282 code,
283 relocs,
284 &.{},
285 match,
286 sect,
287 );
288 try macho_file.addAtomToSection(atom, match);
289 }
290 return;
291 };
292
246293 // You would expect that the symbol table is at least pre-sorted based on symbol's type:
247294 // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance,
248295 // 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)
250297 const context = Context{
251298 .object = self,
252299 };
253 var sorted_all_syms = try std.ArrayList(SymbolAtIndex).initCapacity(gpa, self.in_symtab.len);
300 var sorted_all_syms = try std.ArrayList(SymbolAtIndex).initCapacity(gpa, in_symtab.len);
254301 defer sorted_all_syms.deinit();
255302
256 for (self.in_symtab) |_, index| {
303 for (in_symtab) |_, index| {
257304 sorted_all_syms.appendAssumeCapacity(.{ .index = @intCast(u32, index) });
258305 }
259306
......@@ -282,6 +329,8 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
282329 const subsections_via_symbols = self.header.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;
283330
284331 for (self.sections.items) |sect, id| {
332 if (sect.isDebug()) continue;
333
285334 const sect_id = @intCast(u8, id);
286335 log.debug("splitting section '{s},{s}' into atoms", .{ sect.segName(), sect.sectName() });
287336
......@@ -530,8 +579,9 @@ fn createAtomFromSubsection(
530579}
531580
532581pub fn getSourceSymbol(self: Object, index: u32) ?macho.nlist_64 {
533 if (index >= self.in_symtab.len) return null;
534 return self.in_symtab[index];
582 const symtab = self.in_symtab.?;
583 if (index >= symtab.len) return null;
584 return symtab[index];
535585}
536586
537587pub fn getSourceSection(self: Object, index: u16) macho.section_64 {
......@@ -636,8 +686,9 @@ pub fn getSectionContents(self: Object, sect: macho.section_64) error{Overflow}!
636686}
637687
638688pub fn getString(self: Object, off: u32) []const u8 {
639 assert(off < self.in_strtab.len);
640 return mem.sliceTo(@ptrCast([*:0]const u8, self.in_strtab.ptr + off), 0);
689 const strtab = self.in_strtab.?;
690 assert(off < strtab.len);
691 return mem.sliceTo(@ptrCast([*:0]const u8, strtab.ptr + off), 0);
641692}
642693
643694pub fn getAtomForSymbol(self: Object, sym_index: u32) ?*Atom {
src/link/MachO/dead_strip.zig+3-1
......@@ -179,7 +179,9 @@ fn prune(arena: Allocator, alive: std.AutoHashMap(*Atom, void), macho_file: *Mac
179179 loop = false;
180180
181181 for (macho_file.objects.items) |object| {
182 for (object.in_symtab) |_, source_index| {
182 const in_symtab = object.in_symtab orelse continue;
183
184 for (in_symtab) |_, source_index| {
183185 const atom = object.getAtomForSymbol(@intCast(u32, source_index)) orelse continue;
184186 if (alive.contains(atom)) continue;
185187