Commit bdbb1dbe15

Jakub Konka <kubkon@jakubkonka.com>
2024-02-06 13:56:28
macho: refactor markExports, markImportsExports and claimUnresolved
1 parent 352e27c
Changed files (4)
src/link/MachO/Archive.zig
@@ -144,8 +144,32 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index:
 }
 
 pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
-    _ = comp;
-    _ = module_obj_path;
+    const gpa = comp.gpa;
+
+    var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
+    defer positionals.deinit();
+
+    try positionals.ensureUnusedCapacity(comp.objects.len);
+    positionals.appendSliceAssumeCapacity(comp.objects);
+
+    for (comp.c_object_table.keys()) |key| {
+        try positionals.append(.{ .path = key.status.success.object_path });
+    }
+
+    if (module_obj_path) |path| try positionals.append(.{ .path = path });
+
+    for (positionals.items) |obj| {
+        // TODO: parse for archive meaning don't unpack objects
+        _ = obj;
+    }
+
+    if (comp.link_errors.items.len > 0) return error.FlushFailure;
+
+    // First, we flush relocatable object file generated with our backends.
+    if (macho_file.getZigObject()) |zo| {
+        zo.resolveSymbols(macho_file);
+        zo.asFile().claimUnresolvedRelocatable(macho_file);
+    }
 
     var err = try macho_file.addErrorWithNotes(0);
     try err.addMsg(macho_file, "TODO implement flushStaticLib", .{});
@@ -158,6 +182,7 @@ const link = @import("../../link.zig");
 const log = std.log.scoped(.link);
 const macho = std.macho;
 const mem = std.mem;
+const relocatable = @import("relocatable.zig");
 const std = @import("std");
 
 const Allocator = mem.Allocator;
src/link/MachO/file.zig
@@ -44,6 +44,97 @@ pub const File = union(enum) {
         }
     }
 
+    pub fn claimUnresolved(file: File, macho_file: *MachO) error{OutOfMemory}!void {
+        assert(file == .object or file == .zig_object);
+
+        for (file.getSymbols(), 0..) |sym_index, i| {
+            const nlist_idx = @as(Symbol.Index, @intCast(i));
+            const nlist = switch (file) {
+                .object => |x| x.symtab.items(.nlist)[nlist_idx],
+                .zig_object => |x| x.symtab.items(.nlist)[nlist_idx],
+                else => unreachable,
+            };
+            if (!nlist.ext()) continue;
+            if (!nlist.undf()) continue;
+
+            const sym = macho_file.getSymbol(sym_index);
+            if (sym.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 = 0;
+                sym.nlist_idx = 0;
+                sym.file = macho_file.internal_object.?;
+                sym.flags.weak = false;
+                sym.flags.weak_ref = nlist.weakRef();
+                sym.flags.import = is_import;
+                sym.visibility = .global;
+                try macho_file.getInternalObject().?.symbols.append(macho_file.base.comp.gpa, sym_index);
+            }
+        }
+    }
+
+    pub fn claimUnresolvedRelocatable(file: File, macho_file: *MachO) void {
+        assert(file == .object or file == .zig_object);
+
+        for (file.getSymbols(), 0..) |sym_index, i| {
+            const nlist_idx = @as(Symbol.Index, @intCast(i));
+            const nlist = switch (file) {
+                .object => |x| x.symtab.items(.nlist)[nlist_idx],
+                .zig_object => |x| x.symtab.items(.nlist)[nlist_idx],
+                else => unreachable,
+            };
+            if (!nlist.ext()) continue;
+            if (!nlist.undf()) continue;
+
+            const sym = macho_file.getSymbol(sym_index);
+            if (sym.getFile(macho_file) != null) continue;
+
+            sym.value = 0;
+            sym.atom = 0;
+            sym.nlist_idx = nlist_idx;
+            sym.file = file.getIndex();
+            sym.flags.weak_ref = nlist.weakRef();
+            sym.flags.import = true;
+            sym.visibility = .global;
+        }
+    }
+
+    pub fn markImportsExports(file: File, macho_file: *MachO) void {
+        assert(file == .object or file == .zig_object);
+
+        for (file.getSymbols()) |sym_index| {
+            const sym = macho_file.getSymbol(sym_index);
+            const other_file = sym.getFile(macho_file) orelse continue;
+            if (sym.visibility != .global) continue;
+            if (other_file == .dylib and !sym.flags.abs) {
+                sym.flags.import = true;
+                continue;
+            }
+            if (other_file.getIndex() == file.getIndex()) {
+                sym.flags.@"export" = true;
+            }
+        }
+    }
+
+    pub fn markExportsRelocatable(file: File, macho_file: *MachO) void {
+        assert(file == .object or file == .zig_object);
+
+        for (file.getSymbols()) |sym_index| {
+            const sym = macho_file.getSymbol(sym_index);
+            const other_file = sym.getFile(macho_file) orelse continue;
+            if (sym.visibility != .global) continue;
+            if (other_file.getIndex() == file.getIndex()) {
+                sym.flags.@"export" = true;
+            }
+        }
+    }
+
     /// Encodes symbol rank so that the following ordering applies:
     /// * strong in object
     /// * weak in object
@@ -110,6 +201,7 @@ pub const File = union(enum) {
     pub const HandleIndex = Index;
 };
 
+const assert = std.debug.assert;
 const macho = std.macho;
 const std = @import("std");
 
src/link/MachO/relocatable.zig
@@ -46,8 +46,8 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u
 
     try macho_file.addUndefinedGlobals();
     try macho_file.resolveSymbols();
-    try markExports(macho_file);
-    try claimUnresolved(macho_file);
+    markExports(macho_file);
+    claimUnresolved(macho_file);
     try initOutputSections(macho_file);
     try macho_file.sortSections();
     try macho_file.addAtomsToSections();
@@ -86,54 +86,21 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u
     try writeHeader(macho_file, ncmds, sizeofcmds);
 }
 
-fn markExports(macho_file: *MachO) error{OutOfMemory}!void {
-    var objects = try std.ArrayList(File.Index).initCapacity(macho_file.base.comp.gpa, macho_file.objects.items.len + 1);
-    defer objects.deinit();
-    if (macho_file.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index);
-    objects.appendSliceAssumeCapacity(macho_file.objects.items);
-
-    for (objects.items) |index| {
-        for (macho_file.getFile(index).?.getSymbols()) |sym_index| {
-            const sym = macho_file.getSymbol(sym_index);
-            const file = sym.getFile(macho_file) orelse continue;
-            if (sym.visibility != .global) continue;
-            if (file.getIndex() == index) {
-                sym.flags.@"export" = true;
-            }
-        }
+fn markExports(macho_file: *MachO) void {
+    if (macho_file.getZigObject()) |zo| {
+        zo.asFile().markExportsRelocatable(macho_file);
+    }
+    for (macho_file.objects.items) |index| {
+        macho_file.getFile(index).?.markExportsRelocatable(macho_file);
     }
 }
 
-fn claimUnresolved(macho_file: *MachO) error{OutOfMemory}!void {
-    var objects = try std.ArrayList(File.Index).initCapacity(macho_file.base.comp.gpa, macho_file.objects.items.len + 1);
-    defer objects.deinit();
-    if (macho_file.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index);
-    objects.appendSliceAssumeCapacity(macho_file.objects.items);
-
-    for (objects.items) |index| {
-        const file = macho_file.getFile(index).?;
-
-        for (file.getSymbols(), 0..) |sym_index, i| {
-            const nlist_idx = @as(Symbol.Index, @intCast(i));
-            const nlist = switch (file) {
-                .object => |x| x.symtab.items(.nlist)[nlist_idx],
-                .zig_object => |x| x.symtab.items(.nlist)[nlist_idx],
-                else => unreachable,
-            };
-            if (!nlist.ext()) continue;
-            if (!nlist.undf()) continue;
-
-            const sym = macho_file.getSymbol(sym_index);
-            if (sym.getFile(macho_file) != null) continue;
-
-            sym.value = 0;
-            sym.atom = 0;
-            sym.nlist_idx = nlist_idx;
-            sym.file = index;
-            sym.flags.weak_ref = nlist.weakRef();
-            sym.flags.import = true;
-            sym.visibility = .global;
-        }
+pub fn claimUnresolved(macho_file: *MachO) void {
+    if (macho_file.getZigObject()) |zo| {
+        zo.asFile().claimUnresolvedRelocatable(macho_file);
+    }
+    for (macho_file.objects.items) |index| {
+        macho_file.getFile(index).?.claimUnresolvedRelocatable(macho_file);
     }
 }
 
src/link/MachO.zig
@@ -379,6 +379,10 @@ pub fn deinit(self: *MachO) void {
 }
 
 pub fn flush(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
+    // TODO: I think this is just a temp and can be removed once we can emit static archives
+    if (self.base.isStaticLib() and build_options.have_llvm) {
+        return self.base.linkAsArchive(arena, prog_node);
+    }
     try self.flushModule(arena, prog_node);
 }
 
@@ -391,6 +395,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
 
     if (self.llvm_object) |llvm_object| {
         try self.base.emitLlvmObject(arena, llvm_object, prog_node);
+        // TODO: I think this is just a temp and can be removed once we can emit static archives
+        if (self.base.isStaticLib() and build_options.have_llvm) return;
     }
 
     var sub_prog_node = prog_node.start("MachO Flush", 0);
@@ -571,7 +577,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
         },
     };
 
-    try self.markImportsAndExports();
+    self.markImportsAndExports();
     self.deadStripDylibs();
 
     for (self.dylibs.items, 1..) |index, ord| {
@@ -1509,46 +1515,11 @@ fn createObjcSections(self: *MachO) !void {
 }
 
 fn claimUnresolved(self: *MachO) error{OutOfMemory}!void {
-    const gpa = self.base.comp.gpa;
-
-    var objects = try std.ArrayList(File.Index).initCapacity(gpa, self.objects.items.len + 1);
-    defer objects.deinit();
-    if (self.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index);
-    objects.appendSliceAssumeCapacity(self.objects.items);
-
-    for (objects.items) |index| {
-        const file = self.getFile(index).?;
-
-        for (file.getSymbols(), 0..) |sym_index, i| {
-            const nlist_idx = @as(Symbol.Index, @intCast(i));
-            const nlist = switch (file) {
-                .object => |x| x.symtab.items(.nlist)[nlist_idx],
-                .zig_object => |x| x.symtab.items(.nlist)[nlist_idx],
-                else => unreachable,
-            };
-            if (!nlist.ext()) continue;
-            if (!nlist.undf()) continue;
-
-            const sym = self.getSymbol(sym_index);
-            if (sym.getFile(self) != null) continue;
-
-            const is_import = switch (self.undefined_treatment) {
-                .@"error" => false,
-                .warn, .suppress => nlist.weakRef(),
-                .dynamic_lookup => true,
-            };
-            if (is_import) {
-                sym.value = 0;
-                sym.atom = 0;
-                sym.nlist_idx = 0;
-                sym.file = self.internal_object.?;
-                sym.flags.weak = false;
-                sym.flags.weak_ref = nlist.weakRef();
-                sym.flags.import = is_import;
-                sym.visibility = .global;
-                try self.getInternalObject().?.symbols.append(self.base.comp.gpa, sym_index);
-            }
-        }
+    if (self.getZigObject()) |zo| {
+        try zo.asFile().claimUnresolved(self);
+    }
+    for (self.objects.items) |index| {
+        try self.getFile(index).?.claimUnresolved(self);
     }
 }
 
@@ -1574,26 +1545,12 @@ fn checkDuplicates(self: *MachO) !void {
     try self.reportDuplicates(dupes);
 }
 
-fn markImportsAndExports(self: *MachO) error{OutOfMemory}!void {
-    const gpa = self.base.comp.gpa;
-    var objects = try std.ArrayList(File.Index).initCapacity(gpa, self.objects.items.len + 1);
-    defer objects.deinit();
-    if (self.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index);
-    objects.appendSliceAssumeCapacity(self.objects.items);
-
-    for (objects.items) |index| {
-        for (self.getFile(index).?.getSymbols()) |sym_index| {
-            const sym = self.getSymbol(sym_index);
-            const file = sym.getFile(self) orelse continue;
-            if (sym.visibility != .global) continue;
-            if (file == .dylib and !sym.flags.abs) {
-                sym.flags.import = true;
-                continue;
-            }
-            if (file.getIndex() == index) {
-                sym.flags.@"export" = true;
-            }
-        }
+fn markImportsAndExports(self: *MachO) void {
+    if (self.getZigObject()) |zo| {
+        zo.asFile().markImportsExports(self);
+    }
+    for (self.objects.items) |index| {
+        self.getFile(index).?.markImportsExports(self);
     }
 
     for (self.undefined_symbols.items) |index| {