authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-20 06:41:30+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-22 12:06:02+02:00
log2b84592858fe004fcae1372f7a5f97e10a81c2e3
treef0ebc5be3d85396d423e837b023057f6258a194a
parent5d9fd5bcdeb9f7a1af50b0eaffd22b61f3e440a6

macho: run more things in parallel


18 files changed, 564 insertions(+), 301 deletions(-)

src/arch/x86_64/Emit.zig+3-3
......@@ -163,12 +163,12 @@ pub fn emitMir(emit: *Emit) Error!void {
163163 const zo = macho_file.getZigObject().?;
164164 const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?;
165165 const sym = &zo.symbols.items[data.sym_index];
166 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
166 if (sym.getSectionFlags().needs_zig_got and !is_obj_or_static_lib) {
167167 _ = try sym.getOrCreateZigGotEntry(data.sym_index, macho_file);
168168 }
169 const @"type": link.File.MachO.Relocation.Type = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
169 const @"type": link.File.MachO.Relocation.Type = if (sym.getSectionFlags().needs_zig_got and !is_obj_or_static_lib)
170170 .zig_got_load
171 else if (sym.flags.needs_got)
171 else if (sym.getSectionFlags().needs_got)
172172 // TODO: it is possible to emit .got_load here that can potentially be relaxed
173173 // however this requires always to use a MOVQ mnemonic
174174 .got
src/arch/x86_64/Lower.zig+1-1
......@@ -451,7 +451,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
451451 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
452452 },
453453 .mov => {
454 if (is_obj_or_static_lib and macho_sym.flags.needs_zig_got) emit_mnemonic = .lea;
454 if (is_obj_or_static_lib and macho_sym.getSectionFlags().needs_zig_got) emit_mnemonic = .lea;
455455 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
456456 },
457457 else => unreachable,
src/codegen.zig+1-1
......@@ -924,7 +924,7 @@ fn genDeclRef(
924924 const name = decl.name.toSlice(ip);
925925 const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
926926 const sym_index = try macho_file.getGlobalSymbol(name, lib_name);
927 zo.symbols.items[sym_index].flags.needs_got = true;
927 zo.symbols.items[sym_index].setSectionFlags(.{ .needs_got = true });
928928 return GenResult.mcv(.{ .load_symbol = sym_index });
929929 }
930930 const sym_index = try zo.getOrCreateMetadataForDecl(macho_file, decl_index);
src/link/MachO.zig+423-180
......@@ -25,8 +25,10 @@ sections: std.MultiArrayList(Section) = .{},
2525resolver: SymbolResolver = .{},
2626/// This table will be populated after `scanRelocs` has run.
2727/// Key is symbol index.
28undefs: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(Ref)) = .{},
29dupes: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)) = .{},
28undefs: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(Ref)) = .{},
29undefs_mutex: std.Thread.Mutex = .{},
30dupes: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)) = .{},
31dupes_mutex: std.Thread.Mutex = .{},
3032
3133dyld_info_cmd: macho.dyld_info_command = .{},
3234symtab_cmd: macho.symtab_command = .{},
......@@ -93,9 +95,9 @@ debug_str_sect_index: ?u8 = null,
9395debug_aranges_sect_index: ?u8 = null,
9496debug_line_sect_index: ?u8 = null,
9597
96has_tlv: bool = false,
97binds_to_weak: bool = false,
98weak_defines: bool = false,
98has_tlv: AtomicBool = AtomicBool.init(false),
99binds_to_weak: AtomicBool = AtomicBool.init(false),
100weak_defines: AtomicBool = AtomicBool.init(false),
99101has_errors: AtomicBool = AtomicBool.init(false),
100102
101103/// Options
......@@ -306,20 +308,15 @@ pub fn deinit(self: *MachO) void {
306308 self.sections.deinit(gpa);
307309
308310 self.resolver.deinit(gpa);
309 {
310 var it = self.undefs.iterator();
311 while (it.next()) |entry| {
312 entry.value_ptr.deinit(gpa);
313 }
314 self.undefs.deinit(gpa);
311
312 for (self.undefs.values()) |*val| {
313 val.deinit(gpa);
315314 }
316 {
317 var it = self.dupes.iterator();
318 while (it.next()) |entry| {
319 entry.value_ptr.deinit(gpa);
320 }
321 self.dupes.deinit(gpa);
315 self.undefs.deinit(gpa);
316 for (self.dupes.values()) |*val| {
317 val.deinit(gpa);
322318 }
319 self.dupes.deinit(gpa);
323320
324321 self.symtab.deinit(gpa);
325322 self.strtab.deinit(gpa);
......@@ -553,12 +550,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
553550 else => |e| return e,
554551 };
555552 }
556 self.writeSectionsAndUpdateLinkeditSizes() catch |err| {
557 switch (err) {
558 error.ResolveFailed => return error.FlushFailure,
559 else => |e| return e,
560 }
561 };
553 try self.writeSectionsAndUpdateLinkeditSizes();
562554
563555 try self.writeSectionsToFile();
564556 try self.allocateLinkeditSegment();
......@@ -907,25 +899,25 @@ pub fn parseInputFiles(self: *MachO) !void {
907899 defer wg.wait();
908900
909901 for (self.objects.items) |index| {
910 tp.spawnWg(&wg, parseInputFileWorker, .{ self, index });
902 tp.spawnWg(&wg, parseInputFileWorker, .{ self, self.getFile(index).? });
911903 }
912904 for (self.dylibs.items) |index| {
913 tp.spawnWg(&wg, parseInputFileWorker, .{ self, index });
905 tp.spawnWg(&wg, parseInputFileWorker, .{ self, self.getFile(index).? });
914906 }
915907 }
916908
917909 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;
918910}
919911
920fn parseInputFileWorker(self: *MachO, index: File.Index) void {
921 self.getFile(index).?.parse(self) catch |err| {
912fn parseInputFileWorker(self: *MachO, file: File) void {
913 file.parse(self) catch |err| {
922914 switch (err) {
923915 error.MalformedObject,
924916 error.MalformedDylib,
925917 error.InvalidCpuArch,
926918 error.InvalidTarget,
927919 => {}, // already reported
928 else => |e| self.reportParseError2(index, "unexpected error: parsing input file failed with error {s}", .{@errorName(e)}) catch {},
920 else => |e| self.reportParseError2(file.getIndex(), "unexpected error: parsing input file failed with error {s}", .{@errorName(e)}) catch {},
929921 }
930922 _ = self.has_errors.swap(true, .seq_cst);
931923 };
......@@ -1286,13 +1278,50 @@ fn markLive(self: *MachO) void {
12861278}
12871279
12881280fn convertTentativeDefsAndResolveSpecialSymbols(self: *MachO) !void {
1289 for (self.objects.items) |index| {
1290 try self.getFile(index).?.object.convertTentativeDefinitions(self);
1291 }
1292 if (self.getInternalObject()) |obj| {
1293 try obj.resolveBoundarySymbols(self);
1294 try obj.resolveObjcMsgSendSymbols(self);
1281 const tp = self.base.comp.thread_pool;
1282 var wg: WaitGroup = .{};
1283 {
1284 wg.reset();
1285 defer wg.wait();
1286 for (self.objects.items) |index| {
1287 tp.spawnWg(&wg, convertTentativeDefinitionsWorker, .{ self, self.getFile(index).?.object });
1288 }
1289 if (self.getInternalObject()) |obj| {
1290 tp.spawnWg(&wg, resolveSpecialSymbolsWorker, .{ self, obj });
1291 }
12951292 }
1293 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;
1294}
1295
1296fn convertTentativeDefinitionsWorker(self: *MachO, object: *Object) void {
1297 const tracy = trace(@src());
1298 defer tracy.end();
1299 object.convertTentativeDefinitions(self) catch |err| {
1300 self.reportParseError2(
1301 object.index,
1302 "unexpected error occurred while converting tentative symbols into defined symbols: {s}",
1303 .{@errorName(err)},
1304 ) catch {};
1305 _ = self.has_errors.swap(true, .seq_cst);
1306 };
1307}
1308
1309fn resolveSpecialSymbolsWorker(self: *MachO, obj: *InternalObject) void {
1310 const tracy = trace(@src());
1311 defer tracy.end();
1312 obj.resolveBoundarySymbols(self) catch |err| {
1313 self.reportUnexpectedError("unexpected error occurred while resolving boundary symbols: {s}", .{
1314 @errorName(err),
1315 }) catch {};
1316 _ = self.has_errors.swap(true, .seq_cst);
1317 return;
1318 };
1319 obj.resolveObjcMsgSendSymbols(self) catch |err| {
1320 self.reportUnexpectedError("unexpected error occurred while resolving ObjC msgsend stubs: {s}", .{
1321 @errorName(err),
1322 }) catch {};
1323 _ = self.has_errors.swap(true, .seq_cst);
1324 };
12961325}
12971326
12981327pub fn dedupLiterals(self: *MachO) !void {
......@@ -1313,14 +1342,20 @@ pub fn dedupLiterals(self: *MachO) !void {
13131342 try object.resolveLiterals(&lp, self);
13141343 }
13151344
1316 if (self.getZigObject()) |zo| {
1317 zo.dedupLiterals(lp, self);
1318 }
1319 for (self.objects.items) |index| {
1320 self.getFile(index).?.object.dedupLiterals(lp, self);
1321 }
1322 if (self.getInternalObject()) |object| {
1323 object.dedupLiterals(lp, self);
1345 const tp = self.base.comp.thread_pool;
1346 var wg: WaitGroup = .{};
1347 {
1348 wg.reset();
1349 defer wg.wait();
1350 if (self.getZigObject()) |zo| {
1351 tp.spawnWg(&wg, File.dedupLiterals, .{ zo.asFile(), lp, self });
1352 }
1353 for (self.objects.items) |index| {
1354 tp.spawnWg(&wg, File.dedupLiterals, .{ self.getFile(index).?, lp, self });
1355 }
1356 if (self.getInternalObject()) |object| {
1357 tp.spawnWg(&wg, File.dedupLiterals, .{ object.asFile(), lp, self });
1358 }
13241359 }
13251360}
13261361
......@@ -1334,18 +1369,41 @@ fn claimUnresolved(self: *MachO) void {
13341369}
13351370
13361371fn checkDuplicates(self: *MachO) !void {
1337 if (self.getZigObject()) |zo| {
1338 try zo.asFile().checkDuplicates(self);
1339 }
1340 for (self.objects.items) |index| {
1341 try self.getFile(index).?.checkDuplicates(self);
1342 }
1343 if (self.getInternalObject()) |obj| {
1344 try obj.asFile().checkDuplicates(self);
1372 const tracy = trace(@src());
1373 defer tracy.end();
1374
1375 const tp = self.base.comp.thread_pool;
1376 var wg: WaitGroup = .{};
1377 {
1378 wg.reset();
1379 defer wg.wait();
1380 if (self.getZigObject()) |zo| {
1381 tp.spawnWg(&wg, checkDuplicatesWorker, .{ self, zo.asFile() });
1382 }
1383 for (self.objects.items) |index| {
1384 tp.spawnWg(&wg, checkDuplicatesWorker, .{ self, self.getFile(index).? });
1385 }
1386 if (self.getInternalObject()) |obj| {
1387 tp.spawnWg(&wg, checkDuplicatesWorker, .{ self, obj.asFile() });
1388 }
13451389 }
1390
1391 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;
1392
13461393 try self.reportDuplicates();
13471394}
13481395
1396fn checkDuplicatesWorker(self: *MachO, file: File) void {
1397 const tracy = trace(@src());
1398 defer tracy.end();
1399 file.checkDuplicates(self) catch |err| {
1400 self.reportParseError2(file.getIndex(), "failed to check for duplicate definitions: {s}", .{
1401 @errorName(err),
1402 }) catch {};
1403 _ = self.has_errors.swap(true, .seq_cst);
1404 };
1405}
1406
13491407fn markImportsAndExports(self: *MachO) void {
13501408 const tracy = trace(@src());
13511409 defer tracy.end();
......@@ -1384,16 +1442,26 @@ fn scanRelocs(self: *MachO) !void {
13841442 const tracy = trace(@src());
13851443 defer tracy.end();
13861444
1387 if (self.getZigObject()) |zo| {
1388 try zo.scanRelocs(self);
1389 }
1390 for (self.objects.items) |index| {
1391 try self.getFile(index).?.object.scanRelocs(self);
1392 }
1393 if (self.getInternalObject()) |obj| {
1394 obj.scanRelocs(self);
1445 const tp = self.base.comp.thread_pool;
1446 var wg: WaitGroup = .{};
1447
1448 {
1449 wg.reset();
1450 defer wg.wait();
1451
1452 if (self.getZigObject()) |zo| {
1453 tp.spawnWg(&wg, scanRelocsWorker, .{ self, zo.asFile() });
1454 }
1455 for (self.objects.items) |index| {
1456 tp.spawnWg(&wg, scanRelocsWorker, .{ self, self.getFile(index).? });
1457 }
1458 if (self.getInternalObject()) |obj| {
1459 tp.spawnWg(&wg, scanRelocsWorker, .{ self, obj.asFile() });
1460 }
13951461 }
13961462
1463 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;
1464
13971465 try self.reportUndefs();
13981466
13991467 if (self.getZigObject()) |zo| {
......@@ -1410,25 +1478,61 @@ fn scanRelocs(self: *MachO) !void {
14101478 }
14111479}
14121480
1481fn scanRelocsWorker(self: *MachO, file: File) void {
1482 file.scanRelocs(self) catch |err| {
1483 self.reportParseError2(file.getIndex(), "failed to scan relocations: {s}", .{
1484 @errorName(err),
1485 }) catch {};
1486 _ = self.has_errors.swap(true, .seq_cst);
1487 };
1488}
1489
1490fn sortGlobalSymbolsByName(self: *MachO, symbols: []SymbolResolver.Index) void {
1491 const lessThan = struct {
1492 fn lessThan(ctx: *MachO, lhs: SymbolResolver.Index, rhs: SymbolResolver.Index) bool {
1493 const lhs_name = ctx.resolver.keys.items[lhs - 1].getName(ctx);
1494 const rhs_name = ctx.resolver.keys.items[rhs - 1].getName(ctx);
1495 return mem.order(u8, lhs_name, rhs_name) == .lt;
1496 }
1497 }.lessThan;
1498 mem.sort(SymbolResolver.Index, symbols, self, lessThan);
1499}
1500
14131501fn reportUndefs(self: *MachO) !void {
14141502 const tracy = trace(@src());
14151503 defer tracy.end();
14161504
14171505 if (self.undefined_treatment == .suppress or
14181506 self.undefined_treatment == .dynamic_lookup) return;
1507 if (self.undefs.keys().len == 0) return; // Nothing to do
14191508
1509 const gpa = self.base.comp.gpa;
14201510 const max_notes = 4;
14211511
1422 var has_undefs = false;
1423 var it = self.undefs.iterator();
1424 while (it.next()) |entry| {
1425 const undef_sym = self.resolver.keys.items[entry.key_ptr.* - 1];
1426 const notes = entry.value_ptr.*;
1512 // We will sort by name, and then by file to ensure deterministic output.
1513 var keys = try std.ArrayList(SymbolResolver.Index).initCapacity(gpa, self.undefs.keys().len);
1514 defer keys.deinit();
1515 keys.appendSliceAssumeCapacity(self.undefs.keys());
1516 self.sortGlobalSymbolsByName(keys.items);
1517
1518 const refLessThan = struct {
1519 fn lessThan(ctx: void, lhs: Ref, rhs: Ref) bool {
1520 _ = ctx;
1521 return lhs.lessThan(rhs);
1522 }
1523 }.lessThan;
1524
1525 for (self.undefs.values()) |*refs| {
1526 mem.sort(Ref, refs.items, {}, refLessThan);
1527 }
1528
1529 for (keys.items) |key| {
1530 const undef_sym = self.resolver.keys.items[key - 1];
1531 const notes = self.undefs.get(key).?;
14271532 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
14281533
14291534 var err = try self.base.addErrorWithNotes(nnotes);
14301535 try err.addMsg("undefined symbol: {s}", .{undef_sym.getName(self)});
1431 has_undefs = true;
14321536
14331537 var inote: usize = 0;
14341538 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
......@@ -1443,7 +1547,8 @@ fn reportUndefs(self: *MachO) !void {
14431547 try err.addNote("referenced {d} more times", .{remaining});
14441548 }
14451549 }
1446 if (has_undefs) return error.HasUndefinedSymbols;
1550
1551 return error.HasUndefinedSymbols;
14471552}
14481553
14491554fn initOutputSections(self: *MachO) !void {
......@@ -1679,7 +1784,7 @@ pub fn sortSections(self: *MachO) !void {
16791784 if (self.getZigObject()) |zo| {
16801785 for (zo.getAtoms()) |atom_index| {
16811786 const atom = zo.getAtom(atom_index) orelse continue;
1682 if (!atom.flags.alive) continue;
1787 if (!atom.isAlive()) continue;
16831788 atom.out_n_sect = backlinks[atom.out_n_sect];
16841789 }
16851790 }
......@@ -1688,7 +1793,7 @@ pub fn sortSections(self: *MachO) !void {
16881793 const file = self.getFile(index).?;
16891794 for (file.getAtoms()) |atom_index| {
16901795 const atom = file.getAtom(atom_index) orelse continue;
1691 if (!atom.flags.alive) continue;
1796 if (!atom.isAlive()) continue;
16921797 atom.out_n_sect = backlinks[atom.out_n_sect];
16931798 }
16941799 }
......@@ -1696,7 +1801,7 @@ pub fn sortSections(self: *MachO) !void {
16961801 if (self.getInternalObject()) |object| {
16971802 for (object.getAtoms()) |atom_index| {
16981803 const atom = object.getAtom(atom_index) orelse continue;
1699 if (!atom.flags.alive) continue;
1804 if (!atom.isAlive()) continue;
17001805 atom.out_n_sect = backlinks[atom.out_n_sect];
17011806 }
17021807 }
......@@ -1737,7 +1842,7 @@ pub fn addAtomsToSections(self: *MachO) !void {
17371842 if (self.getZigObject()) |zo| {
17381843 for (zo.getAtoms()) |atom_index| {
17391844 const atom = zo.getAtom(atom_index) orelse continue;
1740 if (!atom.flags.alive) continue;
1845 if (!atom.isAlive()) continue;
17411846 if (self.isZigSection(atom.out_n_sect)) continue;
17421847 const atoms = &self.sections.items(.atoms)[atom.out_n_sect];
17431848 try atoms.append(gpa, .{ .index = atom_index, .file = zo.index });
......@@ -1747,7 +1852,7 @@ pub fn addAtomsToSections(self: *MachO) !void {
17471852 const file = self.getFile(index).?;
17481853 for (file.getAtoms()) |atom_index| {
17491854 const atom = file.getAtom(atom_index) orelse continue;
1750 if (!atom.flags.alive) continue;
1855 if (!atom.isAlive()) continue;
17511856 const atoms = &self.sections.items(.atoms)[atom.out_n_sect];
17521857 try atoms.append(gpa, .{ .index = atom_index, .file = index });
17531858 }
......@@ -1755,7 +1860,7 @@ pub fn addAtomsToSections(self: *MachO) !void {
17551860 if (self.getInternalObject()) |object| {
17561861 for (object.getAtoms()) |atom_index| {
17571862 const atom = object.getAtom(atom_index) orelse continue;
1758 if (!atom.flags.alive) continue;
1863 if (!atom.isAlive()) continue;
17591864 const atoms = &self.sections.items(.atoms)[atom.out_n_sect];
17601865 try atoms.append(gpa, .{ .index = atom_index, .file = object.index });
17611866 }
......@@ -1774,46 +1879,43 @@ fn calcSectionSizes(self: *MachO) !void {
17741879 header.@"align" = 3;
17751880 }
17761881
1777 const slice = self.sections.slice();
1778 for (slice.items(.header), slice.items(.atoms)) |*header, atoms| {
1779 if (atoms.items.len == 0) continue;
1780 if (self.requiresThunks() and header.isCode()) continue;
1781
1782 for (atoms.items) |ref| {
1783 const atom = ref.getAtom(self).?;
1784 const atom_alignment = atom.alignment.toByteUnits() orelse 1;
1785 const offset = mem.alignForward(u64, header.size, atom_alignment);
1786 const padding = offset - header.size;
1787 atom.value = offset;
1788 header.size += padding + atom.size;
1789 header.@"align" = @max(header.@"align", atom.alignment.toLog2Units());
1790 }
1791 }
1792
1793 if (self.requiresThunks()) {
1882 const tp = self.base.comp.thread_pool;
1883 var wg: WaitGroup = .{};
1884 {
1885 wg.reset();
1886 defer wg.wait();
1887 const slice = self.sections.slice();
17941888 for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| {
1795 if (!header.isCode()) continue;
17961889 if (atoms.items.len == 0) continue;
1890 if (self.requiresThunks() and header.isCode()) continue;
1891 tp.spawnWg(&wg, calcSectionSizeWorker, .{ self, @as(u8, @intCast(i)) });
1892 }
17971893
1798 // Create jump/branch range extenders if needed.
1799 try thunks.createThunks(@intCast(i), self);
1894 if (self.requiresThunks()) {
1895 for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| {
1896 if (!header.isCode()) continue;
1897 if (atoms.items.len == 0) continue;
1898 tp.spawnWg(&wg, createThunksWorker, .{ self, @as(u8, @intCast(i)) });
1899 }
18001900 }
1801 }
18021901
1803 // At this point, we can also calculate symtab and data-in-code linkedit section sizes
1804 if (self.getZigObject()) |zo| {
1805 zo.asFile().calcSymtabSize(self);
1806 }
1807 for (self.objects.items) |index| {
1808 self.getFile(index).?.calcSymtabSize(self);
1809 }
1810 for (self.dylibs.items) |index| {
1811 self.getFile(index).?.calcSymtabSize(self);
1812 }
1813 if (self.getInternalObject()) |obj| {
1814 obj.asFile().calcSymtabSize(self);
1902 // At this point, we can also calculate symtab and data-in-code linkedit section sizes
1903 if (self.getZigObject()) |zo| {
1904 tp.spawnWg(&wg, File.calcSymtabSize, .{ zo.asFile(), self });
1905 }
1906 for (self.objects.items) |index| {
1907 tp.spawnWg(&wg, File.calcSymtabSize, .{ self.getFile(index).?, self });
1908 }
1909 for (self.dylibs.items) |index| {
1910 tp.spawnWg(&wg, File.calcSymtabSize, .{ self.getFile(index).?, self });
1911 }
1912 if (self.getInternalObject()) |obj| {
1913 tp.spawnWg(&wg, File.calcSymtabSize, .{ obj.asFile(), self });
1914 }
18151915 }
18161916
1917 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;
1918
18171919 try self.calcSymtabSize();
18181920
18191921 if (self.got_sect_index) |idx| {
......@@ -1861,6 +1963,49 @@ fn calcSectionSizes(self: *MachO) !void {
18611963 }
18621964}
18631965
1966fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void {
1967 const tracy = trace(@src());
1968 defer tracy.end();
1969 const doWork = struct {
1970 fn doWork(macho_file: *MachO, header: *macho.section_64, atoms: []const Ref) !void {
1971 for (atoms) |ref| {
1972 const atom = ref.getAtom(macho_file).?;
1973 const atom_alignment = atom.alignment.toByteUnits() orelse 1;
1974 const offset = mem.alignForward(u64, header.size, atom_alignment);
1975 const padding = offset - header.size;
1976 atom.value = offset;
1977 header.size += padding + atom.size;
1978 header.@"align" = @max(header.@"align", atom.alignment.toLog2Units());
1979 }
1980 }
1981 }.doWork;
1982 const slice = self.sections.slice();
1983 const header = &slice.items(.header)[sect_id];
1984 const atoms = slice.items(.atoms)[sect_id].items;
1985 doWork(self, header, atoms) catch |err| {
1986 self.reportUnexpectedError("failed to calculate size of section '{s},{s}': {s}", .{
1987 header.segName(),
1988 header.sectName(),
1989 @errorName(err),
1990 }) catch {};
1991 _ = self.has_errors.swap(true, .seq_cst);
1992 };
1993}
1994
1995fn createThunksWorker(self: *MachO, sect_id: u8) void {
1996 const tracy = trace(@src());
1997 defer tracy.end();
1998 thunks.createThunks(sect_id, self) catch |err| {
1999 const header = self.sections.items(.header)[sect_id];
2000 self.reportUnexpectedError("failed to create thunks and calculate size of section '{s},{s}': {s}", .{
2001 header.segName(),
2002 header.sectName(),
2003 @errorName(err),
2004 }) catch {};
2005 _ = self.has_errors.swap(true, .seq_cst);
2006 };
2007}
2008
18642009fn generateUnwindInfo(self: *MachO) !void {
18652010 const tracy = trace(@src());
18662011 defer tracy.end();
......@@ -2249,64 +2394,98 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void {
22492394 try self.strtab.resize(gpa, cmd.strsize);
22502395 self.strtab.items[0] = 0;
22512396
2252 for (self.objects.items) |index| {
2253 try self.getFile(index).?.writeAtoms(self);
2254 }
2255 if (self.getZigObject()) |zo| {
2256 try zo.writeAtoms(self);
2257 }
2258 if (self.getInternalObject()) |obj| {
2259 try obj.asFile().writeAtoms(self);
2260 }
2261 for (self.thunks.items) |thunk| {
2262 const out = self.sections.items(.out)[thunk.out_n_sect].items;
2263 const off = math.cast(usize, thunk.value) orelse return error.Overflow;
2264 const size = thunk.size();
2265 var stream = std.io.fixedBufferStream(out[off..][0..size]);
2266 try thunk.write(self, stream.writer());
2267 }
2397 const tp = self.base.comp.thread_pool;
2398 var wg: WaitGroup = .{};
2399 {
2400 wg.reset();
2401 defer wg.wait();
22682402
2269 const slice = self.sections.slice();
2270 for (&[_]?u8{
2271 self.eh_frame_sect_index,
2272 self.unwind_info_sect_index,
2273 self.got_sect_index,
2274 self.stubs_sect_index,
2275 self.la_symbol_ptr_sect_index,
2276 self.tlv_ptr_sect_index,
2277 self.objc_stubs_sect_index,
2278 }) |maybe_sect_id| {
2279 if (maybe_sect_id) |sect_id| {
2280 const out = slice.items(.out)[sect_id].items;
2281 try self.writeSyntheticSection(sect_id, out);
2403 for (self.objects.items) |index| {
2404 tp.spawnWg(&wg, writeAtomsWorker, .{ self, self.getFile(index).? });
2405 }
2406 if (self.getZigObject()) |zo| {
2407 tp.spawnWg(&wg, writeAtomsWorker, .{ self, zo.asFile() });
2408 }
2409 if (self.getInternalObject()) |obj| {
2410 tp.spawnWg(&wg, writeAtomsWorker, .{ self, obj.asFile() });
2411 }
2412 for (self.thunks.items) |thunk| {
2413 tp.spawnWg(&wg, writeThunkWorker, .{ self, thunk });
22822414 }
2283 }
22842415
2285 if (self.la_symbol_ptr_sect_index) |_| {
2286 try self.updateLazyBindSize();
2287 }
2416 const slice = self.sections.slice();
2417 for (&[_]?u8{
2418 self.eh_frame_sect_index,
2419 self.unwind_info_sect_index,
2420 self.got_sect_index,
2421 self.stubs_sect_index,
2422 self.la_symbol_ptr_sect_index,
2423 self.tlv_ptr_sect_index,
2424 self.objc_stubs_sect_index,
2425 }) |maybe_sect_id| {
2426 if (maybe_sect_id) |sect_id| {
2427 const out = slice.items(.out)[sect_id].items;
2428 tp.spawnWg(&wg, writeSyntheticSectionWorker, .{ self, sect_id, out });
2429 }
2430 }
22882431
2289 try self.rebase.updateSize(self);
2290 try self.bind.updateSize(self);
2291 try self.weak_bind.updateSize(self);
2292 try self.export_trie.updateSize(self);
2293 try self.data_in_code.updateSize(self);
2432 if (self.la_symbol_ptr_sect_index) |_| {
2433 tp.spawnWg(&wg, updateLazyBindSizeWorker, .{self});
2434 }
22942435
2295 if (self.getZigObject()) |zo| {
2296 zo.asFile().writeSymtab(self, self);
2297 }
2298 for (self.objects.items) |index| {
2299 self.getFile(index).?.writeSymtab(self, self);
2300 }
2301 for (self.dylibs.items) |index| {
2302 self.getFile(index).?.writeSymtab(self, self);
2303 }
2304 if (self.getInternalObject()) |obj| {
2305 obj.asFile().writeSymtab(self, self);
2436 tp.spawnWg(&wg, updateLinkeditSizeWorker, .{ self, .rebase });
2437 tp.spawnWg(&wg, updateLinkeditSizeWorker, .{ self, .bind });
2438 tp.spawnWg(&wg, updateLinkeditSizeWorker, .{ self, .weak_bind });
2439 tp.spawnWg(&wg, updateLinkeditSizeWorker, .{ self, .export_trie });
2440 tp.spawnWg(&wg, updateLinkeditSizeWorker, .{ self, .data_in_code });
2441
2442 if (self.getZigObject()) |zo| {
2443 tp.spawnWg(&wg, File.writeSymtab, .{ zo.asFile(), self, self });
2444 }
2445 for (self.objects.items) |index| {
2446 tp.spawnWg(&wg, File.writeSymtab, .{ self.getFile(index).?, self, self });
2447 }
2448 for (self.dylibs.items) |index| {
2449 tp.spawnWg(&wg, File.writeSymtab, .{ self.getFile(index).?, self, self });
2450 }
2451 if (self.getInternalObject()) |obj| {
2452 tp.spawnWg(&wg, File.writeSymtab, .{ obj.asFile(), self, self });
2453 }
23062454 }
2455
2456 if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure;
2457}
2458
2459fn writeAtomsWorker(self: *MachO, file: File) void {
2460 const tracy = trace(@src());
2461 defer tracy.end();
2462 file.writeAtoms(self) catch |err| {
2463 self.reportParseError2(file.getIndex(), "failed to resolve relocations and write atoms: {s}", .{
2464 @errorName(err),
2465 }) catch {};
2466 _ = self.has_errors.swap(true, .seq_cst);
2467 };
23072468}
23082469
2309fn writeSyntheticSection(self: *MachO, sect_id: u8, out: []u8) !void {
2470fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
2471 const tracy = trace(@src());
2472 defer tracy.end();
2473 const doWork = struct {
2474 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
2475 const off = th.value;
2476 const size = th.size();
2477 var stream = std.io.fixedBufferStream(buffer[off..][0..size]);
2478 try th.write(macho_file, stream.writer());
2479 }
2480 }.doWork;
2481 const out = self.sections.items(.out)[thunk.out_n_sect].items;
2482 doWork(thunk, out, self) catch |err| {
2483 self.reportUnexpectedError("failed to write contents of thunk: {s}", .{@errorName(err)}) catch {};
2484 _ = self.has_errors.swap(true, .seq_cst);
2485 };
2486}
2487
2488fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {
23102489 const tracy = trace(@src());
23112490 defer tracy.end();
23122491
......@@ -2320,6 +2499,22 @@ fn writeSyntheticSection(self: *MachO, sect_id: u8, out: []u8) !void {
23202499 objc_stubs,
23212500 };
23222501
2502 const doWork = struct {
2503 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {
2504 var stream = std.io.fixedBufferStream(buffer);
2505 switch (tag) {
2506 .eh_frame => eh_frame.write(macho_file, buffer),
2507 .unwind_info => try macho_file.unwind_info.write(macho_file, buffer),
2508 .got => try macho_file.got.write(macho_file, stream.writer()),
2509 .stubs => try macho_file.stubs.write(macho_file, stream.writer()),
2510 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, stream.writer()),
2511 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, stream.writer()),
2512 .objc_stubs => try macho_file.objc_stubs.write(macho_file, stream.writer()),
2513 }
2514 }
2515 }.doWork;
2516
2517 const header = self.sections.items(.header)[sect_id];
23232518 const tag: Tag = tag: {
23242519 if (self.eh_frame_sect_index != null and
23252520 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 {
23372532 self.objc_stubs_sect_index.? == sect_id) break :tag .objc_stubs;
23382533 unreachable;
23392534 };
2340 var stream = std.io.fixedBufferStream(out);
2341 switch (tag) {
2342 .eh_frame => eh_frame.write(self, out),
2343 .unwind_info => try self.unwind_info.write(self, out),
2344 .got => try self.got.write(self, stream.writer()),
2345 .stubs => try self.stubs.write(self, stream.writer()),
2346 .la_symbol_ptr => try self.la_symbol_ptr.write(self, stream.writer()),
2347 .tlv_ptr => try self.tlv_ptr.write(self, stream.writer()),
2348 .objc_stubs => try self.objc_stubs.write(self, stream.writer()),
2349 }
2535 doWork(self, tag, out) catch |err| {
2536 self.reportUnexpectedError("could not write section '{s},{s}': {s}", .{
2537 header.segName(),
2538 header.sectName(),
2539 @errorName(err),
2540 }) catch {};
2541 _ = self.has_errors.swap(true, .seq_cst);
2542 };
23502543}
23512544
2352fn updateLazyBindSize(self: *MachO) !void {
2545fn updateLazyBindSizeWorker(self: *MachO) void {
23532546 const tracy = trace(@src());
23542547 defer tracy.end();
2355 try self.lazy_bind.updateSize(self);
2356 const sect_id = self.stubs_helper_sect_index.?;
2357 const out = &self.sections.items(.out)[sect_id];
2358 var stream = std.io.fixedBufferStream(out.items);
2359 try self.stubs_helper.write(self, stream.writer());
2548 const doWork = struct {
2549 fn doWork(macho_file: *MachO) !void {
2550 try macho_file.lazy_bind.updateSize(macho_file);
2551 const sect_id = macho_file.stubs_helper_sect_index.?;
2552 const out = &macho_file.sections.items(.out)[sect_id];
2553 var stream = std.io.fixedBufferStream(out.items);
2554 try macho_file.stubs_helper.write(macho_file, stream.writer());
2555 }
2556 }.doWork;
2557 doWork(self) catch |err| {
2558 self.reportUnexpectedError("could not calculate size of lazy binding section: {s}", .{
2559 @errorName(err),
2560 }) catch {};
2561 _ = self.has_errors.swap(true, .seq_cst);
2562 };
2563}
2564
2565pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum {
2566 rebase,
2567 bind,
2568 weak_bind,
2569 export_trie,
2570 data_in_code,
2571}) void {
2572 const res = switch (tag) {
2573 .rebase => self.rebase.updateSize(self),
2574 .bind => self.bind.updateSize(self),
2575 .weak_bind => self.weak_bind.updateSize(self),
2576 .export_trie => self.export_trie.updateSize(self),
2577 .data_in_code => self.data_in_code.updateSize(self),
2578 };
2579 res catch |err| {
2580 self.reportUnexpectedError("could not calculate size of {s} section: {s}", .{
2581 @tagName(tag),
2582 @errorName(err),
2583 }) catch {};
2584 _ = self.has_errors.swap(true, .seq_cst);
2585 };
23602586}
23612587
23622588fn writeSectionsToFile(self: *MachO) !void {
......@@ -2684,13 +2910,13 @@ fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {
26842910 header.flags |= macho.MH_NO_REEXPORTED_DYLIBS;
26852911 }
26862912
2687 if (self.has_tlv) {
2913 if (self.has_tlv.load(.seq_cst)) {
26882914 header.flags |= macho.MH_HAS_TLV_DESCRIPTORS;
26892915 }
2690 if (self.binds_to_weak) {
2916 if (self.binds_to_weak.load(.seq_cst)) {
26912917 header.flags |= macho.MH_BINDS_TO_WEAK;
26922918 }
2693 if (self.weak_defines) {
2919 if (self.weak_defines.load(.seq_cst)) {
26942920 header.flags |= macho.MH_WEAK_DEFINES;
26952921 }
26962922
......@@ -3586,19 +3812,29 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
35863812 const tracy = trace(@src());
35873813 defer tracy.end();
35883814
3815 if (self.dupes.keys().len == 0) return; // Nothing to do
3816
3817 const gpa = self.base.comp.gpa;
35893818 const max_notes = 3;
35903819
3591 var has_dupes = false;
3592 var it = self.dupes.iterator();
3593 while (it.next()) |entry| {
3594 const sym = self.resolver.keys.items[entry.key_ptr.* - 1];
3595 const notes = entry.value_ptr.*;
3820 // We will sort by name, and then by file to ensure deterministic output.
3821 var keys = try std.ArrayList(SymbolResolver.Index).initCapacity(gpa, self.dupes.keys().len);
3822 defer keys.deinit();
3823 keys.appendSliceAssumeCapacity(self.dupes.keys());
3824 self.sortGlobalSymbolsByName(keys.items);
3825
3826 for (self.dupes.values()) |*refs| {
3827 mem.sort(File.Index, refs.items, {}, std.sort.asc(File.Index));
3828 }
3829
3830 for (keys.items) |key| {
3831 const sym = self.resolver.keys.items[key - 1];
3832 const notes = self.dupes.get(key).?;
35963833 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
35973834
35983835 var err = try self.base.addErrorWithNotes(nnotes + 1);
35993836 try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)});
36003837 try err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()});
3601 has_dupes = true;
36023838
36033839 var inote: usize = 0;
36043840 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
......@@ -3611,7 +3847,7 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
36113847 try err.addNote("defined {d} more times", .{remaining});
36123848 }
36133849 }
3614 if (has_dupes) return error.HasDuplicates;
3850 return error.HasDuplicates;
36153851}
36163852
36173853pub fn getDebugSymbols(self: *MachO) ?*DebugSymbols {
......@@ -4210,6 +4446,13 @@ pub const Ref = struct {
42104446 return ref.index == other.index and ref.file == other.file;
42114447 }
42124448
4449 pub fn lessThan(ref: Ref, other: Ref) bool {
4450 if (ref.file == other.file) {
4451 return ref.index < other.index;
4452 }
4453 return ref.file < other.file;
4454 }
4455
42134456 pub fn getFile(ref: Ref, macho_file: *MachO) ?File {
42144457 return macho_file.getFile(ref.file);
42154458 }
src/link/MachO/Atom.zig+36-29
......@@ -26,7 +26,11 @@ off: u64 = 0,
2626/// Index of this atom in the linker's atoms table.
2727atom_index: Index = 0,
2828
29flags: Flags = .{},
29/// Specifies whether this atom is alive or has been garbage collected.
30alive: AtomicBool = AtomicBool.init(true),
31
32/// Specifies if this atom has been visited during garbage collection.
33visited: AtomicBool = AtomicBool.init(false),
3034
3135/// Points to the previous and next neighbors, based on the `text_offset`.
3236/// 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 {
98102 }
99103}
100104
105pub fn isAlive(self: Atom) bool {
106 return self.alive.load(.seq_cst);
107}
108
109pub fn setAlive(self: *Atom, alive: bool) void {
110 _ = self.alive.swap(alive, .seq_cst);
111}
112
101113pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk {
102114 const extra = self.getExtra(macho_file);
103115 return macho_file.getThunk(extra.thunk);
......@@ -350,7 +362,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void {
350362 _ = free_list.swapRemove(i);
351363 }
352364
353 self.flags.alive = true;
365 self.setAlive(true);
354366}
355367
356368pub fn shrink(self: *Atom, macho_file: *MachO) void {
......@@ -444,7 +456,7 @@ pub fn freeRelocs(self: *Atom, macho_file: *MachO) void {
444456pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
445457 const tracy = trace(@src());
446458 defer tracy.end();
447 assert(self.flags.alive);
459 assert(self.isAlive());
448460
449461 const relocs = self.getRelocs(macho_file);
450462
......@@ -455,12 +467,12 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
455467 .branch => {
456468 const symbol = rel.getTargetSymbol(self, macho_file);
457469 if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) {
458 symbol.flags.stubs = true;
470 symbol.setSectionFlags(.{ .stubs = true });
459471 if (symbol.flags.weak) {
460 macho_file.binds_to_weak = true;
472 macho_file.binds_to_weak.store(true, .seq_cst);
461473 }
462474 } else if (mem.startsWith(u8, symbol.getName(macho_file), "_objc_msgSend$")) {
463 symbol.flags.objc_stubs = true;
475 symbol.setSectionFlags(.{ .objc_stubs = true });
464476 }
465477 },
466478
......@@ -474,19 +486,19 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
474486 symbol.flags.interposable or
475487 macho_file.getTarget().cpu.arch == .aarch64) // TODO relax on arm64
476488 {
477 symbol.flags.needs_got = true;
489 symbol.setSectionFlags(.{ .needs_got = true });
478490 if (symbol.flags.weak) {
479 macho_file.binds_to_weak = true;
491 macho_file.binds_to_weak.store(true, .seq_cst);
480492 }
481493 }
482494 },
483495
484496 .zig_got_load => {
485 assert(rel.getTargetSymbol(self, macho_file).flags.has_zig_got);
497 assert(rel.getTargetSymbol(self, macho_file).getSectionFlags().has_zig_got);
486498 },
487499
488500 .got => {
489 rel.getTargetSymbol(self, macho_file).flags.needs_got = true;
501 rel.getTargetSymbol(self, macho_file).setSectionFlags(.{ .needs_got = true });
490502 },
491503
492504 .tlv,
......@@ -502,9 +514,9 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
502514 );
503515 }
504516 if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) {
505 symbol.flags.tlv_ptr = true;
517 symbol.setSectionFlags(.{ .tlv_ptr = true });
506518 if (symbol.flags.weak) {
507 macho_file.binds_to_weak = true;
519 macho_file.binds_to_weak.store(true, .seq_cst);
508520 }
509521 }
510522 },
......@@ -514,17 +526,17 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
514526 if (rel.tag == .@"extern") {
515527 const symbol = rel.getTargetSymbol(self, macho_file);
516528 if (symbol.isTlvInit(macho_file)) {
517 macho_file.has_tlv = true;
529 macho_file.has_tlv.store(true, .seq_cst);
518530 continue;
519531 }
520532 if (symbol.flags.import) {
521533 if (symbol.flags.weak) {
522 macho_file.binds_to_weak = true;
534 macho_file.binds_to_weak.store(true, .seq_cst);
523535 }
524536 continue;
525537 }
526538 if (symbol.flags.@"export" and symbol.flags.weak) {
527 macho_file.binds_to_weak = true;
539 macho_file.binds_to_weak.store(true, .seq_cst);
528540 }
529541 }
530542 }
......@@ -548,6 +560,8 @@ fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool {
548560 const file = self.getFile(macho_file);
549561 const ref = file.getSymbolRef(rel.target, macho_file);
550562 if (ref.getFile(macho_file) == null) {
563 macho_file.undefs_mutex.lock();
564 defer macho_file.undefs_mutex.unlock();
551565 const gpa = macho_file.base.comp.gpa;
552566 const gop = try macho_file.undefs.getOrPut(gpa, file.getGlobals()[rel.target]);
553567 if (!gop.found_existing) {
......@@ -724,7 +738,7 @@ fn resolveRelocInner(
724738 assert(rel.tag == .@"extern");
725739 assert(rel.meta.length == 2);
726740 assert(rel.meta.pcrel);
727 if (rel.getTargetSymbol(self, macho_file).flags.has_got) {
741 if (rel.getTargetSymbol(self, macho_file).getSectionFlags().has_got) {
728742 try writer.writeInt(i32, @intCast(G + A - P), .little);
729743 } else {
730744 try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file);
......@@ -748,7 +762,7 @@ fn resolveRelocInner(
748762 assert(rel.meta.length == 2);
749763 assert(rel.meta.pcrel);
750764 const sym = rel.getTargetSymbol(self, macho_file);
751 if (sym.flags.tlv_ptr) {
765 if (sym.getSectionFlags().tlv_ptr) {
752766 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));
753767 try writer.writeInt(i32, @intCast(S_ + A - P), .little);
754768 } else {
......@@ -776,7 +790,7 @@ fn resolveRelocInner(
776790 const target = switch (rel.type) {
777791 .page => S + A,
778792 .got_load_page => G + A,
779 .tlvp_page => if (sym.flags.tlv_ptr) blk: {
793 .tlvp_page => if (sym.getSectionFlags().tlv_ptr) blk: {
780794 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));
781795 break :blk S_ + A;
782796 } else S + A,
......@@ -831,7 +845,7 @@ fn resolveRelocInner(
831845
832846 const sym = rel.getTargetSymbol(self, macho_file);
833847 const target = target: {
834 const target = if (sym.flags.tlv_ptr) blk: {
848 const target = if (sym.getSectionFlags().tlv_ptr) blk: {
835849 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));
836850 break :blk S_ + A;
837851 } else S + A;
......@@ -869,7 +883,7 @@ fn resolveRelocInner(
869883 }
870884 };
871885
872 var inst = if (sym.flags.tlv_ptr) aarch64.Instruction{
886 var inst = if (sym.getSectionFlags().tlv_ptr) aarch64.Instruction{
873887 .load_store_register = .{
874888 .rt = reg_info.rd,
875889 .rn = reg_info.rn,
......@@ -1142,7 +1156,7 @@ fn format2(
11421156 atom.out_n_sect, atom.alignment, atom.size,
11431157 atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk,
11441158 });
1145 if (!atom.flags.alive) try writer.writeAll(" : [*]");
1159 if (!atom.isAlive()) try writer.writeAll(" : [*]");
11461160 if (atom.getUnwindRecords(macho_file).len > 0) {
11471161 try writer.writeAll(" : unwind{ ");
11481162 const extra = atom.getExtra(macho_file);
......@@ -1158,14 +1172,6 @@ fn format2(
11581172
11591173pub const Index = u32;
11601174
1161pub const Flags = packed struct {
1162 /// Specifies whether this atom is alive or has been garbage collected.
1163 alive: bool = true,
1164
1165 /// Specifies if this atom has been visited during garbage collection.
1166 visited: bool = false,
1167};
1168
11691175pub const Extra = struct {
11701176 /// Index of the range extension thunk of this atom.
11711177 thunk: u32 = 0,
......@@ -1209,6 +1215,7 @@ const trace = @import("../../tracy.zig").trace;
12091215
12101216const Allocator = mem.Allocator;
12111217const Atom = @This();
1218const AtomicBool = std.atomic.Value(bool);
12121219const File = @import("file.zig").File;
12131220const MachO = @import("../MachO.zig");
12141221const Object = @import("Object.zig");
src/link/MachO/InternalObject.zig+8-8
......@@ -389,7 +389,7 @@ pub fn resolveObjcMsgSendSymbols(self: *InternalObject, macho_file: *MachO) !voi
389389 };
390390 sym.nlist_idx = nlist_idx;
391391 sym.extra = try self.addSymbolExtra(gpa, .{ .objc_selrefs = selrefs_index });
392 sym.flags.objc_stubs = true;
392 sym.setSectionFlags(.{ .objc_stubs = true });
393393
394394 const idx = ref.getFile(macho_file).?.object.globals.items[ref.index];
395395 try self.globals.append(gpa, idx);
......@@ -427,7 +427,7 @@ pub fn resolveLiterals(self: *InternalObject, lp: *MachO.LiteralPool, macho_file
427427 const lp_sym = lp.getSymbol(res.index, macho_file);
428428 const lp_atom = lp_sym.getAtom(macho_file).?;
429429 lp_atom.alignment = lp_atom.alignment.max(atom.alignment);
430 atom.flags.alive = false;
430 atom.setAlive(false);
431431 }
432432 atom.addExtra(.{ .literal_pool_index = res.index }, macho_file);
433433 }
......@@ -439,7 +439,7 @@ pub fn dedupLiterals(self: *InternalObject, lp: MachO.LiteralPool, macho_file: *
439439
440440 for (self.getAtoms()) |atom_index| {
441441 const atom = self.getAtom(atom_index) orelse continue;
442 if (!atom.flags.alive) continue;
442 if (!atom.isAlive()) continue;
443443
444444 const relocs = blk: {
445445 const extra = atom.getExtra(macho_file);
......@@ -464,7 +464,7 @@ pub fn dedupLiterals(self: *InternalObject, lp: MachO.LiteralPool, macho_file: *
464464 }
465465
466466 for (self.symbols.items) |*sym| {
467 if (!sym.flags.objc_stubs) continue;
467 if (!sym.getSectionFlags().objc_stubs) continue;
468468 const extra = sym.getExtra(macho_file);
469469 const file = sym.getFile(macho_file).?;
470470 if (file.getIndex() != self.index) continue;
......@@ -490,20 +490,20 @@ pub fn scanRelocs(self: *InternalObject, macho_file: *MachO) void {
490490 if (self.getEntryRef(macho_file)) |ref| {
491491 if (ref.getFile(macho_file) != null) {
492492 const sym = ref.getSymbol(macho_file).?;
493 if (sym.flags.import) sym.flags.stubs = true;
493 if (sym.flags.import) sym.setSectionFlags(.{ .stubs = true });
494494 }
495495 }
496496 if (self.getDyldStubBinderRef(macho_file)) |ref| {
497497 if (ref.getFile(macho_file) != null) {
498498 const sym = ref.getSymbol(macho_file).?;
499 sym.flags.needs_got = true;
499 sym.setSectionFlags(.{ .needs_got = true });
500500 }
501501 }
502502 if (self.getObjcMsgSendRef(macho_file)) |ref| {
503503 if (ref.getFile(macho_file) != null) {
504504 const sym = ref.getSymbol(macho_file).?;
505505 // TODO is it always needed, or only if we are synthesising fast stubs
506 sym.flags.needs_got = true;
506 sym.setSectionFlags(.{ .needs_got = true });
507507 }
508508 }
509509}
......@@ -570,7 +570,7 @@ pub fn writeAtoms(self: *InternalObject, macho_file: *MachO) !void {
570570
571571 for (self.getAtoms()) |atom_index| {
572572 const atom = self.getAtom(atom_index) orelse continue;
573 if (!atom.flags.alive) continue;
573 if (!atom.isAlive()) continue;
574574 const sect = atom.getInputSection(macho_file);
575575 if (sect.isZerofill()) continue;
576576 const off = std.math.cast(usize, atom.value) orelse return error.Overflow;
src/link/MachO/Object.zig+12-12
......@@ -263,7 +263,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
263263 mem.eql(u8, isec.sectName(), "__compact_unwind") or
264264 isec.attrs() & macho.S_ATTR_DEBUG != 0)
265265 {
266 atom.flags.alive = false;
266 atom.setAlive(false);
267267 }
268268 }
269269
......@@ -645,7 +645,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
645645 const lp_sym = lp.getSymbol(res.index, macho_file);
646646 const lp_atom = lp_sym.getAtom(macho_file).?;
647647 lp_atom.alignment = lp_atom.alignment.max(atom.alignment);
648 atom.flags.alive = false;
648 atom.setAlive(false);
649649 }
650650 atom.addExtra(.{ .literal_pool_index = res.index }, macho_file);
651651 }
......@@ -683,7 +683,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
683683 const lp_sym = lp.getSymbol(res.index, macho_file);
684684 const lp_atom = lp_sym.getAtom(macho_file).?;
685685 lp_atom.alignment = lp_atom.alignment.max(atom.alignment);
686 atom.flags.alive = false;
686 atom.setAlive(false);
687687 }
688688 atom.addExtra(.{ .literal_pool_index = res.index }, macho_file);
689689 }
......@@ -697,7 +697,7 @@ pub fn dedupLiterals(self: *Object, lp: MachO.LiteralPool, macho_file: *MachO) v
697697
698698 for (self.getAtoms()) |atom_index| {
699699 const atom = self.getAtom(atom_index) orelse continue;
700 if (!atom.flags.alive) continue;
700 if (!atom.isAlive()) continue;
701701
702702 const relocs = blk: {
703703 const extra = atom.getExtra(macho_file);
......@@ -990,7 +990,7 @@ fn initRelocs(self: *Object, file: File.Handle, cpu_arch: std.Target.Cpu.Arch, m
990990 var next_reloc: u32 = 0;
991991 for (subsections.items) |subsection| {
992992 const atom = self.getAtom(subsection.atom).?;
993 if (!atom.flags.alive) continue;
993 if (!atom.isAlive()) continue;
994994 if (next_reloc >= relocs.items.len) break;
995995 const end_addr = atom.off + atom.size;
996996 const rel_index = next_reloc;
......@@ -1483,7 +1483,7 @@ pub fn resolveSymbols(self: *Object, macho_file: *MachO) !void {
14831483 if (!nlist.ext()) continue;
14841484 if (nlist.sect()) {
14851485 const atom = self.getAtom(atom_index).?;
1486 if (!atom.flags.alive) continue;
1486 if (!atom.isAlive()) continue;
14871487 }
14881488
14891489 const gop = try macho_file.resolver.getOrPut(gpa, .{
......@@ -1552,7 +1552,7 @@ pub fn scanRelocs(self: *Object, macho_file: *MachO) !void {
15521552
15531553 for (self.getAtoms()) |atom_index| {
15541554 const atom = self.getAtom(atom_index) orelse continue;
1555 if (!atom.flags.alive) continue;
1555 if (!atom.isAlive()) continue;
15561556 const sect = atom.getInputSection(macho_file);
15571557 if (sect.isZerofill()) continue;
15581558 try atom.scanRelocs(macho_file);
......@@ -1563,10 +1563,10 @@ pub fn scanRelocs(self: *Object, macho_file: *MachO) !void {
15631563 if (!rec.alive) continue;
15641564 if (rec.getFde(macho_file)) |fde| {
15651565 if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| {
1566 sym.flags.needs_got = true;
1566 sym.setSectionFlags(.{ .needs_got = true });
15671567 }
15681568 } else if (rec.getPersonality(macho_file)) |sym| {
1569 sym.flags.needs_got = true;
1569 sym.setSectionFlags(.{ .needs_got = true });
15701570 }
15711571 }
15721572}
......@@ -1745,7 +1745,7 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
17451745 const ref = self.getSymbolRef(@intCast(i), macho_file);
17461746 const file = ref.getFile(macho_file) orelse continue;
17471747 if (file.getIndex() != self.index) continue;
1748 if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue;
1748 if (sym.getAtom(macho_file)) |atom| if (!atom.isAlive()) continue;
17491749 if (sym.isSymbolStab(macho_file)) continue;
17501750 const name = sym.getName(macho_file);
17511751 if (name.len == 0) continue;
......@@ -1854,7 +1854,7 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void {
18541854 }
18551855 for (self.getAtoms()) |atom_index| {
18561856 const atom = self.getAtom(atom_index) orelse continue;
1857 if (!atom.flags.alive) continue;
1857 if (!atom.isAlive()) continue;
18581858 const sect = atom.getInputSection(macho_file);
18591859 if (sect.isZerofill()) continue;
18601860 const value = math.cast(usize, atom.value) orelse return error.Overflow;
......@@ -1893,7 +1893,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
18931893 }
18941894 for (self.getAtoms()) |atom_index| {
18951895 const atom = self.getAtom(atom_index) orelse continue;
1896 if (!atom.flags.alive) continue;
1896 if (!atom.isAlive()) continue;
18971897 const sect = atom.getInputSection(macho_file);
18981898 if (sect.isZerofill()) continue;
18991899 const value = math.cast(usize, atom.value) orelse return error.Overflow;
src/link/MachO/Symbol.zig+24-10
......@@ -23,6 +23,8 @@ nlist_idx: u32 = 0,
2323/// Misc flags for the symbol packaged as packed struct for compression.
2424flags: Flags = .{},
2525
26sect_flags: std.atomic.Value(u8) = std.atomic.Value(u8).init(0),
27
2628visibility: Visibility = .local,
2729
2830extra: u32 = 0,
......@@ -69,6 +71,14 @@ pub fn getOutputSectionIndex(symbol: Symbol, macho_file: *MachO) u8 {
6971 return symbol.out_n_sect;
7072}
7173
74pub fn getSectionFlags(symbol: Symbol) SectionFlags {
75 return @bitCast(symbol.sect_flags.load(.seq_cst));
76}
77
78pub fn setSectionFlags(symbol: *Symbol, flags: SectionFlags) void {
79 _ = symbol.sect_flags.fetchOr(@bitCast(flags), .seq_cst);
80}
81
7282pub fn getFile(symbol: Symbol, macho_file: *MachO) ?File {
7383 return macho_file.getFile(symbol.file);
7484}
......@@ -116,9 +126,9 @@ pub fn getAddress(symbol: Symbol, opts: struct {
116126 stubs: bool = true,
117127}, macho_file: *MachO) u64 {
118128 if (opts.stubs) {
119 if (symbol.flags.stubs) {
129 if (symbol.getSectionFlags().stubs) {
120130 return symbol.getStubsAddress(macho_file);
121 } else if (symbol.flags.objc_stubs) {
131 } else if (symbol.getSectionFlags().objc_stubs) {
122132 return symbol.getObjcStubsAddress(macho_file);
123133 }
124134 }
......@@ -127,25 +137,25 @@ pub fn getAddress(symbol: Symbol, opts: struct {
127137}
128138
129139pub fn getGotAddress(symbol: Symbol, macho_file: *MachO) u64 {
130 if (!symbol.flags.has_got) return 0;
140 if (!symbol.getSectionFlags().has_got) return 0;
131141 const extra = symbol.getExtra(macho_file);
132142 return macho_file.got.getAddress(extra.got, macho_file);
133143}
134144
135145pub fn getStubsAddress(symbol: Symbol, macho_file: *MachO) u64 {
136 if (!symbol.flags.stubs) return 0;
146 if (!symbol.getSectionFlags().stubs) return 0;
137147 const extra = symbol.getExtra(macho_file);
138148 return macho_file.stubs.getAddress(extra.stubs, macho_file);
139149}
140150
141151pub fn getObjcStubsAddress(symbol: Symbol, macho_file: *MachO) u64 {
142 if (!symbol.flags.objc_stubs) return 0;
152 if (!symbol.getSectionFlags().objc_stubs) return 0;
143153 const extra = symbol.getExtra(macho_file);
144154 return macho_file.objc_stubs.getAddress(extra.objc_stubs, macho_file);
145155}
146156
147157pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 {
148 if (!symbol.flags.objc_stubs) return 0;
158 if (!symbol.getSectionFlags().objc_stubs) return 0;
149159 const extra = symbol.getExtra(macho_file);
150160 const file = symbol.getFile(macho_file).?;
151161 return switch (file) {
......@@ -155,7 +165,7 @@ pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 {
155165}
156166
157167pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 {
158 if (!symbol.flags.tlv_ptr) return 0;
168 if (!symbol.getSectionFlags().tlv_ptr) return 0;
159169 const extra = symbol.getExtra(macho_file);
160170 return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file);
161171}
......@@ -167,14 +177,14 @@ const GetOrCreateZigGotEntryResult = struct {
167177
168178pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult {
169179 assert(!macho_file.base.isRelocatable());
170 assert(symbol.flags.needs_zig_got);
171 if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).zig_got };
180 assert(symbol.getSectionFlags().needs_zig_got);
181 if (symbol.getSectionFlags().has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).zig_got };
172182 const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file);
173183 return .{ .found_existing = false, .index = index };
174184}
175185
176186pub fn getZigGotAddress(symbol: Symbol, macho_file: *MachO) u64 {
177 if (!symbol.flags.has_zig_got) return 0;
187 if (!symbol.getSectionFlags().has_zig_got) return 0;
178188 const extras = symbol.getExtra(macho_file);
179189 return macho_file.zig_got.entryAddress(extras.zig_got, macho_file);
180190}
......@@ -384,7 +394,9 @@ pub const Flags = packed struct {
384394
385395 /// Whether the symbol makes into the output symtab or not.
386396 output_symtab: bool = false,
397};
387398
399pub const SectionFlags = packed struct(u8) {
388400 /// Whether the symbol contains __got indirection.
389401 needs_got: bool = false,
390402 has_got: bool = false,
......@@ -401,6 +413,8 @@ pub const Flags = packed struct {
401413
402414 /// Whether the symbol contains __objc_stubs indirection.
403415 objc_stubs: bool = false,
416
417 _: u1 = 0,
404418};
405419
406420pub const Visibility = enum {
src/link/MachO/UnwindInfo.zig+1-1
......@@ -53,7 +53,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
5353 for (macho_file.sections.items(.atoms)) |atoms| {
5454 for (atoms.items) |ref| {
5555 const atom = ref.getAtom(macho_file) orelse continue;
56 if (!atom.flags.alive) continue;
56 if (!atom.isAlive()) continue;
5757 const recs = atom.getUnwindRecords(macho_file);
5858 const file = atom.getFile(macho_file);
5959 try info.records.ensureUnusedCapacity(gpa, recs.len);
src/link/MachO/ZigObject.zig+19-19
......@@ -245,7 +245,7 @@ pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) !void {
245245 if (!nlist.ext()) continue;
246246 if (nlist.sect()) {
247247 const atom = self.getAtom(atom_index).?;
248 if (!atom.flags.alive) continue;
248 if (!atom.isAlive()) continue;
249249 }
250250
251251 const gop = try macho_file.resolver.getOrPut(gpa, .{
......@@ -391,7 +391,7 @@ pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void {
391391pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void {
392392 for (self.getAtoms()) |atom_index| {
393393 const atom = self.getAtom(atom_index) orelse continue;
394 if (!atom.flags.alive) continue;
394 if (!atom.isAlive()) continue;
395395 const sect = atom.getInputSection(macho_file);
396396 if (sect.isZerofill()) continue;
397397 try atom.scanRelocs(macho_file);
......@@ -403,7 +403,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {
403403 var has_error = false;
404404 for (self.getAtoms()) |atom_index| {
405405 const atom = self.getAtom(atom_index) orelse continue;
406 if (!atom.flags.alive) continue;
406 if (!atom.isAlive()) continue;
407407 const sect = &macho_file.sections.items(.header)[atom.out_n_sect];
408408 if (sect.isZerofill()) continue;
409409 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 {
450450pub fn calcNumRelocs(self: *ZigObject, macho_file: *MachO) void {
451451 for (self.getAtoms()) |atom_index| {
452452 const atom = self.getAtom(atom_index) orelse continue;
453 if (!atom.flags.alive) continue;
453 if (!atom.isAlive()) continue;
454454 const header = &macho_file.sections.items(.header)[atom.out_n_sect];
455455 if (header.isZerofill()) continue;
456456 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 {
465465
466466 for (self.getAtoms()) |atom_index| {
467467 const atom = self.getAtom(atom_index) orelse continue;
468 if (!atom.flags.alive) continue;
468 if (!atom.isAlive()) continue;
469469 const header = macho_file.sections.items(.header)[atom.out_n_sect];
470470 const relocs = macho_file.sections.items(.relocs)[atom.out_n_sect].items;
471471 if (header.isZerofill()) continue;
......@@ -505,7 +505,7 @@ pub fn writeAtomsRelocatable(self: *ZigObject, macho_file: *MachO) !void {
505505
506506 for (self.getAtoms()) |atom_index| {
507507 const atom = self.getAtom(atom_index) orelse continue;
508 if (!atom.flags.alive) continue;
508 if (!atom.isAlive()) continue;
509509 const sect = atom.getInputSection(macho_file);
510510 if (sect.isZerofill()) continue;
511511 if (macho_file.isZigSection(atom.out_n_sect)) continue;
......@@ -529,7 +529,7 @@ pub fn writeAtoms(self: *ZigObject, macho_file: *MachO) !void {
529529
530530 for (self.getAtoms()) |atom_index| {
531531 const atom = self.getAtom(atom_index) orelse continue;
532 if (!atom.flags.alive) continue;
532 if (!atom.isAlive()) continue;
533533 const sect = atom.getInputSection(macho_file);
534534 if (sect.isZerofill()) continue;
535535 if (macho_file.isZigSection(atom.out_n_sect)) continue;
......@@ -549,7 +549,7 @@ pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) void {
549549 const ref = self.getSymbolRef(@intCast(i), macho_file);
550550 const file = ref.getFile(macho_file) orelse continue;
551551 if (file.getIndex() != self.index) continue;
552 if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue;
552 if (sym.getAtom(macho_file)) |atom| if (!atom.isAlive()) continue;
553553 sym.flags.output_symtab = true;
554554 if (sym.isLocal()) {
555555 sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
......@@ -914,7 +914,7 @@ pub fn updateDecl(
914914 const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
915915 const index = try self.getGlobalSymbol(macho_file, name, lib_name);
916916 const sym = &self.symbols.items[index];
917 sym.flags.needs_got = true;
917 sym.setSectionFlags(.{ .needs_got = true });
918918 return;
919919 }
920920
......@@ -993,7 +993,7 @@ fn updateDeclCode(
993993 const sym_name = try std.fmt.allocPrintZ(gpa, "_{s}", .{decl.fqn.toSlice(ip)});
994994 defer gpa.free(sym_name);
995995 sym.name = try self.strtab.insert(gpa, sym_name);
996 atom.flags.alive = true;
996 atom.setAlive(true);
997997 atom.name = sym.name;
998998 nlist.n_strx = sym.name;
999999 nlist.n_type = macho.N_SECT;
......@@ -1018,7 +1018,7 @@ fn updateDeclCode(
10181018
10191019 if (!macho_file.base.isRelocatable()) {
10201020 log.debug(" (updating offset table entry)", .{});
1021 assert(sym.flags.has_zig_got);
1021 assert(sym.getSectionFlags().has_zig_got);
10221022 const extra = sym.getExtra(macho_file);
10231023 try macho_file.zig_got.writeOne(macho_file, extra.zig_got);
10241024 }
......@@ -1034,7 +1034,7 @@ fn updateDeclCode(
10341034 errdefer self.freeDeclMetadata(macho_file, sym_index);
10351035
10361036 sym.value = 0;
1037 sym.flags.needs_zig_got = true;
1037 sym.setSectionFlags(.{ .needs_zig_got = true });
10381038 nlist.n_value = 0;
10391039
10401040 if (!macho_file.base.isRelocatable()) {
......@@ -1098,7 +1098,7 @@ fn createTlvInitializer(
10981098 const atom = sym.getAtom(macho_file).?;
10991099 sym.out_n_sect = sect_index;
11001100 atom.out_n_sect = sect_index;
1101 atom.flags.alive = true;
1101 atom.setAlive(true);
11021102 atom.alignment = alignment;
11031103 atom.size = code.len;
11041104 nlist.n_sect = sect_index + 1;
......@@ -1143,7 +1143,7 @@ fn createTlvDescriptor(
11431143
11441144 sym.value = 0;
11451145 sym.name = try self.strtab.insert(gpa, name);
1146 atom.flags.alive = true;
1146 atom.setAlive(true);
11471147 atom.name = sym.name;
11481148 nlist.n_strx = sym.name;
11491149 nlist.n_sect = sect_index + 1;
......@@ -1317,7 +1317,7 @@ fn lowerConst(
13171317 self.symtab.items(.size)[sym.nlist_idx] = code.len;
13181318
13191319 const atom = sym.getAtom(macho_file).?;
1320 atom.flags.alive = true;
1320 atom.setAlive(true);
13211321 atom.alignment = required_alignment;
13221322 atom.size = code.len;
13231323 atom.out_n_sect = output_section_index;
......@@ -1490,7 +1490,7 @@ fn updateLazySymbol(
14901490 self.symtab.items(.size)[sym.nlist_idx] = code.len;
14911491
14921492 const atom = sym.getAtom(macho_file).?;
1493 atom.flags.alive = true;
1493 atom.setAlive(true);
14941494 atom.name = name_str_index;
14951495 atom.alignment = required_alignment;
14961496 atom.size = code.len;
......@@ -1500,7 +1500,7 @@ fn updateLazySymbol(
15001500 errdefer self.freeDeclMetadata(macho_file, symbol_index);
15011501
15021502 sym.value = 0;
1503 sym.flags.needs_zig_got = true;
1503 sym.setSectionFlags(.{ .needs_zig_got = true });
15041504 nlist.n_value = 0;
15051505
15061506 if (!macho_file.base.isRelocatable()) {
......@@ -1576,7 +1576,7 @@ pub fn getOrCreateMetadataForDecl(
15761576 if (isThreadlocal(macho_file, decl_index)) {
15771577 sym.flags.tlv = true;
15781578 } else {
1579 sym.flags.needs_zig_got = true;
1579 sym.setSectionFlags(.{ .needs_zig_got = true });
15801580 }
15811581 gop.value_ptr.* = .{ .symbol_index = sym_index };
15821582 }
......@@ -1611,7 +1611,7 @@ pub fn getOrCreateMetadataForLazySymbol(
16111611 .unused => {
16121612 const symbol_index = try self.newSymbolWithAtom(gpa, 0, macho_file);
16131613 const sym = &self.symbols.items[symbol_index];
1614 sym.flags.needs_zig_got = true;
1614 sym.setSectionFlags(.{ .needs_zig_got = true });
16151615 metadata.symbol_index.* = symbol_index;
16161616 },
16171617 .pending_flush => return metadata.symbol_index.*,
src/link/MachO/dead_strip.zig+10-10
......@@ -82,9 +82,8 @@ fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), macho_file: *MachO) !v
8282}
8383
8484fn markAtom(atom: *Atom) bool {
85 const already_visited = atom.flags.visited;
86 atom.flags.visited = true;
87 return atom.flags.alive and !already_visited;
85 const already_visited = atom.visited.swap(true, .seq_cst);
86 return atom.isAlive() and !already_visited;
8887}
8988
9089fn 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 {
105104 !(mem.eql(u8, isec.sectName(), "__eh_frame") or
106105 mem.eql(u8, isec.sectName(), "__compact_unwind") or
107106 isec.attrs() & macho.S_ATTR_DEBUG != 0) and
108 !atom.flags.alive and refersLive(atom, macho_file))
107 !atom.isAlive() and refersLive(atom, macho_file))
109108 {
110109 markLive(atom, macho_file);
111110 loop = true;
......@@ -116,8 +115,8 @@ fn mark(roots: []*Atom, objects: []const File.Index, macho_file: *MachO) void {
116115}
117116
118117fn markLive(atom: *Atom, macho_file: *MachO) void {
119 assert(atom.flags.visited);
120 atom.flags.alive = true;
118 assert(atom.visited.load(.seq_cst));
119 atom.setAlive(true);
121120 track_live_log.debug("{}marking live atom({d},{s})", .{
122121 track_live_level,
123122 atom.atom_index,
......@@ -170,7 +169,7 @@ fn refersLive(atom: *Atom, macho_file: *MachO) bool {
170169 },
171170 };
172171 if (target_atom) |ta| {
173 if (ta.flags.alive) return true;
172 if (ta.isAlive()) return true;
174173 }
175174 }
176175 return false;
......@@ -181,9 +180,10 @@ fn prune(objects: []const File.Index, macho_file: *MachO) void {
181180 const file = macho_file.getFile(index).?;
182181 for (file.getAtoms()) |atom_index| {
183182 const atom = file.getAtom(atom_index) orelse continue;
184 if (atom.flags.alive and !atom.flags.visited) {
185 atom.flags.alive = false;
186 atom.markUnwindRecordsDead(macho_file);
183 if (!atom.visited.load(.seq_cst)) {
184 if (atom.alive.cmpxchgStrong(true, false, .seq_cst, .seq_cst) == null) {
185 atom.markUnwindRecordsDead(macho_file);
186 }
187187 }
188188 }
189189 }
src/link/MachO/dyld_info/Rebase.zig+1-1
......@@ -35,7 +35,7 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
3535 const file = macho_file.getFile(index).?;
3636 for (file.getAtoms()) |atom_index| {
3737 const atom = file.getAtom(atom_index) orelse continue;
38 if (!atom.flags.alive) continue;
38 if (!atom.isAlive()) continue;
3939 if (atom.getInputSection(macho_file).isZerofill()) continue;
4040 const atom_addr = atom.getAddress(macho_file);
4141 const seg_id = macho_file.sections.items(.segment_id)[atom.out_n_sect];
src/link/MachO/dyld_info/Trie.zig+3-3
......@@ -102,7 +102,7 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void {
102102 if (ref.getFile(macho_file) == null) continue;
103103 const sym = ref.getSymbol(macho_file).?;
104104 if (!sym.flags.@"export") continue;
105 if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue;
105 if (sym.getAtom(macho_file)) |atom| if (!atom.isAlive()) continue;
106106 var flags: u64 = if (sym.flags.abs)
107107 macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
108108 else if (sym.flags.tlv)
......@@ -111,8 +111,8 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void {
111111 macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
112112 if (sym.flags.weak) {
113113 flags |= macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
114 macho_file.weak_defines = true;
115 macho_file.binds_to_weak = true;
114 macho_file.weak_defines.store(true, .seq_cst);
115 macho_file.binds_to_weak.store(true, .seq_cst);
116116 }
117117 try self.put(gpa, .{
118118 .name = sym.getName(macho_file),
src/link/MachO/dyld_info/bind.zig+3-6
......@@ -10,10 +10,7 @@ pub const Entry = struct {
1010 if (entry.target.eql(other.target)) {
1111 return entry.offset < other.offset;
1212 }
13 if (entry.target.file == other.target.file) {
14 return entry.target.index < other.target.index;
15 }
16 return entry.target.file < other.target.file;
13 return entry.target.lessThan(other.target);
1714 }
1815 return entry.segment_id < other.segment_id;
1916 }
......@@ -47,7 +44,7 @@ pub const Bind = struct {
4744 const file = macho_file.getFile(index).?;
4845 for (file.getAtoms()) |atom_index| {
4946 const atom = file.getAtom(atom_index) orelse continue;
50 if (!atom.flags.alive) continue;
47 if (!atom.isAlive()) continue;
5148 if (atom.getInputSection(macho_file).isZerofill()) continue;
5249 const atom_addr = atom.getAddress(macho_file);
5350 const relocs = atom.getRelocs(macho_file);
......@@ -299,7 +296,7 @@ pub const WeakBind = struct {
299296 const file = macho_file.getFile(index).?;
300297 for (file.getAtoms()) |atom_index| {
301298 const atom = file.getAtom(atom_index) orelse continue;
302 if (!atom.flags.alive) continue;
299 if (!atom.isAlive()) continue;
303300 if (atom.getInputSection(macho_file).isZerofill()) continue;
304301 const atom_addr = atom.getAddress(macho_file);
305302 const relocs = atom.getRelocs(macho_file);
src/link/MachO/file.zig+11-9
......@@ -37,11 +37,10 @@ pub const File = union(enum) {
3737 }
3838
3939 pub fn scanRelocs(file: File, macho_file: *MachO) !void {
40 switch (file) {
40 return switch (file) {
4141 .dylib => unreachable,
42 .internal => |x| x.scanRelocs(macho_file),
4342 inline else => |x| x.scanRelocs(macho_file),
44 }
43 };
4544 }
4645
4746 /// Encodes symbol rank so that the following ordering applies:
......@@ -182,19 +181,19 @@ pub const File = union(enum) {
182181 if (ref.getFile(macho_file) == null) continue;
183182 if (ref.file != file.getIndex()) continue;
184183 const sym = ref.getSymbol(macho_file).?;
185 if (sym.flags.needs_got) {
184 if (sym.getSectionFlags().needs_got) {
186185 log.debug("'{s}' needs GOT", .{sym.getName(macho_file)});
187186 try macho_file.got.addSymbol(ref, macho_file);
188187 }
189 if (sym.flags.stubs) {
188 if (sym.getSectionFlags().stubs) {
190189 log.debug("'{s}' needs STUBS", .{sym.getName(macho_file)});
191190 try macho_file.stubs.addSymbol(ref, macho_file);
192191 }
193 if (sym.flags.tlv_ptr) {
192 if (sym.getSectionFlags().tlv_ptr) {
194193 log.debug("'{s}' needs TLV pointer", .{sym.getName(macho_file)});
195194 try macho_file.tlv_ptr.addSymbol(ref, macho_file);
196195 }
197 if (sym.flags.objc_stubs) {
196 if (sym.getSectionFlags().objc_stubs) {
198197 log.debug("'{s}' needs OBJC STUBS", .{sym.getName(macho_file)});
199198 try macho_file.objc_stubs.addSymbol(ref, macho_file);
200199 }
......@@ -268,6 +267,9 @@ pub const File = union(enum) {
268267 const ref_file = ref.getFile(macho_file) orelse continue;
269268 if (ref_file.getIndex() == file.getIndex()) continue;
270269
270 macho_file.dupes_mutex.lock();
271 defer macho_file.dupes_mutex.unlock();
272
271273 const gop = try macho_file.dupes.getOrPut(gpa, file.getGlobals()[i]);
272274 if (!gop.found_existing) {
273275 gop.value_ptr.* = .{};
......@@ -281,7 +283,7 @@ pub const File = union(enum) {
281283 defer tracy.end();
282284 for (file.getAtoms()) |atom_index| {
283285 const atom = file.getAtom(atom_index) orelse continue;
284 if (!atom.flags.alive) continue;
286 if (!atom.isAlive()) continue;
285287 atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file);
286288 }
287289 }
......@@ -295,7 +297,7 @@ pub const File = union(enum) {
295297
296298 pub fn writeAtoms(file: File, macho_file: *MachO) !void {
297299 return switch (file) {
298 .dylib, .zig_object => unreachable,
300 .dylib => unreachable,
299301 inline else => |x| x.writeAtoms(macho_file),
300302 };
301303 }
src/link/MachO/relocatable.zig+1-1
......@@ -261,7 +261,7 @@ fn initOutputSections(macho_file: *MachO) !void {
261261 const file = macho_file.getFile(index).?;
262262 for (file.getAtoms()) |atom_index| {
263263 const atom = file.getAtom(atom_index) orelse continue;
264 if (!atom.flags.alive) continue;
264 if (!atom.isAlive()) continue;
265265 atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file);
266266 }
267267 }
src/link/MachO/synthetic.zig+4-4
......@@ -24,8 +24,8 @@ pub const ZigGotSection = struct {
2424 const entry = &zig_got.entries.items[index];
2525 entry.* = sym_index;
2626 const symbol = &zo.symbols.items[sym_index];
27 assert(symbol.flags.needs_zig_got);
28 symbol.flags.has_zig_got = true;
27 assert(symbol.getSectionFlags().needs_zig_got);
28 symbol.setSectionFlags(.{ .has_zig_got = true });
2929 symbol.addExtra(.{ .zig_got = index }, macho_file);
3030 return index;
3131 }
......@@ -121,7 +121,7 @@ pub const GotSection = struct {
121121 const entry = try got.symbols.addOne(gpa);
122122 entry.* = ref;
123123 const symbol = ref.getSymbol(macho_file).?;
124 symbol.flags.has_got = true;
124 symbol.setSectionFlags(.{ .has_got = true });
125125 symbol.addExtra(.{ .got = index }, macho_file);
126126 }
127127
......@@ -689,7 +689,7 @@ pub const DataInCode = struct {
689689 dices[next_dice].offset < end_off) : (next_dice += 1)
690690 {}
691691
692 if (atom.flags.alive) for (dices[start_dice..next_dice]) |d| {
692 if (atom.isAlive()) for (dices[start_dice..next_dice]) |d| {
693693 dice.entries.appendAssumeCapacity(.{
694694 .atom_ref = .{ .index = atom_index, .file = index },
695695 .offset = @intCast(d.offset - start_off),
src/link/MachO/thunks.zig+3-3
......@@ -17,7 +17,7 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void {
1717 while (i < atoms.len) {
1818 const start = i;
1919 const start_atom = atoms[start].getAtom(macho_file).?;
20 assert(start_atom.flags.alive);
20 assert(start_atom.isAlive());
2121 start_atom.value = advance(header, start_atom.size, start_atom.alignment);
2222 i += 1;
2323
......@@ -25,7 +25,7 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void {
2525 header.size - start_atom.value < max_allowed_distance) : (i += 1)
2626 {
2727 const atom = atoms[i].getAtom(macho_file).?;
28 assert(atom.flags.alive);
28 assert(atom.isAlive());
2929 atom.value = advance(header, atom.size, atom.alignment);
3030 }
3131
......@@ -71,7 +71,7 @@ fn scanRelocs(thunk_index: Thunk.Index, gpa: Allocator, atoms: []const MachO.Ref
7171
7272fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
7373 const target = rel.getTargetSymbol(atom.*, macho_file);
74 if (target.flags.stubs or target.flags.objc_stubs) return false;
74 if (target.getSectionFlags().stubs or target.getSectionFlags().objc_stubs) return false;
7575 if (atom.out_n_sect != target.getOutputSectionIndex(macho_file)) return false;
7676 const target_atom = target.getAtom(macho_file).?;
7777 if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false;