Commit bd9d8bd462

Jakub Konka <kubkon@jakubkonka.com>
2024-01-17 08:33:58
macho: create Atom for Decl in ZigObject
1 parent 9509fad
Changed files (4)
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;
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,
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();
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 atom_index = try self.getOrCreateAtomForDecl(decl_index);
-    // const sym_index = self.getAtom(atom_index).getSymbolIndex().?;
-    // Atom.freeRelocations(self, atom_index);
-
-    // const comp = macho_file.base.comp;
-    // const gpa = comp.gpa;
-
-    // var code_buffer = std.ArrayList(u8).init(gpa);
-    // defer code_buffer.deinit();
-
-    // 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 sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
+    // TODO: free relocs if any
+
+    const gpa = macho_file.base.comp.gpa;
+    var code_buffer = std.ArrayList(u8).init(gpa);
+    defer code_buffer.deinit();
+
+    var decl_state: ?Dwarf.DeclState = null; // TODO: Dwarf
+    defer if (decl_state) |*ds| ds.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,
+    });
+
+    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;