Commit c7de5e5111

Jakub Konka <kubkon@jakubkonka.com>
2024-01-17 18:59:24
macho: re-implement updateDeclCode
1 parent 0b2133d
Changed files (1)
src
link
src/link/MachO/ZigObject.zig
@@ -296,8 +296,16 @@ pub fn updateDecl(
         },
     };
     const sect_index = try self.getDeclOutputSection(macho_file, decl, code);
-    _ = sect_index;
-    // const addr = try self.updateDeclCode(decl_index, code);
+    const is_threadlocal = switch (macho_file.sections.items(.header[sect_index].type())) {
+        macho.S_THREAD_LOCAL_ZEROFILL, macho.S_THREAD_LOCAL_REGULAR => true,
+        else => false,
+    };
+    if (is_threadlocal) {
+        // TODO: emit TLV
+        @panic("TODO updateDecl for TLS");
+    } else {
+        try self.updateDeclCode(macho_file, decl_index, sym_index, sect_index, code);
+    }
 
     // if (decl_state) |*ds| {
     //     try self.d_sym.?.dwarf.commitDeclState(
@@ -314,6 +322,89 @@ pub fn updateDecl(
     // try self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
 }
 
+fn updateDeclCode(
+    self: *ZigObject,
+    macho_file: *MachO,
+    decl_index: Module.Decl.Index,
+    sym_index: Symbol.Index,
+    sect_index: u8,
+    code: []const u8,
+) !void {
+    const gpa = self.base.comp.gpa;
+    const mod = self.base.comp.module.?;
+    const decl = mod.declPtr(decl_index);
+    const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
+
+    log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
+
+    const required_alignment = decl.getAlignment(mod);
+
+    const sect = &macho_file.sections.items(.header)[sect_index];
+    const sym = macho_file.getSymbol(sym_index);
+    const nlist = &self.symtab.items(.nlist)[sym.nlist_idx];
+    const size = &self.symtab.items(.size)[sym.nlist_idx];
+    const atom = sym.getAtom(macho_file).?;
+
+    sym.out_n_sect = sect_index;
+    atom.out_n_sect = sect_index;
+
+    sym.name = try macho_file.strings.insert(gpa, decl_name);
+    atom.flags.alive = true;
+    atom.name = sym.name;
+    nlist.n_strx = sym.name;
+    nlist.n_type = macho.N_SECT;
+    nlist.n_sect = sect_index + 1;
+    size = code.len;
+
+    const old_size = atom.size;
+    const old_vaddr = atom.value;
+    atom.alignment = required_alignment;
+    atom.size = code.len;
+
+    if (old_size > 0) {
+        const capacity = atom.capacity(macho_file);
+        const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
+
+        if (need_realloc) {
+            try atom.grow(macho_file);
+            log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom.value });
+            if (old_vaddr != atom.value) {
+                sym.value = atom.value;
+                nlist.n_value = atom.value;
+
+                if (!macho_file.base.isRelocatable()) {
+                    log.debug("  (updating offset table entry)", .{});
+                    assert(sym.flags.has_zig_got);
+                    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 (atom.next_index == null) {
+            const needed_size = (sym.value + code.len) - sect.addr;
+            sect.size = needed_size;
+        }
+    } else {
+        try atom.allocate(macho_file);
+        // TODO: freeDeclMetadata in case of error
+
+        sym.value = atom.value;
+        sym.flags.needs_zig_got = true;
+        nlist.n_value = atom.value;
+
+        if (!macho_file.base.isRelocatable()) {
+            const gop = try sym.getOrCreateZigGotEntry(sym_index, macho_file);
+            try macho_file.zig_got.writeOne(macho_file, gop.index);
+        }
+    }
+
+    if (!sect.isZerofill()) {
+        const file_offset = sect.offset + sym.value - sect.addr;
+        try macho_file.base.file.?.pwriteAll(code, file_offset);
+    }
+}
+
 fn getDeclOutputSection(
     self: *ZigObject,
     macho_file: *MachO,