mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 12:27:41 +00:00
macho: re-enable relocatable mode
This commit is contained in:
parent
90c54f1eb6
commit
b62281a9c8
@ -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 {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
// if (comp.link_errors.items.len > 0) return error.FlushFailure;
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
// try createSegment(macho_file);
|
||||
// try allocateSections(macho_file);
|
||||
// allocateSegment(macho_file);
|
||||
if (build_options.enable_logging) {
|
||||
state_log.debug("{}", .{macho_file.dumpState()});
|
||||
}
|
||||
|
||||
// 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);
|
||||
try writeSections(macho_file);
|
||||
sortRelocs(macho_file);
|
||||
try writeSectionsToFile(macho_file);
|
||||
|
||||
// if (build_options.enable_logging) {
|
||||
// state_log.debug("{}", .{macho_file.dumpState()});
|
||||
// }
|
||||
// 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);
|
||||
|
||||
// try macho_file.calcSymtabSize();
|
||||
// try writeAtoms(macho_file);
|
||||
// try writeCompactUnwind(macho_file);
|
||||
// try writeEhFrame(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);
|
||||
|
||||
// // 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);
|
||||
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.eh_frame_sect_index) |_| {
|
||||
try calcEhFrameSize(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.unwind_info_sect_index) |index| {
|
||||
calcCompactUnwindSize(macho_file, index);
|
||||
}
|
||||
try macho_file.data_in_code.updateSize(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);
|
||||
}
|
||||
calcCompactUnwindSize(macho_file);
|
||||
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);
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
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 (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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
entries.appendAssumeCapacity(out);
|
||||
offset += @sizeOf(macho.compact_unwind_entry);
|
||||
}
|
||||
try macho_file.getFile(index).?.object.writeAtomsRelocatable(macho_file);
|
||||
macho_file.getFile(index).?.writeSymtab(macho_file, macho_file);
|
||||
}
|
||||
|
||||
assert(entries.items.len == nrecs);
|
||||
assert(relocs.items.len == header.nreloc);
|
||||
if (macho_file.eh_frame_sect_index) |_| {
|
||||
try writeEhFrame(macho_file);
|
||||
}
|
||||
|
||||
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);
|
||||
if (macho_file.unwind_info_sect_index) |_| {
|
||||
for (macho_file.objects.items) |index| {
|
||||
try macho_file.getFile(index).?.object.writeCompactUnwindRelocatable(macho_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
const code = try gpa.alloc(u8, size);
|
||||
defer gpa.free(code);
|
||||
fn writeSectionsToFile(macho_file: *MachO) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
var relocs = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);
|
||||
defer relocs.deinit();
|
||||
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);
|
||||
}
|
||||
|
||||
try eh_frame.writeRelocs(macho_file, code, &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);
|
||||
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 } {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user