Commit 174de37cef

Jakub Konka <kubkon@jakubkonka.com>
2024-07-10 16:36:32
macho: fix compile errors
1 parent 5b4c0cc
src/arch/x86_64/CodeGen.zig
@@ -12362,8 +12362,9 @@ fn genCall(self: *Self, info: union(enum) {
                         try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }, .{});
                         try self.asmRegister(.{ ._, .call }, .rax);
                     } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
-                        const sym_index = try macho_file.getZigObject().?.getOrCreateMetadataForDecl(macho_file, func.owner_decl);
-                        const sym = macho_file.getSymbol(sym_index);
+                        const zo = macho_file.getZigObject().?;
+                        const sym_index = try zo.getOrCreateMetadataForDecl(macho_file, func.owner_decl);
+                        const sym = zo.symbols.items[sym_index];
                         try self.genSetReg(
                             .rax,
                             Type.usize,
@@ -15396,9 +15397,10 @@ fn genLazySymbolRef(
             else => unreachable,
         }
     } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
-        const sym_index = macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err|
+        const zo = macho_file.getZigObject().?;
+        const sym_index = zo.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err|
             return self.fail("{s} creating lazy symbol", .{@errorName(err)});
-        const sym = macho_file.getSymbol(sym_index);
+        const sym = zo.symbols.items[sym_index];
         switch (tag) {
             .lea, .call => try self.genSetReg(
                 reg,
src/arch/x86_64/Emit.zig
@@ -162,7 +162,7 @@ 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];
+                    const sym = &zo.symbols.items[data.sym_index];
                     if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
                         _ = try sym.getOrCreateZigGotEntry(data.sym_index, macho_file);
                     }
src/link/MachO/dyld_info/bind.zig
@@ -1,17 +1,19 @@
 pub const Entry = struct {
-    target: Symbol.Index,
+    target: MachO.Ref,
     offset: u64,
     segment_id: u8,
     addend: i64,
 
     pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool {
+        _ = ctx;
         if (entry.segment_id == other.segment_id) {
-            if (entry.target == other.target) {
+            if (entry.target.eql(other.target)) {
                 return entry.offset < other.offset;
             }
-            const entry_name = ctx.getSymbol(entry.target).getName(ctx);
-            const other_name = ctx.getSymbol(other.target).getName(ctx);
-            return std.mem.lessThan(u8, entry_name, other_name);
+            if (entry.target.file == other.target.file) {
+                return entry.target.index < other.target.index;
+            }
+            return entry.target.file < other.target.file;
         }
         return entry.segment_id < other.segment_id;
     }
@@ -44,7 +46,7 @@ pub const Bind = struct {
         for (objects.items) |index| {
             const file = macho_file.getFile(index).?;
             for (file.getAtoms()) |atom_index| {
-                const atom = macho_file.getAtom(atom_index) orelse continue;
+                const atom = file.getAtom(atom_index) orelse continue;
                 if (!atom.flags.alive) continue;
                 if (atom.getInputSection(macho_file).isZerofill()) continue;
                 const atom_addr = atom.getAddress(macho_file);
@@ -55,10 +57,10 @@ pub const Bind = struct {
                     if (rel.type != .unsigned or rel.meta.length != 3 or rel.tag != .@"extern") continue;
                     const rel_offset = rel.offset - atom.off;
                     const addend = rel.addend + rel.getRelocAddend(cpu_arch);
-                    const sym = rel.getTargetSymbol(macho_file);
+                    const sym = rel.getTargetSymbol(atom.*, macho_file);
                     if (sym.isTlvInit(macho_file)) continue;
                     const entry = Entry{
-                        .target = rel.target,
+                        .target = rel.getTargetSymbolRef(atom.*, macho_file),
                         .offset = atom_addr + rel_offset - seg.vmaddr,
                         .segment_id = seg_id,
                         .addend = addend,
@@ -74,7 +76,7 @@ pub const Bind = struct {
             const seg_id = macho_file.sections.items(.segment_id)[sid];
             const seg = macho_file.segments.items[seg_id];
             for (macho_file.got.symbols.items, 0..) |ref, idx| {
-                const sym = macho_file.getSymbol(ref);
+                const sym = ref.getSymbol(macho_file).?;
                 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
                 const entry = Entry{
                     .target = ref,
@@ -93,7 +95,7 @@ pub const Bind = struct {
             const seg_id = macho_file.sections.items(.segment_id)[sid];
             const seg = macho_file.segments.items[seg_id];
             for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
-                const sym = macho_file.getSymbol(ref);
+                const sym = ref.getSymbol(macho_file).?;
                 const addr = sect.addr + idx * @sizeOf(u64);
                 const bind_entry = Entry{
                     .target = ref,
@@ -112,7 +114,7 @@ pub const Bind = struct {
             const seg = macho_file.segments.items[seg_id];
 
             for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
-                const sym = macho_file.getSymbol(ref);
+                const sym = ref.getSymbol(macho_file).?;
                 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);
                 const entry = Entry{
                     .target = ref,
@@ -162,7 +164,7 @@ pub const Bind = struct {
         var addend: i64 = 0;
         var count: usize = 0;
         var skip: u64 = 0;
-        var target: ?Symbol.Index = null;
+        var target: ?MachO.Ref = null;
 
         var state: enum {
             start,
@@ -173,7 +175,7 @@ pub const Bind = struct {
         var i: usize = 0;
         while (i < entries.len) : (i += 1) {
             const current = entries[i];
-            if (target == null or target.? != current.target) {
+            if (target == null or !target.?.eql(current.target)) {
                 switch (state) {
                     .start => {},
                     .bind_single => try doBind(writer),
@@ -182,7 +184,7 @@ pub const Bind = struct {
                 state = .start;
                 target = current.target;
 
-                const sym = ctx.getSymbol(current.target);
+                const sym = current.target.getSymbol(ctx).?;
                 const name = sym.getName(ctx);
                 const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
                 const ordinal: i16 = ord: {
@@ -296,7 +298,7 @@ pub const WeakBind = struct {
         for (objects.items) |index| {
             const file = macho_file.getFile(index).?;
             for (file.getAtoms()) |atom_index| {
-                const atom = macho_file.getAtom(atom_index) orelse continue;
+                const atom = file.getAtom(atom_index) orelse continue;
                 if (!atom.flags.alive) continue;
                 if (atom.getInputSection(macho_file).isZerofill()) continue;
                 const atom_addr = atom.getAddress(macho_file);
@@ -307,10 +309,10 @@ pub const WeakBind = struct {
                     if (rel.type != .unsigned or rel.meta.length != 3 or rel.tag != .@"extern") continue;
                     const rel_offset = rel.offset - atom.off;
                     const addend = rel.addend + rel.getRelocAddend(cpu_arch);
-                    const sym = rel.getTargetSymbol(macho_file);
+                    const sym = rel.getTargetSymbol(atom.*, macho_file);
                     if (sym.isTlvInit(macho_file)) continue;
                     const entry = Entry{
-                        .target = rel.target,
+                        .target = rel.getTargetSymbolRef(atom.*, macho_file),
                         .offset = atom_addr + rel_offset - seg.vmaddr,
                         .segment_id = seg_id,
                         .addend = addend,
@@ -326,7 +328,7 @@ pub const WeakBind = struct {
             const seg_id = macho_file.sections.items(.segment_id)[sid];
             const seg = macho_file.segments.items[seg_id];
             for (macho_file.got.symbols.items, 0..) |ref, idx| {
-                const sym = macho_file.getSymbol(ref);
+                const sym = ref.getSymbol(macho_file).?;
                 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
                 const entry = Entry{
                     .target = ref,
@@ -346,7 +348,7 @@ pub const WeakBind = struct {
             const seg = macho_file.segments.items[seg_id];
 
             for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
-                const sym = macho_file.getSymbol(ref);
+                const sym = ref.getSymbol(macho_file).?;
                 const addr = sect.addr + idx * @sizeOf(u64);
                 const bind_entry = Entry{
                     .target = ref,
@@ -365,7 +367,7 @@ pub const WeakBind = struct {
             const seg = macho_file.segments.items[seg_id];
 
             for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
-                const sym = macho_file.getSymbol(ref);
+                const sym = ref.getSymbol(macho_file).?;
                 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);
                 const entry = Entry{
                     .target = ref,
@@ -415,7 +417,7 @@ pub const WeakBind = struct {
         var addend: i64 = 0;
         var count: usize = 0;
         var skip: u64 = 0;
-        var target: ?Symbol.Index = null;
+        var target: ?MachO.Ref = null;
 
         var state: enum {
             start,
@@ -426,7 +428,7 @@ pub const WeakBind = struct {
         var i: usize = 0;
         while (i < entries.len) : (i += 1) {
             const current = entries[i];
-            if (target == null or target.? != current.target) {
+            if (target == null or !target.?.eql(current.target)) {
                 switch (state) {
                     .start => {},
                     .bind_single => try doBind(writer),
@@ -435,7 +437,7 @@ pub const WeakBind = struct {
                 state = .start;
                 target = current.target;
 
-                const sym = ctx.getSymbol(current.target);
+                const sym = current.target.getSymbol(ctx).?;
                 const name = sym.getName(ctx);
                 const flags: u8 = 0; // TODO NON_WEAK_DEFINITION
 
@@ -536,7 +538,7 @@ pub const LazyBind = struct {
         const seg = macho_file.segments.items[seg_id];
 
         for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
-            const sym = macho_file.getSymbol(ref);
+            const sym = ref.getSymbol(macho_file).?;
             const addr = sect.addr + idx * @sizeOf(u64);
             const bind_entry = Entry{
                 .target = ref,
@@ -565,7 +567,7 @@ pub const LazyBind = struct {
         for (self.entries.items) |entry| {
             self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len));
 
-            const sym = ctx.getSymbol(entry.target);
+            const sym = entry.target.getSymbol(ctx).?;
             const name = sym.getName(ctx);
             const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
             const ordinal: i16 = ord: {
src/link/MachO/dyld_info/Rebase.zig
@@ -34,7 +34,7 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
     for (objects.items) |index| {
         const file = macho_file.getFile(index).?;
         for (file.getAtoms()) |atom_index| {
-            const atom = macho_file.getAtom(atom_index) orelse continue;
+            const atom = file.getAtom(atom_index) orelse continue;
             if (!atom.flags.alive) continue;
             if (atom.getInputSection(macho_file).isZerofill()) continue;
             const atom_addr = atom.getAddress(macho_file);
@@ -43,7 +43,7 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
             for (atom.getRelocs(macho_file)) |rel| {
                 if (rel.type != .unsigned or rel.meta.length != 3) continue;
                 if (rel.tag == .@"extern") {
-                    const sym = rel.getTargetSymbol(macho_file);
+                    const sym = rel.getTargetSymbol(atom.*, macho_file);
                     if (sym.isTlvInit(macho_file)) continue;
                     if (sym.flags.import) continue;
                 }
@@ -72,7 +72,7 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
         const seg_id = macho_file.sections.items(.segment_id)[sid];
         const seg = macho_file.segments.items[seg_id];
         for (macho_file.got.symbols.items, 0..) |ref, idx| {
-            const sym = macho_file.getSymbol(ref);
+            const sym = ref.getSymbol(macho_file).?;
             const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
             if (!sym.flags.import) {
                 try rebase.entries.append(gpa, .{
@@ -88,7 +88,7 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
         const seg_id = macho_file.sections.items(.segment_id)[sid];
         const seg = macho_file.segments.items[seg_id];
         for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
-            const sym = macho_file.getSymbol(ref);
+            const sym = ref.getSymbol(macho_file).?;
             const addr = sect.addr + idx * @sizeOf(u64);
             const rebase_entry = Rebase.Entry{
                 .offset = addr - seg.vmaddr,
@@ -104,7 +104,7 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
         const seg_id = macho_file.sections.items(.segment_id)[sid];
         const seg = macho_file.segments.items[seg_id];
         for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
-            const sym = macho_file.getSymbol(ref);
+            const sym = ref.getSymbol(macho_file).?;
             const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);
             if (!sym.flags.import) {
                 try rebase.entries.append(gpa, .{
src/link/MachO/dyld_info/Trie.zig
@@ -94,33 +94,31 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void {
     const gpa = macho_file.base.comp.gpa;
 
     try self.init(gpa);
-    // TODO
-    // try self.nodes.ensureUnusedCapacity(gpa, macho_file.resolver.values.items.len * 2);
-    // try self.edges.ensureUnusedCapacity(gpa, macho_file.resolver.values.items.len * 2);
+    try self.nodes.ensureUnusedCapacity(gpa, macho_file.resolver.values.items.len * 2);
+    try self.edges.ensureUnusedCapacity(gpa, macho_file.resolver.values.items.len * 2);
 
     const seg = macho_file.getTextSegment();
-    for (macho_file.objects.items) |index| {
-        for (macho_file.getFile(index).?.getSymbols()) |ref| {
-            const sym = macho_file.getSymbol(ref);
-            if (!sym.flags.@"export") continue;
-            if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue;
-            var flags: u64 = if (sym.flags.abs)
-                macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
-            else if (sym.flags.tlv)
-                macho.EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
-            else
-                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;
-            }
-            try self.put(gpa, .{
-                .name = sym.getName(macho_file),
-                .vmaddr_offset = sym.getAddress(.{ .stubs = false }, macho_file) - seg.vmaddr,
-                .export_flags = flags,
-            });
+    for (macho_file.resolver.values.items) |ref| {
+        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;
+        var flags: u64 = if (sym.flags.abs)
+            macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
+        else if (sym.flags.tlv)
+            macho.EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
+        else
+            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;
         }
+        try self.put(gpa, .{
+            .name = sym.getName(macho_file),
+            .vmaddr_offset = sym.getAddress(.{ .stubs = false }, macho_file) - seg.vmaddr,
+            .export_flags = flags,
+        });
     }
 
     try self.finalize(gpa);
src/link/MachO/Atom.zig
@@ -213,7 +213,8 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 {
 /// File offset relocation happens transparently, so it is not included in
 /// this calculation.
 pub fn capacity(self: Atom, macho_file: *MachO) u64 {
-    const next_addr = if (macho_file.getAtom(self.next_index)) |next|
+    const zo = macho_file.getZigObject().?;
+    const next_addr = if (zo.getAtom(self.next_index)) |next|
         next.getAddress(macho_file)
     else
         std.math.maxInt(u32);
@@ -222,7 +223,8 @@ pub fn capacity(self: Atom, macho_file: *MachO) u64 {
 
 pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {
     // No need to keep a free list node for the last block.
-    const next = macho_file.getAtom(self.next_index) orelse return false;
+    const zo = macho_file.getZigObject().?;
+    const next = zo.getAtom(self.next_index) orelse return false;
     const cap = next.getAddress(macho_file) - self.getAddress(macho_file);
     const ideal_cap = MachO.padToIdeal(self.size);
     if (cap <= ideal_cap) return false;
@@ -231,6 +233,7 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {
 }
 
 pub fn allocate(self: *Atom, macho_file: *MachO) !void {
+    const zo = macho_file.getZigObject().?;
     const sect = &macho_file.sections.items(.header)[self.out_n_sect];
     const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect];
     const last_atom_index = &macho_file.sections.items(.last_atom_index)[self.out_n_sect];
@@ -250,7 +253,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void {
         var i: usize = free_list.items.len;
         while (i < free_list.items.len) {
             const big_atom_index = free_list.items[i];
-            const big_atom = macho_file.getAtom(big_atom_index).?;
+            const big_atom = zo.getAtom(big_atom_index).?;
             // We now have a pointer to a live atom that has too much capacity.
             // Is it enough that we could fit this new atom?
             const cap = big_atom.capacity(macho_file);
@@ -282,7 +285,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void {
                 free_list_removal = i;
             }
             break :blk new_start_vaddr;
-        } else if (macho_file.getAtom(last_atom_index.*)) |last| {
+        } else if (zo.getAtom(last_atom_index.*)) |last| {
             const ideal_capacity = MachO.padToIdeal(last.size);
             const ideal_capacity_end_vaddr = last.value + ideal_capacity;
             const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);
@@ -302,7 +305,7 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void {
     });
 
     const expand_section = if (atom_placement) |placement_index|
-        macho_file.getAtom(placement_index).?.next_index == 0
+        zo.getAtom(placement_index).?.next_index == 0
     else
         true;
     if (expand_section) {
@@ -327,15 +330,15 @@ pub fn allocate(self: *Atom, macho_file: *MachO) !void {
     // This function can also reallocate an atom.
     // In this case we need to "unplug" it from its previous location before
     // plugging it in to its new location.
-    if (macho_file.getAtom(self.prev_index)) |prev| {
+    if (zo.getAtom(self.prev_index)) |prev| {
         prev.next_index = self.next_index;
     }
-    if (macho_file.getAtom(self.next_index)) |next| {
+    if (zo.getAtom(self.next_index)) |next| {
         next.prev_index = self.prev_index;
     }
 
     if (atom_placement) |big_atom_index| {
-        const big_atom = macho_file.getAtom(big_atom_index).?;
+        const big_atom = zo.getAtom(big_atom_index).?;
         self.prev_index = big_atom_index;
         self.next_index = big_atom.next_index;
         big_atom.next_index = self.atom_index;
@@ -365,6 +368,7 @@ pub fn free(self: *Atom, macho_file: *MachO) void {
 
     const comp = macho_file.base.comp;
     const gpa = comp.gpa;
+    const zo = macho_file.getZigObject().?;
     const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect];
     const last_atom_index = &macho_file.sections.items(.last_atom_index)[self.out_n_sect];
     var already_have_free_list_node = false;
@@ -383,9 +387,9 @@ pub fn free(self: *Atom, macho_file: *MachO) void {
         }
     }
 
-    if (macho_file.getAtom(last_atom_index.*)) |last_atom| {
+    if (zo.getAtom(last_atom_index.*)) |last_atom| {
         if (last_atom.atom_index == self.atom_index) {
-            if (macho_file.getAtom(self.prev_index)) |_| {
+            if (zo.getAtom(self.prev_index)) |_| {
                 // TODO shrink the section size here
                 last_atom_index.* = self.prev_index;
             } else {
@@ -394,7 +398,7 @@ pub fn free(self: *Atom, macho_file: *MachO) void {
         }
     }
 
-    if (macho_file.getAtom(self.prev_index)) |prev| {
+    if (zo.getAtom(self.prev_index)) |prev| {
         prev.next_index = self.next_index;
         if (!already_have_free_list_node and prev.*.freeListEligible(macho_file)) {
             // The free list is heuristics, it doesn't have to be perfect, so we can
@@ -405,7 +409,7 @@ pub fn free(self: *Atom, macho_file: *MachO) void {
         self.prev_index = 0;
     }
 
-    if (macho_file.getAtom(self.next_index)) |next| {
+    if (zo.getAtom(self.next_index)) |next| {
         next.prev_index = self.prev_index;
     } else {
         self.next_index = 0;
@@ -423,7 +427,7 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void {
     const gpa = macho_file.base.comp.gpa;
     const file = self.getFile(macho_file);
     assert(file == .zig_object);
-    var extra = self.getExtra(macho_file).?;
+    var extra = self.getExtra(macho_file);
     const rels = &file.zig_object.relocs.items[extra.rel_index];
     try rels.append(gpa, reloc);
     extra.rel_count += 1;
@@ -432,7 +436,7 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void {
 
 pub fn freeRelocs(self: *Atom, macho_file: *MachO) void {
     self.getFile(macho_file).zig_object.freeAtomRelocs(self.*, macho_file);
-    var extra = self.getExtra(macho_file).?;
+    var extra = self.getExtra(macho_file);
     extra.rel_count = 0;
     self.setExtra(extra, macho_file);
 }
@@ -630,7 +634,7 @@ fn resolveRelocInner(
     const TLS = @as(i64, @intCast(macho_file.getTlsAddress()));
     const SUB = if (subtractor) |sub| @as(i64, @intCast(sub.getTargetAddress(self, macho_file))) else 0;
     // Address of the __got_zig table entry if any.
-    const ZIG_GOT = @as(i64, @intCast(rel.getZigGotTargetAddress(self, macho_file)));
+    const ZIG_GOT = @as(i64, @intCast(rel.getZigGotTargetAddress(macho_file)));
 
     const divExact = struct {
         fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {
src/link/MachO/DebugSymbols.zig
@@ -175,8 +175,9 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64
 }
 
 pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
+    const zo = macho_file.getZigObject().?;
     for (self.relocs.items) |*reloc| {
-        const sym = macho_file.getSymbol(reloc.target);
+        const sym = zo.symbols.items[reloc.target];
         const sym_name = sym.getName(macho_file);
         const addr = switch (reloc.type) {
             .direct_load => sym.getAddress(.{}, macho_file),
@@ -382,23 +383,22 @@ pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 {
     cmd.symoff = off;
 
     try self.symtab.resize(gpa, cmd.nsyms);
-    try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1);
+    try self.strtab.resize(gpa, cmd.strsize);
+    self.strtab.items[0] = 0;
 
     if (macho_file.getZigObject()) |zo| {
         zo.writeSymtab(macho_file, self);
     }
     for (macho_file.objects.items) |index| {
-        try macho_file.getFile(index).?.writeSymtab(macho_file, self);
+        macho_file.getFile(index).?.writeSymtab(macho_file, self);
     }
     for (macho_file.dylibs.items) |index| {
-        try macho_file.getFile(index).?.writeSymtab(macho_file, self);
+        macho_file.getFile(index).?.writeSymtab(macho_file, self);
     }
     if (macho_file.getInternalObject()) |internal| {
         internal.writeSymtab(macho_file, self);
     }
 
-    assert(self.strtab.items.len == cmd.strsize);
-
     try self.file.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff);
 
     return off + cmd.nsyms * @sizeOf(macho.nlist_64);
src/link/MachO/Dylib.zig
@@ -6,7 +6,7 @@ strtab: std.ArrayListUnmanaged(u8) = .{},
 id: ?Id = null,
 ordinal: u16 = 0,
 
-symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
+symbols: std.ArrayListUnmanaged(Symbol) = .{},
 symbols_extra: std.ArrayListUnmanaged(u32) = .{},
 globals: std.ArrayListUnmanaged(MachO.SymbolResolver.Index) = .{},
 dependents: std.ArrayListUnmanaged(Id) = .{},
@@ -516,7 +516,7 @@ pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void {
     }
 }
 
-pub fn resolveSymbols(self: *Dylib, macho_file: *MachO) void {
+pub fn resolveSymbols(self: *Dylib, macho_file: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -584,7 +584,7 @@ pub fn calcSymtabSize(self: *Dylib, macho_file: *MachO) void {
     }
 }
 
-pub fn writeSymtab(self: Dylib, macho_file: *MachO) void {
+pub fn writeSymtab(self: Dylib, macho_file: *MachO, ctx: anytype) void {
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -594,13 +594,13 @@ pub fn writeSymtab(self: Dylib, macho_file: *MachO) void {
         const file = ref.getFile(macho_file) orelse continue;
         if (file.getIndex() != self.index) continue;
         const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
-        const out_sym = &macho_file.symtab.items[idx];
+        const out_sym = &ctx.symtab.items[idx];
         out_sym.n_strx = n_strx;
         sym.setOutputSym(macho_file, out_sym);
         const name = sym.getName(macho_file);
-        @memcpy(macho_file.strtab.items[n_strx..][0..name.len], name);
+        @memcpy(ctx.strtab.items[n_strx..][0..name.len], name);
         n_strx += @intCast(name.len);
-        macho_file.strtab.items[n_strx] = 0;
+        ctx.strtab.items[n_strx] = 0;
         n_strx += 1;
     }
 }
@@ -718,10 +718,16 @@ fn formatSymtab(
     _ = unused_fmt_string;
     _ = options;
     const dylib = ctx.dylib;
+    const macho_file = ctx.macho_file;
     try writer.writeAll("  globals\n");
-    for (dylib.symbols.items) |index| {
-        const global = ctx.macho_file.getSymbol(index);
-        try writer.print("    {}\n", .{global.fmt(ctx.macho_file)});
+    for (dylib.symbols.items, 0..) |sym, i| {
+        const ref = dylib.getSymbolRef(@intCast(i), macho_file);
+        if (ref.getFile(macho_file) == null) {
+            // TODO any better way of handling this?
+            try writer.print("    {s} : unclaimed\n", .{sym.getName(macho_file)});
+        } else {
+            try writer.print("    {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
+        }
     }
 }
 
src/link/MachO/file.zig
@@ -30,10 +30,10 @@ pub const File = union(enum) {
         }
     }
 
-    pub fn resolveSymbols(file: File, macho_file: *MachO) void {
-        switch (file) {
+    pub fn resolveSymbols(file: File, macho_file: *MachO) !void {
+        return switch (file) {
             inline else => |x| x.resolveSymbols(macho_file),
-        }
+        };
     }
 
     pub fn scanRelocs(file: File, macho_file: *MachO) !void {
@@ -147,19 +147,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.getSectionFlags().got) {
+            if (sym.flags.needs_got) {
                 log.debug("'{s}' needs GOT", .{sym.getName(macho_file)});
                 try macho_file.got.addSymbol(ref, macho_file);
             }
-            if (sym.getSectionFlags().stubs) {
+            if (sym.flags.stubs) {
                 log.debug("'{s}' needs STUBS", .{sym.getName(macho_file)});
                 try macho_file.stubs.addSymbol(ref, macho_file);
             }
-            if (sym.getSectionFlags().tlv_ptr) {
+            if (sym.flags.tlv_ptr) {
                 log.debug("'{s}' needs TLV pointer", .{sym.getName(macho_file)});
                 try macho_file.tlv_ptr.addSymbol(ref, macho_file);
             }
-            if (sym.getSectionFlags().objc_stubs) {
+            if (sym.flags.objc_stubs) {
                 log.debug("'{s}' needs OBJC STUBS", .{sym.getName(macho_file)});
                 try macho_file.objc_stubs.addSymbol(ref, macho_file);
             }
@@ -171,7 +171,7 @@ pub const File = union(enum) {
         defer tracy.end();
         for (file.getAtoms()) |atom_index| {
             const atom = file.getAtom(atom_index) orelse continue;
-            if (!atom.alive.load(.seq_cst)) continue;
+            if (!atom.flags.alive) continue;
             atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file);
         }
     }
@@ -185,18 +185,18 @@ pub const File = union(enum) {
 
     pub fn writeAtoms(file: File, macho_file: *MachO) !void {
         return switch (file) {
-            .dylib => unreachable,
+            .dylib, .zig_object => unreachable,
             inline else => |x| x.writeAtoms(macho_file),
         };
     }
 
-    pub fn calcSymtabSize(file: File, macho_file: *MachO) !void {
+    pub fn calcSymtabSize(file: File, macho_file: *MachO) void {
         return switch (file) {
             inline else => |x| x.calcSymtabSize(macho_file),
         };
     }
 
-    pub fn writeSymtab(file: File, macho_file: *MachO, ctx: anytype) !void {
+    pub fn writeSymtab(file: File, macho_file: *MachO, ctx: anytype) void {
         return switch (file) {
             inline else => |x| x.writeSymtab(macho_file, ctx),
         };
src/link/MachO/InternalObject.zig
@@ -16,7 +16,7 @@ objc_selrefs: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64),
 force_undefined: std.ArrayListUnmanaged(Symbol.Index) = .{},
 entry_index: ?Symbol.Index = null,
 dyld_stub_binder_index: ?Symbol.Index = null,
-dyld_private: ?Symbol.Index = null,
+dyld_private_index: ?Symbol.Index = null,
 objc_msg_send_index: ?Symbol.Index = null,
 mh_execute_header_index: ?Symbol.Index = null,
 mh_dylib_header_index: ?Symbol.Index = null,
@@ -206,7 +206,7 @@ pub fn resolveBoundarySymbols(self: *InternalObject, macho_file: *MachO) !void {
         const nlist_idx: u32 = @intCast(self.symtab.items.len);
         const nlist = self.symtab.addOneAssumeCapacity();
         nlist.* = .{
-            .n_strx = name_off.pos,
+            .n_strx = name_off,
             .n_type = macho.N_SECT,
             .n_sect = 0,
             .n_desc = 0,
@@ -273,7 +273,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
     const nlist_idx: u32 = @intCast(self.symtab.items.len);
     const nlist = try self.symtab.addOne(gpa);
     nlist.* = .{
-        .n_strx = name_str.pos,
+        .n_strx = name_str,
         .n_type = macho.N_SECT,
         .n_sect = @intCast(n_sect + 1),
         .n_desc = 0,
@@ -286,12 +286,12 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
 }
 
 fn addObjcSelrefsSection(self: *InternalObject, methname_sym_index: Symbol.Index, macho_file: *MachO) !Symbol.Index {
-    const gpa = macho_file.base.allocator;
+    const gpa = macho_file.base.comp.gpa;
     const atom_index = try self.addAtom(gpa);
     try self.atoms_indexes.append(gpa, atom_index);
     const atom = self.getAtom(atom_index).?;
     atom.size = @sizeOf(u64);
-    atom.alignment = 3;
+    atom.alignment = .@"8";
 
     const n_sect = try self.addSection(gpa, "__DATA", "__objc_selrefs");
     const sect = &self.sections.items(.header)[n_sect];
@@ -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.setSectionFlags(.{ .objc_stubs = true });
+        sym.flags.objc_stubs = true;
 
         const idx = ref.getFile(macho_file).?.object.globals.items[ref.index];
         try self.globals.append(gpa, idx);
@@ -417,7 +417,7 @@ pub fn resolveLiterals(self: *InternalObject, lp: *MachO.LiteralPool, macho_file
         const target = rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?;
         try buffer.ensureUnusedCapacity(target.size);
         buffer.resize(target.size) catch unreachable;
-        @memcpy(buffer.items, self.getSectionData(target.n_sect));
+        @memcpy(buffer.items, try self.getSectionData(target.n_sect));
         const res = try lp.insert(gpa, header.type(), buffer.items);
         buffer.clearRetainingCapacity();
         if (!res.found_existing) {
@@ -425,7 +425,7 @@ pub fn resolveLiterals(self: *InternalObject, lp: *MachO.LiteralPool, macho_file
         } else {
             const lp_sym = lp.getSymbol(res.index, macho_file);
             const lp_atom = lp_sym.getAtom(macho_file).?;
-            lp_atom.alignment = @max(lp_atom.alignment, atom.alignment);
+            lp_atom.alignment = lp_atom.alignment.max(atom.alignment);
             atom.flags.alive = false;
         }
         atom.addExtra(.{ .literal_pool_index = res.index }, macho_file);
@@ -438,7 +438,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.alive.load(.seq_cst)) continue;
+        if (!atom.flags.alive) continue;
 
         const relocs = blk: {
             const extra = atom.getExtra(macho_file);
@@ -463,7 +463,7 @@ pub fn dedupLiterals(self: *InternalObject, lp: MachO.LiteralPool, macho_file: *
     }
 
     for (self.symbols.items) |*sym| {
-        if (!sym.getSectionFlags().objc_stubs) continue;
+        if (!sym.flags.objc_stubs) continue;
         const extra = sym.getExtra(macho_file);
         const file = sym.getFile(macho_file).?;
         if (file.getIndex() != self.index) continue;
@@ -495,14 +495,14 @@ pub fn scanRelocs(self: *InternalObject, macho_file: *MachO) void {
     if (self.getDyldStubBinderRef(macho_file)) |ref| {
         if (ref.getFile(macho_file) != null) {
             const sym = ref.getSymbol(macho_file).?;
-            sym.flags.got = true;
+            sym.flags.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.got = true;
+            sym.flags.needs_got = true;
         }
     }
 }
@@ -569,30 +569,30 @@ pub fn writeAtoms(self: *InternalObject, macho_file: *MachO) !void {
 
     for (self.getAtoms()) |atom_index| {
         const atom = self.getAtom(atom_index) orelse continue;
-        if (!atom.alive.load(.seq_cst)) continue;
+        if (!atom.flags.alive) continue;
         const sect = atom.getInputSection(macho_file);
         if (sect.isZerofill()) continue;
         const off = atom.value;
         const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items[off..][0..atom.size];
-        @memcpy(buffer, self.getSectionData(atom.n_sect));
+        @memcpy(buffer, try self.getSectionData(atom.n_sect));
         try atom.resolveRelocs(macho_file, buffer);
     }
 }
 
-pub fn writeSymtab(self: InternalObject, macho_file: *MachO) void {
+pub fn writeSymtab(self: InternalObject, macho_file: *MachO, ctx: anytype) void {
     var n_strx = self.output_symtab_ctx.stroff;
     for (self.symbols.items, 0..) |sym, i| {
         const ref = self.getSymbolRef(@intCast(i), macho_file);
         const file = ref.getFile(macho_file) orelse continue;
         if (file.getIndex() != self.index) continue;
         const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
-        const out_sym = &macho_file.symtab.items[idx];
+        const out_sym = &ctx.symtab.items[idx];
         out_sym.n_strx = n_strx;
         sym.setOutputSym(macho_file, out_sym);
         const name = sym.getName(macho_file);
-        @memcpy(macho_file.strtab.items[n_strx..][0..name.len], name);
+        @memcpy(ctx.strtab.items[n_strx..][0..name.len], name);
         n_strx += @intCast(name.len);
-        macho_file.strtab.items[n_strx] = 0;
+        ctx.strtab.items[n_strx] = 0;
         n_strx += 1;
     }
 }
@@ -640,7 +640,7 @@ pub fn asFile(self: *InternalObject) File {
 }
 
 pub fn getAtomRelocs(self: *const InternalObject, atom: Atom, macho_file: *MachO) []const Relocation {
-    const extra = atom.getExtra(macho_file).?;
+    const extra = atom.getExtra(macho_file);
     const relocs = self.sections.items(.relocs)[atom.n_sect];
     return relocs.items[extra.rel_index..][0..extra.rel_count];
 }
src/link/MachO/Object.zig
@@ -11,10 +11,10 @@ sections: std.MultiArrayList(Section) = .{},
 symtab: std.MultiArrayList(Nlist) = .{},
 strtab: std.ArrayListUnmanaged(u8) = .{},
 
-symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
+symbols: std.ArrayListUnmanaged(Symbol) = .{},
 symbols_extra: std.ArrayListUnmanaged(u32) = .{},
 globals: std.ArrayListUnmanaged(MachO.SymbolResolver.Index) = .{},
-atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
+atoms: std.ArrayListUnmanaged(Atom) = .{},
 atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
 atoms_extra: std.ArrayListUnmanaged(u32) = .{},
 
@@ -228,7 +228,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
 
     // Parse DWARF __TEXT,__eh_frame section
     if (self.eh_frame_sect_index) |index| {
-        try self.initEhFrameRecords(index, macho_file);
+        try self.initEhFrameRecords(gpa, index, handle, macho_file);
     }
 
     // Parse Apple's __LD,__compact_unwind section
@@ -261,7 +261,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
 
     try self.parseDebugInfo(macho_file);
 
-    for (self.atoms.items) |atom_index| {
+    for (self.getAtoms()) |atom_index| {
         const atom = self.getAtom(atom_index) orelse continue;
         const isec = atom.getInputSection(macho_file);
         if (mem.eql(u8, isec.sectName(), "__eh_frame") or
@@ -606,7 +606,7 @@ fn initPointerLiterals(self: *Object, allocator: Allocator, macho_file: *MachO)
     }
 }
 
-pub fn resolveLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) !void {
+pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -646,7 +646,7 @@ pub fn resolveLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO)
                 } else {
                     const lp_sym = lp.getSymbol(res.index, macho_file);
                     const lp_atom = lp_sym.getAtom(macho_file).?;
-                    lp_atom.alignment = @max(lp_atom.alignment, atom.alignment);
+                    lp_atom.alignment = lp_atom.alignment.max(atom.alignment);
                     atom.flags.alive = false;
                 }
                 atom.addExtra(.{ .literal_pool_index = res.index }, macho_file);
@@ -684,7 +684,7 @@ pub fn resolveLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO)
                 } else {
                     const lp_sym = lp.getSymbol(res.index, macho_file);
                     const lp_atom = lp_sym.getAtom(macho_file).?;
-                    lp_atom.alignment = @max(lp_atom.alignment, atom.alignment);
+                    lp_atom.alignment = lp_atom.alignment.max(atom.alignment);
                     atom.flags.alive = false;
                 }
                 atom.addExtra(.{ .literal_pool_index = res.index }, macho_file);
@@ -823,7 +823,7 @@ fn initSymbols(self: *Object, allocator: Allocator, macho_file: *MachO) !void {
         const index = self.addSymbolAssumeCapacity();
         const symbol = &self.symbols.items[index];
         symbol.value = nlist.n_value;
-        symbol.name = .{ .pos = nlist.n_strx, .len = @intCast(self.getNStrx(nlist.n_strx).len + 1) };
+        symbol.name = nlist.n_strx;
         symbol.nlist_idx = @intCast(i);
         symbol.extra = self.addSymbolExtraAssumeCapacity(.{});
 
@@ -838,7 +838,9 @@ fn initSymbols(self: *Object, allocator: Allocator, macho_file: *MachO) !void {
         symbol.flags.tentative = nlist.tentative();
         symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip();
         symbol.flags.dyn_ref = nlist.n_desc & macho.REFERENCED_DYNAMICALLY != 0;
-        symbol.flags.interposable = nlist.ext() and (nlist.sect() or nlist.abs()) and macho_file.options.dylib and macho_file.options.namespace == .flat and !nlist.pext();
+        symbol.flags.interposable = nlist.ext() and (nlist.sect() or nlist.abs()) and macho_file.base.isDynLib() and !nlist.pext();
+        // TODO
+        // symbol.flags.interposable = nlist.ext() and (nlist.sect() or nlist.abs()) and macho_file.base.isDynLib() and macho_file.options.namespace == .flat and !nlist.pext();
 
         if (nlist.sect() and
             self.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES)
@@ -869,7 +871,7 @@ fn initSymbolStabs(self: *Object, allocator: Allocator, nlists: anytype, macho_f
         fn find(fs: @This(), addr: u64) ?Symbol.Index {
             // TODO binary search since we have the list sorted
             for (fs.entries) |nlist| {
-                if (nlist.nlist.n_value == addr) return fs.ctx.symbols.items[nlist.idx];
+                if (nlist.nlist.n_value == addr) return @intCast(nlist.idx);
             }
             return null;
         }
@@ -920,17 +922,17 @@ fn initSymbolStabs(self: *Object, allocator: Allocator, nlists: anytype, macho_f
             switch (nlist.n_type) {
                 macho.N_BNSYM => {
                     stab.is_func = true;
-                    stab.symbol = sym_lookup.find(nlist.n_value);
+                    stab.index = sym_lookup.find(nlist.n_value);
                     // TODO validate
                     i += 3;
                 },
                 macho.N_GSYM => {
                     stab.is_func = false;
-                    stab.symbol = sym_lookup.find(addr_lookup.get(self.getString(nlist.n_strx)).?);
+                    stab.index = sym_lookup.find(addr_lookup.get(self.getString(nlist.n_strx)).?);
                 },
                 macho.N_STSYM => {
                     stab.is_func = false;
-                    stab.symbol = sym_lookup.find(nlist.n_value);
+                    stab.index = sym_lookup.find(nlist.n_value);
                 },
                 else => {
                     try macho_file.reportParseError2(self.index, "unhandled symbol stab type 0x{x}", .{
@@ -1103,9 +1105,9 @@ fn initUnwindRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fil
         ctx: *const Object,
 
         fn find(fs: @This(), addr: u64) ?Symbol.Index {
-            for (fs.ctx.symbols.items, 0..) |sym_index, i| {
+            for (0..fs.ctx.symbols.items.len) |i| {
                 const nlist = fs.ctx.symtab.items(.nlist)[i];
-                if (nlist.ext() and nlist.n_value == addr) return sym_index;
+                if (nlist.ext() and nlist.n_value == addr) return @intCast(i);
             }
             return null;
         }
@@ -1274,7 +1276,7 @@ fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target.
             // Create a null record
             const rec_index = try self.addUnwindRecord(allocator);
             const rec = self.getUnwindRecord(rec_index);
-            const atom = macho_file.getAtom(meta.atom).?;
+            const atom = self.getAtom(meta.atom).?;
             try self.unwind_records_indexes.append(allocator, rec_index);
             rec.length = @intCast(meta.size);
             rec.atom = meta.atom;
@@ -1468,17 +1470,17 @@ fn findCompileUnit(self: *Object, args: struct {
     };
 }
 
-pub fn resolveSymbols(self: *Object, macho_file: *MachO) void {
+pub fn resolveSymbols(self: *Object, macho_file: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
 
-    const gpa = macho_file.base.allocator;
+    const gpa = macho_file.base.comp.gpa;
 
     for (self.symtab.items(.nlist), self.symtab.items(.atom), self.globals.items, 0..) |nlist, atom_index, *global, i| {
         if (!nlist.ext()) continue;
         if (nlist.sect()) {
             const atom = self.getAtom(atom_index).?;
-            if (!atom.alive.load(.seq_cst)) continue;
+            if (!atom.flags.alive) continue;
         }
 
         const gop = try macho_file.resolver.getOrPut(gpa, .{
@@ -1643,7 +1645,7 @@ pub fn claimUnresolved(self: *Object, macho_file: *MachO) void {
 
         if (self.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue;
 
-        const is_import = switch (macho_file.options.undefined_treatment) {
+        const is_import = switch (macho_file.undefined_treatment) {
             .@"error" => false,
             .warn, .suppress => nlist.weakRef(),
             .dynamic_lookup => true,
@@ -1682,8 +1684,8 @@ pub fn claimUnresolvedRelocatable(self: *Object, macho_file: *MachO) void {
     }
 }
 
-fn addSection(self: *Object, allocator: Allocator, segname: []const u8, sectname: []const u8) !u32 {
-    const n_sect = @as(u32, @intCast(try self.sections.addOne(allocator)));
+fn addSection(self: *Object, allocator: Allocator, segname: []const u8, sectname: []const u8) !u8 {
+    const n_sect = @as(u8, @intCast(try self.sections.addOne(allocator)));
     self.sections.set(n_sect, .{
         .header = .{
             .sectname = MachO.makeStaticString(sectname),
@@ -1799,7 +1801,7 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ
     try writer.writeAll(data);
 }
 
-pub fn calcSymtabSize(self: *Object, macho_file: *MachO) !void {
+pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -1821,27 +1823,27 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) !void {
             continue;
         sym.flags.output_symtab = true;
         if (sym.isLocal()) {
-            try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
+            sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
             self.output_symtab_ctx.nlocals += 1;
         } else if (sym.flags.@"export") {
-            try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file);
+            sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file);
             self.output_symtab_ctx.nexports += 1;
         } else {
             assert(sym.flags.import);
-            try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file);
+            sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file);
             self.output_symtab_ctx.nimports += 1;
         }
         self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1));
     }
 
     if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo())
-        try self.calcStabsSize(macho_file);
+        self.calcStabsSize(macho_file);
 }
 
-pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
+pub fn calcStabsSize(self: *Object, macho_file: *MachO) void {
     if (self.compile_unit) |cu| {
-        const comp_dir = cu.getCompDir(self);
-        const tu_name = cu.getTuName(self);
+        const comp_dir = cu.getCompDir(self.*);
+        const tu_name = cu.getTuName(self.*);
 
         self.output_symtab_ctx.nstabs += 4; // N_SO, N_SO, N_OSO, N_SO
         self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir
@@ -1876,12 +1878,12 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
 
         for (self.stab_files.items) |sf| {
             self.output_symtab_ctx.nstabs += 4; // N_SO, N_SO, N_OSO, N_SO
-            self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getCompDir(self).len + 1)); // comp_dir
-            self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getTuName(self).len + 1)); // tu_name
-            self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getOsoPath(self).len + 1)); // path
+            self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getCompDir(self.*).len + 1)); // comp_dir
+            self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getTuName(self.*).len + 1)); // tu_name
+            self.output_symtab_ctx.strsize += @as(u32, @intCast(sf.getOsoPath(self.*).len + 1)); // path
 
             for (sf.stabs.items) |stab| {
-                const sym = stab.getSymbol(macho_file) orelse continue;
+                const sym = stab.getSymbol(self.*) orelse continue;
                 const file = sym.getFile(macho_file).?;
                 if (file.getIndex() != self.index) continue;
                 if (!sym.flags.output_symtab) continue;
@@ -2065,7 +2067,7 @@ pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {
     }
 }
 
-pub fn writeSymtab(self: Object, macho_file: *MachO) void {
+pub fn writeSymtab(self: Object, macho_file: *MachO, ctx: anytype) void {
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -2075,21 +2077,21 @@ pub fn writeSymtab(self: Object, macho_file: *MachO) void {
         const file = ref.getFile(macho_file) orelse continue;
         if (file.getIndex() != self.index) continue;
         const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
-        const out_sym = &macho_file.symtab.items[idx];
+        const out_sym = &ctx.symtab.items[idx];
         out_sym.n_strx = n_strx;
         sym.setOutputSym(macho_file, out_sym);
         const name = sym.getName(macho_file);
-        @memcpy(macho_file.strtab.items[n_strx..][0..name.len], name);
+        @memcpy(ctx.strtab.items[n_strx..][0..name.len], name);
         n_strx += @intCast(name.len);
-        macho_file.strtab.items[n_strx] = 0;
+        ctx.strtab.items[n_strx] = 0;
         n_strx += 1;
     }
 
     if (macho_file.base.comp.config.debug_format != .strip and self.hasDebugInfo())
-        try self.writeStabs(n_strx, macho_file);
+        self.writeStabs(n_strx, macho_file, ctx);
 }
 
-pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
+pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) void {
     const writeFuncStab = struct {
         inline fn writeFuncStab(
             n_strx: u32,
@@ -2097,7 +2099,7 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
             n_value: u64,
             size: u64,
             index: u32,
-            context: *MachO,
+            context: anytype,
         ) void {
             context.symtab.items[index] = .{
                 .n_strx = 0,
@@ -2139,7 +2141,7 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
 
         // Open scope
         // N_SO comp_dir
-        macho_file.symtab.items[index] = .{
+        ctx.symtab.items[index] = .{
             .n_strx = n_strx,
             .n_type = macho.N_SO,
             .n_sect = 0,
@@ -2147,9 +2149,9 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
             .n_value = 0,
         };
         index += 1;
-        @memcpy(macho_file.strtab.items[n_strx..][0..comp_dir.len], comp_dir);
+        @memcpy(ctx.strtab.items[n_strx..][0..comp_dir.len], comp_dir);
         n_strx += @intCast(comp_dir.len);
-        macho_file.strtab.items[n_strx] = 0;
+        ctx.strtab.items[n_strx] = 0;
         n_strx += 1;
         // N_SO tu_name
         macho_file.symtab.items[index] = .{
@@ -2160,12 +2162,12 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
             .n_value = 0,
         };
         index += 1;
-        @memcpy(macho_file.strtab.items[n_strx..][0..tu_name.len], tu_name);
+        @memcpy(ctx.strtab.items[n_strx..][0..tu_name.len], tu_name);
         n_strx += @intCast(tu_name.len);
-        macho_file.strtab.items[n_strx] = 0;
+        ctx.strtab.items[n_strx] = 0;
         n_strx += 1;
         // N_OSO path
-        macho_file.symtab.items[index] = .{
+        ctx.symtab.items[index] = .{
             .n_strx = n_strx,
             .n_type = macho.N_OSO,
             .n_sect = 0,
@@ -2174,20 +2176,20 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
         };
         index += 1;
         if (self.in_archive) |ar| {
-            @memcpy(macho_file.strtab.items[n_strx..][0..ar.path.len], ar.path);
+            @memcpy(ctx.strtab.items[n_strx..][0..ar.path.len], ar.path);
             n_strx += @intCast(ar.path.len);
-            macho_file.strtab.items[n_strx] = '(';
+            ctx.strtab.items[n_strx] = '(';
             n_strx += 1;
-            @memcpy(macho_file.strtab.items[n_strx..][0..self.path.len], self.path);
+            @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path);
             n_strx += @intCast(self.path.len);
-            macho_file.strtab.items[n_strx] = ')';
+            ctx.strtab.items[n_strx] = ')';
             n_strx += 1;
-            macho_file.strtab.items[n_strx] = 0;
+            ctx.strtab.items[n_strx] = 0;
             n_strx += 1;
         } else {
-            @memcpy(macho_file.strtab.items[n_strx..][0..self.path.len], self.path);
+            @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path);
             n_strx += @intCast(self.path.len);
-            macho_file.strtab.items[n_strx] = 0;
+            ctx.strtab.items[n_strx] = 0;
             n_strx += 1;
         }
 
@@ -2203,17 +2205,17 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
             const sect = macho_file.sections.items(.header)[sym.getOutputSectionIndex(macho_file)];
             const sym_n_strx = n_strx: {
                 const symtab_index = sym.getOutputSymtabIndex(macho_file).?;
-                const osym = macho_file.symtab.items[symtab_index];
+                const osym = ctx.symtab.items[symtab_index];
                 break :n_strx osym.n_strx;
             };
             const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.getOutputSectionIndex(macho_file) + 1) else 0;
             const sym_n_value = sym.getAddress(.{}, macho_file);
             const sym_size = sym.getSize(macho_file);
             if (sect.isCode()) {
-                writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, macho_file);
+                writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);
                 index += 4;
             } else if (sym.visibility == .global) {
-                macho_file.symtab.items[index] = .{
+                ctx.symtab.items[index] = .{
                     .n_strx = sym_n_strx,
                     .n_type = macho.N_GSYM,
                     .n_sect = sym_n_sect,
@@ -2222,7 +2224,7 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
                 };
                 index += 1;
             } else {
-                macho_file.symtab.items[index] = .{
+                ctx.symtab.items[index] = .{
                     .n_strx = sym_n_strx,
                     .n_type = macho.N_STSYM,
                     .n_sect = sym_n_sect,
@@ -2235,7 +2237,7 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
 
         // Close scope
         // N_SO
-        macho_file.symtab.items[index] = .{
+        ctx.symtab.items[index] = .{
             .n_strx = 0,
             .n_type = macho.N_SO,
             .n_sect = 0,
@@ -2246,13 +2248,13 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
         assert(self.hasSymbolStabs());
 
         for (self.stab_files.items) |sf| {
-            const comp_dir = sf.getCombDir(self);
+            const comp_dir = sf.getCompDir(self);
             const tu_name = sf.getTuName(self);
             const oso_path = sf.getOsoPath(self);
 
             // Open scope
             // N_SO comp_dir
-            macho_file.symtab.items[index] = .{
+            ctx.symtab.items[index] = .{
                 .n_strx = n_strx,
                 .n_type = macho.N_SO,
                 .n_sect = 0,
@@ -2260,12 +2262,12 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
                 .n_value = 0,
             };
             index += 1;
-            @memcpy(macho_file.strtab.items[n_strx..][0..comp_dir.len], comp_dir);
+            @memcpy(ctx.strtab.items[n_strx..][0..comp_dir.len], comp_dir);
             n_strx += @intCast(comp_dir.len);
-            macho_file.strtab.items[n_strx] = 0;
+            ctx.strtab.items[n_strx] = 0;
             n_strx += 1;
             // N_SO tu_name
-            macho_file.symtab.items[index] = .{
+            ctx.symtab.items[index] = .{
                 .n_strx = n_strx,
                 .n_type = macho.N_SO,
                 .n_sect = 0,
@@ -2273,12 +2275,12 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
                 .n_value = 0,
             };
             index += 1;
-            @memcpy(macho_file.strtab.items[n_strx..][0..tu_name.len], tu_name);
+            @memcpy(ctx.strtab.items[n_strx..][0..tu_name.len], tu_name);
             n_strx += @intCast(tu_name.len);
-            macho_file.strtab.items[n_strx] = 0;
+            ctx.strtab.items[n_strx] = 0;
             n_strx += 1;
             // N_OSO path
-            macho_file.symtab.items[index] = .{
+            ctx.symtab.items[index] = .{
                 .n_strx = n_strx,
                 .n_type = macho.N_OSO,
                 .n_sect = 0,
@@ -2286,29 +2288,29 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
                 .n_value = sf.getOsoModTime(self),
             };
             index += 1;
-            @memcpy(macho_file.strtab.items[n_strx..][0..oso_path.len], oso_path);
+            @memcpy(ctx.strtab.items[n_strx..][0..oso_path.len], oso_path);
             n_strx += @intCast(oso_path.len);
-            macho_file.strtab.items[n_strx] = 0;
+            ctx.strtab.items[n_strx] = 0;
             n_strx += 1;
 
             for (sf.stabs.items) |stab| {
-                const sym = stab.getSymbol(macho_file) orelse continue;
+                const sym = stab.getSymbol(self) orelse continue;
                 const file = sym.getFile(macho_file).?;
                 if (file.getIndex() != self.index) continue;
                 if (!sym.flags.output_symtab) continue;
                 const sym_n_strx = n_strx: {
                     const symtab_index = sym.getOutputSymtabIndex(macho_file).?;
-                    const osym = macho_file.symtab.items[symtab_index];
+                    const osym = ctx.symtab.items[symtab_index];
                     break :n_strx osym.n_strx;
                 };
                 const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.getOutputSectionIndex(macho_file) + 1) else 0;
                 const sym_n_value = sym.getAddress(.{}, macho_file);
                 const sym_size = sym.getSize(macho_file);
                 if (stab.is_func) {
-                    writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, macho_file);
+                    writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);
                     index += 4;
                 } else if (sym.visibility == .global) {
-                    macho_file.symtab.items[index] = .{
+                    ctx.symtab.items[index] = .{
                         .n_strx = sym_n_strx,
                         .n_type = macho.N_GSYM,
                         .n_sect = sym_n_sect,
@@ -2317,7 +2319,7 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
                     };
                     index += 1;
                 } else {
-                    macho_file.symtab.items[index] = .{
+                    ctx.symtab.items[index] = .{
                         .n_strx = sym_n_strx,
                         .n_type = macho.N_STSYM,
                         .n_sect = sym_n_sect,
@@ -2330,7 +2332,7 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
 
             // Close scope
             // N_SO
-            macho_file.symtab.items[index] = .{
+            ctx.symtab.items[index] = .{
                 .n_strx = 0,
                 .n_type = macho.N_SO,
                 .n_sect = 0,
@@ -2343,7 +2345,7 @@ pub fn writeStabs(self: *const Object, stroff: u32, macho_file: *MachO) void {
 }
 
 pub fn getAtomRelocs(self: *const Object, atom: Atom, macho_file: *MachO) []const Relocation {
-    const extra = atom.getExtra(macho_file).?;
+    const extra = atom.getExtra(macho_file);
     const relocs = self.sections.items(.relocs)[atom.n_sect];
     return relocs.items[extra.rel_index..][0..extra.rel_count];
 }
@@ -2402,7 +2404,7 @@ pub fn asFile(self: *Object) File {
 }
 
 const AddAtomArgs = struct {
-    name: MachO.String,
+    name: u32,
     n_sect: u8,
     off: u64,
     size: u64,
@@ -2420,7 +2422,7 @@ fn addAtom(self: *Object, allocator: Allocator, args: AddAtomArgs) !Atom.Index {
         .size = args.size,
         .off = args.off,
         .extra = try self.addAtomExtra(allocator, .{}),
-        .alignment = args.alignment,
+        .alignment = Atom.Alignment.fromLog2Units(args.alignment),
     };
     return atom_index;
 }
@@ -2693,12 +2695,12 @@ fn formatSymtab(
     }
     for (object.stab_files.items) |sf| {
         try writer.print("  stabs({s},{s},{s})\n", .{
-            sf.getCompDir(object),
-            sf.getTuName(object),
-            sf.getOsoPath(object),
+            sf.getCompDir(object.*),
+            sf.getTuName(object.*),
+            sf.getOsoPath(object.*),
         });
         for (sf.stabs.items) |stab| {
-            try writer.print("    {}", .{stab.fmt(object)});
+            try writer.print("    {}", .{stab.fmt(object.*)});
         }
     }
 }
@@ -2744,33 +2746,33 @@ const StabFile = struct {
     comp_dir: u32,
     stabs: std.ArrayListUnmanaged(Stab) = .{},
 
-    fn getCompDir(sf: StabFile, object: *const Object) [:0]const u8 {
+    fn getCompDir(sf: StabFile, object: Object) [:0]const u8 {
         const nlist = object.symtab.items(.nlist)[sf.comp_dir];
         return object.getString(nlist.n_strx);
     }
 
-    fn getTuName(sf: StabFile, object: *const Object) [:0]const u8 {
+    fn getTuName(sf: StabFile, object: Object) [:0]const u8 {
         const nlist = object.symtab.items(.nlist)[sf.comp_dir + 1];
         return object.getString(nlist.n_strx);
     }
 
-    fn getOsoPath(sf: StabFile, object: *const Object) [:0]const u8 {
+    fn getOsoPath(sf: StabFile, object: Object) [:0]const u8 {
         const nlist = object.symtab.items(.nlist)[sf.comp_dir + 2];
         return object.getString(nlist.n_strx);
     }
 
-    fn getOsoModTime(sf: StabFile, object: *const Object) u64 {
+    fn getOsoModTime(sf: StabFile, object: Object) u64 {
         const nlist = object.symtab.items(.nlist)[sf.comp_dir + 2];
         return nlist.n_value;
     }
 
     const Stab = struct {
         is_func: bool = true,
-        symbol: ?Symbol.Index = null,
+        index: ?Symbol.Index = null,
 
-        fn getSymbol(stab: Stab, object: *const Object) ?*Symbol {
+        fn getSymbol(stab: Stab, object: Object) ?Symbol {
             const index = stab.index orelse return null;
-            return &object.symbols.items[index];
+            return object.symbols.items[index];
         }
 
         pub fn format(
@@ -2786,9 +2788,9 @@ const StabFile = struct {
             @compileError("do not format stabs directly");
         }
 
-        const StabFormatContext = struct { Stab, *const Object };
+        const StabFormatContext = struct { Stab, Object };
 
-        pub fn fmt(stab: Stab, object: *const Object) std.fmt.Formatter(format2) {
+        pub fn fmt(stab: Stab, object: Object) std.fmt.Formatter(format2) {
             return .{ .data = .{ stab, object } };
         }
 
@@ -2817,11 +2819,11 @@ const CompileUnit = struct {
     comp_dir: u32,
     tu_name: u32,
 
-    fn getCompDir(cu: CompileUnit, object: *const Object) [:0]const u8 {
+    fn getCompDir(cu: CompileUnit, object: Object) [:0]const u8 {
         return object.getString(cu.comp_dir);
     }
 
-    fn getTuName(cu: CompileUnit, object: *const Object) [:0]const u8 {
+    fn getTuName(cu: CompileUnit, object: Object) [:0]const u8 {
         return object.getString(cu.tu_name);
     }
 };
@@ -2840,15 +2842,14 @@ const CompactUnwindCtx = struct {
 
 const x86_64 = struct {
     fn parseRelocs(
-        self: *const Object,
-        n_sect: u8,
+        self: *Object,
         sect: macho.section_64,
         out: *std.ArrayListUnmanaged(Relocation),
+        handle: File.Handle,
         macho_file: *MachO,
     ) !void {
         const gpa = macho_file.base.comp.gpa;
 
-        const handle = macho_file.getFileHandle(self.file_handle);
         const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
         defer gpa.free(relocs_buffer);
         {
@@ -2857,8 +2858,12 @@ const x86_64 = struct {
         }
         const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
 
-        const code = try self.getSectionData(@intCast(n_sect), macho_file);
+        const code = try gpa.alloc(u8, sect.size);
         defer gpa.free(code);
+        {
+            const amt = try handle.preadAll(code, sect.offset + self.offset);
+            if (amt != code.len) return error.InputOutput;
+        }
 
         try out.ensureTotalCapacityPrecise(gpa, relocs.len);
 
@@ -2880,8 +2885,9 @@ const x86_64 = struct {
                 .X86_64_RELOC_SIGNED_4 => 4,
                 else => 0,
             };
+            var is_extern = rel.r_extern == 1;
 
-            const target = if (rel.r_extern == 0) blk: {
+            const target = if (!is_extern) blk: {
                 const nsect = rel.r_symbolnum - 1;
                 const taddr: i64 = if (rel.r_pcrel == 1)
                     @as(i64, @intCast(sect.addr)) + rel.r_address + addend + 4
@@ -2893,9 +2899,15 @@ const x86_64 = struct {
                     });
                     return error.MalformedObject;
                 };
-                addend = taddr - @as(i64, @intCast(macho_file.getAtom(target).?.getInputAddress(macho_file)));
+                const target_atom = self.getAtom(target).?;
+                addend = taddr - @as(i64, @intCast(target_atom.getInputAddress(macho_file)));
+                const isec = target_atom.getInputSection(macho_file);
+                if (isCstringLiteral(isec) or isFixedSizeLiteral(isec) or isPtrLiteral(isec)) {
+                    is_extern = true;
+                    break :blk target_atom.getExtra(macho_file).literal_symbol_index;
+                }
                 break :blk target;
-            } else self.symbols.items[rel.r_symbolnum];
+            } else rel.r_symbolnum;
 
             const has_subtractor = if (i > 0 and
                 @as(macho.reloc_type_x86_64, @enumFromInt(relocs[i - 1].r_type)) == .X86_64_RELOC_SUBTRACTOR)
@@ -2909,7 +2921,7 @@ const x86_64 = struct {
                 break :blk true;
             } else false;
 
-            const @"type": Relocation.Type = validateRelocType(rel, rel_type) catch |err| {
+            const @"type": Relocation.Type = validateRelocType(rel, rel_type, is_extern) catch |err| {
                 switch (err) {
                     error.Pcrel => try macho_file.reportParseError2(
                         self.index,
@@ -2936,7 +2948,7 @@ const x86_64 = struct {
             };
 
             out.appendAssumeCapacity(.{
-                .tag = if (rel.r_extern == 1) .@"extern" else .local,
+                .tag = if (is_extern) .@"extern" else .local,
                 .offset = @as(u32, @intCast(rel.r_address)),
                 .target = target,
                 .addend = addend,
@@ -2951,7 +2963,7 @@ const x86_64 = struct {
         }
     }
 
-    fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_x86_64) !Relocation.Type {
+    fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_x86_64, is_extern: bool) !Relocation.Type {
         switch (rel_type) {
             .X86_64_RELOC_UNSIGNED => {
                 if (rel.r_pcrel == 1) return error.Pcrel;
@@ -2971,7 +2983,7 @@ const x86_64 = struct {
             => {
                 if (rel.r_pcrel == 0) return error.NonPcrel;
                 if (rel.r_length != 2) return error.InvalidLength;
-                if (rel.r_extern == 0) return error.NonExtern;
+                if (!is_extern) return error.NonExtern;
                 return switch (rel_type) {
                     .X86_64_RELOC_BRANCH => .branch,
                     .X86_64_RELOC_GOT_LOAD => .got_load,
@@ -3002,15 +3014,14 @@ const x86_64 = struct {
 
 const aarch64 = struct {
     fn parseRelocs(
-        self: *const Object,
-        n_sect: u8,
+        self: *Object,
         sect: macho.section_64,
         out: *std.ArrayListUnmanaged(Relocation),
+        handle: File.Handle,
         macho_file: *MachO,
     ) !void {
         const gpa = macho_file.base.comp.gpa;
 
-        const handle = macho_file.getFileHandle(self.file_handle);
         const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
         defer gpa.free(relocs_buffer);
         {
@@ -3019,8 +3030,12 @@ const aarch64 = struct {
         }
         const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
 
-        const code = try self.getSectionData(@intCast(n_sect), macho_file);
+        const code = try gpa.alloc(u8, sect.size);
         defer gpa.free(code);
+        {
+            const amt = try handle.preadAll(code, sect.offset + self.offset);
+            if (amt != code.len) return error.InputOutput;
+        }
 
         try out.ensureTotalCapacityPrecise(gpa, relocs.len);
 
@@ -3066,8 +3081,9 @@ const aarch64 = struct {
             }
 
             const rel_type: macho.reloc_type_arm64 = @enumFromInt(rel.r_type);
+            var is_extern = rel.r_extern == 1;
 
-            const target = if (rel.r_extern == 0) blk: {
+            const target = if (!is_extern) blk: {
                 const nsect = rel.r_symbolnum - 1;
                 const taddr: i64 = if (rel.r_pcrel == 1)
                     @as(i64, @intCast(sect.addr)) + rel.r_address + addend
@@ -3079,9 +3095,15 @@ const aarch64 = struct {
                     });
                     return error.MalformedObject;
                 };
-                addend = taddr - @as(i64, @intCast(macho_file.getAtom(target).?.getInputAddress(macho_file)));
+                const target_atom = self.getAtom(target).?;
+                addend = taddr - @as(i64, @intCast(target_atom.getInputAddress(macho_file)));
+                const isec = target_atom.getInputSection(macho_file);
+                if (isCstringLiteral(isec) or isFixedSizeLiteral(isec) or isPtrLiteral(isec)) {
+                    is_extern = true;
+                    break :blk target_atom.getExtra(macho_file).literal_symbol_index;
+                }
                 break :blk target;
-            } else self.symbols.items[rel.r_symbolnum];
+            } else rel.r_symbolnum;
 
             const has_subtractor = if (i > 0 and
                 @as(macho.reloc_type_arm64, @enumFromInt(relocs[i - 1].r_type)) == .ARM64_RELOC_SUBTRACTOR)
@@ -3095,7 +3117,7 @@ const aarch64 = struct {
                 break :blk true;
             } else false;
 
-            const @"type": Relocation.Type = validateRelocType(rel, rel_type) catch |err| {
+            const @"type": Relocation.Type = validateRelocType(rel, rel_type, is_extern) catch |err| {
                 switch (err) {
                     error.Pcrel => try macho_file.reportParseError2(
                         self.index,
@@ -3122,7 +3144,7 @@ const aarch64 = struct {
             };
 
             out.appendAssumeCapacity(.{
-                .tag = if (rel.r_extern == 1) .@"extern" else .local,
+                .tag = if (is_extern) .@"extern" else .local,
                 .offset = @as(u32, @intCast(rel.r_address)),
                 .target = target,
                 .addend = addend,
@@ -3137,7 +3159,7 @@ const aarch64 = struct {
         }
     }
 
-    fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_arm64) !Relocation.Type {
+    fn validateRelocType(rel: macho.relocation_info, rel_type: macho.reloc_type_arm64, is_extern: bool) !Relocation.Type {
         switch (rel_type) {
             .ARM64_RELOC_UNSIGNED => {
                 if (rel.r_pcrel == 1) return error.Pcrel;
@@ -3158,7 +3180,7 @@ const aarch64 = struct {
             => {
                 if (rel.r_pcrel == 0) return error.NonPcrel;
                 if (rel.r_length != 2) return error.InvalidLength;
-                if (rel.r_extern == 0) return error.NonExtern;
+                if (!is_extern) return error.NonExtern;
                 return switch (rel_type) {
                     .ARM64_RELOC_BRANCH26 => .branch,
                     .ARM64_RELOC_PAGE21 => .page,
@@ -3175,7 +3197,7 @@ const aarch64 = struct {
             => {
                 if (rel.r_pcrel == 1) return error.Pcrel;
                 if (rel.r_length != 2) return error.InvalidLength;
-                if (rel.r_extern == 0) return error.NonExtern;
+                if (!is_extern) return error.NonExtern;
                 return switch (rel_type) {
                     .ARM64_RELOC_PAGEOFF12 => .pageoff,
                     .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => .got_load_pageoff,
src/link/MachO/Symbol.zig
@@ -150,7 +150,7 @@ pub fn getObjcSelrefsAddress(symbol: Symbol, macho_file: *MachO) u64 {
     const file = symbol.getFile(macho_file).?;
     return switch (file) {
         .dylib, .zig_object => unreachable,
-        .object, .internal => |x| x.symbols.items[extra.objc_selrefs].getAddress(.{}, macho_file),
+        inline else => |x| x.symbols.items[extra.objc_selrefs].getAddress(.{}, macho_file),
     };
 }
 
@@ -186,7 +186,7 @@ pub fn getOutputSymtabIndex(symbol: Symbol, macho_file: *MachO) ?u32 {
     const symtab_ctx = switch (file) {
         inline else => |x| x.output_symtab_ctx,
     };
-    var idx = symbol.getExtra(macho_file).?.symtab;
+    var idx = symbol.getExtra(macho_file).symtab;
     if (symbol.isLocal()) {
         idx += symtab_ctx.ilocal;
     } else if (symbol.flags.@"export") {
src/link/MachO/synthetic.zig
@@ -23,7 +23,7 @@ pub const ZigGotSection = struct {
         const index = try zig_got.allocateEntry(gpa);
         const entry = &zig_got.entries.items[index];
         entry.* = sym_index;
-        const symbol = zo.getSymbol(sym_index);
+        const symbol = &zo.symbols.items[sym_index];
         assert(symbol.flags.needs_zig_got);
         symbol.flags.has_zig_got = true;
         symbol.addExtra(.{ .zig_got = index }, macho_file);
@@ -56,7 +56,7 @@ pub const ZigGotSection = struct {
         const zo = macho_file.getZigObject().?;
         const off = zig_got.entryOffset(index, macho_file);
         const entry = zig_got.entries.items[index];
-        const value = zo.getSymbol(entry).getAddress(.{ .stubs = false }, macho_file);
+        const value = zo.symbols.items[entry].getAddress(.{ .stubs = false }, macho_file);
 
         var buf: [8]u8 = undefined;
         std.mem.writeInt(u64, &buf, value, .little);
@@ -66,7 +66,7 @@ pub const ZigGotSection = struct {
     pub fn writeAll(zig_got: ZigGotSection, macho_file: *MachO, writer: anytype) !void {
         const zo = macho_file.getZigObject().?;
         for (zig_got.entries.items) |entry| {
-            const symbol = zo.getSymbol(entry);
+            const symbol = zo.symbols.items[entry];
             const value = symbol.address(.{ .stubs = false }, macho_file);
             try writer.writeInt(u64, value, .little);
         }
@@ -94,7 +94,7 @@ pub const ZigGotSection = struct {
         const zo = macho_file.getZigObject().?;
         try writer.writeAll("__zig_got\n");
         for (zig_got.entries.items, 0..) |entry, index| {
-            const symbol = zo.getSymbol(entry);
+            const symbol = zo.symbols.items[entry];
             try writer.print("  {d}@0x{x} => {d}@0x{x} ({s})\n", .{
                 index,
                 zig_got.entryAddress(@intCast(index), macho_file),
@@ -694,7 +694,7 @@ pub const DataInCode = struct {
                     dices[next_dice].offset < end_off) : (next_dice += 1)
                 {}
 
-                if (atom.alive.load(.seq_cst)) for (dices[start_dice..next_dice]) |d| {
+                if (atom.flags.alive) for (dices[start_dice..next_dice]) |d| {
                     dice.entries.appendAssumeCapacity(.{
                         .offset = @intCast(atom.getAddress(macho_file) + d.offset - start_off - base_address),
                         .length = d.length,
src/link/MachO/thunks.zig
@@ -37,7 +37,7 @@ pub fn createThunks(sect_id: u8, macho_file: *MachO) !void {
 
         // Scan relocs in the group and create trampolines for any unreachable callsite
         try scanRelocs(thunk_index, gpa, atoms[start..i], macho_file);
-        thunk.value = try advance(header, thunk.size(), .@"4");
+        thunk.value = advance(header, thunk.size(), .@"4");
 
         log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) });
     }
@@ -99,8 +99,8 @@ pub const Thunk = struct {
         return header.addr + thunk.value;
     }
 
-    pub fn getTargetAddress(thunk: Thunk, sym_index: Symbol.Index, macho_file: *MachO) u64 {
-        return thunk.getAddress(macho_file) + thunk.symbols.getIndex(sym_index).? * trampoline_size;
+    pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
+        return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;
     }
 
     pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
src/link/MachO/UnwindInfo.zig
@@ -473,11 +473,11 @@ pub const Record = struct {
     }
 
     pub fn getAtom(rec: Record, macho_file: *MachO) *Atom {
-        return macho_file.getAtom(rec.atom).?;
+        return rec.getObject(macho_file).getAtom(rec.atom).?;
     }
 
     pub fn getLsdaAtom(rec: Record, macho_file: *MachO) ?*Atom {
-        return macho_file.getAtom(rec.lsda);
+        return rec.getObject(macho_file).getAtom(rec.lsda);
     }
 
     pub fn getPersonality(rec: Record, macho_file: *MachO) ?*Symbol {
src/link/MachO/ZigObject.zig
@@ -343,6 +343,36 @@ pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !voi
     try writer.writeAll(self.data.items);
 }
 
+pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void {
+    const tracy = trace(@src());
+    defer tracy.end();
+
+    for (self.symbols.items, 0..) |*sym, i| {
+        const nlist = self.symtab.items(.nlist)[i];
+        if (!nlist.ext()) continue;
+        if (!nlist.undf()) continue;
+
+        if (self.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue;
+
+        const is_import = switch (macho_file.undefined_treatment) {
+            .@"error" => false,
+            .warn, .suppress => nlist.weakRef(),
+            .dynamic_lookup => true,
+        };
+        if (is_import) {
+            sym.value = 0;
+            sym.atom_ref = .{ .index = 0, .file = 0 };
+            sym.flags.weak = false;
+            sym.flags.weak_ref = nlist.weakRef();
+            sym.flags.import = is_import;
+            sym.visibility = .global;
+
+            const idx = self.globals.items[i];
+            macho_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i), .file = self.index };
+        }
+    }
+}
+
 pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void {
     for (self.getAtoms()) |atom_index| {
         const atom = self.getAtom(atom_index) orelse continue;
@@ -378,7 +408,7 @@ pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) void {
     }
 }
 
-pub fn writeSymtab(self: ZigObject, macho_file: *MachO) void {
+pub fn writeSymtab(self: ZigObject, macho_file: *MachO, ctx: anytype) void {
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -388,13 +418,13 @@ pub fn writeSymtab(self: ZigObject, macho_file: *MachO) void {
         const file = ref.getFile(macho_file) orelse continue;
         if (file.getIndex() != self.index) continue;
         const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
-        const out_sym = &macho_file.symtab.items[idx];
+        const out_sym = &ctx.symtab.items[idx];
         out_sym.n_strx = n_strx;
         sym.setOutputSym(macho_file, out_sym);
         const name = sym.getName(macho_file);
-        @memcpy(macho_file.strtab.items[n_strx..][0..name.len], name);
+        @memcpy(ctx.strtab.items[n_strx..][0..name.len], name);
         n_strx += @intCast(name.len);
-        macho_file.strtab.items[n_strx] = 0;
+        ctx.strtab.items[n_strx] = 0;
         n_strx += 1;
     }
 }
@@ -1098,7 +1128,7 @@ pub fn lowerUnnamedConst(
         },
     };
     const sym = self.symbols.items[sym_index];
-    try unnamed_consts.append(gpa, sym.atom);
+    try unnamed_consts.append(gpa, sym.atom_ref.index);
     return sym_index;
 }
 
src/link/MachO.zig
@@ -529,7 +529,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
         dylib.ordinal = @intCast(ord);
     }
 
-    try self.claimUnresolved();
+    self.claimUnresolved();
 
     self.scanRelocs() catch |err| switch (err) {
         error.HasUndefinedSymbols => return error.FlushFailure,
@@ -603,7 +603,12 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
 
         if (has_resolve_error) return error.FlushFailure;
     }
-    try self.writeSectionsAndUpdateLinkeditSizes();
+    self.writeSectionsAndUpdateLinkeditSizes() catch |err| {
+        switch (err) {
+            error.ResolveFailed => return error.FlushFailure,
+            else => |e| return e,
+        }
+    };
 
     try self.writeSectionsToFile();
     try self.allocateLinkeditSegment();
@@ -1450,12 +1455,12 @@ pub fn dedupLiterals(self: *MachO) !void {
     }
 }
 
-fn claimUnresolved(self: *MachO) error{OutOfMemory}!void {
+fn claimUnresolved(self: *MachO) void {
     if (self.getZigObject()) |zo| {
-        try zo.asFile().claimUnresolved(self);
+        zo.claimUnresolved(self);
     }
     for (self.objects.items) |index| {
-        try self.getFile(index).?.claimUnresolved(self);
+        self.getFile(index).?.object.claimUnresolved(self);
     }
 }
 
@@ -2402,7 +2407,7 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void {
     }
 
     if (self.la_symbol_ptr_sect_index) |_| {
-        try self.updatelazyBindSize();
+        try self.updateLazyBindSize();
     }
 
     try self.rebase.updateSize(self);
@@ -2412,16 +2417,16 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void {
     try self.data_in_code.updateSize(self);
 
     if (self.getZigObject()) |zo| {
-        zo.asFile().writeSymtab(self);
+        zo.asFile().writeSymtab(self, self);
     }
     for (self.objects.items) |index| {
-        self.getFile(index).?.writeSymtab(self);
+        self.getFile(index).?.writeSymtab(self, self);
     }
     for (self.dylibs.items) |index| {
-        self.getFile(index).?.writeSymtab(self);
+        self.getFile(index).?.writeSymtab(self, self);
     }
     if (self.getInternalObject()) |obj| {
-        obj.asFile().writeSymtab(self);
+        obj.asFile().writeSymtab(self, self);
     }
 }
 
@@ -2484,7 +2489,7 @@ fn writeSectionsToFile(self: *MachO) !void {
 
     const slice = self.sections.slice();
     for (slice.items(.header), slice.items(.out)) |header, out| {
-        try self.base.file.pwriteAll(out.items, header.offset);
+        try self.base.file.?.pwriteAll(out.items, header.offset);
     }
 }
 
@@ -2501,7 +2506,7 @@ fn writeDyldInfo(self: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
 
-    const gpa = self.base.allocator;
+    const gpa = self.base.comp.gpa;
     const base_off = self.getLinkeditSegment().fileoff;
     const cmd = self.dyld_info_cmd;
     var needed_size: u32 = 0;
@@ -2527,14 +2532,14 @@ fn writeDyldInfo(self: *MachO) !void {
     try self.lazy_bind.write(writer);
     try stream.seekTo(cmd.export_off - base_off);
     try self.export_trie.write(writer);
-    try self.base.file.pwriteAll(buffer, cmd.rebase_off);
+    try self.base.file.?.pwriteAll(buffer, cmd.rebase_off);
 }
 
 pub fn writeDataInCode(self: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
     const cmd = self.data_in_code_cmd;
-    try self.base.file.pwriteAll(mem.sliceAsBytes(self.data_in_code.entries.items), cmd.dataoff);
+    try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.data_in_code.entries.items), cmd.dataoff);
 }
 
 fn writeIndsymtab(self: *MachO) !void {
@@ -2546,15 +2551,15 @@ fn writeIndsymtab(self: *MachO) !void {
     var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size);
     defer buffer.deinit();
     try self.indsymtab.write(self, buffer.writer());
-    try self.base.file.pwriteAll(buffer.items, cmd.indirectsymoff);
+    try self.base.file.?.pwriteAll(buffer.items, cmd.indirectsymoff);
 }
 
 pub fn writeSymtabToFile(self: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
     const cmd = self.symtab_cmd;
-    try self.base.file.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff);
-    try self.base.file.pwriteAll(self.strtab.items, cmd.stroff);
+    try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff);
+    try self.base.file.?.pwriteAll(self.strtab.items, cmd.stroff);
 }
 
 fn writeUnwindInfo(self: *MachO) !void {
@@ -2687,18 +2692,20 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
     try load_commands.writeDylinkerLC(writer);
     ncmds += 1;
 
-    if (self.entry_index) |global_index| {
-        const sym = self.getSymbol(global_index);
-        const seg = self.getTextSegment();
-        const entryoff: u32 = if (sym.getFile(self) == null)
-            0
-        else
-            @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));
-        try writer.writeStruct(macho.entry_point_command{
-            .entryoff = entryoff,
-            .stacksize = self.base.stack_size,
-        });
-        ncmds += 1;
+    if (self.getInternalObject()) |obj| {
+        if (obj.getEntryRef(self)) |ref| {
+            const sym = ref.getSymbol(self).?;
+            const seg = self.getTextSegment();
+            const entryoff: u32 = if (sym.getFile(self) == null)
+                0
+            else
+                @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));
+            try writer.writeStruct(macho.entry_point_command{
+                .entryoff = entryoff,
+                .stacksize = self.base.stack_size,
+            });
+            ncmds += 1;
+        }
     }
 
     if (self.base.isDynLib()) {