diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-07-20 06:41:30 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-07-22 12:06:02 +0200 |
| commit | 2b84592858fe004fcae1372f7a5f97e10a81c2e3 (patch) | |
| tree | f0ebc5be3d85396d423e837b023057f6258a194a /src/link | |
| parent | 5d9fd5bcdeb9f7a1af50b0eaffd22b61f3e440a6 (diff) | |
| download | zig-2b84592858fe004fcae1372f7a5f97e10a81c2e3.tar.gz zig-2b84592858fe004fcae1372f7a5f97e10a81c2e3.zip | |
macho: run more things in parallel
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/MachO.zig | 603 | ||||
| -rw-r--r-- | src/link/MachO/Atom.zig | 65 | ||||
| -rw-r--r-- | src/link/MachO/InternalObject.zig | 16 | ||||
| -rw-r--r-- | src/link/MachO/Object.zig | 24 | ||||
| -rw-r--r-- | src/link/MachO/Symbol.zig | 34 | ||||
| -rw-r--r-- | src/link/MachO/UnwindInfo.zig | 2 | ||||
| -rw-r--r-- | src/link/MachO/ZigObject.zig | 38 | ||||
| -rw-r--r-- | src/link/MachO/dead_strip.zig | 20 | ||||
| -rw-r--r-- | src/link/MachO/dyld_info/Rebase.zig | 2 | ||||
| -rw-r--r-- | src/link/MachO/dyld_info/Trie.zig | 6 | ||||
| -rw-r--r-- | src/link/MachO/dyld_info/bind.zig | 9 | ||||
| -rw-r--r-- | src/link/MachO/file.zig | 20 | ||||
| -rw-r--r-- | src/link/MachO/relocatable.zig | 2 | ||||
| -rw-r--r-- | src/link/MachO/synthetic.zig | 8 | ||||
| -rw-r--r-- | src/link/MachO/thunks.zig | 6 |
15 files changed, 559 insertions, 296 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 29b2e5eb40..3c5b56b394 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -25,8 +25,10 @@ sections: std.MultiArrayList(Section) = .{}, resolver: SymbolResolver = .{}, /// This table will be populated after `scanRelocs` has run. /// Key is symbol index. -undefs: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(Ref)) = .{}, -dupes: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)) = .{}, +undefs: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(Ref)) = .{}, +undefs_mutex: std.Thread.Mutex = .{}, +dupes: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)) = .{}, +dupes_mutex: std.Thread.Mutex = .{}, dyld_info_cmd: macho.dyld_info_command = .{}, symtab_cmd: macho.symtab_command = .{}, @@ -93,9 +95,9 @@ debug_str_sect_index: ?u8 = null, debug_aranges_sect_index: ?u8 = null, debug_line_sect_index: ?u8 = null, -has_tlv: bool = false, -binds_to_weak: bool = false, -weak_defines: bool = false, +has_tlv: AtomicBool = AtomicBool.init(false), +binds_to_weak: AtomicBool = AtomicBool.init(false), +weak_defines: AtomicBool = AtomicBool.init(false), has_errors: AtomicBool = AtomicBool.init(false), /// Options @@ -306,20 +308,15 @@ pub fn deinit(self: *MachO) void { self.sections.deinit(gpa); self.resolver.deinit(gpa); - { - var it = self.undefs.iterator(); - while (it.next()) |entry| { - entry.value_ptr.deinit(gpa); - } - self.undefs.deinit(gpa); + + for (self.undefs.values()) |*val| { + val.deinit(gpa); } - { - var it = self.dupes.iterator(); - while (it.next()) |entry| { - entry.value_ptr.deinit(gpa); - } - self.dupes.deinit(gpa); + self.undefs.deinit(gpa); + for (self.dupes.values()) |*val| { + val.deinit(gpa); } + self.dupes.deinit(gpa); self.symtab.deinit(gpa); self.strtab.deinit(gpa); @@ -553,12 +550,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n else => |e| return e, }; } - self.writeSectionsAndUpdateLinkeditSizes() catch |err| { - switch (err) { - error.ResolveFailed => return error.FlushFailure, - else => |e| return e, - } - }; + try self.writeSectionsAndUpdateLinkeditSizes(); try self.writeSectionsToFile(); try self.allocateLinkeditSegment(); @@ -907,25 +899,25 @@ pub fn parseInputFiles(self: *MachO) !void { defer wg.wait(); for (self.objects.items) |index| { - tp.spawnWg(&wg, parseInputFileWorker, .{ self, index }); + tp.spawnWg(&wg, parseInputFileWorker, .{ self, self.getFile(index).? }); } for (self.dylibs.items) |index| { - tp.spawnWg(&wg, parseInputFileWorker, .{ self, index }); + tp.spawnWg(&wg, parseInputFileWorker, .{ self, self.getFile(index).? }); } } if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure; } -fn parseInputFileWorker(self: *MachO, index: File.Index) void { - self.getFile(index).?.parse(self) catch |err| { +fn parseInputFileWorker(self: *MachO, file: File) void { + file.parse(self) catch |err| { switch (err) { error.MalformedObject, error.MalformedDylib, error.InvalidCpuArch, error.InvalidTarget, => {}, // already reported - else => |e| self.reportParseError2(index, "unexpected error: parsing input file failed with error {s}", .{@errorName(e)}) catch {}, + else => |e| self.reportParseError2(file.getIndex(), "unexpected error: parsing input file failed with error {s}", .{@errorName(e)}) catch {}, } _ = self.has_errors.swap(true, .seq_cst); }; @@ -1286,13 +1278,50 @@ fn markLive(self: *MachO) void { } fn convertTentativeDefsAndResolveSpecialSymbols(self: *MachO) !void { - for (self.objects.items) |index| { - try self.getFile(index).?.object.convertTentativeDefinitions(self); - } - if (self.getInternalObject()) |obj| { - try obj.resolveBoundarySymbols(self); - try obj.resolveObjcMsgSendSymbols(self); + const tp = self.base.comp.thread_pool; + var wg: WaitGroup = .{}; + { + wg.reset(); + defer wg.wait(); + for (self.objects.items) |index| { + tp.spawnWg(&wg, convertTentativeDefinitionsWorker, .{ self, self.getFile(index).?.object }); + } + if (self.getInternalObject()) |obj| { + tp.spawnWg(&wg, resolveSpecialSymbolsWorker, .{ self, obj }); + } } + if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure; +} + +fn convertTentativeDefinitionsWorker(self: *MachO, object: *Object) void { + const tracy = trace(@src()); + defer tracy.end(); + object.convertTentativeDefinitions(self) catch |err| { + self.reportParseError2( + object.index, + "unexpected error occurred while converting tentative symbols into defined symbols: {s}", + .{@errorName(err)}, + ) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; +} + +fn resolveSpecialSymbolsWorker(self: *MachO, obj: *InternalObject) void { + const tracy = trace(@src()); + defer tracy.end(); + obj.resolveBoundarySymbols(self) catch |err| { + self.reportUnexpectedError("unexpected error occurred while resolving boundary symbols: {s}", .{ + @errorName(err), + }) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + return; + }; + obj.resolveObjcMsgSendSymbols(self) catch |err| { + self.reportUnexpectedError("unexpected error occurred while resolving ObjC msgsend stubs: {s}", .{ + @errorName(err), + }) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; } pub fn dedupLiterals(self: *MachO) !void { @@ -1313,14 +1342,20 @@ pub fn dedupLiterals(self: *MachO) !void { try object.resolveLiterals(&lp, self); } - if (self.getZigObject()) |zo| { - zo.dedupLiterals(lp, self); - } - for (self.objects.items) |index| { - self.getFile(index).?.object.dedupLiterals(lp, self); - } - if (self.getInternalObject()) |object| { - object.dedupLiterals(lp, self); + const tp = self.base.comp.thread_pool; + var wg: WaitGroup = .{}; + { + wg.reset(); + defer wg.wait(); + if (self.getZigObject()) |zo| { + tp.spawnWg(&wg, File.dedupLiterals, .{ zo.asFile(), lp, self }); + } + for (self.objects.items) |index| { + tp.spawnWg(&wg, File.dedupLiterals, .{ self.getFile(index).?, lp, self }); + } + if (self.getInternalObject()) |object| { + tp.spawnWg(&wg, File.dedupLiterals, .{ object.asFile(), lp, self }); + } } } @@ -1334,18 +1369,41 @@ fn claimUnresolved(self: *MachO) void { } fn checkDuplicates(self: *MachO) !void { - if (self.getZigObject()) |zo| { - try zo.asFile().checkDuplicates(self); - } - for (self.objects.items) |index| { - try self.getFile(index).?.checkDuplicates(self); - } - if (self.getInternalObject()) |obj| { - try obj.asFile().checkDuplicates(self); + const tracy = trace(@src()); + defer tracy.end(); + + const tp = self.base.comp.thread_pool; + var wg: WaitGroup = .{}; + { + wg.reset(); + defer wg.wait(); + if (self.getZigObject()) |zo| { + tp.spawnWg(&wg, checkDuplicatesWorker, .{ self, zo.asFile() }); + } + for (self.objects.items) |index| { + tp.spawnWg(&wg, checkDuplicatesWorker, .{ self, self.getFile(index).? }); + } + if (self.getInternalObject()) |obj| { + tp.spawnWg(&wg, checkDuplicatesWorker, .{ self, obj.asFile() }); + } } + + if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure; + try self.reportDuplicates(); } +fn checkDuplicatesWorker(self: *MachO, file: File) void { + const tracy = trace(@src()); + defer tracy.end(); + file.checkDuplicates(self) catch |err| { + self.reportParseError2(file.getIndex(), "failed to check for duplicate definitions: {s}", .{ + @errorName(err), + }) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; +} + fn markImportsAndExports(self: *MachO) void { const tracy = trace(@src()); defer tracy.end(); @@ -1384,16 +1442,26 @@ fn scanRelocs(self: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); - if (self.getZigObject()) |zo| { - try zo.scanRelocs(self); - } - for (self.objects.items) |index| { - try self.getFile(index).?.object.scanRelocs(self); - } - if (self.getInternalObject()) |obj| { - obj.scanRelocs(self); + const tp = self.base.comp.thread_pool; + var wg: WaitGroup = .{}; + + { + wg.reset(); + defer wg.wait(); + + if (self.getZigObject()) |zo| { + tp.spawnWg(&wg, scanRelocsWorker, .{ self, zo.asFile() }); + } + for (self.objects.items) |index| { + tp.spawnWg(&wg, scanRelocsWorker, .{ self, self.getFile(index).? }); + } + if (self.getInternalObject()) |obj| { + tp.spawnWg(&wg, scanRelocsWorker, .{ self, obj.asFile() }); + } } + if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure; + try self.reportUndefs(); if (self.getZigObject()) |zo| { @@ -1410,25 +1478,61 @@ fn scanRelocs(self: *MachO) !void { } } +fn scanRelocsWorker(self: *MachO, file: File) void { + file.scanRelocs(self) catch |err| { + self.reportParseError2(file.getIndex(), "failed to scan relocations: {s}", .{ + @errorName(err), + }) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; +} + +fn sortGlobalSymbolsByName(self: *MachO, symbols: []SymbolResolver.Index) void { + const lessThan = struct { + fn lessThan(ctx: *MachO, lhs: SymbolResolver.Index, rhs: SymbolResolver.Index) bool { + const lhs_name = ctx.resolver.keys.items[lhs - 1].getName(ctx); + const rhs_name = ctx.resolver.keys.items[rhs - 1].getName(ctx); + return mem.order(u8, lhs_name, rhs_name) == .lt; + } + }.lessThan; + mem.sort(SymbolResolver.Index, symbols, self, lessThan); +} + fn reportUndefs(self: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); if (self.undefined_treatment == .suppress or self.undefined_treatment == .dynamic_lookup) return; + if (self.undefs.keys().len == 0) return; // Nothing to do + const gpa = self.base.comp.gpa; const max_notes = 4; - var has_undefs = false; - var it = self.undefs.iterator(); - while (it.next()) |entry| { - const undef_sym = self.resolver.keys.items[entry.key_ptr.* - 1]; - const notes = entry.value_ptr.*; + // We will sort by name, and then by file to ensure deterministic output. + var keys = try std.ArrayList(SymbolResolver.Index).initCapacity(gpa, self.undefs.keys().len); + defer keys.deinit(); + keys.appendSliceAssumeCapacity(self.undefs.keys()); + self.sortGlobalSymbolsByName(keys.items); + + const refLessThan = struct { + fn lessThan(ctx: void, lhs: Ref, rhs: Ref) bool { + _ = ctx; + return lhs.lessThan(rhs); + } + }.lessThan; + + for (self.undefs.values()) |*refs| { + mem.sort(Ref, refs.items, {}, refLessThan); + } + + for (keys.items) |key| { + const undef_sym = self.resolver.keys.items[key - 1]; + const notes = self.undefs.get(key).?; const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); var err = try self.base.addErrorWithNotes(nnotes); try err.addMsg("undefined symbol: {s}", .{undef_sym.getName(self)}); - has_undefs = true; var inote: usize = 0; while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { @@ -1443,7 +1547,8 @@ fn reportUndefs(self: *MachO) !void { try err.addNote("referenced {d} more times", .{remaining}); } } - if (has_undefs) return error.HasUndefinedSymbols; + + return error.HasUndefinedSymbols; } fn initOutputSections(self: *MachO) !void { @@ -1679,7 +1784,7 @@ pub fn sortSections(self: *MachO) !void { if (self.getZigObject()) |zo| { for (zo.getAtoms()) |atom_index| { const atom = zo.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; atom.out_n_sect = backlinks[atom.out_n_sect]; } } @@ -1688,7 +1793,7 @@ pub fn sortSections(self: *MachO) !void { const file = self.getFile(index).?; for (file.getAtoms()) |atom_index| { const atom = file.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; atom.out_n_sect = backlinks[atom.out_n_sect]; } } @@ -1696,7 +1801,7 @@ pub fn sortSections(self: *MachO) !void { if (self.getInternalObject()) |object| { for (object.getAtoms()) |atom_index| { const atom = object.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; atom.out_n_sect = backlinks[atom.out_n_sect]; } } @@ -1737,7 +1842,7 @@ pub fn addAtomsToSections(self: *MachO) !void { if (self.getZigObject()) |zo| { for (zo.getAtoms()) |atom_index| { const atom = zo.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; if (self.isZigSection(atom.out_n_sect)) continue; const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; try atoms.append(gpa, .{ .index = atom_index, .file = zo.index }); @@ -1747,7 +1852,7 @@ pub fn addAtomsToSections(self: *MachO) !void { const file = self.getFile(index).?; for (file.getAtoms()) |atom_index| { const atom = file.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; try atoms.append(gpa, .{ .index = atom_index, .file = index }); } @@ -1755,7 +1860,7 @@ pub fn addAtomsToSections(self: *MachO) !void { if (self.getInternalObject()) |object| { for (object.getAtoms()) |atom_index| { const atom = object.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; try atoms.append(gpa, .{ .index = atom_index, .file = object.index }); } @@ -1774,46 +1879,43 @@ fn calcSectionSizes(self: *MachO) !void { header.@"align" = 3; } - const slice = self.sections.slice(); - for (slice.items(.header), slice.items(.atoms)) |*header, atoms| { - if (atoms.items.len == 0) continue; - if (self.requiresThunks() and header.isCode()) continue; - - for (atoms.items) |ref| { - const atom = ref.getAtom(self).?; - const atom_alignment = atom.alignment.toByteUnits() orelse 1; - const offset = mem.alignForward(u64, header.size, atom_alignment); - const padding = offset - header.size; - atom.value = offset; - header.size += padding + atom.size; - header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); - } - } - - if (self.requiresThunks()) { + const tp = self.base.comp.thread_pool; + var wg: WaitGroup = .{}; + { + wg.reset(); + defer wg.wait(); + const slice = self.sections.slice(); for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| { - if (!header.isCode()) continue; if (atoms.items.len == 0) continue; + if (self.requiresThunks() and header.isCode()) continue; + tp.spawnWg(&wg, calcSectionSizeWorker, .{ self, @as(u8, @intCast(i)) }); + } - // Create jump/branch range extenders if needed. - try thunks.createThunks(@intCast(i), self); + if (self.requiresThunks()) { + for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| { + if (!header.isCode()) continue; + if (atoms.items.len == 0) continue; + tp.spawnWg(&wg, createThunksWorker, .{ self, @as(u8, @intCast(i)) }); + } } - } - // At this point, we can also calculate symtab and data-in-code linkedit section sizes - if (self.getZigObject()) |zo| { - zo.asFile().calcSymtabSize(self); - } - for (self.objects.items) |index| { - self.getFile(index).?.calcSymtabSize(self); - } - for (self.dylibs.items) |index| { - self.getFile(index).?.calcSymtabSize(self); - } - if (self.getInternalObject()) |obj| { - obj.asFile().calcSymtabSize(self); + // At this point, we can also calculate symtab and data-in-code linkedit section sizes + if (self.getZigObject()) |zo| { + tp.spawnWg(&wg, File.calcSymtabSize, .{ zo.asFile(), self }); + } + for (self.objects.items) |index| { + tp.spawnWg(&wg, File.calcSymtabSize, .{ self.getFile(index).?, self }); + } + for (self.dylibs.items) |index| { + tp.spawnWg(&wg, File.calcSymtabSize, .{ self.getFile(index).?, self }); + } + if (self.getInternalObject()) |obj| { + tp.spawnWg(&wg, File.calcSymtabSize, .{ obj.asFile(), self }); + } } + if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure; + try self.calcSymtabSize(); if (self.got_sect_index) |idx| { @@ -1861,6 +1963,49 @@ fn calcSectionSizes(self: *MachO) !void { } } +fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void { + const tracy = trace(@src()); + defer tracy.end(); + const doWork = struct { + fn doWork(macho_file: *MachO, header: *macho.section_64, atoms: []const Ref) !void { + for (atoms) |ref| { + const atom = ref.getAtom(macho_file).?; + const atom_alignment = atom.alignment.toByteUnits() orelse 1; + const offset = mem.alignForward(u64, header.size, atom_alignment); + const padding = offset - header.size; + atom.value = offset; + header.size += padding + atom.size; + header.@"align" = @max(header.@"align", atom.alignment.toLog2Units()); + } + } + }.doWork; + const slice = self.sections.slice(); + const header = &slice.items(.header)[sect_id]; + const atoms = slice.items(.atoms)[sect_id].items; + doWork(self, header, atoms) catch |err| { + self.reportUnexpectedError("failed to calculate size of section '{s},{s}': {s}", .{ + header.segName(), + header.sectName(), + @errorName(err), + }) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; +} + +fn createThunksWorker(self: *MachO, sect_id: u8) void { + const tracy = trace(@src()); + defer tracy.end(); + thunks.createThunks(sect_id, self) catch |err| { + const header = self.sections.items(.header)[sect_id]; + self.reportUnexpectedError("failed to create thunks and calculate size of section '{s},{s}': {s}", .{ + header.segName(), + header.sectName(), + @errorName(err), + }) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; +} + fn generateUnwindInfo(self: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); @@ -2249,64 +2394,98 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void { try self.strtab.resize(gpa, cmd.strsize); self.strtab.items[0] = 0; - for (self.objects.items) |index| { - try self.getFile(index).?.writeAtoms(self); - } - if (self.getZigObject()) |zo| { - try zo.writeAtoms(self); - } - if (self.getInternalObject()) |obj| { - try obj.asFile().writeAtoms(self); - } - for (self.thunks.items) |thunk| { - const out = self.sections.items(.out)[thunk.out_n_sect].items; - const off = math.cast(usize, thunk.value) orelse return error.Overflow; - const size = thunk.size(); - var stream = std.io.fixedBufferStream(out[off..][0..size]); - try thunk.write(self, stream.writer()); - } + const tp = self.base.comp.thread_pool; + var wg: WaitGroup = .{}; + { + wg.reset(); + defer wg.wait(); - const slice = self.sections.slice(); - for (&[_]?u8{ - self.eh_frame_sect_index, - self.unwind_info_sect_index, - self.got_sect_index, - self.stubs_sect_index, - self.la_symbol_ptr_sect_index, - self.tlv_ptr_sect_index, - self.objc_stubs_sect_index, - }) |maybe_sect_id| { - if (maybe_sect_id) |sect_id| { - const out = slice.items(.out)[sect_id].items; - try self.writeSyntheticSection(sect_id, out); + for (self.objects.items) |index| { + tp.spawnWg(&wg, writeAtomsWorker, .{ self, self.getFile(index).? }); + } + if (self.getZigObject()) |zo| { + tp.spawnWg(&wg, writeAtomsWorker, .{ self, zo.asFile() }); + } + if (self.getInternalObject()) |obj| { + tp.spawnWg(&wg, writeAtomsWorker, .{ self, obj.asFile() }); + } + for (self.thunks.items) |thunk| { + tp.spawnWg(&wg, writeThunkWorker, .{ self, thunk }); } - } - if (self.la_symbol_ptr_sect_index) |_| { - try self.updateLazyBindSize(); - } + const slice = self.sections.slice(); + for (&[_]?u8{ + self.eh_frame_sect_index, + self.unwind_info_sect_index, + self.got_sect_index, + self.stubs_sect_index, + self.la_symbol_ptr_sect_index, + self.tlv_ptr_sect_index, + self.objc_stubs_sect_index, + }) |maybe_sect_id| { + if (maybe_sect_id) |sect_id| { + const out = slice.items(.out)[sect_id].items; + tp.spawnWg(&wg, writeSyntheticSectionWorker, .{ self, sect_id, out }); + } + } - try self.rebase.updateSize(self); - try self.bind.updateSize(self); - try self.weak_bind.updateSize(self); - try self.export_trie.updateSize(self); - try self.data_in_code.updateSize(self); + if (self.la_symbol_ptr_sect_index) |_| { + tp.spawnWg(&wg, updateLazyBindSizeWorker, .{self}); + } - if (self.getZigObject()) |zo| { - zo.asFile().writeSymtab(self, self); - } - for (self.objects.items) |index| { - self.getFile(index).?.writeSymtab(self, self); - } - for (self.dylibs.items) |index| { - self.getFile(index).?.writeSymtab(self, self); - } - if (self.getInternalObject()) |obj| { - obj.asFile().writeSymtab(self, self); + tp.spawnWg(&wg, updateLinkeditSizeWorker, .{ self, .rebase }); + tp.spawnWg(&wg, updateLinkeditSizeWorker, .{ self, .bind }); + tp.spawnWg(&wg, updateLinkeditSizeWorker, .{ self, .weak_bind }); + tp.spawnWg(&wg, updateLinkeditSizeWorker, .{ self, .export_trie }); + tp.spawnWg(&wg, updateLinkeditSizeWorker, .{ self, .data_in_code }); + + if (self.getZigObject()) |zo| { + tp.spawnWg(&wg, File.writeSymtab, .{ zo.asFile(), self, self }); + } + for (self.objects.items) |index| { + tp.spawnWg(&wg, File.writeSymtab, .{ self.getFile(index).?, self, self }); + } + for (self.dylibs.items) |index| { + tp.spawnWg(&wg, File.writeSymtab, .{ self.getFile(index).?, self, self }); + } + if (self.getInternalObject()) |obj| { + tp.spawnWg(&wg, File.writeSymtab, .{ obj.asFile(), self, self }); + } } + + if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure; +} + +fn writeAtomsWorker(self: *MachO, file: File) void { + const tracy = trace(@src()); + defer tracy.end(); + file.writeAtoms(self) catch |err| { + self.reportParseError2(file.getIndex(), "failed to resolve relocations and write atoms: {s}", .{ + @errorName(err), + }) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; } -fn writeSyntheticSection(self: *MachO, sect_id: u8, out: []u8) !void { +fn writeThunkWorker(self: *MachO, thunk: Thunk) void { + const tracy = trace(@src()); + defer tracy.end(); + const doWork = struct { + fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void { + const off = th.value; + const size = th.size(); + var stream = std.io.fixedBufferStream(buffer[off..][0..size]); + try th.write(macho_file, stream.writer()); + } + }.doWork; + const out = self.sections.items(.out)[thunk.out_n_sect].items; + doWork(thunk, out, self) catch |err| { + self.reportUnexpectedError("failed to write contents of thunk: {s}", .{@errorName(err)}) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; +} + +fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void { const tracy = trace(@src()); defer tracy.end(); @@ -2320,6 +2499,22 @@ fn writeSyntheticSection(self: *MachO, sect_id: u8, out: []u8) !void { objc_stubs, }; + const doWork = struct { + fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void { + var stream = std.io.fixedBufferStream(buffer); + switch (tag) { + .eh_frame => eh_frame.write(macho_file, buffer), + .unwind_info => try macho_file.unwind_info.write(macho_file, buffer), + .got => try macho_file.got.write(macho_file, stream.writer()), + .stubs => try macho_file.stubs.write(macho_file, stream.writer()), + .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, stream.writer()), + .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, stream.writer()), + .objc_stubs => try macho_file.objc_stubs.write(macho_file, stream.writer()), + } + } + }.doWork; + + const header = self.sections.items(.header)[sect_id]; const tag: Tag = tag: { if (self.eh_frame_sect_index != null and self.eh_frame_sect_index.? == sect_id) break :tag .eh_frame; @@ -2337,26 +2532,57 @@ fn writeSyntheticSection(self: *MachO, sect_id: u8, out: []u8) !void { self.objc_stubs_sect_index.? == sect_id) break :tag .objc_stubs; unreachable; }; - var stream = std.io.fixedBufferStream(out); - switch (tag) { - .eh_frame => eh_frame.write(self, out), - .unwind_info => try self.unwind_info.write(self, out), - .got => try self.got.write(self, stream.writer()), - .stubs => try self.stubs.write(self, stream.writer()), - .la_symbol_ptr => try self.la_symbol_ptr.write(self, stream.writer()), - .tlv_ptr => try self.tlv_ptr.write(self, stream.writer()), - .objc_stubs => try self.objc_stubs.write(self, stream.writer()), - } + doWork(self, tag, out) catch |err| { + self.reportUnexpectedError("could not write section '{s},{s}': {s}", .{ + header.segName(), + header.sectName(), + @errorName(err), + }) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; } -fn updateLazyBindSize(self: *MachO) !void { +fn updateLazyBindSizeWorker(self: *MachO) void { const tracy = trace(@src()); defer tracy.end(); - try self.lazy_bind.updateSize(self); - const sect_id = self.stubs_helper_sect_index.?; - const out = &self.sections.items(.out)[sect_id]; - var stream = std.io.fixedBufferStream(out.items); - try self.stubs_helper.write(self, stream.writer()); + const doWork = struct { + fn doWork(macho_file: *MachO) !void { + try macho_file.lazy_bind.updateSize(macho_file); + const sect_id = macho_file.stubs_helper_sect_index.?; + const out = &macho_file.sections.items(.out)[sect_id]; + var stream = std.io.fixedBufferStream(out.items); + try macho_file.stubs_helper.write(macho_file, stream.writer()); + } + }.doWork; + doWork(self) catch |err| { + self.reportUnexpectedError("could not calculate size of lazy binding section: {s}", .{ + @errorName(err), + }) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; +} + +pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum { + rebase, + bind, + weak_bind, + export_trie, + data_in_code, +}) void { + const res = switch (tag) { + .rebase => self.rebase.updateSize(self), + .bind => self.bind.updateSize(self), + .weak_bind => self.weak_bind.updateSize(self), + .export_trie => self.export_trie.updateSize(self), + .data_in_code => self.data_in_code.updateSize(self), + }; + res catch |err| { + self.reportUnexpectedError("could not calculate size of {s} section: {s}", .{ + @tagName(tag), + @errorName(err), + }) catch {}; + _ = self.has_errors.swap(true, .seq_cst); + }; } fn writeSectionsToFile(self: *MachO) !void { @@ -2684,13 +2910,13 @@ fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void { header.flags |= macho.MH_NO_REEXPORTED_DYLIBS; } - if (self.has_tlv) { + if (self.has_tlv.load(.seq_cst)) { header.flags |= macho.MH_HAS_TLV_DESCRIPTORS; } - if (self.binds_to_weak) { + if (self.binds_to_weak.load(.seq_cst)) { header.flags |= macho.MH_BINDS_TO_WEAK; } - if (self.weak_defines) { + if (self.weak_defines.load(.seq_cst)) { header.flags |= macho.MH_WEAK_DEFINES; } @@ -3586,19 +3812,29 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void { const tracy = trace(@src()); defer tracy.end(); + if (self.dupes.keys().len == 0) return; // Nothing to do + + const gpa = self.base.comp.gpa; const max_notes = 3; - var has_dupes = false; - var it = self.dupes.iterator(); - while (it.next()) |entry| { - const sym = self.resolver.keys.items[entry.key_ptr.* - 1]; - const notes = entry.value_ptr.*; + // We will sort by name, and then by file to ensure deterministic output. + var keys = try std.ArrayList(SymbolResolver.Index).initCapacity(gpa, self.dupes.keys().len); + defer keys.deinit(); + keys.appendSliceAssumeCapacity(self.dupes.keys()); + self.sortGlobalSymbolsByName(keys.items); + + for (self.dupes.values()) |*refs| { + mem.sort(File.Index, refs.items, {}, std.sort.asc(File.Index)); + } + + for (keys.items) |key| { + const sym = self.resolver.keys.items[key - 1]; + const notes = self.dupes.get(key).?; const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); var err = try self.base.addErrorWithNotes(nnotes + 1); try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)}); try err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()}); - has_dupes = true; var inote: usize = 0; while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { @@ -3611,7 +3847,7 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void { try err.addNote("defined {d} more times", .{remaining}); } } - if (has_dupes) return error.HasDuplicates; + return error.HasDuplicates; } pub fn getDebugSymbols(self: *MachO) ?*DebugSymbols { @@ -4210,6 +4446,13 @@ pub const Ref = struct { return ref.index == other.index and ref.file == other.file; } + pub fn lessThan(ref: Ref, other: Ref) bool { + if (ref.file == other.file) { + return ref.index < other.index; + } + return ref.file < other.file; + } + pub fn getFile(ref: Ref, macho_file: *MachO) ?File { return macho_file.getFile(ref.file); } diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 64cdd46281..579e3e7513 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -26,7 +26,11 @@ off: u64 = 0, /// Index of this atom in the linker's atoms table. atom_index: Index = 0, -flags: Flags = .{}, +/// Specifies whether this atom is alive or has been garbage collected. +alive: AtomicBool = AtomicBool.init(true), + +/// Specifies if this atom has been visited during garbage collection. +visited: AtomicBool = AtomicBool.init(false), /// Points to the previous and next neighbors, based on the `text_offset`. /// This can be used to find, for example, the capacity of this `TextBlock`. @@ -98,6 +102,14 @@ pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void { } } +pub fn isAlive(self: Atom) bool { + return self.alive.load(.seq_cst); +} + +pub fn setAlive(self: *Atom, alive: bool) void { + _ = self.alive.swap(alive, .seq_cst); +} + pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk { const extra = self.getExtra(macho_file); return macho_file.getThunk(extra.thunk); @@ -350,7 +362,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void { _ = free_list.swapRemove(i); } - self.flags.alive = true; + self.setAlive(true); } pub fn shrink(self: *Atom, macho_file: *MachO) void { @@ -444,7 +456,7 @@ pub fn freeRelocs(self: *Atom, macho_file: *MachO) void { pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); - assert(self.flags.alive); + assert(self.isAlive()); const relocs = self.getRelocs(macho_file); @@ -455,12 +467,12 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { .branch => { const symbol = rel.getTargetSymbol(self, macho_file); if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) { - symbol.flags.stubs = true; + symbol.setSectionFlags(.{ .stubs = true }); if (symbol.flags.weak) { - macho_file.binds_to_weak = true; + macho_file.binds_to_weak.store(true, .seq_cst); } } else if (mem.startsWith(u8, symbol.getName(macho_file), "_objc_msgSend$")) { - symbol.flags.objc_stubs = true; + symbol.setSectionFlags(.{ .objc_stubs = true }); } }, @@ -474,19 +486,19 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { symbol.flags.interposable or macho_file.getTarget().cpu.arch == .aarch64) // TODO relax on arm64 { - symbol.flags.needs_got = true; + symbol.setSectionFlags(.{ .needs_got = true }); if (symbol.flags.weak) { - macho_file.binds_to_weak = true; + macho_file.binds_to_weak.store(true, .seq_cst); } } }, .zig_got_load => { - assert(rel.getTargetSymbol(self, macho_file).flags.has_zig_got); + assert(rel.getTargetSymbol(self, macho_file).getSectionFlags().has_zig_got); }, .got => { - rel.getTargetSymbol(self, macho_file).flags.needs_got = true; + rel.getTargetSymbol(self, macho_file).setSectionFlags(.{ .needs_got = true }); }, .tlv, @@ -502,9 +514,9 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { ); } if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) { - symbol.flags.tlv_ptr = true; + symbol.setSectionFlags(.{ .tlv_ptr = true }); if (symbol.flags.weak) { - macho_file.binds_to_weak = true; + macho_file.binds_to_weak.store(true, .seq_cst); } } }, @@ -514,17 +526,17 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { if (rel.tag == .@"extern") { const symbol = rel.getTargetSymbol(self, macho_file); if (symbol.isTlvInit(macho_file)) { - macho_file.has_tlv = true; + macho_file.has_tlv.store(true, .seq_cst); continue; } if (symbol.flags.import) { if (symbol.flags.weak) { - macho_file.binds_to_weak = true; + macho_file.binds_to_weak.store(true, .seq_cst); } continue; } if (symbol.flags.@"export" and symbol.flags.weak) { - macho_file.binds_to_weak = true; + macho_file.binds_to_weak.store(true, .seq_cst); } } } @@ -548,6 +560,8 @@ fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool { const file = self.getFile(macho_file); const ref = file.getSymbolRef(rel.target, macho_file); if (ref.getFile(macho_file) == null) { + macho_file.undefs_mutex.lock(); + defer macho_file.undefs_mutex.unlock(); const gpa = macho_file.base.comp.gpa; const gop = try macho_file.undefs.getOrPut(gpa, file.getGlobals()[rel.target]); if (!gop.found_existing) { @@ -724,7 +738,7 @@ fn resolveRelocInner( assert(rel.tag == .@"extern"); assert(rel.meta.length == 2); assert(rel.meta.pcrel); - if (rel.getTargetSymbol(self, macho_file).flags.has_got) { + if (rel.getTargetSymbol(self, macho_file).getSectionFlags().has_got) { try writer.writeInt(i32, @intCast(G + A - P), .little); } else { try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file); @@ -748,7 +762,7 @@ fn resolveRelocInner( assert(rel.meta.length == 2); assert(rel.meta.pcrel); const sym = rel.getTargetSymbol(self, macho_file); - if (sym.flags.tlv_ptr) { + if (sym.getSectionFlags().tlv_ptr) { const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); try writer.writeInt(i32, @intCast(S_ + A - P), .little); } else { @@ -776,7 +790,7 @@ fn resolveRelocInner( const target = switch (rel.type) { .page => S + A, .got_load_page => G + A, - .tlvp_page => if (sym.flags.tlv_ptr) blk: { + .tlvp_page => if (sym.getSectionFlags().tlv_ptr) blk: { const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); break :blk S_ + A; } else S + A, @@ -831,7 +845,7 @@ fn resolveRelocInner( const sym = rel.getTargetSymbol(self, macho_file); const target = target: { - const target = if (sym.flags.tlv_ptr) blk: { + const target = if (sym.getSectionFlags().tlv_ptr) blk: { const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); break :blk S_ + A; } else S + A; @@ -869,7 +883,7 @@ fn resolveRelocInner( } }; - var inst = if (sym.flags.tlv_ptr) aarch64.Instruction{ + var inst = if (sym.getSectionFlags().tlv_ptr) aarch64.Instruction{ .load_store_register = .{ .rt = reg_info.rd, .rn = reg_info.rn, @@ -1142,7 +1156,7 @@ fn format2( atom.out_n_sect, atom.alignment, atom.size, atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk, }); - if (!atom.flags.alive) try writer.writeAll(" : [*]"); + if (!atom.isAlive()) try writer.writeAll(" : [*]"); if (atom.getUnwindRecords(macho_file).len > 0) { try writer.writeAll(" : unwind{ "); const extra = atom.getExtra(macho_file); @@ -1158,14 +1172,6 @@ fn format2( pub const Index = u32; -pub const Flags = packed struct { - /// Specifies whether this atom is alive or has been garbage collected. - alive: bool = true, - - /// Specifies if this atom has been visited during garbage collection. - visited: bool = false, -}; - pub const Extra = struct { /// Index of the range extension thunk of this atom. thunk: u32 = 0, @@ -1209,6 +1215,7 @@ const trace = @import("../../tracy.zig").trace; const Allocator = mem.Allocator; const Atom = @This(); +const AtomicBool = std.atomic.Value(bool); const File = @import("file.zig").File; const MachO = @import("../MachO.zig"); const Object = @import("Object.zig"); diff --git a/src/link/MachO/InternalObject.zig b/src/link/MachO/InternalObject.zig index ca6a53e983..004997145e 100644 --- a/src/link/MachO/InternalObject.zig +++ b/src/link/MachO/InternalObject.zig @@ -389,7 +389,7 @@ pub fn resolveObjcMsgSendSymbols(self: *InternalObject, macho_file: *MachO) !voi }; sym.nlist_idx = nlist_idx; sym.extra = try self.addSymbolExtra(gpa, .{ .objc_selrefs = selrefs_index }); - sym.flags.objc_stubs = true; + sym.setSectionFlags(.{ .objc_stubs = true }); const idx = ref.getFile(macho_file).?.object.globals.items[ref.index]; try self.globals.append(gpa, idx); @@ -427,7 +427,7 @@ pub fn resolveLiterals(self: *InternalObject, lp: *MachO.LiteralPool, macho_file const lp_sym = lp.getSymbol(res.index, macho_file); const lp_atom = lp_sym.getAtom(macho_file).?; lp_atom.alignment = lp_atom.alignment.max(atom.alignment); - atom.flags.alive = false; + atom.setAlive(false); } atom.addExtra(.{ .literal_pool_index = res.index }, macho_file); } @@ -439,7 +439,7 @@ pub fn dedupLiterals(self: *InternalObject, lp: MachO.LiteralPool, macho_file: * for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const relocs = blk: { const extra = atom.getExtra(macho_file); @@ -464,7 +464,7 @@ pub fn dedupLiterals(self: *InternalObject, lp: MachO.LiteralPool, macho_file: * } for (self.symbols.items) |*sym| { - if (!sym.flags.objc_stubs) continue; + if (!sym.getSectionFlags().objc_stubs) continue; const extra = sym.getExtra(macho_file); const file = sym.getFile(macho_file).?; if (file.getIndex() != self.index) continue; @@ -490,20 +490,20 @@ pub fn scanRelocs(self: *InternalObject, macho_file: *MachO) void { if (self.getEntryRef(macho_file)) |ref| { if (ref.getFile(macho_file) != null) { const sym = ref.getSymbol(macho_file).?; - if (sym.flags.import) sym.flags.stubs = true; + if (sym.flags.import) sym.setSectionFlags(.{ .stubs = true }); } } if (self.getDyldStubBinderRef(macho_file)) |ref| { if (ref.getFile(macho_file) != null) { const sym = ref.getSymbol(macho_file).?; - sym.flags.needs_got = true; + sym.setSectionFlags(.{ .needs_got = true }); } } if (self.getObjcMsgSendRef(macho_file)) |ref| { if (ref.getFile(macho_file) != null) { const sym = ref.getSymbol(macho_file).?; // TODO is it always needed, or only if we are synthesising fast stubs - sym.flags.needs_got = true; + sym.setSectionFlags(.{ .needs_got = true }); } } } @@ -570,7 +570,7 @@ pub fn writeAtoms(self: *InternalObject, macho_file: *MachO) !void { for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const sect = atom.getInputSection(macho_file); if (sect.isZerofill()) continue; const off = std.math.cast(usize, atom.value) orelse return error.Overflow; diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 6e7af207fd..47bee7befe 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -263,7 +263,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { mem.eql(u8, isec.sectName(), "__compact_unwind") or isec.attrs() & macho.S_ATTR_DEBUG != 0) { - atom.flags.alive = false; + atom.setAlive(false); } } @@ -645,7 +645,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO const lp_sym = lp.getSymbol(res.index, macho_file); const lp_atom = lp_sym.getAtom(macho_file).?; lp_atom.alignment = lp_atom.alignment.max(atom.alignment); - atom.flags.alive = false; + atom.setAlive(false); } atom.addExtra(.{ .literal_pool_index = res.index }, macho_file); } @@ -683,7 +683,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO const lp_sym = lp.getSymbol(res.index, macho_file); const lp_atom = lp_sym.getAtom(macho_file).?; lp_atom.alignment = lp_atom.alignment.max(atom.alignment); - atom.flags.alive = false; + atom.setAlive(false); } atom.addExtra(.{ .literal_pool_index = res.index }, macho_file); } @@ -697,7 +697,7 @@ pub fn dedupLiterals(self: *Object, lp: MachO.LiteralPool, macho_file: *MachO) v for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const relocs = blk: { const extra = atom.getExtra(macho_file); @@ -990,7 +990,7 @@ fn initRelocs(self: *Object, file: File.Handle, cpu_arch: std.Target.Cpu.Arch, m var next_reloc: u32 = 0; for (subsections.items) |subsection| { const atom = self.getAtom(subsection.atom).?; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; if (next_reloc >= relocs.items.len) break; const end_addr = atom.off + atom.size; const rel_index = next_reloc; @@ -1483,7 +1483,7 @@ pub fn resolveSymbols(self: *Object, macho_file: *MachO) !void { if (!nlist.ext()) continue; if (nlist.sect()) { const atom = self.getAtom(atom_index).?; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; } const gop = try macho_file.resolver.getOrPut(gpa, .{ @@ -1552,7 +1552,7 @@ pub fn scanRelocs(self: *Object, macho_file: *MachO) !void { for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const sect = atom.getInputSection(macho_file); if (sect.isZerofill()) continue; try atom.scanRelocs(macho_file); @@ -1563,10 +1563,10 @@ pub fn scanRelocs(self: *Object, macho_file: *MachO) !void { if (!rec.alive) continue; if (rec.getFde(macho_file)) |fde| { if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| { - sym.flags.needs_got = true; + sym.setSectionFlags(.{ .needs_got = true }); } } else if (rec.getPersonality(macho_file)) |sym| { - sym.flags.needs_got = true; + sym.setSectionFlags(.{ .needs_got = true }); } } } @@ -1745,7 +1745,7 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void { const ref = self.getSymbolRef(@intCast(i), macho_file); const file = ref.getFile(macho_file) orelse continue; if (file.getIndex() != self.index) continue; - if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue; + if (sym.getAtom(macho_file)) |atom| if (!atom.isAlive()) continue; if (sym.isSymbolStab(macho_file)) continue; const name = sym.getName(macho_file); if (name.len == 0) continue; @@ -1854,7 +1854,7 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void { } for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const sect = atom.getInputSection(macho_file); if (sect.isZerofill()) continue; const value = math.cast(usize, atom.value) orelse return error.Overflow; @@ -1893,7 +1893,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void { } for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const sect = atom.getInputSection(macho_file); if (sect.isZerofill()) continue; const value = math.cast(usize, atom.value) orelse return error.Overflow; diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 72cd55bf5a..99f49f1112 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -23,6 +23,8 @@ nlist_idx: u32 = 0, /// Misc flags for the symbol packaged as packed struct for compression. flags: Flags = .{}, +sect_flags: std.atomic.Value(u8) = std.atomic.Value(u8).init(0), + visibility: Visibility = .local, extra: u32 = 0, @@ -69,6 +71,14 @@ pub fn getOutputSectionIndex(symbol: Symbol, macho_file: *MachO) u8 { return symbol.out_n_sect; } +pub fn getSectionFlags(symbol: Symbol) SectionFlags { + return @bitCast(symbol.sect_flags.load(.seq_cst)); +} + +pub fn setSectionFlags(symbol: *Symbol, flags: SectionFlags) void { + _ = symbol.sect_flags.fetchOr(@bitCast(flags), .seq_cst); +} + pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File { return macho_file.getFile(symbol.file); } @@ -116,9 +126,9 @@ pub fn getAddress(symbol: Symbol, opts: struct { stubs: bool = true, }, macho_file: *MachO) u64 { if (opts.stubs) { - if (symbol.flags.stubs) { + if (symbol.getSectionFlags().stubs) { return symbol.getStubsAddress(macho_file); - } else if (symbol.flags.objc_stubs) { + } else if (symbol.getSectionFlags().objc_stubs) { return symbol.getObjcStubsAddress(macho_file); } } @@ -127,25 +137,25 @@ pub fn getAddress(symbol: Symbol, opts: struct { } pub fn getGotAddress(symbol: Symbol, macho_file: *MachO) u64 { - if (!symbol.flags.has_got) return 0; + if (!symbol.getSectionFlags().has_got) return 0; const extra = symbol.getExtra(macho_file); return macho_file.got.getAddress(extra.got, macho_file); } pub fn getStubsAddress(symbol: Symbol, macho_file: *MachO) u64 { - if (!symbol.flags.stubs) return 0; + if (!symbol.getSectionFlags().stubs) return 0; const extra = symbol.getExtra(macho_file); return macho_file.stubs.getAddress(extra.stubs, macho_file); } pub fn getObjcStubsAddress(symbol: Symbol, macho_file: *MachO) u64 { - if (!symbol.flags.objc_stubs) return 0; + if (!symbol.getSectionFlags().objc_stubs) return 0; const extra = symbol.getExtra(macho_file); return macho_file.objc_stubs.getAddress(extra.objc_stubs, macho_file); } pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 { - if (!symbol.flags.objc_stubs) return 0; + if (!symbol.getSectionFlags().objc_stubs) return 0; const extra = symbol.getExtra(macho_file); const file = symbol.getFile(macho_file).?; return switch (file) { @@ -155,7 +165,7 @@ pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 { } pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 { - if (!symbol.flags.tlv_ptr) return 0; + if (!symbol.getSectionFlags().tlv_ptr) return 0; const extra = symbol.getExtra(macho_file); return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file); } @@ -167,14 +177,14 @@ const GetOrCreateZigGotEntryResult = struct { pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult { assert(!macho_file.base.isRelocatable()); - assert(symbol.flags.needs_zig_got); - if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).zig_got }; + assert(symbol.getSectionFlags().needs_zig_got); + if (symbol.getSectionFlags().has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).zig_got }; const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file); return .{ .found_existing = false, .index = index }; } pub fn getZigGotAddress(symbol: Symbol, macho_file: *MachO) u64 { - if (!symbol.flags.has_zig_got) return 0; + if (!symbol.getSectionFlags().has_zig_got) return 0; const extras = symbol.getExtra(macho_file); return macho_file.zig_got.entryAddress(extras.zig_got, macho_file); } @@ -384,7 +394,9 @@ pub const Flags = packed struct { /// Whether the symbol makes into the output symtab or not. output_symtab: bool = false, +}; +pub const SectionFlags = packed struct(u8) { /// Whether the symbol contains __got indirection. needs_got: bool = false, has_got: bool = false, @@ -401,6 +413,8 @@ pub const Flags = packed struct { /// Whether the symbol contains __objc_stubs indirection. objc_stubs: bool = false, + + _: u1 = 0, }; pub const Visibility = enum { diff --git a/src/link/MachO/UnwindInfo.zig b/src/link/MachO/UnwindInfo.zig index 8fb4b2ce63..42172b8518 100644 --- a/src/link/MachO/UnwindInfo.zig +++ b/src/link/MachO/UnwindInfo.zig @@ -53,7 +53,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { for (macho_file.sections.items(.atoms)) |atoms| { for (atoms.items) |ref| { const atom = ref.getAtom(macho_file) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const recs = atom.getUnwindRecords(macho_file); const file = atom.getFile(macho_file); try info.records.ensureUnusedCapacity(gpa, recs.len); diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index f8ec5171f4..c18af2d35b 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -245,7 +245,7 @@ pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) !void { if (!nlist.ext()) continue; if (nlist.sect()) { const atom = self.getAtom(atom_index).?; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; } const gop = try macho_file.resolver.getOrPut(gpa, .{ @@ -391,7 +391,7 @@ pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void { pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void { for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const sect = atom.getInputSection(macho_file); if (sect.isZerofill()) continue; try atom.scanRelocs(macho_file); @@ -403,7 +403,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void { var has_error = false; for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const sect = &macho_file.sections.items(.header)[atom.out_n_sect]; if (sect.isZerofill()) continue; if (!macho_file.isZigSection(atom.out_n_sect)) continue; // Non-Zig sections are handled separately @@ -450,7 +450,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void { pub fn calcNumRelocs(self: *ZigObject, macho_file: *MachO) void { for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const header = &macho_file.sections.items(.header)[atom.out_n_sect]; if (header.isZerofill()) continue; if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue; @@ -465,7 +465,7 @@ pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void { for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const header = macho_file.sections.items(.header)[atom.out_n_sect]; const relocs = macho_file.sections.items(.relocs)[atom.out_n_sect].items; if (header.isZerofill()) continue; @@ -505,7 +505,7 @@ pub fn writeAtomsRelocatable(self: *ZigObject, macho_file: *MachO) !void { for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const sect = atom.getInputSection(macho_file); if (sect.isZerofill()) continue; if (macho_file.isZigSection(atom.out_n_sect)) continue; @@ -529,7 +529,7 @@ pub fn writeAtoms(self: *ZigObject, macho_file: *MachO) !void { for (self.getAtoms()) |atom_index| { const atom = self.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; const sect = atom.getInputSection(macho_file); if (sect.isZerofill()) continue; if (macho_file.isZigSection(atom.out_n_sect)) continue; @@ -549,7 +549,7 @@ pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) void { const ref = self.getSymbolRef(@intCast(i), macho_file); const file = ref.getFile(macho_file) orelse continue; if (file.getIndex() != self.index) continue; - if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue; + if (sym.getAtom(macho_file)) |atom| if (!atom.isAlive()) continue; sym.flags.output_symtab = true; if (sym.isLocal()) { sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file); @@ -914,7 +914,7 @@ pub fn updateDecl( const lib_name = variable.lib_name.toSlice(&mod.intern_pool); const index = try self.getGlobalSymbol(macho_file, name, lib_name); const sym = &self.symbols.items[index]; - sym.flags.needs_got = true; + sym.setSectionFlags(.{ .needs_got = true }); return; } @@ -993,7 +993,7 @@ fn updateDeclCode( const sym_name = try std.fmt.allocPrintZ(gpa, "_{s}", .{decl.fqn.toSlice(ip)}); defer gpa.free(sym_name); sym.name = try self.strtab.insert(gpa, sym_name); - atom.flags.alive = true; + atom.setAlive(true); atom.name = sym.name; nlist.n_strx = sym.name; nlist.n_type = macho.N_SECT; @@ -1018,7 +1018,7 @@ fn updateDeclCode( if (!macho_file.base.isRelocatable()) { log.debug(" (updating offset table entry)", .{}); - assert(sym.flags.has_zig_got); + assert(sym.getSectionFlags().has_zig_got); const extra = sym.getExtra(macho_file); try macho_file.zig_got.writeOne(macho_file, extra.zig_got); } @@ -1034,7 +1034,7 @@ fn updateDeclCode( errdefer self.freeDeclMetadata(macho_file, sym_index); sym.value = 0; - sym.flags.needs_zig_got = true; + sym.setSectionFlags(.{ .needs_zig_got = true }); nlist.n_value = 0; if (!macho_file.base.isRelocatable()) { @@ -1098,7 +1098,7 @@ fn createTlvInitializer( const atom = sym.getAtom(macho_file).?; sym.out_n_sect = sect_index; atom.out_n_sect = sect_index; - atom.flags.alive = true; + atom.setAlive(true); atom.alignment = alignment; atom.size = code.len; nlist.n_sect = sect_index + 1; @@ -1143,7 +1143,7 @@ fn createTlvDescriptor( sym.value = 0; sym.name = try self.strtab.insert(gpa, name); - atom.flags.alive = true; + atom.setAlive(true); atom.name = sym.name; nlist.n_strx = sym.name; nlist.n_sect = sect_index + 1; @@ -1317,7 +1317,7 @@ fn lowerConst( self.symtab.items(.size)[sym.nlist_idx] = code.len; const atom = sym.getAtom(macho_file).?; - atom.flags.alive = true; + atom.setAlive(true); atom.alignment = required_alignment; atom.size = code.len; atom.out_n_sect = output_section_index; @@ -1490,7 +1490,7 @@ fn updateLazySymbol( self.symtab.items(.size)[sym.nlist_idx] = code.len; const atom = sym.getAtom(macho_file).?; - atom.flags.alive = true; + atom.setAlive(true); atom.name = name_str_index; atom.alignment = required_alignment; atom.size = code.len; @@ -1500,7 +1500,7 @@ fn updateLazySymbol( errdefer self.freeDeclMetadata(macho_file, symbol_index); sym.value = 0; - sym.flags.needs_zig_got = true; + sym.setSectionFlags(.{ .needs_zig_got = true }); nlist.n_value = 0; if (!macho_file.base.isRelocatable()) { @@ -1576,7 +1576,7 @@ pub fn getOrCreateMetadataForDecl( if (isThreadlocal(macho_file, decl_index)) { sym.flags.tlv = true; } else { - sym.flags.needs_zig_got = true; + sym.setSectionFlags(.{ .needs_zig_got = true }); } gop.value_ptr.* = .{ .symbol_index = sym_index }; } @@ -1611,7 +1611,7 @@ pub fn getOrCreateMetadataForLazySymbol( .unused => { const symbol_index = try self.newSymbolWithAtom(gpa, 0, macho_file); const sym = &self.symbols.items[symbol_index]; - sym.flags.needs_zig_got = true; + sym.setSectionFlags(.{ .needs_zig_got = true }); metadata.symbol_index.* = symbol_index; }, .pending_flush => return metadata.symbol_index.*, diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig index eb27109a82..30f53d3744 100644 --- a/src/link/MachO/dead_strip.zig +++ b/src/link/MachO/dead_strip.zig @@ -82,9 +82,8 @@ fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), macho_file: *MachO) !v } fn markAtom(atom: *Atom) bool { - const already_visited = atom.flags.visited; - atom.flags.visited = true; - return atom.flags.alive and !already_visited; + const already_visited = atom.visited.swap(true, .seq_cst); + return atom.isAlive() and !already_visited; } fn mark(roots: []*Atom, objects: []const File.Index, macho_file: *MachO) void { @@ -105,7 +104,7 @@ fn mark(roots: []*Atom, objects: []const File.Index, macho_file: *MachO) void { !(mem.eql(u8, isec.sectName(), "__eh_frame") or mem.eql(u8, isec.sectName(), "__compact_unwind") or isec.attrs() & macho.S_ATTR_DEBUG != 0) and - !atom.flags.alive and refersLive(atom, macho_file)) + !atom.isAlive() and refersLive(atom, macho_file)) { markLive(atom, macho_file); loop = true; @@ -116,8 +115,8 @@ fn mark(roots: []*Atom, objects: []const File.Index, macho_file: *MachO) void { } fn markLive(atom: *Atom, macho_file: *MachO) void { - assert(atom.flags.visited); - atom.flags.alive = true; + assert(atom.visited.load(.seq_cst)); + atom.setAlive(true); track_live_log.debug("{}marking live atom({d},{s})", .{ track_live_level, atom.atom_index, @@ -170,7 +169,7 @@ fn refersLive(atom: *Atom, macho_file: *MachO) bool { }, }; if (target_atom) |ta| { - if (ta.flags.alive) return true; + if (ta.isAlive()) return true; } } return false; @@ -181,9 +180,10 @@ fn prune(objects: []const File.Index, macho_file: *MachO) void { const file = macho_file.getFile(index).?; for (file.getAtoms()) |atom_index| { const atom = file.getAtom(atom_index) orelse continue; - if (atom.flags.alive and !atom.flags.visited) { - atom.flags.alive = false; - atom.markUnwindRecordsDead(macho_file); + if (!atom.visited.load(.seq_cst)) { + if (atom.alive.cmpxchgStrong(true, false, .seq_cst, .seq_cst) == null) { + atom.markUnwindRecordsDead(macho_file); + } } } } diff --git a/src/link/MachO/dyld_info/Rebase.zig b/src/link/MachO/dyld_info/Rebase.zig index c0bcb42ed1..8809f130ff 100644 --- a/src/link/MachO/dyld_info/Rebase.zig +++ b/src/link/MachO/dyld_info/Rebase.zig @@ -35,7 +35,7 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void { const file = macho_file.getFile(index).?; for (file.getAtoms()) |atom_index| { const atom = file.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; if (atom.getInputSection(macho_file).isZerofill()) continue; const atom_addr = atom.getAddress(macho_file); const seg_id = macho_file.sections.items(.segment_id)[atom.out_n_sect]; diff --git a/src/link/MachO/dyld_info/Trie.zig b/src/link/MachO/dyld_info/Trie.zig index 44e6cd4234..aed7b61df8 100644 --- a/src/link/MachO/dyld_info/Trie.zig +++ b/src/link/MachO/dyld_info/Trie.zig @@ -102,7 +102,7 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void { if (ref.getFile(macho_file) == null) continue; const sym = ref.getSymbol(macho_file).?; if (!sym.flags.@"export") continue; - if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue; + if (sym.getAtom(macho_file)) |atom| if (!atom.isAlive()) continue; var flags: u64 = if (sym.flags.abs) macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE else if (sym.flags.tlv) @@ -111,8 +111,8 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void { macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR; if (sym.flags.weak) { flags |= macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION; - macho_file.weak_defines = true; - macho_file.binds_to_weak = true; + macho_file.weak_defines.store(true, .seq_cst); + macho_file.binds_to_weak.store(true, .seq_cst); } try self.put(gpa, .{ .name = sym.getName(macho_file), diff --git a/src/link/MachO/dyld_info/bind.zig b/src/link/MachO/dyld_info/bind.zig index 94e7c7ef29..310118af41 100644 --- a/src/link/MachO/dyld_info/bind.zig +++ b/src/link/MachO/dyld_info/bind.zig @@ -10,10 +10,7 @@ pub const Entry = struct { if (entry.target.eql(other.target)) { return entry.offset < other.offset; } - if (entry.target.file == other.target.file) { - return entry.target.index < other.target.index; - } - return entry.target.file < other.target.file; + return entry.target.lessThan(other.target); } return entry.segment_id < other.segment_id; } @@ -47,7 +44,7 @@ pub const Bind = struct { const file = macho_file.getFile(index).?; for (file.getAtoms()) |atom_index| { const atom = file.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; if (atom.getInputSection(macho_file).isZerofill()) continue; const atom_addr = atom.getAddress(macho_file); const relocs = atom.getRelocs(macho_file); @@ -299,7 +296,7 @@ pub const WeakBind = struct { const file = macho_file.getFile(index).?; for (file.getAtoms()) |atom_index| { const atom = file.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; if (atom.getInputSection(macho_file).isZerofill()) continue; const atom_addr = atom.getAddress(macho_file); const relocs = atom.getRelocs(macho_file); diff --git a/src/link/MachO/file.zig b/src/link/MachO/file.zig index 2959001833..4c585c7609 100644 --- a/src/link/MachO/file.zig +++ b/src/link/MachO/file.zig @@ -37,11 +37,10 @@ pub const File = union(enum) { } pub fn scanRelocs(file: File, macho_file: *MachO) !void { - switch (file) { + return switch (file) { .dylib => unreachable, - .internal => |x| x.scanRelocs(macho_file), inline else => |x| x.scanRelocs(macho_file), - } + }; } /// Encodes symbol rank so that the following ordering applies: @@ -182,19 +181,19 @@ pub const File = union(enum) { if (ref.getFile(macho_file) == null) continue; if (ref.file != file.getIndex()) continue; const sym = ref.getSymbol(macho_file).?; - if (sym.flags.needs_got) { + if (sym.getSectionFlags().needs_got) { log.debug("'{s}' needs GOT", .{sym.getName(macho_file)}); try macho_file.got.addSymbol(ref, macho_file); } - if (sym.flags.stubs) { + if (sym.getSectionFlags().stubs) { log.debug("'{s}' needs STUBS", .{sym.getName(macho_file)}); try macho_file.stubs.addSymbol(ref, macho_file); } - if (sym.flags.tlv_ptr) { + if (sym.getSectionFlags().tlv_ptr) { log.debug("'{s}' needs TLV pointer", .{sym.getName(macho_file)}); try macho_file.tlv_ptr.addSymbol(ref, macho_file); } - if (sym.flags.objc_stubs) { + if (sym.getSectionFlags().objc_stubs) { log.debug("'{s}' needs OBJC STUBS", .{sym.getName(macho_file)}); try macho_file.objc_stubs.addSymbol(ref, macho_file); } @@ -268,6 +267,9 @@ pub const File = union(enum) { const ref_file = ref.getFile(macho_file) orelse continue; if (ref_file.getIndex() == file.getIndex()) continue; + macho_file.dupes_mutex.lock(); + defer macho_file.dupes_mutex.unlock(); + const gop = try macho_file.dupes.getOrPut(gpa, file.getGlobals()[i]); if (!gop.found_existing) { gop.value_ptr.* = .{}; @@ -281,7 +283,7 @@ pub const File = union(enum) { defer tracy.end(); for (file.getAtoms()) |atom_index| { const atom = file.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file); } } @@ -295,7 +297,7 @@ pub const File = union(enum) { pub fn writeAtoms(file: File, macho_file: *MachO) !void { return switch (file) { - .dylib, .zig_object => unreachable, + .dylib => unreachable, inline else => |x| x.writeAtoms(macho_file), }; } diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index 4a1b8e2dc1..5e047414c4 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -261,7 +261,7 @@ fn initOutputSections(macho_file: *MachO) !void { const file = macho_file.getFile(index).?; for (file.getAtoms()) |atom_index| { const atom = file.getAtom(atom_index) orelse continue; - if (!atom.flags.alive) continue; + if (!atom.isAlive()) continue; atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file); } } diff --git a/src/link/MachO/synthetic.zig b/src/link/MachO/synthetic.zig index d7316d63b7..5285412bb7 100644 --- a/src/link/MachO/synthetic.zig +++ b/src/link/MachO/synthetic.zig @@ -24,8 +24,8 @@ pub const ZigGotSection = struct { const entry = &zig_got.entries.items[index]; entry.* = sym_index; const symbol = &zo.symbols.items[sym_index]; - assert(symbol.flags.needs_zig_got); - symbol.flags.has_zig_got = true; + assert(symbol.getSectionFlags().needs_zig_got); + symbol.setSectionFlags(.{ .has_zig_got = true }); symbol.addExtra(.{ .zig_got = index }, macho_file); return index; } @@ -121,7 +121,7 @@ pub const GotSection = struct { const entry = try got.symbols.addOne(gpa); entry.* = ref; const symbol = ref.getSymbol(macho_file).?; - symbol.flags.has_got = true; + symbol.setSectionFlags(.{ .has_got = true }); symbol.addExtra(.{ .got = index }, macho_file); } @@ -689,7 +689,7 @@ pub const DataInCode = struct { dices[next_dice].offset < end_off) : (next_dice += 1) {} - if (atom.flags.alive) for (dices[start_dice..next_dice]) |d| { + if (atom.isAlive()) for (dices[start_dice..next_dice]) |d| { dice.entries.appendAssumeCapacity(.{ .atom_ref = .{ .index = atom_index, .file = index }, .offset = @intCast(d.offset - start_off), diff --git a/src/link/MachO/thunks.zig b/src/link/MachO/thunks.zig index 2f2bd177e4..37013c54c4 100644 --- a/src/link/MachO/thunks.zig +++ b/src/link/MachO/thunks.zig @@ -17,7 +17,7 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void { while (i < atoms.len) { const start = i; const start_atom = atoms[start].getAtom(macho_file).?; - assert(start_atom.flags.alive); + assert(start_atom.isAlive()); start_atom.value = advance(header, start_atom.size, start_atom.alignment); i += 1; @@ -25,7 +25,7 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void { header.size - start_atom.value < max_allowed_distance) : (i += 1) { const atom = atoms[i].getAtom(macho_file).?; - assert(atom.flags.alive); + assert(atom.isAlive()); atom.value = advance(header, atom.size, atom.alignment); } @@ -71,7 +71,7 @@ fn scanRelocs(thunk_index: Thunk.Index, gpa: Allocator, atoms: []const MachO.Ref fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { const target = rel.getTargetSymbol(atom.*, macho_file); - if (target.flags.stubs or target.flags.objc_stubs) return false; + if (target.getSectionFlags().stubs or target.getSectionFlags().objc_stubs) return false; if (atom.out_n_sect != target.getOutputSectionIndex(macho_file)) return false; const target_atom = target.getAtom(macho_file).?; if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; |
