Commit b62281a9c8
Changed files (5)
src
src/link/MachO/Atom.zig
@@ -1008,6 +1008,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
.r_extern = 0,
.r_type = @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_ADDEND),
};
+ i += 1;
}
const r_type: macho.reloc_type_arm64 = switch (rel.type) {
src/link/MachO/file.zig
@@ -118,7 +118,24 @@ pub const File = union(enum) {
};
}
+ pub fn getNlists(file: File) []macho.nlist_64 {
+ return switch (file) {
+ .dylib => unreachable,
+ .internal => |x| x.symtab.items,
+ inline else => |x| x.symtab.items(.nlist),
+ };
+ }
+
+ pub fn getGlobals(file: File) []MachO.SymbolResolver.Index {
+ return switch (file) {
+ inline else => |x| x.globals.items,
+ };
+ }
+
pub fn markImportsExports(file: File, macho_file: *MachO) void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
const nsyms = switch (file) {
.dylib => unreachable,
inline else => |x| x.symbols.items.len,
@@ -138,7 +155,25 @@ pub const File = union(enum) {
}
}
+ pub fn markExportsRelocatable(file: File, macho_file: *MachO) void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ assert(file == .object or file == .zig_object);
+
+ for (file.getSymbols(), 0..) |*sym, i| {
+ const ref = file.getSymbolRef(@intCast(i), macho_file);
+ const other_file = ref.getFile(macho_file) orelse continue;
+ if (other_file.getIndex() != file.getIndex()) continue;
+ if (sym.visibility != .global) continue;
+ sym.flags.@"export" = true;
+ }
+ }
+
pub fn createSymbolIndirection(file: File, macho_file: *MachO) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
const nsyms = switch (file) {
inline else => |x| x.symbols.items.len,
};
@@ -166,6 +201,59 @@ pub const File = union(enum) {
}
}
+ pub fn claimUnresolved(file: File, macho_file: *MachO) void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ assert(file == .object or file == .zig_object);
+
+ for (file.getSymbols(), file.getNlists(), 0..) |*sym, nlist, i| {
+ if (!nlist.ext()) continue;
+ if (!nlist.undf()) continue;
+
+ if (file.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 = file.getGlobals()[i];
+ macho_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i), .file = file.getIndex() };
+ }
+ }
+ }
+
+ pub fn claimUnresolvedRelocatable(file: File, macho_file: *MachO) void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ assert(file == .object or file == .zig_object);
+
+ for (file.getSymbols(), file.getNlists(), 0..) |*sym, nlist, i| {
+ if (!nlist.ext()) continue;
+ if (!nlist.undf()) continue;
+ if (file.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue;
+
+ sym.value = 0;
+ sym.atom_ref = .{ .index = 0, .file = 0 };
+ sym.flags.weak_ref = nlist.weakRef();
+ sym.flags.import = true;
+ sym.visibility = .global;
+
+ const idx = file.getGlobals()[i];
+ macho_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i), .file = file.getIndex() };
+ }
+ }
+
pub fn initOutputSections(file: File, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
src/link/MachO/Object.zig
@@ -1636,56 +1636,6 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {
}
}
-pub fn claimUnresolved(self: *Object, 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 claimUnresolvedRelocatable(self: *Object, macho_file: *MachO) void {
- const tracy = trace(@src());
- defer tracy.end();
-
- for (self.symbols.items, self.symtab.items(.nlist), 0..) |*sym, nlist, i| {
- if (!nlist.ext()) continue;
- if (!nlist.undf()) continue;
- if (self.getSymbolRef(@intCast(i), macho_file).getFile(macho_file) != null) continue;
-
- sym.value = 0;
- sym.atom_ref = .{ .index = 0, .file = 0 };
- sym.flags.weak_ref = nlist.weakRef();
- sym.flags.import = true;
- sym.visibility = .global;
-
- const idx = self.globals.items[i];
- macho_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i), .file = self.index };
- }
-}
-
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, .{
@@ -1936,7 +1886,7 @@ pub fn writeAtomsRelocatable(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;
const headers = self.sections.items(.header);
const sections_data = try gpa.alloc([]const u8, headers.len);
defer {
@@ -1995,15 +1945,17 @@ pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
+ const cpu_arch = macho_file.getTarget().cpu.arch;
+
const addReloc = struct {
- fn addReloc(offset: u32, cpu_arch: std.Target.Cpu.Arch) !macho.relocation_info {
+ fn addReloc(offset: u32, arch: std.Target.Cpu.Arch) !macho.relocation_info {
return .{
.r_address = math.cast(i32, offset) orelse return error.Overflow,
.r_symbolnum = 0,
.r_pcrel = 0,
.r_length = 3,
.r_extern = 0,
- .r_type = switch (cpu_arch) {
+ .r_type = switch (arch) {
.aarch64 => @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
.x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
else => unreachable,
@@ -2039,7 +1991,7 @@ pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {
const atom = rec.getAtom(macho_file);
const addr = rec.getAtomAddress(macho_file);
out.rangeStart = addr;
- var reloc = try addReloc(offset, macho_file.options.cpu_arch.?);
+ var reloc = try addReloc(offset, cpu_arch);
reloc.r_symbolnum = atom.out_n_sect + 1;
relocs[reloc_index] = reloc;
reloc_index += 1;
@@ -2048,7 +2000,7 @@ pub fn writeCompactUnwindRelocatable(self: *Object, 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 = try addReloc(offset + 16, macho_file.options.cpu_arch.?);
+ var reloc = try addReloc(offset + 16, cpu_arch);
reloc.r_symbolnum = r_symbolnum;
reloc.r_extern = 1;
relocs[reloc_index] = reloc;
@@ -2059,7 +2011,7 @@ pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {
if (rec.getLsdaAtom(macho_file)) |atom| {
const addr = rec.getLsdaAddress(macho_file);
out.lsda = addr;
- var reloc = try addReloc(offset + 24, macho_file.options.cpu_arch.?);
+ var reloc = try addReloc(offset + 24, cpu_arch);
reloc.r_symbolnum = atom.out_n_sect + 1;
relocs[reloc_index] = reloc;
reloc_index += 1;
src/link/MachO/relocatable.zig
@@ -26,70 +26,51 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]c
return;
}
- @panic("TODO -r mode");
-
- // 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)},
- // ),
- // };
- // }
+ 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();
- // try macho_file.parseDebugInfo();
- // try macho_file.dedupLiterals();
- // markExports(macho_file);
- // claimUnresolved(macho_file);
- // try initOutputSections(macho_file);
- // try macho_file.sortSections();
- // try macho_file.addAtomsToSections();
- // try calcSectionSizes(macho_file);
-
- // try createSegment(macho_file);
- // try allocateSections(macho_file);
- // allocateSegment(macho_file);
-
- // var off = off: {
- // const seg = macho_file.segments.items[0];
- // const off = math.cast(u32, seg.fileoff + seg.filesize) orelse return error.Overflow;
- // break :off mem.alignForward(u32, off, @alignOf(macho.relocation_info));
- // };
- // off = allocateSectionsRelocs(macho_file, off);
-
- // if (build_options.enable_logging) {
- // state_log.debug("{}", .{macho_file.dumpState()});
- // }
+ if (comp.link_errors.items.len > 0) return error.FlushFailure;
- // try macho_file.calcSymtabSize();
- // try writeAtoms(macho_file);
- // try writeCompactUnwind(macho_file);
- // try writeEhFrame(macho_file);
+ try macho_file.resolveSymbols();
+ try macho_file.dedupLiterals();
+ markExports(macho_file);
+ claimUnresolved(macho_file);
+ try initOutputSections(macho_file);
+ try macho_file.sortSections();
+ try macho_file.addAtomsToSections();
+ try calcSectionSizes(macho_file);
- // off = mem.alignForward(u32, off, @alignOf(u64));
- // off = try macho_file.writeDataInCode(0, off);
- // off = mem.alignForward(u32, off, @alignOf(u64));
- // off = try macho_file.writeSymtab(off);
- // off = mem.alignForward(u32, off, @alignOf(u64));
- // off = try macho_file.writeStrtab(off);
+ try createSegment(macho_file);
+ try allocateSections(macho_file);
+ allocateSegment(macho_file);
- // // In order to please Apple ld (and possibly other MachO linkers in the wild),
- // // we will now sanitize segment names of Zig-specific segments.
- // sanitizeZigSections(macho_file);
+ if (build_options.enable_logging) {
+ state_log.debug("{}", .{macho_file.dumpState()});
+ }
- // const ncmds, const sizeofcmds = try writeLoadCommands(macho_file);
- // try writeHeader(macho_file, ncmds, sizeofcmds);
+ try writeSections(macho_file);
+ sortRelocs(macho_file);
+ try writeSectionsToFile(macho_file);
+
+ // In order to please Apple ld (and possibly other MachO linkers in the wild),
+ // we will now sanitize segment names of Zig-specific segments.
+ sanitizeZigSections(macho_file);
+
+ const ncmds, const sizeofcmds = try writeLoadCommands(macho_file);
+ try writeHeader(macho_file, ncmds, sizeofcmds);
}
pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
@@ -353,9 +334,9 @@ pub fn claimUnresolved(macho_file: *MachO) void {
fn initOutputSections(macho_file: *MachO) !void {
for (macho_file.objects.items) |index| {
- const object = macho_file.getFile(index).?.object;
- for (object.atoms.items) |atom_index| {
- const atom = macho_file.getAtom(atom_index) orelse continue;
+ const file = macho_file.getFile(index).?;
+ for (file.getAtoms()) |atom_index| {
+ const atom = file.getAtom(atom_index) orelse continue;
if (!atom.flags.alive) continue;
atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(macho_file), macho_file);
}
@@ -383,69 +364,141 @@ 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| {
+ for (macho_file.sections.items(.atoms), 0..) |atoms, i| {
if (atoms.items.len == 0) continue;
- for (atoms.items) |atom_index| {
- const atom = macho_file.getAtom(atom_index).?;
- const atom_alignment = atom.alignment.toByteUnits() orelse 1;
- const offset = mem.alignForward(u64, header.size, atom_alignment);
- const padding = offset - header.size;
- atom.value = offset;
- header.size += padding + atom.size;
- header.@"align" = @max(header.@"align", atom.alignment.toLog2Units());
- header.nreloc += atom.calcNumRelocs(macho_file);
- }
+ calcSectionSize(macho_file, @intCast(i));
}
- if (macho_file.unwind_info_sect_index) |index| {
- calcCompactUnwindSize(macho_file, index);
+ if (macho_file.eh_frame_sect_index) |_| {
+ try calcEhFrameSize(macho_file);
}
- if (macho_file.eh_frame_sect_index) |index| {
- const sect = &macho_file.sections.items(.header)[index];
- sect.size = try eh_frame.calcSize(macho_file);
- sect.@"align" = 3;
- sect.nreloc = eh_frame.calcNumRelocs(macho_file);
+ for (macho_file.objects.items) |index| {
+ if (macho_file.unwind_info_sect_index) |_| {
+ macho_file.getFile(index).?.object.calcCompactUnwindSizeRelocatable(macho_file);
+ }
+ macho_file.getFile(index).?.calcSymtabSize(macho_file);
}
- if (macho_file.getZigObject()) |zo| {
- for (zo.atoms.items) |atom_index| {
- const atom = macho_file.getAtom(atom_index) orelse continue;
- if (!atom.flags.alive) continue;
- const header = &macho_file.sections.items(.header)[atom.out_n_sect];
- if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue;
- header.nreloc += atom.calcNumRelocs(macho_file);
- }
+ try macho_file.data_in_code.updateSize(macho_file);
+
+ calcCompactUnwindSize(macho_file);
+ calcSymtabSize(macho_file);
+
+ // TODO
+ // if (macho_file.getZigObject()) |zo| {
+ // for (zo.atoms.items) |atom_index| {
+ // const atom = macho_file.getAtom(atom_index) orelse continue;
+ // if (!atom.flags.alive) continue;
+ // const header = &macho_file.sections.items(.header)[atom.out_n_sect];
+ // if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue;
+ // header.nreloc += atom.calcNumRelocs(macho_file);
+ // }
+ // }
+}
+
+fn calcSectionSize(macho_file: *MachO, sect_id: u8) void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const slice = macho_file.sections.slice();
+ const header = &slice.items(.header)[sect_id];
+ const atoms = slice.items(.atoms)[sect_id].items;
+ for (atoms) |ref| {
+ const atom = ref.getAtom(macho_file).?;
+ const atom_alignment = atom.alignment.toByteUnits() orelse 1;
+ const offset = mem.alignForward(u64, header.size, atom_alignment);
+ const padding = offset - header.size;
+ atom.value = offset;
+ header.size += padding + atom.size;
+ header.@"align" = @max(header.@"align", atom.alignment.toLog2Units());
+ const nreloc = atom.calcNumRelocs(macho_file);
+ atom.addExtra(.{ .rel_out_index = header.nreloc, .rel_out_count = nreloc }, macho_file);
+ header.nreloc += nreloc;
}
}
-fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {
- var size: u32 = 0;
+fn calcEhFrameSize(macho_file: *MachO) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const header = &macho_file.sections.items(.header)[macho_file.eh_frame_sect_index.?];
+ header.size = try eh_frame.calcSize(macho_file);
+ header.@"align" = 3;
+ header.nreloc = eh_frame.calcNumRelocs(macho_file);
+}
+
+fn calcCompactUnwindSize(macho_file: *MachO) void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ var nrec: u32 = 0;
var nreloc: u32 = 0;
for (macho_file.objects.items) |index| {
- const object = macho_file.getFile(index).?.object;
- for (object.unwind_records_indexes.items) |irec| {
- const rec = object.getUnwindRecord(irec);
- if (!rec.alive) continue;
- size += @sizeOf(macho.compact_unwind_entry);
- nreloc += 1;
- if (rec.getPersonality(macho_file)) |_| {
- nreloc += 1;
- }
- if (rec.getLsdaAtom(macho_file)) |_| {
- nreloc += 1;
- }
- }
+ const ctx = &macho_file.getFile(index).?.object.compact_unwind_ctx;
+ ctx.rec_index = nrec;
+ ctx.reloc_index = nreloc;
+ nrec += ctx.rec_count;
+ nreloc += ctx.reloc_count;
}
- const sect = &macho_file.sections.items(.header)[sect_index];
- sect.size = size;
+ const sect = &macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];
+ sect.size = nrec * @sizeOf(macho.compact_unwind_entry);
sect.nreloc = nreloc;
sect.@"align" = 3;
}
+fn calcSymtabSize(macho_file: *MachO) void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ var nlocals: u32 = 0;
+ var nstabs: u32 = 0;
+ var nexports: u32 = 0;
+ var nimports: u32 = 0;
+ var strsize: u32 = 1;
+
+ for (macho_file.objects.items) |index| {
+ const object = macho_file.getFile(index).?.object;
+ const ctx = &object.output_symtab_ctx;
+ ctx.ilocal = nlocals;
+ ctx.istab = nstabs;
+ ctx.iexport = nexports;
+ ctx.iimport = nimports;
+ ctx.stroff = strsize;
+ nlocals += ctx.nlocals;
+ nstabs += ctx.nstabs;
+ nexports += ctx.nexports;
+ nimports += ctx.nimports;
+ strsize += ctx.strsize;
+ }
+
+ for (macho_file.objects.items) |index| {
+ const object = macho_file.getFile(index).?.object;
+ const ctx = &object.output_symtab_ctx;
+ ctx.istab += nlocals;
+ ctx.iexport += nlocals + nstabs;
+ ctx.iimport += nlocals + nstabs + nexports;
+ }
+
+ {
+ const cmd = &macho_file.symtab_cmd;
+ cmd.nsyms = nlocals + nstabs + nexports + nimports;
+ cmd.strsize = strsize;
+ }
+
+ {
+ const cmd = &macho_file.dysymtab_cmd;
+ cmd.ilocalsym = 0;
+ cmd.nlocalsym = nlocals + nstabs;
+ cmd.iextdefsym = nlocals + nstabs;
+ cmd.nextdefsym = nexports;
+ cmd.iundefsym = nlocals + nstabs + nexports;
+ cmd.nundefsym = nimports;
+ }
+}
+
fn allocateSections(macho_file: *MachO) !void {
const slice = macho_file.sections.slice();
for (slice.items(.header)) |*header| {
@@ -463,6 +516,37 @@ fn allocateSections(macho_file: *MachO) !void {
}
header.size = needed_size;
}
+
+ var fileoff: u32 = 0;
+ for (slice.items(.header)) |header| {
+ fileoff = @max(fileoff, header.offset + @as(u32, @intCast(header.size)));
+ }
+
+ for (slice.items(.header)) |*header| {
+ if (header.nreloc == 0) continue;
+ header.reloff = mem.alignForward(u32, fileoff, @alignOf(macho.relocation_info));
+ fileoff = header.reloff + header.nreloc * @sizeOf(macho.relocation_info);
+ }
+
+ // In -r mode, there is no LINKEDIT segment and so we allocate required LINKEDIT commands
+ // as if they were detached or part of the single segment.
+
+ // DATA_IN_CODE
+ {
+ const cmd = &macho_file.data_in_code_cmd;
+ cmd.dataoff = fileoff;
+ fileoff += cmd.datasize;
+ fileoff = mem.alignForward(u32, fileoff, @alignOf(u64));
+ }
+
+ // SYMTAB
+ {
+ const cmd = &macho_file.symtab_cmd;
+ cmd.symoff = fileoff;
+ fileoff += cmd.nsyms * @sizeOf(macho.nlist_64);
+ fileoff = mem.alignForward(u32, fileoff, @alignOf(u32));
+ cmd.stroff = fileoff;
+ }
}
/// Renames segment names in Zig sections to standard MachO segment names such as
@@ -525,232 +609,77 @@ fn allocateSegment(macho_file: *MachO) void {
seg.filesize = fileoff - seg.fileoff;
}
-fn allocateSectionsRelocs(macho_file: *MachO, off: u32) u32 {
- var fileoff = off;
- const slice = macho_file.sections.slice();
- for (slice.items(.header)) |*header| {
- if (header.nreloc == 0) continue;
- header.reloff = mem.alignForward(u32, fileoff, @alignOf(macho.relocation_info));
- fileoff = header.reloff + header.nreloc * @sizeOf(macho.relocation_info);
- }
- return fileoff;
-}
-
// We need to sort relocations in descending order to be compatible with Apple's linker.
fn sortReloc(ctx: void, lhs: macho.relocation_info, rhs: macho.relocation_info) bool {
_ = ctx;
return lhs.r_address > rhs.r_address;
}
-fn writeAtoms(macho_file: *MachO) !void {
+fn sortRelocs(macho_file: *MachO) void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ for (macho_file.sections.items(.relocs)) |*relocs| {
+ mem.sort(macho.relocation_info, relocs.items, {}, sortReloc);
+ }
+}
+
+fn writeSections(macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.comp.gpa;
const cpu_arch = macho_file.getTarget().cpu.arch;
const slice = macho_file.sections.slice();
-
- var relocs = std.ArrayList(macho.relocation_info).init(gpa);
- defer relocs.deinit();
-
- for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| {
- if (atoms.items.len == 0) continue;
+ for (slice.items(.header), slice.items(.out), slice.items(.relocs)) |header, *out, *relocs| {
if (header.isZerofill()) continue;
- if (macho_file.isZigSection(@intCast(i)) or macho_file.isDebugSection(@intCast(i))) continue;
-
- const size = math.cast(usize, header.size) orelse return error.Overflow;
- const code = try gpa.alloc(u8, size);
- defer gpa.free(code);
+ try out.resize(gpa, header.size);
const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0;
- @memset(code, padding_byte);
-
- try relocs.ensureTotalCapacity(header.nreloc);
-
- for (atoms.items) |atom_index| {
- const atom = macho_file.getAtom(atom_index).?;
- assert(atom.flags.alive);
- const off = math.cast(usize, atom.value) orelse return error.Overflow;
- const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
- try atom.getData(macho_file, code[off..][0..atom_size]);
- try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs);
- }
-
- assert(relocs.items.len == header.nreloc);
-
- 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);
-
- relocs.clearRetainingCapacity();
+ @memset(out.items, padding_byte);
+ try relocs.resize(gpa, header.nreloc);
}
- if (macho_file.getZigObject()) |zo| {
- // TODO: this is ugly; perhaps we should aggregrate before?
- var zo_relocs = std.AutoArrayHashMap(u8, std.ArrayList(macho.relocation_info)).init(gpa);
- defer {
- for (zo_relocs.values()) |*list| {
- list.deinit();
- }
- zo_relocs.deinit();
- }
-
- for (macho_file.sections.items(.header), 0..) |header, n_sect| {
- if (header.isZerofill()) continue;
- if (!macho_file.isZigSection(@intCast(n_sect)) and !macho_file.isDebugSection(@intCast(n_sect))) continue;
- const gop = try zo_relocs.getOrPut(@intCast(n_sect));
- if (gop.found_existing) continue;
- gop.value_ptr.* = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);
- }
+ const cmd = macho_file.symtab_cmd;
+ try macho_file.symtab.resize(gpa, cmd.nsyms);
+ try macho_file.strtab.resize(gpa, cmd.strsize);
+ macho_file.strtab.items[0] = 0;
- for (zo.atoms.items) |atom_index| {
- const atom = macho_file.getAtom(atom_index) orelse continue;
- if (!atom.flags.alive) continue;
- const header = macho_file.sections.items(.header)[atom.out_n_sect];
- if (header.isZerofill()) continue;
- if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue;
- if (atom.getRelocs(macho_file).len == 0) continue;
- const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
- const code = try gpa.alloc(u8, atom_size);
- defer gpa.free(code);
- atom.getData(macho_file, code) catch |err| switch (err) {
- error.InputOutput => {
- try macho_file.reportUnexpectedError("fetching code for '{s}' failed", .{
- atom.getName(macho_file),
- });
- return error.FlushFailure;
- },
- else => |e| {
- try macho_file.reportUnexpectedError("unexpected error while fetching code for '{s}': {s}", .{
- atom.getName(macho_file),
- @errorName(e),
- });
- return error.FlushFailure;
- },
- };
- const file_offset = header.offset + atom.value;
- const rels = zo_relocs.getPtr(atom.out_n_sect).?;
- try atom.writeRelocs(macho_file, code, rels);
- try macho_file.base.file.?.pwriteAll(code, file_offset);
- }
-
- for (zo_relocs.keys(), zo_relocs.values()) |sect_id, rels| {
- const header = macho_file.sections.items(.header)[sect_id];
- assert(rels.items.len == header.nreloc);
- mem.sort(macho.relocation_info, rels.items, {}, sortReloc);
- try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(rels.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.comp.gpa;
- const header = macho_file.sections.items(.header)[sect_index];
-
- const nrecs = math.cast(usize, @divExact(header.size, @sizeOf(macho.compact_unwind_entry))) orelse return error.Overflow;
- var entries = try std.ArrayList(macho.compact_unwind_entry).initCapacity(gpa, nrecs);
- defer entries.deinit();
-
- var relocs = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);
- defer relocs.deinit();
-
- const addReloc = struct {
- fn addReloc(offset: i32, cpu_arch: std.Target.Cpu.Arch) macho.relocation_info {
- return .{
- .r_address = offset,
- .r_symbolnum = 0,
- .r_pcrel = 0,
- .r_length = 3,
- .r_extern = 0,
- .r_type = switch (cpu_arch) {
- .aarch64 => @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
- .x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
- else => unreachable,
- },
- };
- }
- }.addReloc;
-
- var offset: i32 = 0;
for (macho_file.objects.items) |index| {
- const object = macho_file.getFile(index).?.object;
- for (object.unwind_records_indexes.items) |irec| {
- const rec = object.getUnwindRecord(irec);
- if (!rec.alive) continue;
-
- var out: macho.compact_unwind_entry = .{
- .rangeStart = 0,
- .rangeLength = rec.length,
- .compactUnwindEncoding = rec.enc.enc,
- .personalityFunction = 0,
- .lsda = 0,
- };
-
- {
- // Function address
- const atom = rec.getAtom(macho_file);
- const addr = rec.getAtomAddress(macho_file);
- out.rangeStart = addr;
- var reloc = addReloc(offset, macho_file.getTarget().cpu.arch);
- reloc.r_symbolnum = atom.out_n_sect + 1;
- relocs.appendAssumeCapacity(reloc);
- }
-
- // 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.getTarget().cpu.arch);
- reloc.r_symbolnum = r_symbolnum;
- reloc.r_extern = 1;
- relocs.appendAssumeCapacity(reloc);
- }
+ try macho_file.getFile(index).?.object.writeAtomsRelocatable(macho_file);
+ macho_file.getFile(index).?.writeSymtab(macho_file, macho_file);
+ }
- // LSDA address
- if (rec.getLsdaAtom(macho_file)) |atom| {
- const addr = rec.getLsdaAddress(macho_file);
- out.lsda = addr;
- var reloc = addReloc(offset + 24, macho_file.getTarget().cpu.arch);
- reloc.r_symbolnum = atom.out_n_sect + 1;
- relocs.appendAssumeCapacity(reloc);
- }
+ if (macho_file.eh_frame_sect_index) |_| {
+ try writeEhFrame(macho_file);
+ }
- entries.appendAssumeCapacity(out);
- offset += @sizeOf(macho.compact_unwind_entry);
+ if (macho_file.unwind_info_sect_index) |_| {
+ for (macho_file.objects.items) |index| {
+ try macho_file.getFile(index).?.object.writeCompactUnwindRelocatable(macho_file);
}
}
-
- assert(entries.items.len == nrecs);
- assert(relocs.items.len == header.nreloc);
-
- 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);
}
fn writeEhFrame(macho_file: *MachO) !void {
- const sect_index = macho_file.eh_frame_sect_index orelse return;
- const gpa = macho_file.base.comp.gpa;
- const header = macho_file.sections.items(.header)[sect_index];
- const size = math.cast(usize, header.size) orelse return error.Overflow;
-
- const code = try gpa.alloc(u8, size);
- defer gpa.free(code);
-
- var relocs = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);
- defer relocs.deinit();
+ const sect_index = macho_file.eh_frame_sect_index.?;
+ const buffer = macho_file.sections.items(.out)[sect_index];
+ const relocs = macho_file.sections.items(.relocs)[sect_index];
+ try eh_frame.writeRelocs(macho_file, buffer.items, relocs.items);
+}
- try eh_frame.writeRelocs(macho_file, code, &relocs);
- assert(relocs.items.len == header.nreloc);
+fn writeSectionsToFile(macho_file: *MachO) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
- mem.sort(macho.relocation_info, relocs.items, {}, sortReloc);
+ const slice = macho_file.sections.slice();
+ for (slice.items(.header), slice.items(.out), slice.items(.relocs)) |header, out, relocs| {
+ try macho_file.base.file.?.pwriteAll(out.items, header.offset);
+ try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
+ }
- // 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.writeDataInCode();
+ try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff);
+ try macho_file.base.file.?.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff);
}
fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {
src/link/MachO.zig
@@ -290,10 +290,16 @@ pub fn deinit(self: *MachO) void {
self.dylibs.deinit(gpa);
self.segments.deinit(gpa);
- for (self.sections.items(.atoms), self.sections.items(.out), self.sections.items(.thunks)) |*atoms, *out, *thnks| {
+ for (
+ self.sections.items(.atoms),
+ self.sections.items(.out),
+ self.sections.items(.thunks),
+ self.sections.items(.relocs),
+ ) |*atoms, *out, *thnks, *relocs| {
atoms.deinit(gpa);
out.deinit(gpa);
thnks.deinit(gpa);
+ relocs.deinit(gpa);
}
self.sections.deinit(gpa);
@@ -1457,10 +1463,10 @@ pub fn dedupLiterals(self: *MachO) !void {
fn claimUnresolved(self: *MachO) void {
if (self.getZigObject()) |zo| {
- zo.claimUnresolved(self);
+ zo.asFile().claimUnresolved(self);
}
for (self.objects.items) |index| {
- self.getFile(index).?.object.claimUnresolved(self);
+ self.getFile(index).?.claimUnresolved(self);
}
}
@@ -3987,6 +3993,7 @@ const Section = struct {
last_atom_index: Atom.Index = 0,
thunks: std.ArrayListUnmanaged(Thunk.Index) = .{},
out: std.ArrayListUnmanaged(u8) = .{},
+ relocs: std.ArrayListUnmanaged(macho.relocation_info) = .{},
};
pub const LiteralPool = struct {