diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 7aaca00366..007df845f6 100644 --- a/src/link/MachO/ZigObject.zig +++ b/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,