macho: update ZigObject to use new ownership model

This commit is contained in:
Jakub Konka 2024-07-10 16:28:00 +02:00
parent f8b5466aef
commit 5b4c0cc1f9
6 changed files with 320 additions and 200 deletions

View File

@ -51,12 +51,12 @@ pub fn emitMir(emit: *Emit) Error!void {
});
} else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {
// Add relocation to the decl.
const atom = macho_file.getSymbol(symbol.atom_index).getAtom(macho_file).?;
const sym_index = macho_file.getZigObject().?.symbols.items[symbol.sym_index];
const zo = macho_file.getZigObject().?;
const atom = zo.symbols.items[symbol.atom_index].getAtom(macho_file).?;
try atom.addReloc(macho_file, .{
.tag = .@"extern",
.offset = end_offset - 4,
.target = sym_index,
.target = symbol.sym_index,
.addend = 0,
.type = .branch,
.meta = .{
@ -160,11 +160,11 @@ pub fn emitMir(emit: *Emit) Error!void {
.Obj => true,
.Lib => emit.lower.link_mode == .static,
};
const atom = macho_file.getSymbol(data.atom_index).getAtom(macho_file).?;
const sym_index = macho_file.getZigObject().?.symbols.items[data.sym_index];
const sym = macho_file.getSymbol(sym_index);
const zo = macho_file.getZigObject().?;
const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?;
const sym = zo.symbols.items[data.sym_index];
if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
_ = try sym.getOrCreateZigGotEntry(sym_index, macho_file);
_ = try sym.getOrCreateZigGotEntry(data.sym_index, macho_file);
}
const @"type": link.File.MachO.Relocation.Type = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
.zig_got_load
@ -179,7 +179,7 @@ pub fn emitMir(emit: *Emit) Error!void {
try atom.addReloc(macho_file, .{
.tag = .@"extern",
.offset = @intCast(end_offset - 4),
.target = sym_index,
.target = data.sym_index,
.addend = 0,
.type = @"type",
.meta = .{

View File

@ -425,8 +425,8 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
else => unreachable,
};
} else if (lower.bin_file.cast(link.File.MachO)) |macho_file| {
const sym_index = macho_file.getZigObject().?.symbols.items[sym.sym_index];
const macho_sym = macho_file.getSymbol(sym_index);
const zo = macho_file.getZigObject().?;
const macho_sym = zo.symbols.items[sym.sym_index];
if (macho_sym.flags.tlv) {
_ = lower.reloc(.{ .linker_reloc = sym });

View File

@ -901,15 +901,16 @@ fn genDeclRef(
}
return GenResult.mcv(.{ .load_symbol = sym.esym_index });
} else if (lf.cast(link.File.MachO)) |macho_file| {
const zo = macho_file.getZigObject().?;
if (is_extern) {
const name = decl.name.toSlice(ip);
const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
const sym_index = try macho_file.getGlobalSymbol(name, lib_name);
macho_file.getSymbol(macho_file.getZigObject().?.symbols.items[sym_index]).flags.needs_got = true;
zo.symbols.items[sym_index].flags.needs_got = true;
return GenResult.mcv(.{ .load_symbol = sym_index });
}
const sym_index = try macho_file.getZigObject().?.getOrCreateMetadataForDecl(macho_file, decl_index);
const sym = macho_file.getSymbol(sym_index);
const sym_index = try zo.getOrCreateMetadataForDecl(macho_file, decl_index);
const sym = zo.symbols.items[sym_index];
if (is_threadlocal) {
return GenResult.mcv(.{ .load_tlv = sym.nlist_idx });
}
@ -956,7 +957,7 @@ fn genUnnamedConst(
},
.macho => {
const macho_file = lf.cast(link.File.MachO).?;
const local = macho_file.getSymbol(local_sym_index);
const local = macho_file.getZigObject().?.symbols.items[local_sym_index];
return GenResult.mcv(.{ .load_symbol = local.nlist_idx });
},
.coff => {

View File

@ -290,8 +290,10 @@ pub fn deinit(self: *MachO) void {
self.dylibs.deinit(gpa);
self.segments.deinit(gpa);
for (self.sections.items(.atoms)) |*list| {
list.deinit(gpa);
for (self.sections.items(.atoms), self.sections.items(.out), self.sections.items(.thunks)) |*atoms, *out, *thnks| {
atoms.deinit(gpa);
out.deinit(gpa);
thnks.deinit(gpa);
}
self.sections.deinit(gpa);
@ -561,8 +563,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
if (self.getZigObject()) |zo| {
var has_resolve_error = false;
for (zo.atoms.items) |atom_index| {
const atom = self.getAtom(atom_index) orelse continue;
for (zo.getAtoms()) |atom_index| {
const atom = zo.getAtom(atom_index) orelse continue;
if (!atom.flags.alive) continue;
const sect = &self.sections.items(.header)[atom.out_n_sect];
if (sect.isZerofill()) continue;
@ -573,7 +575,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
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(self, code) catch |err| switch (err) {
zo.getAtomData(self, atom.*, code) catch |err| switch (err) {
error.InputOutput => {
try self.reportUnexpectedError("fetching code for '{s}' failed", .{
atom.getName(self),
@ -1524,7 +1526,7 @@ fn scanRelocs(self: *MachO) !void {
try self.getFile(index).?.object.scanRelocs(self);
}
if (self.getInternalObject()) |obj| {
try obj.scanRelocs(self);
obj.scanRelocs(self);
}
try self.reportUndefs();
@ -2394,7 +2396,7 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void {
self.objc_stubs_sect_index,
}) |maybe_sect_id| {
if (maybe_sect_id) |sect_id| {
const out = &slice.items(.out)[sect_id];
const out = slice.items(.out)[sect_id].items;
try self.writeSyntheticSection(sect_id, out);
}
}
@ -3970,9 +3972,11 @@ pub const base_tag: link.File.Tag = link.File.Tag.macho;
const Section = struct {
header: macho.section_64,
segment_id: u8,
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
atoms: std.ArrayListUnmanaged(Ref) = .{},
free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
last_atom_index: Atom.Index = 0,
thunks: std.ArrayListUnmanaged(Thunk.Index) = .{},
out: std.ArrayListUnmanaged(u8) = .{},
};
pub const LiteralPool = struct {
@ -4018,7 +4022,7 @@ pub const LiteralPool = struct {
return .{
.found_existing = gop.found_existing,
.index = @intCast(gop.index),
.atom = &lp.values.items[gop.index],
.ref = &lp.values.items[gop.index],
};
}

View File

@ -423,7 +423,6 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void {
const gpa = macho_file.base.comp.gpa;
const file = self.getFile(macho_file);
assert(file == .zig_object);
assert(self.flags.relocs);
var extra = self.getExtra(macho_file).?;
const rels = &file.zig_object.relocs.items[extra.rel_index];
try rels.append(gpa, reloc);
@ -432,7 +431,6 @@ pub fn addReloc(self: *Atom, macho_file: *MachO, reloc: Relocation) !void {
}
pub fn freeRelocs(self: *Atom, macho_file: *MachO) void {
if (!self.flags.relocs) return;
self.getFile(macho_file).zig_object.freeAtomRelocs(self.*, macho_file);
var extra = self.getExtra(macho_file).?;
extra.rel_count = 0;

View File

@ -6,9 +6,15 @@ index: File.Index,
symtab: std.MultiArrayList(Nlist) = .{},
strtab: StringTable = .{},
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
symbols: std.ArrayListUnmanaged(Symbol) = .{},
symbols_extra: std.ArrayListUnmanaged(u32) = .{},
globals: std.ArrayListUnmanaged(MachO.SymbolResolver.Index) = .{},
/// Maps string index (so name) into nlist index for the global symbol defined within this
/// module.
globals_lookup: std.AutoHashMapUnmanaged(u32, u32) = .{},
atoms: std.ArrayListUnmanaged(Atom) = .{},
atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
atoms_extra: std.ArrayListUnmanaged(u32) = .{},
/// Table of tracked LazySymbols.
lazy_syms: LazySymbolTable = .{},
@ -58,10 +64,13 @@ debug_info_header_dirty: bool = false,
debug_line_header_dirty: bool = false,
pub fn init(self: *ZigObject, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
const comp = macho_file.base.comp;
const gpa = comp.gpa;
try self.atoms.append(gpa, 0); // null input section
try self.atoms.append(gpa, .{ .extra = try self.addAtomExtra(gpa, .{}) }); // null input section
try self.strtab.buffer.append(gpa, 0);
switch (comp.config.debug_format) {
@ -84,8 +93,12 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
self.symtab.deinit(allocator);
self.strtab.deinit(allocator);
self.symbols.deinit(allocator);
self.atoms.deinit(allocator);
self.symbols_extra.deinit(allocator);
self.globals.deinit(allocator);
self.globals_lookup.deinit(allocator);
self.atoms.deinit(allocator);
self.atoms_indexes.deinit(allocator);
self.atoms_extra.deinit(allocator);
{
var it = self.decls.iterator();
@ -139,32 +152,21 @@ fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index {
return index;
}
pub fn addAtom(self: *ZigObject, macho_file: *MachO) !Symbol.Index {
const gpa = macho_file.base.comp.gpa;
const atom_index = try macho_file.addAtom();
const symbol_index = try macho_file.addSymbol();
const nlist_index = try self.addNlist(gpa);
try self.atoms.append(gpa, atom_index);
try self.symbols.append(gpa, symbol_index);
const atom = macho_file.getAtom(atom_index).?;
atom.file = self.index;
atom.atom_index = atom_index;
const symbol = macho_file.getSymbol(symbol_index);
symbol.file = self.index;
symbol.atom = atom_index;
pub fn createAtomForDecl(self: *ZigObject, allocator: Allocator, macho_file: *MachO) !Symbol.Index {
const atom_index = try self.addAtom(allocator);
const symbol_index = try self.addSymbol(allocator);
const nlist_index = try self.addNlist(allocator);
self.symtab.items(.atom)[nlist_index] = atom_index;
try self.atoms_indexes.append(allocator, atom_index);
const symbol = &self.symbols.items[symbol_index];
symbol.atom_ref = .{ .index = atom_index, .file = self.index };
symbol.nlist_idx = nlist_index;
symbol.extra = try self.addSymbolExtra(allocator, .{});
const relocs_index = @as(u32, @intCast(self.relocs.items.len));
const relocs = try self.relocs.addOne(gpa);
const relocs = try self.relocs.addOne(allocator);
relocs.* = .{};
try atom.addExtra(.{ .rel_index = relocs_index, .rel_count = 0 }, macho_file);
atom.flags.relocs = true;
const atom = self.getAtom(atom_index).?;
atom.addExtra(.{ .rel_index = relocs_index, .rel_count = 0 }, macho_file);
return symbol_index;
}
@ -191,89 +193,51 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8
}
pub fn getAtomRelocs(self: *ZigObject, atom: Atom, macho_file: *MachO) []const Relocation {
if (!atom.flags.relocs) return &[0]Relocation{};
const extra = atom.getExtra(macho_file).?;
const extra = atom.getExtra(macho_file);
const relocs = self.relocs.items[extra.rel_index];
return relocs.items[0..extra.rel_count];
}
pub fn freeAtomRelocs(self: *ZigObject, atom: Atom, macho_file: *MachO) void {
if (atom.flags.relocs) {
const extra = atom.getExtra(macho_file).?;
self.relocs.items[extra.rel_index].clearRetainingCapacity();
}
const extra = atom.getExtra(macho_file);
self.relocs.items[extra.rel_index].clearRetainingCapacity();
}
pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) void {
pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
for (self.symbols.items, 0..) |index, i| {
const nlist_idx = @as(Symbol.Index, @intCast(i));
const nlist = self.symtab.items(.nlist)[nlist_idx];
const atom_index = self.symtab.items(.atom)[nlist_idx];
const gpa = macho_file.base.comp.gpa;
for (self.symtab.items(.nlist), self.symtab.items(.atom), self.globals.items, 0..) |nlist, atom_index, *global, i| {
if (!nlist.ext()) continue;
if (nlist.undf() and !nlist.tentative()) continue;
if (nlist.sect()) {
const atom = macho_file.getAtom(atom_index).?;
const atom = self.getAtom(atom_index).?;
if (!atom.flags.alive) continue;
}
const symbol = macho_file.getSymbol(index);
const gop = try macho_file.resolver.getOrPut(gpa, .{
.index = @intCast(i),
.file = self.index,
}, macho_file);
if (!gop.found_existing) {
gop.ref.* = .{ .index = 0, .file = 0 };
}
global.* = gop.index;
if (nlist.undf() and !nlist.tentative()) continue;
if (gop.ref.getFile(macho_file) == null) {
gop.ref.* = .{ .index = @intCast(i), .file = self.index };
continue;
}
if (self.asFile().getSymbolRank(.{
.archive = false,
.weak = nlist.weakDef(),
.tentative = nlist.tentative(),
}) < symbol.getSymbolRank(macho_file)) {
const value = if (nlist.sect()) blk: {
const atom = macho_file.getAtom(atom_index).?;
break :blk nlist.n_value - atom.getInputAddress(macho_file);
} else nlist.n_value;
const out_n_sect = if (nlist.sect()) macho_file.getAtom(atom_index).?.out_n_sect else 0;
symbol.value = value;
symbol.atom = atom_index;
symbol.out_n_sect = out_n_sect;
symbol.nlist_idx = nlist_idx;
symbol.file = self.index;
symbol.flags.weak = nlist.weakDef();
symbol.flags.abs = nlist.abs();
symbol.flags.tentative = nlist.tentative();
symbol.flags.weak_ref = false;
symbol.flags.dyn_ref = nlist.n_desc & macho.REFERENCED_DYNAMICALLY != 0;
symbol.flags.no_dead_strip = symbol.flags.no_dead_strip or nlist.noDeadStrip();
// TODO: symbol.flags.interposable = macho_file.base.isDynLib() and macho_file.options.namespace == .flat and !nlist.pext();
symbol.flags.interposable = false;
if (nlist.sect() and
macho_file.sections.items(.header)[nlist.n_sect - 1].type() == macho.S_THREAD_LOCAL_VARIABLES)
{
symbol.flags.tlv = true;
}
}) < gop.ref.getSymbol(macho_file).?.getSymbolRank(macho_file)) {
gop.ref.* = .{ .index = @intCast(i), .file = self.index };
}
// Regardless of who the winner is, we still merge symbol visibility here.
if (nlist.pext() or (nlist.weakDef() and nlist.weakRef())) {
if (symbol.visibility != .global) {
symbol.visibility = .hidden;
}
} else {
symbol.visibility = .global;
}
}
}
pub fn resetGlobals(self: *ZigObject, macho_file: *MachO) void {
for (self.symbols.items, 0..) |sym_index, nlist_idx| {
if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue;
const sym = macho_file.getSymbol(sym_index);
const name = sym.name;
const global = sym.flags.global;
const weak_ref = sym.flags.weak_ref;
sym.* = .{};
sym.name = name;
sym.flags.global = global;
sym.flags.weak_ref = weak_ref;
}
}
@ -281,12 +245,13 @@ pub fn markLive(self: *ZigObject, macho_file: *MachO) void {
const tracy = trace(@src());
defer tracy.end();
for (self.symbols.items, 0..) |index, nlist_idx| {
const nlist = self.symtab.items(.nlist)[nlist_idx];
for (0..self.symbols.items.len) |i| {
const nlist = self.symtab.items(.nlist)[i];
if (!nlist.ext()) continue;
const sym = macho_file.getSymbol(index);
const file = sym.getFile(macho_file) orelse continue;
const ref = self.getSymbolRef(@intCast(i), macho_file);
const file = ref.getFile(macho_file) orelse continue;
const sym = ref.getSymbol(macho_file).?;
const should_keep = nlist.undf() or (nlist.tentative() and !sym.flags.tentative);
if (should_keep and file == .object and !file.object.alive) {
file.object.alive = true;
@ -295,24 +260,41 @@ pub fn markLive(self: *ZigObject, macho_file: *MachO) void {
}
}
pub fn checkDuplicates(self: *ZigObject, dupes: anytype, macho_file: *MachO) !void {
for (self.symbols.items, 0..) |index, nlist_idx| {
const sym = macho_file.getSymbol(index);
if (sym.visibility != .global) continue;
const file = sym.getFile(macho_file) orelse continue;
if (file.getIndex() == self.index) continue;
pub fn mergeSymbolVisibility(self: *ZigObject, macho_file: *MachO) void {
const tracy = trace(@src());
defer tracy.end();
const nlist = self.symtab.items(.nlist)[nlist_idx];
if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) {
const gop = try dupes.getOrPut(index);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
try gop.value_ptr.append(macho_file.base.comp.gpa, self.index);
for (self.symbols.items, 0..) |sym, i| {
const ref = self.getSymbolRef(@intCast(i), macho_file);
const global = ref.getSymbol(macho_file) orelse continue;
if (global.visibility != .global) {
global.visibility = sym.visibility;
}
if (sym.flags.weak_ref) {
global.flags.weak_ref = true;
}
}
}
// TODO
// pub fn checkDuplicates(self: *ZigObject, dupes: anytype, macho_file: *MachO) !void {
// for (self.symbols.items, 0..) |index, nlist_idx| {
// const sym = macho_file.getSymbol(index);
// if (sym.visibility != .global) continue;
// const file = sym.getFile(macho_file) orelse continue;
// if (file.getIndex() == self.index) continue;
// const nlist = self.symtab.items(.nlist)[nlist_idx];
// if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) {
// const gop = try dupes.getOrPut(index);
// if (!gop.found_existing) {
// gop.value_ptr.* = .{};
// }
// try gop.value_ptr.append(macho_file.base.comp.gpa, self.index);
// }
// }
// }
pub fn resolveLiterals(self: *ZigObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void {
_ = self;
_ = lp;
@ -362,8 +344,8 @@ pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !voi
}
pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void {
for (self.atoms.items) |atom_index| {
const atom = macho_file.getAtom(atom_index) orelse continue;
for (self.getAtoms()) |atom_index| {
const atom = self.getAtom(atom_index) orelse continue;
if (!atom.flags.alive) continue;
const sect = atom.getInputSection(macho_file);
if (sect.isZerofill()) continue;
@ -371,46 +353,49 @@ pub fn scanRelocs(self: *ZigObject, macho_file: *MachO) !void {
}
}
pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) !void {
pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) void {
const tracy = trace(@src());
defer tracy.end();
for (self.symbols.items) |sym_index| {
const sym = macho_file.getSymbol(sym_index);
const file = sym.getFile(macho_file) orelse continue;
for (self.symbols.items, 0..) |*sym, i| {
const ref = self.getSymbolRef(@intCast(i), macho_file);
const file = ref.getFile(macho_file) orelse continue;
if (file.getIndex() != self.index) continue;
if (sym.getAtom(macho_file)) |atom| if (!atom.flags.alive) continue;
sym.flags.output_symtab = true;
if (sym.isLocal()) {
try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file);
self.output_symtab_ctx.nlocals += 1;
} else if (sym.flags.@"export") {
try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file);
sym.addExtra(.{ .symtab = self.output_symtab_ctx.nexports }, macho_file);
self.output_symtab_ctx.nexports += 1;
} else {
assert(sym.flags.import);
try sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file);
sym.addExtra(.{ .symtab = self.output_symtab_ctx.nimports }, macho_file);
self.output_symtab_ctx.nimports += 1;
}
self.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + 1));
}
}
pub fn writeSymtab(self: ZigObject, macho_file: *MachO, ctx: anytype) void {
pub fn writeSymtab(self: ZigObject, macho_file: *MachO) void {
const tracy = trace(@src());
defer tracy.end();
for (self.symbols.items) |sym_index| {
const sym = macho_file.getSymbol(sym_index);
const file = sym.getFile(macho_file) orelse continue;
var n_strx = self.output_symtab_ctx.stroff;
for (self.symbols.items, 0..) |sym, i| {
const ref = self.getSymbolRef(@intCast(i), macho_file);
const file = ref.getFile(macho_file) orelse continue;
if (file.getIndex() != self.index) continue;
const idx = sym.getOutputSymtabIndex(macho_file) orelse continue;
const n_strx = @as(u32, @intCast(ctx.strtab.items.len));
ctx.strtab.appendSliceAssumeCapacity(sym.getName(macho_file));
ctx.strtab.appendAssumeCapacity(0);
const out_sym = &ctx.symtab.items[idx];
const out_sym = &macho_file.symtab.items[idx];
out_sym.n_strx = n_strx;
sym.setOutputSym(macho_file, out_sym);
const name = sym.getName(macho_file);
@memcpy(macho_file.strtab.items[n_strx..][0..name.len], name);
n_strx += @intCast(name.len);
macho_file.strtab.items[n_strx] = 0;
n_strx += 1;
}
}
@ -523,9 +508,9 @@ pub fn getDeclVAddr(
reloc_info: link.File.RelocInfo,
) !u64 {
const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
const sym = macho_file.getSymbol(sym_index);
const sym = self.symbols.items[sym_index];
const vaddr = sym.getAddress(.{}, macho_file);
const parent_atom = macho_file.getSymbol(reloc_info.parent_atom_index).getAtom(macho_file).?;
const parent_atom = self.symbols.items[reloc_info.parent_atom_index].getAtom(macho_file).?;
try parent_atom.addReloc(macho_file, .{
.tag = .@"extern",
.offset = @intCast(reloc_info.offset),
@ -549,9 +534,9 @@ pub fn getAnonDeclVAddr(
reloc_info: link.File.RelocInfo,
) !u64 {
const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
const sym = macho_file.getSymbol(sym_index);
const sym = self.symbols.items[sym_index];
const vaddr = sym.getAddress(.{}, macho_file);
const parent_atom = macho_file.getSymbol(reloc_info.parent_atom_index).getAtom(macho_file).?;
const parent_atom = self.symbols.items[reloc_info.parent_atom_index].getAtom(macho_file).?;
try parent_atom.addReloc(macho_file, .{
.tag = .@"extern",
.offset = @intCast(reloc_info.offset),
@ -584,7 +569,7 @@ pub fn lowerAnonDecl(
else => explicit_alignment,
};
if (self.anon_decls.get(decl_val)) |metadata| {
const existing_alignment = macho_file.getSymbol(metadata.symbol_index).getAtom(macho_file).?.alignment;
const existing_alignment = self.symbols.items[metadata.symbol_index].getAtom(macho_file).?.alignment;
if (decl_alignment.order(existing_alignment).compare(.lte))
return .ok;
}
@ -628,13 +613,10 @@ fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPoo
}
fn freeDeclMetadata(self: *ZigObject, macho_file: *MachO, sym_index: Symbol.Index) void {
_ = self;
const gpa = macho_file.base.comp.gpa;
const sym = macho_file.getSymbol(sym_index);
const sym = self.symbols.items[sym_index];
sym.getAtom(macho_file).?.free(macho_file);
log.debug("adding %{d} to local symbols free list", .{sym_index});
macho_file.symbols_free_list.append(gpa, sym_index) catch {};
macho_file.symbols.items[sym_index] = .{};
// TODO redo this
// TODO free GOT entry here
}
@ -675,7 +657,7 @@ pub fn updateFunc(
const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
self.freeUnnamedConsts(macho_file, decl_index);
macho_file.getSymbol(sym_index).getAtom(macho_file).?.freeRelocs(macho_file);
self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
@ -708,7 +690,7 @@ pub fn updateFunc(
try self.updateDeclCode(macho_file, pt, decl_index, sym_index, sect_index, code);
if (decl_state) |*ds| {
const sym = macho_file.getSymbol(sym_index);
const sym = self.symbols.items[sym_index];
try self.dwarf.?.commitDeclState(
pt,
decl_index,
@ -743,13 +725,13 @@ pub fn updateDecl(
const name = decl.name.toSlice(&mod.intern_pool);
const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
const index = try self.getGlobalSymbol(macho_file, name, lib_name);
const actual_index = self.symbols.items[index];
macho_file.getSymbol(actual_index).flags.needs_got = true;
const sym = &self.symbols.items[index];
sym.flags.needs_got = true;
return;
}
const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
macho_file.getSymbol(sym_index).getAtom(macho_file).?.freeRelocs(macho_file);
self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
const gpa = macho_file.base.comp.gpa;
var code_buffer = std.ArrayList(u8).init(gpa);
@ -784,7 +766,7 @@ pub fn updateDecl(
}
if (decl_state) |*ds| {
const sym = macho_file.getSymbol(sym_index);
const sym = self.symbols.items[sym_index];
try self.dwarf.?.commitDeclState(
pt,
decl_index,
@ -816,7 +798,7 @@ fn updateDeclCode(
const required_alignment = decl.getAlignment(pt);
const sect = &macho_file.sections.items(.header)[sect_index];
const sym = macho_file.getSymbol(sym_index);
const sym = &self.symbols.items[sym_index];
const nlist = &self.symtab.items(.nlist)[sym.nlist_idx];
const atom = sym.getAtom(macho_file).?;
@ -850,13 +832,13 @@ fn updateDeclCode(
if (!macho_file.base.isRelocatable()) {
log.debug(" (updating offset table entry)", .{});
assert(sym.flags.has_zig_got);
const extra = sym.getExtra(macho_file).?;
const extra = sym.getExtra(macho_file);
try macho_file.zig_got.writeOne(macho_file, extra.zig_got);
}
}
} else if (code.len < old_size) {
atom.shrink(macho_file);
} else if (macho_file.getAtom(atom.next_index) == null) {
} else if (self.getAtom(atom.next_index) == null) {
const needed_size = atom.value + code.len;
sect.size = needed_size;
}
@ -922,8 +904,8 @@ fn createTlvInitializer(
const sym_name = try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{name});
defer gpa.free(sym_name);
const sym_index = try self.addAtom(macho_file);
const sym = macho_file.getSymbol(sym_index);
const sym_index = try self.createAtomForDecl(gpa, macho_file);
const sym = &self.symbols.items[sym_index];
const nlist = &self.symtab.items(.nlist)[sym.nlist_idx];
const atom = sym.getAtom(macho_file).?;
@ -945,7 +927,6 @@ fn createTlvInitializer(
const slice = macho_file.sections.slice();
const header = slice.items(.header)[sect_index];
const atoms = &slice.items(.atoms)[sect_index];
const gop = try self.tlv_initializers.getOrPut(gpa, atom.atom_index);
assert(!gop.found_existing); // TODO incremental updates
@ -956,8 +937,6 @@ fn createTlvInitializer(
gop.value_ptr.data = try gpa.dupe(u8, code);
}
try atoms.append(gpa, atom.atom_index);
return sym_index;
}
@ -970,7 +949,7 @@ fn createTlvDescriptor(
) !void {
const gpa = macho_file.base.comp.gpa;
const sym = macho_file.getSymbol(sym_index);
const sym = &self.symbols.items[sym_index];
const nlist = &self.symtab.items(.nlist)[sym.nlist_idx];
const atom = sym.getAtom(macho_file).?;
const alignment = Atom.Alignment.fromNonzeroByteUnits(@alignOf(u64));
@ -1000,7 +979,7 @@ fn createTlvDescriptor(
try atom.addReloc(macho_file, .{
.tag = .@"extern",
.offset = 0,
.target = self.symbols.items[tlv_bootstrap_index],
.target = tlv_bootstrap_index,
.addend = 0,
.type = .unsigned,
.meta = .{
@ -1020,11 +999,14 @@ fn createTlvDescriptor(
.pcrel = false,
.has_subtractor = false,
.length = 3,
.symbolnum = @intCast(macho_file.getSymbol(init_sym_index).nlist_idx),
.symbolnum = @intCast(init_sym_index),
},
});
try macho_file.sections.items(.atoms)[sect_index].append(gpa, atom.atom_index);
try macho_file.sections.items(.atoms)[sect_index].append(gpa, .{
.index = atom.atom_index,
.file = self.index,
});
}
fn getDeclOutputSection(
@ -1115,7 +1097,7 @@ pub fn lowerUnnamedConst(
return error.CodegenFail;
},
};
const sym = macho_file.getSymbol(sym_index);
const sym = self.symbols.items[sym_index];
try unnamed_consts.append(gpa, sym.atom);
return sym_index;
}
@ -1140,7 +1122,7 @@ fn lowerConst(
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
const sym_index = try self.addAtom(macho_file);
const sym_index = try self.createAtomForDecl(gpa, macho_file);
const res = try codegen.generateSymbol(&macho_file.base, pt, src_loc, val, &code_buffer, .{
.none = {},
@ -1152,7 +1134,7 @@ fn lowerConst(
.fail => |em| return .{ .fail = em },
};
const sym = macho_file.getSymbol(sym_index);
const sym = &self.symbols.items[sym_index];
const name_str_index = try self.strtab.insert(gpa, name);
sym.name = name_str_index;
sym.out_n_sect = output_section_index;
@ -1218,7 +1200,7 @@ pub fn updateExports(
},
};
const sym_index = metadata.symbol_index;
const nlist_idx = macho_file.getSymbol(sym_index).nlist_idx;
const nlist_idx = self.symbols.items[sym_index].nlist_idx;
const nlist = self.symtab.items(.nlist)[nlist_idx];
for (export_indices) |export_idx| {
@ -1322,7 +1304,7 @@ fn updateLazySymbol(
.code => macho_file.zig_text_sect_index.?,
.const_data => macho_file.zig_const_sect_index.?,
};
const sym = macho_file.getSymbol(symbol_index);
const sym = &self.symbols.items[symbol_index];
sym.name = name_str_index;
sym.out_n_sect = output_section_index;
@ -1382,12 +1364,12 @@ pub fn deleteExport(
const nlist = &self.symtab.items(.nlist)[nlist_index.*];
self.symtab.items(.size)[nlist_index.*] = 0;
_ = self.globals_lookup.remove(nlist.n_strx);
const sym_index = macho_file.globals.get(nlist.n_strx).?;
const sym = macho_file.getSymbol(sym_index);
if (sym.file == self.index) {
_ = macho_file.globals.swapRemove(nlist.n_strx);
sym.* = .{};
}
// TODO actually remove the export
// const sym_index = macho_file.globals.get(nlist.n_strx).?;
// const sym = &self.symbols.items[sym_index];
// if (sym.file == self.index) {
// sym.* = .{};
// }
nlist.* = MachO.null_sym;
}
@ -1404,9 +1386,11 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l
nlist.n_strx = off;
nlist.n_type = macho.N_EXT;
lookup_gop.value_ptr.* = nlist_index;
const global_name_off = try macho_file.strings.insert(gpa, sym_name);
const gop = try macho_file.getOrCreateGlobal(global_name_off);
try self.symbols.append(gpa, gop.index);
_ = try macho_file.resolver.getOrPut(gpa, .{
.index = nlist_index,
.file = self.index,
}, macho_file);
try self.globals.append(gpa, nlist_index);
}
return lookup_gop.value_ptr.*;
}
@ -1420,10 +1404,10 @@ pub fn getOrCreateMetadataForDecl(
const gop = try self.decls.getOrPut(gpa, decl_index);
if (!gop.found_existing) {
const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded;
const sym_index = try self.addAtom(macho_file);
const sym_index = try self.createAtomForDecl(gpa, macho_file);
const mod = macho_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
const sym = macho_file.getSymbol(sym_index);
const sym = &self.symbols.items[sym_index];
if (decl.getOwnedVariable(mod)) |variable| {
if (variable.is_threadlocal and any_non_single_threaded) {
sym.flags.tlv = true;
@ -1463,8 +1447,8 @@ pub fn getOrCreateMetadataForLazySymbol(
};
switch (metadata.state.*) {
.unused => {
const symbol_index = try self.addAtom(macho_file);
const sym = macho_file.getSymbol(symbol_index);
const symbol_index = try self.createAtomForDecl(gpa, macho_file);
const sym = &self.symbols.items[symbol_index];
sym.flags.needs_zig_got = true;
metadata.symbol_index.* = symbol_index;
},
@ -1478,6 +1462,130 @@ pub fn getOrCreateMetadataForLazySymbol(
return symbol_index;
}
fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
const atom_index: Atom.Index = @intCast(self.atoms.items.len);
const atom = try self.atoms.addOne(allocator);
atom.* = .{
.file = self.index,
.atom_index = atom_index,
.extra = try self.addAtomExtra(allocator, .{}),
};
return atom_index;
}
pub fn getAtom(self: *ZigObject, atom_index: Atom.Index) ?*Atom {
if (atom_index == 0) return null;
assert(atom_index < self.atoms.items.len);
return &self.atoms.items[atom_index];
}
pub fn getAtoms(self: *ZigObject) []const Atom.Index {
return self.atoms_indexes.items;
}
fn addAtomExtra(self: *ZigObject, allocator: Allocator, extra: Atom.Extra) !u32 {
const fields = @typeInfo(Atom.Extra).Struct.fields;
try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
return self.addAtomExtraAssumeCapacity(extra);
}
fn addAtomExtraAssumeCapacity(self: *ZigObject, extra: Atom.Extra) u32 {
const index = @as(u32, @intCast(self.atoms_extra.items.len));
const fields = @typeInfo(Atom.Extra).Struct.fields;
inline for (fields) |field| {
self.atoms_extra.appendAssumeCapacity(switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
});
}
return index;
}
pub fn getAtomExtra(self: ZigObject, index: u32) Atom.Extra {
const fields = @typeInfo(Atom.Extra).Struct.fields;
var i: usize = index;
var result: Atom.Extra = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => self.atoms_extra.items[i],
else => @compileError("bad field type"),
};
i += 1;
}
return result;
}
pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {
assert(index > 0);
const fields = @typeInfo(Atom.Extra).Struct.fields;
inline for (fields, 0..) |field, i| {
self.atoms_extra.items[index + i] = switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
};
}
}
fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index {
try self.symbols.ensureUnusedCapacity(allocator, 1);
return self.addSymbolAssumeCapacity();
}
fn addSymbolAssumeCapacity(self: *ZigObject) Symbol.Index {
const index: Symbol.Index = @intCast(self.symbols.items.len);
const symbol = self.symbols.addOneAssumeCapacity();
symbol.* = .{ .file = self.index };
return index;
}
pub fn getSymbolRef(self: ZigObject, index: Symbol.Index, macho_file: *MachO) MachO.Ref {
const global_index = self.globals.items[index];
if (macho_file.resolver.get(global_index)) |ref| return ref;
return .{ .index = index, .file = self.index };
}
pub fn addSymbolExtra(self: *ZigObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
return self.addSymbolExtraAssumeCapacity(extra);
}
fn addSymbolExtraAssumeCapacity(self: *ZigObject, extra: Symbol.Extra) u32 {
const index = @as(u32, @intCast(self.symbols_extra.items.len));
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields) |field| {
self.symbols_extra.appendAssumeCapacity(switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
});
}
return index;
}
pub fn getSymbolExtra(self: ZigObject, index: u32) Symbol.Extra {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
var i: usize = index;
var result: Symbol.Extra = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => self.symbols_extra.items[i],
else => @compileError("bad field type"),
};
i += 1;
}
return result;
}
pub fn setSymbolExtra(self: *ZigObject, index: u32, extra: Symbol.Extra) void {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields, 0..) |field, i| {
self.symbols_extra.items[index + i] = switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
};
}
}
pub fn asFile(self: *ZigObject) File {
return .{ .zig_object = self };
}
@ -1503,9 +1611,16 @@ fn formatSymtab(
_ = unused_fmt_string;
_ = options;
try writer.writeAll(" symbols\n");
for (ctx.self.symbols.items) |index| {
const sym = ctx.macho_file.getSymbol(index);
try writer.print(" {}\n", .{sym.fmt(ctx.macho_file)});
const self = ctx.self;
const macho_file = ctx.macho_file;
for (self.symbols.items, 0) |sym, i| {
const ref = self.getSymbolRef(@intCast(i), macho_file);
if (ref.getFile(macho_file) == null) {
// TODO any better way of handling this?
try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
} else {
try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
}
}
}
@ -1524,10 +1639,12 @@ fn formatAtoms(
) !void {
_ = unused_fmt_string;
_ = options;
const self = ctx.self;
const macho_file = ctx.macho_file;
try writer.writeAll(" atoms\n");
for (ctx.self.atoms.items) |atom_index| {
const atom = ctx.macho_file.getAtom(atom_index) orelse continue;
try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)});
for (self.getAtoms()) |atom_index| {
const atom = self.getAtom(atom_index) orelse continue;
try writer.print(" {}\n", .{atom.fmt(macho_file)});
}
}