diff options
| -rw-r--r-- | src/arch/x86_64/Emit.zig | 16 | ||||
| -rw-r--r-- | src/arch/x86_64/Lower.zig | 4 | ||||
| -rw-r--r-- | src/codegen.zig | 9 | ||||
| -rw-r--r-- | src/link/MachO.zig | 22 | ||||
| -rw-r--r-- | src/link/MachO/Atom.zig | 2 | ||||
| -rw-r--r-- | src/link/MachO/ZigObject.zig | 469 |
6 files changed, 321 insertions, 201 deletions
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index ae54904aaf..2bfb4d6704 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -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 = .{ diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index bf074ff98f..ed77f71488 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -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 }); diff --git a/src/codegen.zig b/src/codegen.zig index 33a0b556f7..3dc3d415be 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -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 => { diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 9703890985..47b8eb2ce1 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -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], }; } diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 2ed86ef66f..b1736f7339 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -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; diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index f731f36b7e..dba3e4c1b1 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -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; - - 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 mergeSymbolVisibility(self: *ZigObject, macho_file: *MachO) void { + const tracy = trace(@src()); + defer tracy.end(); + + 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)}); } } |
