From 10a5536a7c9f9545c292f8e863a7cecd89e9ee54 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 12 Jan 2024 10:46:56 +0100 Subject: [PATCH] macho: re-instate build-obj codepath --- src/link/MachO.zig | 20 ++----- src/link/MachO/Atom.zig | 4 +- src/link/MachO/load_commands.zig | 15 ++--- src/link/MachO/relocatable.zig | 98 ++++++++++++++++++++++---------- 4 files changed, 81 insertions(+), 56 deletions(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 2911832132..5c8e30400d 100644 --- a/src/link/MachO.zig +++ b/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"); diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 1e723d337b..7cd44b162e 100644 --- a/src/link/MachO/Atom.zig +++ b/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); diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 3c3c53f637..bd6a41d39c 100644 --- a/src/link/MachO/load_commands.zig +++ b/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)); diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index 3d2d5b97b9..00513479b9 100644 --- a/src/link/MachO/relocatable.zig +++ b/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");