Commit 8c578ba02c
Changed files (5)
src
src/link/MachO/Atom.zig
@@ -37,6 +37,11 @@ unwind_records: Loc = .{},
flags: Flags = .{},
+/// Points to the previous and next neighbors, based on the `text_offset`.
+/// This can be used to find, for example, the capacity of this `TextBlock`.
+prev_index: Index = 0,
+next_index: Index = 0,
+
pub fn getName(self: Atom, macho_file: *MachO) [:0]const u8 {
return macho_file.strings.getAssumeExists(self.name);
}
@@ -171,6 +176,154 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 {
return osec;
}
+/// Returns how much room there is to grow in virtual address space.
+/// File offset relocation happens transparently, so it is not included in
+/// this calculation.
+pub fn capacity(self: Atom, macho_file: *MachO) u64 {
+ const next_value = if (macho_file.getAtom(self.next_index)) |next| next.value else std.math.maxInt(u32);
+ return next_value - self.value;
+}
+
+pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {
+ // No need to keep a free list node for the last block.
+ const next = macho_file.getAtom(self.next_index) orelse return false;
+ const cap = next.value - self.value;
+ const ideal_cap = MachO.padToIdeal(self.size);
+ if (cap <= ideal_cap) return false;
+ const surplus = cap - ideal_cap;
+ return surplus >= MachO.min_text_capacity;
+}
+
+pub fn allocate(self: *Atom, macho_file: *MachO) !void {
+ const sect = &macho_file.sections.items(.header)[self.out_n_sect];
+ const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect];
+ const last_atom_index = &macho_file.sections.items(.last_atom_index)[self.out_n_sect];
+ const new_atom_ideal_capacity = MachO.padToIdeal(self.size);
+
+ // We use these to indicate our intention to update metadata, placing the new atom,
+ // and possibly removing a free list node.
+ // It would be simpler to do it inside the for loop below, but that would cause a
+ // problem if an error was returned later in the function. So this action
+ // is actually carried out at the end of the function, when errors are no longer possible.
+ var atom_placement: ?Atom.Index = null;
+ var free_list_removal: ?usize = null;
+
+ // First we look for an appropriately sized free list node.
+ // The list is unordered. We'll just take the first thing that works.
+ self.value = blk: {
+ var i: usize = free_list.items.len;
+ while (i < free_list.items.len) {
+ const big_atom_index = free_list.items[i];
+ const big_atom = macho_file.getAtom(big_atom_index).?;
+ // We now have a pointer to a live atom that has too much capacity.
+ // Is it enough that we could fit this new atom?
+ const cap = big_atom.capacity(macho_file);
+ const ideal_capacity = MachO.padToIdeal(cap);
+ const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity;
+ const capacity_end_vaddr = big_atom.value + cap;
+ const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
+ const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned);
+ if (new_start_vaddr < ideal_capacity_end_vaddr) {
+ // Additional bookkeeping here to notice if this free list node
+ // should be deleted because the block that it points to has grown to take up
+ // more of the extra capacity.
+ if (!big_atom.freeListEligible(macho_file)) {
+ _ = free_list.swapRemove(i);
+ } else {
+ i += 1;
+ }
+ continue;
+ }
+ // At this point we know that we will place the new block here. But the
+ // remaining question is whether there is still yet enough capacity left
+ // over for there to still be a free list node.
+ const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr;
+ const keep_free_list_node = remaining_capacity >= MachO.min_text_capacity;
+
+ // Set up the metadata to be updated, after errors are no longer possible.
+ atom_placement = big_atom_index;
+ if (!keep_free_list_node) {
+ free_list_removal = i;
+ }
+ break :blk new_start_vaddr;
+ } else if (macho_file.getAtom(last_atom_index.*)) |last| {
+ const ideal_capacity = MachO.padToIdeal(last.size);
+ const ideal_capacity_end_vaddr = last.value + ideal_capacity;
+ const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);
+ // Set up the metadata to be updated, after errors are no longer possible.
+ atom_placement = last.atom_index;
+ break :blk new_start_vaddr;
+ } else {
+ break :blk sect.addr;
+ }
+ };
+
+ log.debug("allocated atom({d}) : '{s}' at 0x{x} to 0x{x}", .{
+ self.atom_index,
+ self.getName(macho_file),
+ self.value,
+ self.value + self.size,
+ });
+
+ const expand_section = if (atom_placement) |placement_index|
+ macho_file.getAtom(placement_index).?.next_index == 0
+ else
+ true;
+ if (expand_section) {
+ const needed_size = (self.value + self.size) - sect.addr;
+ try macho_file.growSection(self.out_n_sect, needed_size);
+ last_atom_index.* = self.atom_index;
+
+ // const zig_object = macho_file_file.getZigObject().?;
+ // if (zig_object.dwarf) |_| {
+ // // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
+ // // range of the compilation unit. When we expand the text section, this range changes,
+ // // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
+ // zig_object.debug_info_header_dirty = true;
+ // // This becomes dirty for the same reason. We could potentially make this more
+ // // fine-grained with the addition of support for more compilation units. It is planned to
+ // // model each package as a different compilation unit.
+ // zig_object.debug_aranges_section_dirty = true;
+ // }
+ }
+ sect.@"align" = @max(sect.@"align", self.alignment.toLog2Units());
+
+ // This function can also reallocate an atom.
+ // In this case we need to "unplug" it from its previous location before
+ // plugging it in to its new location.
+ if (macho_file.getAtom(self.prev_index)) |prev| {
+ prev.next_index = self.next_index;
+ }
+ if (macho_file.getAtom(self.next_index)) |next| {
+ next.prev_index = self.prev_index;
+ }
+
+ if (atom_placement) |big_atom_index| {
+ const big_atom = macho_file.getAtom(big_atom_index).?;
+ self.prev_index = big_atom_index;
+ self.next_index = big_atom.next_index;
+ big_atom.next_index = self.atom_index;
+ } else {
+ self.prev_index = 0;
+ self.next_index = 0;
+ }
+ if (free_list_removal) |i| {
+ _ = free_list.swapRemove(i);
+ }
+
+ self.flags.alive = true;
+}
+
+pub fn shrink(self: *Atom, macho_file: *MachO) void {
+ _ = self;
+ _ = macho_file;
+}
+
+pub fn grow(self: *Atom, macho_file: *MachO) !void {
+ if (!self.alignment.check(self.value) or self.size > self.capacity(macho_file))
+ try self.allocate(macho_file);
+}
+
pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
src/link/MachO/Symbol.zig
@@ -149,6 +149,25 @@ pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 {
return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file);
}
+const GetOrCreateZigGotEntryResult = struct {
+ found_existing: bool,
+ index: ZigGotSection.Index,
+};
+
+pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult {
+ assert(!macho_file.base.isRelocatable());
+ assert(symbol.flags.needs_zig_got);
+ if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).?.zig_got };
+ const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file);
+ return .{ .found_existing = false, .index = index };
+}
+
+pub fn zigGotAddress(symbol: Symbol, macho_file: *MachO) u64 {
+ if (!symbol.flags.has_zig_got) return 0;
+ const extras = symbol.getExtra(macho_file).?;
+ return macho_file.zig_got.entryAddress(extras.zig_got, macho_file);
+}
+
pub fn getOutputSymtabIndex(symbol: Symbol, macho_file: *MachO) ?u32 {
if (!symbol.flags.output_symtab) return null;
assert(!symbol.isSymbolStab(macho_file));
@@ -170,6 +189,7 @@ pub fn getOutputSymtabIndex(symbol: Symbol, macho_file: *MachO) ?u32 {
const AddExtraOpts = struct {
got: ?u32 = null,
+ zig_got: ?u32 = null,
stubs: ?u32 = null,
objc_stubs: ?u32 = null,
objc_selrefs: ?u32 = null,
@@ -374,6 +394,7 @@ pub const Visibility = enum {
pub const Extra = struct {
got: u32 = 0,
+ zig_got: u32 = 0,
stubs: u32 = 0,
objc_stubs: u32 = 0,
objc_selrefs: u32 = 0,
@@ -393,3 +414,4 @@ const MachO = @import("../MachO.zig");
const Nlist = Object.Nlist;
const Object = @import("Object.zig");
const Symbol = @This();
+const ZigGotSection = @import("synthetic.zig").ZigGotSection;
src/link/MachO/synthetic.zig
@@ -1,3 +1,121 @@
+pub const ZigGotSection = struct {
+ entries: std.ArrayListUnmanaged(Symbol.Index) = .{},
+ dirty: bool = false,
+
+ pub const Index = u32;
+
+ pub fn deinit(zig_got: *ZigGotSection, allocator: Allocator) void {
+ zig_got.entries.deinit(allocator);
+ }
+
+ fn allocateEntry(zig_got: *ZigGotSection, allocator: Allocator) !Index {
+ try zig_got.entries.ensureUnusedCapacity(allocator, 1);
+ // TODO add free list
+ const index = @as(Index, @intCast(zig_got.entries.items.len));
+ _ = zig_got.entries.addOneAssumeCapacity();
+ zig_got.dirty = true;
+ return index;
+ }
+
+ pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, macho_file: *MachO) !Index {
+ const comp = macho_file.base.comp;
+ const gpa = comp.gpa;
+ const index = try zig_got.allocateEntry(gpa);
+ const entry = &zig_got.entries.items[index];
+ entry.* = sym_index;
+ const symbol = macho_file.getSymbol(sym_index);
+ symbol.flags.has_zig_got = true;
+ try symbol.addExtra(.{ .zig_got = index }, macho_file);
+ return index;
+ }
+
+ pub fn entryOffset(zig_got: ZigGotSection, index: Index, macho_file: *MachO) u64 {
+ _ = zig_got;
+ const sect = macho_file.sections.items(.header)[macho_file.zig_got_section_index.?];
+ return sect.offset + @sizeOf(u64) * index;
+ }
+
+ pub fn entryAddress(zig_got: ZigGotSection, index: Index, macho_file: *MachO) u64 {
+ _ = zig_got;
+ const sect = macho_file.sections.items(.header)[macho_file.zig_got_section_index.?];
+ return sect.addr + @sizeOf(u64) * index;
+ }
+
+ pub fn size(zig_got: ZigGotSection, macho_file: *MachO) usize {
+ _ = macho_file;
+ return @sizeOf(u64) * zig_got.entries.items.len;
+ }
+
+ pub fn writeOne(zig_got: *ZigGotSection, macho_file: *MachO, index: Index) !void {
+ if (zig_got.dirty) {
+ const needed_size = zig_got.size(macho_file);
+ try macho_file.growSection(macho_file.zig_got_section_index.?, needed_size);
+ zig_got.dirty = false;
+ }
+ const off = zig_got.entryOffset(index, macho_file);
+ const entry = zig_got.entries.items[index];
+ const value = macho_file.getSymbol(entry).getAddress(.{ .stubs = false }, macho_file);
+
+ var buf: [8]u8 = undefined;
+ std.mem.writeInt(u64, &buf, value, .little);
+ try macho_file.base.file.?.pwriteAll(&buf, off);
+ }
+
+ pub fn writeAll(zig_got: ZigGotSection, macho_file: *MachO, writer: anytype) !void {
+ for (zig_got.entries.items) |entry| {
+ const symbol = macho_file.getSymbol(entry);
+ const value = symbol.address(.{ .stubs = false }, macho_file);
+ try writer.writeInt(u64, value, .little);
+ }
+ }
+
+ pub fn addDyldRelocs(zig_got: ZigGotSection, macho_file: *MachO) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+ const gpa = macho_file.base.comp.gpa;
+ const seg_id = macho_file.sections.items(.segment_id)[macho_file.zig_got_sect_index.?];
+ const seg = macho_file.segments.items[seg_id];
+
+ for (0..zig_got.symbols.items.len) |idx| {
+ const addr = zig_got.entryAddress(@intCast(idx), macho_file);
+ try macho_file.rebase.entries.append(gpa, .{
+ .offset = addr - seg.vmaddr,
+ .segment_id = seg_id,
+ });
+ }
+ }
+
+ const FormatCtx = struct {
+ zig_got: ZigGotSection,
+ macho_file: *MachO,
+ };
+
+ pub fn fmt(zig_got: ZigGotSection, macho_file: *MachO) std.fmt.Formatter(format2) {
+ return .{ .data = .{ .zig_got = zig_got, .macho_file = macho_file } };
+ }
+
+ pub fn format2(
+ ctx: FormatCtx,
+ comptime unused_fmt_string: []const u8,
+ options: std.fmt.FormatOptions,
+ writer: anytype,
+ ) !void {
+ _ = options;
+ _ = unused_fmt_string;
+ try writer.writeAll("__zig_got\n");
+ for (ctx.zig_got.entries.items, 0..) |entry, index| {
+ const symbol = ctx.macho_file.getSymbol(entry);
+ try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
+ index,
+ ctx.zig_got.entryAddress(@intCast(index), ctx.macho_file),
+ entry,
+ symbol.getAddress(.{}, ctx.macho_file),
+ symbol.getName(ctx.macho_file),
+ });
+ }
+ }
+};
+
pub const GotSection = struct {
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
src/link/MachO/ZigObject.zig
@@ -7,9 +7,36 @@ symtab: std.MultiArrayList(Nlist) = .{},
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
+/// Table of tracked LazySymbols.
+lazy_syms: LazySymbolTable = .{},
+
/// Table of tracked Decls.
decls: DeclTable = .{},
+/// Table of unnamed constants associated with a parent `Decl`.
+/// We store them here so that we can free the constants whenever the `Decl`
+/// needs updating or is freed.
+///
+/// For example,
+///
+/// ```zig
+/// const Foo = struct{
+/// a: u8,
+/// };
+///
+/// pub fn main() void {
+/// var foo = Foo{ .a = 1 };
+/// _ = foo;
+/// }
+/// ```
+///
+/// value assigned to label `foo` is an unnamed constant belonging/associated
+/// with `Decl` `main`, and lives as long as that `Decl`.
+unnamed_consts: UnnamedConstTable = .{},
+
+/// Table of tracked AnonDecls.
+anon_decls: AnonDeclTable = .{},
+
/// A table of relocations.
relocs: RelocationTable = .{},
@@ -35,6 +62,24 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
self.decls.deinit(allocator);
}
+ self.lazy_syms.deinit(allocator);
+
+ {
+ var it = self.unnamed_consts.valueIterator();
+ while (it.next()) |syms| {
+ syms.deinit(allocator);
+ }
+ self.unnamed_consts.deinit(allocator);
+ }
+
+ {
+ var it = self.anon_decls.iterator();
+ while (it.next()) |entry| {
+ entry.value_ptr.exports.deinit(allocator);
+ }
+ self.anon_decls.deinit(allocator);
+ }
+
for (self.relocs.items) |*list| {
list.deinit(allocator);
}
@@ -296,7 +341,7 @@ pub fn updateDecl(
},
};
const sect_index = try self.getDeclOutputSection(macho_file, decl, code);
- const is_threadlocal = switch (macho_file.sections.items(.header[sect_index].type())) {
+ 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,
};
@@ -317,21 +362,21 @@ pub fn updateDecl(
// );
// }
- // // Since we updated the vaddr and the size, each corresponding export symbol also
- // // needs to be updated.
- // try self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
+ // Since we updated the vaddr and the size, each corresponding export symbol also
+ // needs to be updated.
+ try self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
}
fn updateDeclCode(
self: *ZigObject,
macho_file: *MachO,
- decl_index: Module.Decl.Index,
+ decl_index: InternPool.DeclIndex,
sym_index: Symbol.Index,
sect_index: u8,
code: []const u8,
) !void {
- const gpa = self.base.comp.gpa;
- const mod = self.base.comp.module.?;
+ const gpa = macho_file.base.comp.gpa;
+ const mod = macho_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
@@ -342,7 +387,6 @@ fn updateDeclCode(
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;
@@ -354,7 +398,7 @@ fn updateDeclCode(
nlist.n_strx = sym.name;
nlist.n_type = macho.N_SECT;
nlist.n_sect = sect_index + 1;
- size = code.len;
+ self.symtab.items(.size)[sym.nlist_idx] = code.len;
const old_size = atom.size;
const old_vaddr = atom.value;
@@ -363,14 +407,14 @@ fn updateDeclCode(
if (old_size > 0) {
const capacity = atom.capacity(macho_file);
- const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
+ const need_realloc = code.len > capacity or !required_alignment.check(sym.getAddress(.{}, macho_file));
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;
+ sym.value = 0;
+ nlist.n_value = 0;
if (!macho_file.base.isRelocatable()) {
log.debug(" (updating offset table entry)", .{});
@@ -381,17 +425,17 @@ fn updateDeclCode(
}
} 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;
+ } else if (macho_file.getAtom(atom.next_index) == null) {
+ const needed_size = (sym.getAddress(.{}, macho_file) + 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.value = 0;
sym.flags.needs_zig_got = true;
- nlist.n_value = atom.value;
+ nlist.n_value = 0;
if (!macho_file.base.isRelocatable()) {
const gop = try sym.getOrCreateZigGotEntry(sym_index, macho_file);
@@ -400,7 +444,7 @@ fn updateDeclCode(
}
if (!sect.isZerofill()) {
- const file_offset = sect.offset + sym.value - sect.addr;
+ const file_offset = sect.offset + sym.getAddress(.{}, macho_file) - sect.addr;
try macho_file.base.file.?.pwriteAll(code, file_offset);
}
}
@@ -478,12 +522,91 @@ pub fn updateExports(
exported: Module.Exported,
exports: []const *Module.Export,
) link.File.UpdateExportsError!void {
- _ = self;
- _ = macho_file;
- _ = mod;
- _ = exported;
- _ = exports;
- @panic("TODO updateExports");
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const gpa = macho_file.base.comp.gpa;
+ const metadata = switch (exported) {
+ .decl_index => |decl_index| blk: {
+ _ = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
+ break :blk self.decls.getPtr(decl_index).?;
+ },
+ .value => |value| self.anon_decls.getPtr(value) orelse blk: {
+ const first_exp = exports[0];
+ const res = try self.lowerAnonDecl(macho_file, value, .none, first_exp.getSrcLoc(mod));
+ switch (res) {
+ .ok => {},
+ .fail => |em| {
+ // TODO maybe it's enough to return an error here and let Module.processExportsInner
+ // handle the error?
+ try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
+ mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
+ return;
+ },
+ }
+ break :blk self.anon_decls.getPtr(value).?;
+ },
+ };
+ const sym_index = metadata.symbol_index;
+ const nlist_idx = macho_file.getSymbol(sym_index).nlist_idx;
+ const nlist = self.symtab.items(.nlist)[nlist_idx];
+
+ for (exports) |exp| {
+ if (exp.opts.section.unwrap()) |section_name| {
+ if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) {
+ try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
+ mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
+ gpa,
+ exp.getSrcLoc(mod),
+ "Unimplemented: ExportOptions.section",
+ .{},
+ ));
+ continue;
+ }
+ }
+ if (exp.opts.linkage == .LinkOnce) {
+ try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
+ gpa,
+ exp.getSrcLoc(mod),
+ "Unimplemented: GlobalLinkage.LinkOnce",
+ .{},
+ ));
+ continue;
+ }
+
+ const exp_name = try std.fmt.allocPrint(gpa, "_{}", .{exp.opts.name.fmt(&mod.intern_pool)});
+ defer gpa.free(exp_name);
+
+ const name_off = try macho_file.strings.insert(gpa, exp_name);
+ const global_nlist_index = if (metadata.@"export"(self, macho_file, exp_name)) |exp_index|
+ exp_index.*
+ else blk: {
+ const global_nlist_index = try self.getGlobalSymbol(macho_file, exp_name, null);
+ try metadata.exports.append(gpa, global_nlist_index);
+ break :blk global_nlist_index;
+ };
+ const global_nlist = &self.symtab.items(.nlist)[global_nlist_index];
+ global_nlist.n_strx = name_off;
+ global_nlist.n_value = nlist.n_value;
+ global_nlist.n_sect = nlist.n_sect;
+ global_nlist.n_type = macho.N_EXT | macho.N_SECT;
+ self.symtab.items(.size)[global_nlist_index] = self.symtab.items(.size)[nlist_idx];
+ self.symtab.items(.atom)[global_nlist_index] = self.symtab.items(.atom)[nlist_idx];
+
+ switch (exp.opts.linkage) {
+ .Internal => {
+ // Symbol should be hidden, or in MachO lingo, private extern.
+ global_nlist.n_type |= macho.N_PEXT;
+ },
+ .Strong => {},
+ .Weak => {
+ // Weak linkage is specified as part of n_desc field.
+ // Symbol's n_type is like for a symbol with strong linkage.
+ global_nlist.n_desc |= macho.N_WEAK_DEF;
+ },
+ else => unreachable,
+ }
+ }
}
/// Must be called only after a successful call to `updateDecl`.
@@ -612,8 +735,19 @@ const DeclMetadata = struct {
return null;
}
};
-const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata);
+const LazySymbolMetadata = struct {
+ const State = enum { unused, pending_flush, flushed };
+ text_symbol_index: Symbol.Index = undefined,
+ data_const_symbol_index: Symbol.Index = undefined,
+ text_state: State = .unused,
+ rodata_state: State = .unused,
+};
+
+const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata);
+const UnnamedConstTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, std.ArrayListUnmanaged(Symbol.Index));
+const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
+const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.OptionalDeclIndex, LazySymbolMetadata);
const RelocationTable = std.ArrayListUnmanaged(std.ArrayListUnmanaged(Relocation));
const assert = std.debug.assert;
src/link/MachO.zig
@@ -70,6 +70,7 @@ symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
strtab: std.ArrayListUnmanaged(u8) = .{},
indsymtab: Indsymtab = .{},
got: GotSection = .{},
+zig_got: ZigGotSection = .{},
stubs: StubsSection = .{},
stubs_helper: StubsHelperSection = .{},
objc_stubs: ObjcStubsSection = .{},
@@ -337,6 +338,7 @@ pub fn deinit(self: *MachO) void {
self.symtab.deinit(gpa);
self.strtab.deinit(gpa);
self.got.deinit(gpa);
+ self.zig_got.deinit(gpa);
self.stubs.deinit(gpa);
self.objc_stubs.deinit(gpa);
self.tlv_ptr.deinit(gpa);
@@ -3157,6 +3159,13 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
}
}
+pub fn growSection(self: *MachO, sect_index: u8, size: u64) !void {
+ _ = self;
+ _ = sect_index;
+ _ = size;
+ @panic("TODO growSection");
+}
+
pub fn getTarget(self: MachO) std.Target {
return self.base.comp.root_mod.resolved_target.result;
}
@@ -3657,6 +3666,7 @@ fn fmtDumpState(
try writer.print("stubs\n{}\n", .{self.stubs.fmt(self)});
try writer.print("objc_stubs\n{}\n", .{self.objc_stubs.fmt(self)});
try writer.print("got\n{}\n", .{self.got.fmt(self)});
+ try writer.print("zig_got\n{}\n", .{self.zig_got.fmt(self)});
try writer.print("tlv_ptr\n{}\n", .{self.tlv_ptr.fmt(self)});
try writer.writeByte('\n');
try writer.print("sections\n{}\n", .{self.fmtSections()});
@@ -3759,6 +3769,8 @@ const Section = struct {
header: macho.section_64,
segment_id: u8,
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
+ free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
+ last_atom_index: Atom.Index = 0,
};
const HotUpdateState = struct {
@@ -4125,4 +4137,5 @@ const TlvPtrSection = synthetic.TlvPtrSection;
const TypedValue = @import("../TypedValue.zig");
const UnwindInfo = @import("MachO/UnwindInfo.zig");
const WeakBindSection = synthetic.WeakBindSection;
+const ZigGotSection = synthetic.ZigGotSection;
const ZigObject = @import("MachO/ZigObject.zig");