diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 222129df0a..98223a9ad2 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -55,7 +55,7 @@ pub fn getData(self: Atom, macho_file: *MachO) []const u8 { pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation { return switch (self.getFile(macho_file)) { - .zig_object => @panic("TODO Atom.getRelocs"), + .zig_object => |x| x.getAtomRelocs(self), .object => |x| x.getAtomRelocs(self), else => unreachable, }; @@ -890,8 +890,8 @@ pub const Flags = packed struct { }; pub const Loc = struct { - pos: usize = 0, - len: usize = 0, + pos: u32 = 0, + len: u32 = 0, }; pub const Alignment = @import("../../InternPool.zig").Alignment; diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 662bab9b1f..3fe4142ebc 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -608,7 +608,7 @@ fn initRelocs(self: *Object, macho_file: *MachO) !void { for (slice.items(.header), slice.items(.relocs), slice.items(.subsections)) |sect, relocs, subsections| { if (sect.isZerofill()) continue; - var next_reloc: usize = 0; + var next_reloc: u32 = 0; for (subsections.items) |subsection| { const atom = macho_file.getAtom(subsection.atom).?; if (!atom.flags.alive) continue; @@ -1767,7 +1767,7 @@ const Subsection = struct { off: u64, }; -const Nlist = struct { +pub const Nlist = struct { nlist: macho.nlist_64, size: u64, atom: Atom.Index, diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 421e9bc02c..a86aea80b5 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -19,7 +19,7 @@ out_n_sect: u16 = 0, /// Index of the source nlist this symbol references. /// Use `getNlist` to pull the nlist from the relevant file. -nlist_idx: u32 = 0, +nlist_idx: Index = 0, /// Misc flags for the symbol packaged as packed struct for compression. flags: Flags = .{}, @@ -352,6 +352,10 @@ pub const Flags = packed struct { needs_got: bool = false, has_got: bool = false, + /// Whether the symbol contains __got_zig indirection. + needs_zig_got: bool = false, + has_zig_got: bool = false, + /// Whether the symbols contains __stubs indirection. stubs: bool = false, @@ -386,5 +390,6 @@ const std = @import("std"); const Atom = @import("Atom.zig"); const File = @import("file.zig").File; const MachO = @import("../MachO.zig"); +const Nlist = Object.Nlist; const Object = @import("Object.zig"); const Symbol = @This(); diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 5030527617..b18b7b4c9d 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -7,6 +7,12 @@ symtab: std.MultiArrayList(Nlist) = .{}, symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, +/// Table of tracked Decls. +decls: DeclTable = .{}, + +/// A table of relocations. +relocs: RelocationTable = .{}, + output_symtab_ctx: MachO.SymtabCtx = .{}, pub fn init(self: *ZigObject, macho_file: *MachO) !void { @@ -20,6 +26,19 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { self.symtab.deinit(allocator); self.symbols.deinit(allocator); self.atoms.deinit(allocator); + + { + var it = self.decls.iterator(); + while (it.next()) |entry| { + entry.value_ptr.exports.deinit(allocator); + } + self.decls.deinit(allocator); + } + + for (self.relocs.items) |*list| { + list.deinit(allocator); + } + self.relocs.deinit(allocator); } fn addNlist(self: *ZigObject, allocator: Allocator) !Symbol.Index { @@ -33,6 +52,38 @@ 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; + + const symbol = macho_file.getSymbol(symbol_index); + symbol.file = self.index; + symbol.atom = atom_index; + + self.symtab.items(.atom)[nlist_index] = atom_index; + symbol.nlist_idx = nlist_index; + + const relocs_index = @as(u32, @intCast(self.relocs.items.len)); + const relocs = try self.relocs.addOne(gpa); + relocs.* = .{}; + atom.relocs = .{ .pos = relocs_index, .len = 0 }; + + return symbol_index; +} + +pub fn getAtomRelocs(self: *ZigObject, atom: Atom) []const Relocation { + const relocs = self.relocs.items[atom.relocs.pos]; + return relocs.items[0..atom.relocs.len]; +} + pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) void { _ = self; _ = macho_file; @@ -216,54 +267,35 @@ pub fn updateDecl( return; } - // const is_threadlocal = if (decl.val.getVariable(mod)) |variable| - // variable.is_threadlocal and comp.config.any_non_single_threaded - // else - // false; - // if (is_threadlocal) return self.updateThreadlocalVariable(mod, decl_index); + const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index); + // TODO: free relocs if any - // const atom_index = try self.getOrCreateAtomForDecl(decl_index); - // const sym_index = self.getAtom(atom_index).getSymbolIndex().?; - // Atom.freeRelocations(self, atom_index); + const gpa = macho_file.base.comp.gpa; + var code_buffer = std.ArrayList(u8).init(gpa); + defer code_buffer.deinit(); - // const comp = macho_file.base.comp; - // const gpa = comp.gpa; + var decl_state: ?Dwarf.DeclState = null; // TODO: Dwarf + defer if (decl_state) |*ds| ds.deinit(); - // var code_buffer = std.ArrayList(u8).init(gpa); - // defer code_buffer.deinit(); + const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; + const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none; + const res = + try codegen.generateSymbol(&macho_file.base, decl.srcLoc(mod), .{ + .ty = decl.ty, + .val = decl_val, + }, &code_buffer, dio, .{ + .parent_atom_index = sym_index, + }); - // var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym| - // try d_sym.dwarf.initDeclState(mod, decl_index) - // else - // null; - // defer if (decl_state) |*ds| ds.deinit(); - - // const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; - // const res = if (decl_state) |*ds| - // try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ - // .ty = decl.ty, - // .val = decl_val, - // }, &code_buffer, .{ - // .dwarf = ds, - // }, .{ - // .parent_atom_index = sym_index, - // }) - // else - // try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ - // .ty = decl.ty, - // .val = decl_val, - // }, &code_buffer, .none, .{ - // .parent_atom_index = sym_index, - // }); - - // const code = switch (res) { - // .ok => code_buffer.items, - // .fail => |em| { - // decl.analysis = .codegen_failure; - // try mod.failed_decls.put(mod.gpa, decl_index, em); - // return; - // }, - // }; + const code = switch (res) { + .ok => code_buffer.items, + .fail => |em| { + decl.analysis = .codegen_failure; + try mod.failed_decls.put(mod.gpa, decl_index, em); + return; + }, + }; + _ = code; // const addr = try self.updateDeclCode(decl_index, code); // if (decl_state) |*ds| { @@ -342,6 +374,32 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l @panic("TODO getGlobalSymbol"); } +pub fn getOrCreateMetadataForDecl( + self: *ZigObject, + macho_file: *MachO, + decl_index: InternPool.DeclIndex, +) !Symbol.Index { + const gpa = macho_file.base.comp.gpa; + 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 mod = macho_file.base.comp.module.?; + const decl = mod.declPtr(decl_index); + const sym = macho_file.getSymbol(self.symbols.items[sym_index]); + if (decl.getOwnedVariable(mod)) |variable| { + if (variable.is_threadlocal and any_non_single_threaded) { + sym.flags.tlv = true; + } + } + if (!sym.flags.tlv) { + sym.flags.needs_zig_got = true; + } + gop.value_ptr.* = .{ .symbol_index = sym_index }; + } + return gop.value_ptr.symbol_index; +} + pub fn asFile(self: *ZigObject) File { return .{ .zig_object = self }; } @@ -395,11 +453,23 @@ fn formatAtoms( } } -const Nlist = struct { - nlist: macho.nlist_64, - size: u64, - atom: Atom.Index, +const DeclMetadata = struct { + symbol_index: Symbol.Index, + /// A list of all exports aliases of this Decl. + exports: std.ArrayListUnmanaged(Symbol.Index) = .{}, + + fn @"export"(m: DeclMetadata, zig_object: *ZigObject, macho_file: *MachO, name: []const u8) ?*u32 { + for (m.exports.items) |*exp| { + const nlist = zig_object.symtab.items(.nlist)[exp.*]; + const exp_name = macho_file.strings.getAssumeExists(nlist.n_strx); + if (mem.eql(u8, name, exp_name)) return exp; + } + return null; + } }; +const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata); + +const RelocationTable = std.ArrayListUnmanaged(std.ArrayListUnmanaged(Relocation)); const assert = std.debug.assert; const builtin = @import("builtin"); @@ -420,8 +490,10 @@ const File = @import("file.zig").File; const InternPool = @import("../../InternPool.zig"); const Liveness = @import("../../Liveness.zig"); const MachO = @import("../MachO.zig"); +const Nlist = Object.Nlist; const Module = @import("../../Module.zig"); const Object = @import("Object.zig"); +const Relocation = @import("Relocation.zig"); const Symbol = @import("Symbol.zig"); const StringTable = @import("../StringTable.zig"); const Type = @import("../../type.zig").Type;