Commit 2b84592858
Changed files (18)
src/arch/x86_64/Emit.zig
@@ -163,12 +163,12 @@ pub fn emitMir(emit: *Emit) Error!void {
const zo = macho_file.getZigObject().?;
const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?;
const sym = &zo.symbols.items[data.sym_index];
- if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
+ if (sym.getSectionFlags().needs_zig_got and !is_obj_or_static_lib) {
_ = try sym.getOrCreateZigGotEntry(data.sym_index, macho_file);
}
- const @"type": link.File.MachO.Relocation.Type = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
+ const @"type": link.File.MachO.Relocation.Type = if (sym.getSectionFlags().needs_zig_got and !is_obj_or_static_lib)
.zig_got_load
- else if (sym.flags.needs_got)
+ else if (sym.getSectionFlags().needs_got)
// TODO: it is possible to emit .got_load here that can potentially be relaxed
// however this requires always to use a MOVQ mnemonic
.got
src/arch/x86_64/Lower.zig
@@ -451,7 +451,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
},
.mov => {
- if (is_obj_or_static_lib and macho_sym.flags.needs_zig_got) emit_mnemonic = .lea;
+ if (is_obj_or_static_lib and macho_sym.getSectionFlags().needs_zig_got) emit_mnemonic = .lea;
break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
},
else => unreachable,
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);
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];
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),
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");
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);
+ }
}
}
}
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),
};
}
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;
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;
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);
}
}
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 {
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),
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;
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);
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.*,
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);
}
src/codegen.zig
@@ -924,7 +924,7 @@ fn genDeclRef(
const name = decl.name.toSlice(ip);
const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
const sym_index = try macho_file.getGlobalSymbol(name, lib_name);
- zo.symbols.items[sym_index].flags.needs_got = true;
+ zo.symbols.items[sym_index].setSectionFlags(.{ .needs_got = true });
return GenResult.mcv(.{ .load_symbol = sym_index });
}
const sym_index = try zo.getOrCreateMetadataForDecl(macho_file, decl_index);