Commit 10a5536a7c

Jakub Konka <kubkon@jakubkonka.com>
2024-01-12 10:46:56
macho: re-instate build-obj codepath
1 parent c2a0a88
src/link/MachO/Atom.zig
@@ -682,7 +682,7 @@ const x86_64 = struct {
 };
 
 pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 {
-    switch (macho_file.options.cpu_arch.?) {
+    switch (macho_file.getTarget().cpu.arch) {
         .aarch64 => {
             var nreloc: u32 = 0;
             for (self.getRelocs(macho_file)) |rel| {
@@ -705,7 +705,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: *std.Arra
     const tracy = trace(@src());
     defer tracy.end();
 
-    const cpu_arch = macho_file.options.cpu_arch.?;
+    const cpu_arch = macho_file.getTarget().cpu.arch;
     const relocs = self.getRelocs(macho_file);
     const sect = macho_file.sections.items(.header)[self.out_n_sect];
     var stream = std.io.fixedBufferStream(code);
src/link/MachO/load_commands.zig
@@ -98,7 +98,6 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) u32 {
 }
 
 pub fn calcLoadCommandsSizeObject(macho_file: *MachO) u32 {
-    const options = &macho_file.options;
     var sizeofcmds: u64 = 0;
 
     // LC_SEGMENT_64
@@ -116,14 +115,12 @@ pub fn calcLoadCommandsSizeObject(macho_file: *MachO) u32 {
     // LC_DYSYMTAB
     sizeofcmds += @sizeOf(macho.dysymtab_command);
 
-    if (options.platform) |platform| {
-        if (platform.isBuildVersionCompatible()) {
-            // LC_BUILD_VERSION
-            sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
-        } else {
-            // LC_VERSION_MIN_*
-            sizeofcmds += @sizeOf(macho.version_min_command);
-        }
+    if (macho_file.platform.isBuildVersionCompatible()) {
+        // LC_BUILD_VERSION
+        sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
+    } else {
+        // LC_VERSION_MIN_*
+        sizeofcmds += @sizeOf(macho.version_min_command);
     }
 
     return @as(u32, @intCast(sizeofcmds));
src/link/MachO/relocatable.zig
@@ -1,4 +1,37 @@
-pub fn flush(macho_file: *MachO) !void {
+pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
+    const gpa = macho_file.base.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| {
+        macho_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
+            error.MalformedObject,
+            error.MalformedArchive,
+            error.InvalidCpuArch,
+            error.InvalidTarget,
+            => continue, // already reported
+            error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type for an object file", .{}),
+            else => |e| try macho_file.reportParseError(
+                obj.path,
+                "unexpected error: parsing input file failed with error {s}",
+                .{@errorName(e)},
+            ),
+        };
+    }
+
+    if (comp.link_errors.items.len > 0) return error.FlushFailure;
+
+    try macho_file.addUndefinedGlobals();
+    try macho_file.resolveSymbols();
     markExports(macho_file);
     claimUnresolved(macho_file);
     try initOutputSections(macho_file);
@@ -9,7 +42,7 @@ pub fn flush(macho_file: *MachO) !void {
     {
         // For relocatable, we only ever need a single segment so create it now.
         const prot: macho.vm_prot_t = macho.PROT.READ | macho.PROT.WRITE | macho.PROT.EXEC;
-        try macho_file.segments.append(macho_file.base.allocator, .{
+        try macho_file.segments.append(gpa, .{
             .cmdsize = @sizeOf(macho.segment_command_64),
             .segname = MachO.makeStaticString(""),
             .maxprot = prot,
@@ -128,17 +161,20 @@ fn initOutputSections(macho_file: *MachO) !void {
 }
 
 fn calcSectionSizes(macho_file: *MachO) !void {
+    const tracy = trace(@src());
+    defer tracy.end();
+
     const slice = macho_file.sections.slice();
     for (slice.items(.header), slice.items(.atoms)) |*header, atoms| {
         if (atoms.items.len == 0) continue;
         for (atoms.items) |atom_index| {
             const atom = macho_file.getAtom(atom_index).?;
-            const atom_alignment = try math.powi(u32, 2, atom.alignment);
+            const atom_alignment = atom.alignment.toByteUnits(1);
             const offset = mem.alignForward(u64, header.size, atom_alignment);
             const padding = offset - header.size;
             atom.value = offset;
             header.size += padding + atom.size;
-            header.@"align" = @max(header.@"align", atom.alignment);
+            header.@"align" = @max(header.@"align", atom.alignment.toLog2Units());
             header.nreloc += atom.calcNumRelocs(macho_file);
         }
     }
@@ -218,8 +254,8 @@ fn writeAtoms(macho_file: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
 
-    const gpa = macho_file.base.allocator;
-    const cpu_arch = macho_file.options.cpu_arch.?;
+    const gpa = macho_file.base.comp.gpa;
+    const cpu_arch = macho_file.getTarget().cpu.arch;
     const slice = macho_file.sections.slice();
 
     for (slice.items(.header), slice.items(.atoms)) |header, atoms| {
@@ -247,14 +283,14 @@ fn writeAtoms(macho_file: *MachO) !void {
         mem.sort(macho.relocation_info, relocs.items, {}, sortReloc);
 
         // TODO scattered writes?
-        try macho_file.base.file.pwriteAll(code, header.offset);
-        try macho_file.base.file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
+        try macho_file.base.file.?.pwriteAll(code, header.offset);
+        try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
     }
 }
 
 fn writeCompactUnwind(macho_file: *MachO) !void {
     const sect_index = macho_file.unwind_info_sect_index orelse return;
-    const gpa = macho_file.base.allocator;
+    const gpa = macho_file.base.comp.gpa;
     const header = macho_file.sections.items(.header)[sect_index];
 
     const nrecs = @divExact(header.size, @sizeOf(macho.compact_unwind_entry));
@@ -301,7 +337,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void {
                 const atom = rec.getAtom(macho_file);
                 const addr = rec.getAtomAddress(macho_file);
                 out.rangeStart = addr;
-                var reloc = addReloc(offset, macho_file.options.cpu_arch.?);
+                var reloc = addReloc(offset, macho_file.getTarget().cpu.arch);
                 reloc.r_symbolnum = atom.out_n_sect + 1;
                 relocs.appendAssumeCapacity(reloc);
             }
@@ -309,7 +345,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void {
             // Personality function
             if (rec.getPersonality(macho_file)) |sym| {
                 const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow;
-                var reloc = addReloc(offset + 16, macho_file.options.cpu_arch.?);
+                var reloc = addReloc(offset + 16, macho_file.getTarget().cpu.arch);
                 reloc.r_symbolnum = r_symbolnum;
                 reloc.r_extern = 1;
                 relocs.appendAssumeCapacity(reloc);
@@ -319,7 +355,7 @@ fn writeCompactUnwind(macho_file: *MachO) !void {
             if (rec.getLsdaAtom(macho_file)) |atom| {
                 const addr = rec.getLsdaAddress(macho_file);
                 out.lsda = addr;
-                var reloc = addReloc(offset + 24, macho_file.options.cpu_arch.?);
+                var reloc = addReloc(offset + 24, macho_file.getTarget().cpu.arch);
                 reloc.r_symbolnum = atom.out_n_sect + 1;
                 relocs.appendAssumeCapacity(reloc);
             }
@@ -335,13 +371,13 @@ fn writeCompactUnwind(macho_file: *MachO) !void {
     mem.sort(macho.relocation_info, relocs.items, {}, sortReloc);
 
     // TODO scattered writes?
-    try macho_file.base.file.pwriteAll(mem.sliceAsBytes(entries.items), header.offset);
-    try macho_file.base.file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
+    try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(entries.items), header.offset);
+    try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
 }
 
 fn writeEhFrame(macho_file: *MachO) !void {
     const sect_index = macho_file.eh_frame_sect_index orelse return;
-    const gpa = macho_file.base.allocator;
+    const gpa = macho_file.base.comp.gpa;
     const header = macho_file.sections.items(.header)[sect_index];
 
     const code = try gpa.alloc(u8, header.size);
@@ -356,12 +392,12 @@ fn writeEhFrame(macho_file: *MachO) !void {
     mem.sort(macho.relocation_info, relocs.items, {}, sortReloc);
 
     // TODO scattered writes?
-    try macho_file.base.file.pwriteAll(code, header.offset);
-    try macho_file.base.file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
+    try macho_file.base.file.?.pwriteAll(code, header.offset);
+    try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
 }
 
 fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {
-    const gpa = macho_file.base.allocator;
+    const gpa = macho_file.base.comp.gpa;
     const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file);
     const buffer = try gpa.alloc(u8, needed_size);
     defer gpa.free(buffer);
@@ -390,19 +426,17 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {
     try writer.writeStruct(macho_file.dysymtab_cmd);
     ncmds += 1;
 
-    if (macho_file.options.platform) |platform| {
-        if (platform.isBuildVersionCompatible()) {
-            try load_commands.writeBuildVersionLC(platform, macho_file.options.sdk_version, writer);
-            ncmds += 1;
-        } else {
-            try load_commands.writeVersionMinLC(platform, macho_file.options.sdk_version, writer);
-            ncmds += 1;
-        }
+    if (macho_file.platform.isBuildVersionCompatible()) {
+        try load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer);
+        ncmds += 1;
+    } else {
+        try load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer);
+        ncmds += 1;
     }
 
     assert(cwriter.bytes_written == needed_size);
 
-    try macho_file.base.file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
+    try macho_file.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
 
     return .{ ncmds, buffer.len };
 }
@@ -419,7 +453,7 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
         header.flags |= macho.MH_SUBSECTIONS_VIA_SYMBOLS;
     }
 
-    switch (macho_file.options.cpu_arch.?) {
+    switch (macho_file.getTarget().cpu.arch) {
         .aarch64 => {
             header.cputype = macho.CPU_TYPE_ARM64;
             header.cpusubtype = macho.CPU_SUBTYPE_ARM_ALL;
@@ -434,19 +468,21 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
     header.ncmds = @intCast(ncmds);
     header.sizeofcmds = @intCast(sizeofcmds);
 
-    try macho_file.base.file.pwriteAll(mem.asBytes(&header), 0);
+    try macho_file.base.file.?.pwriteAll(mem.asBytes(&header), 0);
 }
 
 const assert = std.debug.assert;
 const eh_frame = @import("eh_frame.zig");
+const link = @import("../../link.zig");
 const load_commands = @import("load_commands.zig");
 const macho = std.macho;
 const math = std.math;
 const mem = std.mem;
-const state_log = std.log.scoped(.state);
+const state_log = std.log.scoped(.link_state);
 const std = @import("std");
-const trace = @import("../tracy.zig").trace;
+const trace = @import("../../tracy.zig").trace;
 
 const Atom = @import("Atom.zig");
+const Compilation = @import("../../Compilation.zig");
 const MachO = @import("../MachO.zig");
 const Symbol = @import("Symbol.zig");
src/link/MachO.zig
@@ -369,7 +369,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
     if (comp.verbose_link) try self.dumpArgv(comp);
 
     if (self.base.isStaticLib()) return self.flushStaticLib(comp, module_obj_path);
-    if (self.base.isObject()) return self.flushObject(comp, module_obj_path);
+    if (self.base.isObject()) return relocatable.flush(self, comp, module_obj_path);
 
     var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
     defer positionals.deinit();
@@ -483,7 +483,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
         self.getFile(index).?.dylib.umbrella = index;
     }
 
-    // try self.parseDependentDylibs();
+    // TODO: try self.parseDependentDylibs();
 
     for (self.dylibs.items) |index| {
         const dylib = self.getFile(index).?.dylib;
@@ -783,16 +783,6 @@ fn flushStaticLib(self: *MachO, comp: *Compilation, module_obj_path: ?[]const u8
     return error.FlushFailure;
 }
 
-fn flushObject(self: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
-    _ = comp;
-    _ = module_obj_path;
-
-    var err = try self.addErrorWithNotes(0);
-    try err.addMsg(self, "TODO implement flushObject", .{});
-
-    return error.FlushFailure;
-}
-
 pub fn resolveLibSystem(
     self: *MachO,
     arena: Allocator,
@@ -890,7 +880,7 @@ const ParseError = error{
     UnknownFileType,
 } || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError || tapi.TapiError;
 
-fn parsePositional(self: *MachO, path: []const u8, must_link: bool) ParseError!void {
+pub fn parsePositional(self: *MachO, path: []const u8, must_link: bool) ParseError!void {
     const tracy = trace(@src());
     defer tracy.end();
     if (try Object.isObject(path)) {
@@ -1083,6 +1073,7 @@ fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!File.Index
 //     return false;
 // }
 
+// TODO:
 // fn parseDependentDylibs(
 //     self: *MachO
 // ) !void {
@@ -1212,7 +1203,7 @@ fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!File.Index
 //     }
 // }
 
-fn addUndefinedGlobals(self: *MachO) !void {
+pub fn addUndefinedGlobals(self: *MachO) !void {
     const gpa = self.base.comp.gpa;
 
     try self.undefined_symbols.ensureUnusedCapacity(gpa, self.base.comp.force_undefined_symbols.keys().len);
@@ -4033,6 +4024,7 @@ const fat = @import("MachO/fat.zig");
 const link = @import("../link.zig");
 const llvm_backend = @import("../codegen/llvm.zig");
 const load_commands = @import("MachO/load_commands.zig");
+const relocatable = @import("MachO/relocatable.zig");
 const tapi = @import("tapi.zig");
 const target_util = @import("../target.zig");
 const thunks = @import("MachO/thunks.zig");