Skip to content

Commit 5391541

Browse files
committed
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.
1 parent dfcadd2 commit 5391541

File tree

2 files changed

+63
-10
lines changed

2 files changed

+63
-10
lines changed

src/link/MachO/Object.zig

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ mtime: u64,
2424
contents: []align(@alignOf(u64)) const u8,
2525

2626
header: macho.mach_header_64 = undefined,
27-
in_symtab: []align(1) const macho.nlist_64 = undefined,
28-
in_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.
30+
in_symtab: ?[]align(1) const macho.nlist_64 = null,
31+
in_strtab: ?[]const u8 = null,
2932

3033
symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
3134
sections: 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,17 +246,61 @@ 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
249296
// and address within.
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

532581
pub 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

537587
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}!
636686
}
637687

638688
pub 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

643694
pub fn getAtomForSymbol(self: Object, sym_index: u32) ?*Atom {

src/link/MachO/dead_strip.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

0 commit comments

Comments
 (0)