Commit ef645ab175
Changed files (3)
src
link
src/link/MachO/DebugSymbols.zig
@@ -226,26 +226,20 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
for (self.relocs.items) |*reloc| {
const sym = switch (reloc.type) {
- .direct_load => macho_file.getSymbol(.{ .sym_index = reloc.target, .file = null }),
+ .direct_load => macho_file.getSymbol(.{ .sym_index = reloc.target }),
.got_load => blk: {
- const got_index = macho_file.got_entries_table.get(.{
- .sym_index = reloc.target,
- .file = null,
- }).?;
- const got_entry = macho_file.got_entries.items[got_index];
+ const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?;
+ const got_entry = macho_file.got_table.entries.items[got_index];
break :blk got_entry.getSymbol(macho_file);
},
};
if (sym.n_value == reloc.prev_vaddr) continue;
const sym_name = switch (reloc.type) {
- .direct_load => macho_file.getSymbolName(.{ .sym_index = reloc.target, .file = null }),
+ .direct_load => macho_file.getSymbolName(.{ .sym_index = reloc.target }),
.got_load => blk: {
- const got_index = macho_file.got_entries_table.get(.{
- .sym_index = reloc.target,
- .file = null,
- }).?;
- const got_entry = macho_file.got_entries.items[got_index];
+ const got_index = macho_file.got_table.lookup.get(.{ .sym_index = reloc.target }).?;
+ const got_entry = macho_file.got_table.entries.items[got_index];
break :blk got_entry.getName(macho_file);
},
};
src/link/MachO/Relocation.zig
@@ -46,13 +46,15 @@ pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {
}
pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
- switch (self.type) {
- .got, .got_page, .got_pageoff => return macho_file.getGotAtomIndexForSymbol(self.target),
- .tlv, .tlv_page, .tlv_pageoff => return macho_file.getTlvpAtomIndexForSymbol(self.target),
- else => {},
- }
- if (macho_file.getStubsAtomIndexForSymbol(self.target)) |stubs_atom| return stubs_atom;
- return macho_file.getAtomIndexForSymbol(self.target);
+ return switch (self.type) {
+ .got, .got_page, .got_pageoff => macho_file.got_table.getAtomIndex(macho_file, self.target),
+ .tlv, .tlv_page, .tlv_pageoff => macho_file.tlvp_table.getAtomIndex(macho_file, self.target),
+ .branch => if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index|
+ index
+ else
+ macho_file.getAtomIndexForSymbol(self.target),
+ else => macho_file.getAtomIndexForSymbol(self.target),
+ };
}
pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, code: []u8) void {
src/link/MachO.zig
@@ -5,7 +5,6 @@ const build_options = @import("build_options");
const builtin = @import("builtin");
const assert = std.debug.assert;
const dwarf = std.dwarf;
-const fmt = std.fmt;
const fs = std.fs;
const log = std.log.scoped(.link);
const macho = std.macho;
@@ -155,13 +154,9 @@ stub_helper_preamble_atom_index: ?Atom.Index = null,
strtab: StringTable(.strtab) = .{},
-got_entries: std.ArrayListUnmanaged(Entry) = .{},
-got_entries_free_list: std.ArrayListUnmanaged(u32) = .{},
-got_entries_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
-
-stubs: std.ArrayListUnmanaged(Entry) = .{},
-stubs_free_list: std.ArrayListUnmanaged(u32) = .{},
-stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
+got_table: SectionTable = .{},
+stubs_table: SectionTable = .{},
+tlvp_table: SectionTable = .{},
error_flags: File.ErrorFlags = File.ErrorFlags{},
@@ -270,26 +265,120 @@ const DeclMetadata = struct {
}
};
-const Entry = struct {
- target: SymbolWithLoc,
- // Index into the synthetic symbol table (i.e., file == null).
- sym_index: u32,
+const SectionTable = struct {
+ entries: std.ArrayListUnmanaged(Entry) = .{},
+ free_list: std.ArrayListUnmanaged(u32) = .{},
+ lookup: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
+
+ pub fn deinit(st: *ST, allocator: Allocator) void {
+ st.entries.deinit(allocator);
+ st.free_list.deinit(allocator);
+ st.lookup.deinit(allocator);
+ }
+
+ pub fn allocateEntry(st: *ST, allocator: Allocator, target: SymbolWithLoc) !u32 {
+ try st.entries.ensureUnusedCapacity(allocator, 1);
+ const index = blk: {
+ if (st.free_list.popOrNull()) |index| {
+ log.debug(" (reusing entry index {d})", .{index});
+ break :blk index;
+ } else {
+ log.debug(" (allocating entry at index {d})", .{st.entries.items.len});
+ const index = @intCast(u32, st.entries.items.len);
+ _ = st.entries.addOneAssumeCapacity();
+ break :blk index;
+ }
+ };
+ st.entries.items[index] = .{ .target = target, .sym_index = 0 };
+ try st.lookup.putNoClobber(allocator, target, index);
+ return index;
+ }
- pub fn getSymbol(entry: Entry, macho_file: *MachO) macho.nlist_64 {
- return macho_file.getSymbol(.{ .sym_index = entry.sym_index, .file = null });
+ pub fn freeEntry(st: *ST, allocator: Allocator, target: SymbolWithLoc) void {
+ const index = st.lookup.get(target) orelse return;
+ st.free_list.append(allocator, index) catch {};
+ st.entries.items[index] = .{
+ .target = .{ .sym_index = 0 },
+ .sym_index = 0,
+ };
+ _ = st.lookup.remove(target);
}
- pub fn getSymbolPtr(entry: Entry, macho_file: *MachO) *macho.nlist_64 {
- return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index, .file = null });
+ pub fn getAtomIndex(st: *const ST, macho_file: *MachO, target: SymbolWithLoc) ?Atom.Index {
+ const index = st.lookup.get(target) orelse return null;
+ return st.entries.items[index].getAtomIndex(macho_file);
+ }
+
+ const FormatContext = struct {
+ macho_file: *MachO,
+ st: *const ST,
+ };
+
+ fn fmt(
+ ctx: FormatContext,
+ comptime unused_format_string: []const u8,
+ options: std.fmt.FormatOptions,
+ writer: anytype,
+ ) @TypeOf(writer).Error!void {
+ _ = options;
+ comptime assert(unused_format_string.len == 0);
+ try writer.writeAll("SectionTable:\n");
+ for (ctx.st.entries.items, 0..) |entry, i| {
+ const atom_sym = entry.getSymbol(ctx.macho_file);
+ const target_sym = ctx.macho_file.getSymbol(entry.target);
+ try writer.print(" {d}@{x} => ", .{ i, atom_sym.n_value });
+ if (target_sym.undf()) {
+ try writer.print("import('{s}')", .{
+ ctx.macho_file.getSymbolName(entry.target),
+ });
+ } else {
+ try writer.print("local(%{d}) in object({?d})", .{
+ entry.target.sym_index,
+ entry.target.file,
+ });
+ }
+ try writer.writeByte('\n');
+ }
}
- pub fn getAtomIndex(entry: Entry, macho_file: *MachO) ?Atom.Index {
- return macho_file.getAtomIndexForSymbol(.{ .sym_index = entry.sym_index, .file = null });
+ fn format(st: *const ST, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
+ _ = st;
+ _ = unused_format_string;
+ _ = options;
+ _ = writer;
+ @compileError("do not format SectionTable directly; use st.fmtDebug()");
}
- pub fn getName(entry: Entry, macho_file: *MachO) []const u8 {
- return macho_file.getSymbolName(.{ .sym_index = entry.sym_index, .file = null });
+ pub fn fmtDebug(st: *const ST, macho_file: *MachO) std.fmt.Formatter(fmt) {
+ return .{ .data = .{
+ .macho_file = macho_file,
+ .st = st,
+ } };
}
+
+ const ST = @This();
+
+ const Entry = struct {
+ target: SymbolWithLoc,
+ // Index into the synthetic symbol table (i.e., file == null).
+ sym_index: u32,
+
+ pub fn getSymbol(entry: Entry, macho_file: *MachO) macho.nlist_64 {
+ return macho_file.getSymbol(.{ .sym_index = entry.sym_index });
+ }
+
+ pub fn getSymbolPtr(entry: Entry, macho_file: *MachO) *macho.nlist_64 {
+ return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index });
+ }
+
+ pub fn getAtomIndex(entry: Entry, macho_file: *MachO) ?Atom.Index {
+ return macho_file.getAtomIndexForSymbol(.{ .sym_index = entry.sym_index });
+ }
+
+ pub fn getName(entry: Entry, macho_file: *MachO) []const u8 {
+ return macho_file.getSymbolName(.{ .sym_index = entry.sym_index });
+ }
+ };
};
const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));
@@ -399,7 +488,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
// Create dSYM bundle.
log.debug("creating {s}.dSYM bundle", .{sub_path});
- const d_sym_path = try fmt.allocPrint(
+ const d_sym_path = try std.fmt.allocPrint(
allocator,
"{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",
.{sub_path},
@@ -613,9 +702,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
if (self.dyld_stub_binder_index == null) {
self.dyld_stub_binder_index = try self.addUndefined("dyld_stub_binder", .add_got);
}
- if (!self.base.options.single_threaded) {
- _ = try self.addUndefined("_tlv_bootstrap", .none);
- }
+ // if (!self.base.options.single_threaded) {
+ // _ = try self.addUndefined("_tlv_bootstrap", .none);
+ // }
try self.createMhExecuteHeaderSymbol();
@@ -1757,12 +1846,9 @@ pub fn deinit(self: *MachO) void {
d_sym.deinit();
}
- self.got_entries.deinit(gpa);
- self.got_entries_free_list.deinit(gpa);
- self.got_entries_table.deinit(gpa);
- self.stubs.deinit(gpa);
- self.stubs_free_list.deinit(gpa);
+ self.got_table.deinit(gpa);
self.stubs_table.deinit(gpa);
+ self.tlvp_table.deinit(gpa);
self.strtab.deinit(gpa);
self.locals.deinit(gpa);
@@ -1895,20 +1981,10 @@ fn freeAtom(self: *MachO, atom_index: Atom.Index) void {
self.locals_free_list.append(gpa, sym_index) catch {};
// Try freeing GOT atom if this decl had one
- const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
- if (self.got_entries_table.get(got_target)) |got_index| {
- self.got_entries_free_list.append(gpa, @intCast(u32, got_index)) catch {};
- self.got_entries.items[got_index] = .{
- .target = .{ .sym_index = 0, .file = null },
- .sym_index = 0,
- };
- _ = self.got_entries_table.remove(got_target);
-
- if (self.d_sym) |*d_sym| {
- d_sym.swapRemoveRelocs(sym_index);
- }
+ self.got_table.freeEntry(gpa, .{ .sym_index = sym_index });
- log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index });
+ if (self.d_sym) |*d_sym| {
+ d_sym.swapRemoveRelocs(sym_index);
}
self.locals.items[sym_index].n_type = 0;
@@ -1983,70 +2059,25 @@ fn allocateGlobal(self: *MachO) !u32 {
return index;
}
-fn allocateGotEntry(self: *MachO, target: SymbolWithLoc) !u32 {
- const gpa = self.base.allocator;
- try self.got_entries.ensureUnusedCapacity(gpa, 1);
-
- const index = blk: {
- if (self.got_entries_free_list.popOrNull()) |index| {
- log.debug(" (reusing GOT entry index {d})", .{index});
- break :blk index;
- } else {
- log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.items.len});
- const index = @intCast(u32, self.got_entries.items.len);
- _ = self.got_entries.addOneAssumeCapacity();
- break :blk index;
- }
- };
-
- self.got_entries.items[index] = .{ .target = target, .sym_index = 0 };
- try self.got_entries_table.putNoClobber(gpa, target, index);
-
- return index;
-}
-
fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {
- if (self.got_entries_table.contains(target)) return;
-
- const got_index = try self.allocateGotEntry(target);
+ if (self.got_table.lookup.contains(target)) return;
+ const got_index = try self.got_table.allocateEntry(self.base.allocator, target);
const got_atom_index = try self.createGotAtom(target);
const got_atom = self.getAtom(got_atom_index);
- self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
+ self.got_table.entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
try self.writePtrWidthAtom(got_atom_index);
}
-fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 {
- try self.stubs.ensureUnusedCapacity(self.base.allocator, 1);
-
- const index = blk: {
- if (self.stubs_free_list.popOrNull()) |index| {
- log.debug(" (reusing stub entry index {d})", .{index});
- break :blk index;
- } else {
- log.debug(" (allocating stub entry at index {d})", .{self.stubs.items.len});
- const index = @intCast(u32, self.stubs.items.len);
- _ = self.stubs.addOneAssumeCapacity();
- break :blk index;
- }
- };
-
- self.stubs.items[index] = .{ .target = target, .sym_index = 0 };
- try self.stubs_table.putNoClobber(self.base.allocator, target, index);
-
- return index;
-}
-
fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
- if (self.stubs_table.contains(target)) return;
-
- const stub_index = try self.allocateStubEntry(target);
+ if (self.stubs_table.lookup.contains(target)) return;
+ const stub_index = try self.stubs_table.allocateEntry(self.base.allocator, target);
const stub_helper_atom_index = try self.createStubHelperAtom();
const stub_helper_atom = self.getAtom(stub_helper_atom_index);
const laptr_atom_index = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, target);
const laptr_atom = self.getAtom(laptr_atom_index);
const stub_atom_index = try self.createStubAtom(laptr_atom.getSymbolIndex().?);
const stub_atom = self.getAtom(stub_atom_index);
- self.stubs.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;
+ self.stubs_table.entries.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;
self.markRelocsDirtyByTarget(target);
}
@@ -2431,7 +2462,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64
sym.n_value = vaddr;
log.debug(" (updating GOT entry)", .{});
const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
- const got_atom_index = self.getGotAtomIndexForSymbol(got_target).?;
+ const got_atom_index = self.got_table.getAtomIndex(self, got_target).?;
self.markRelocsDirtyByTarget(got_target);
try self.writePtrWidthAtom(got_atom_index);
}
@@ -3481,8 +3512,8 @@ const SymtabCtx = struct {
fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
const gpa = self.base.allocator;
- const nstubs = @intCast(u32, self.stubs_table.count());
- const ngot_entries = @intCast(u32, self.got_entries_table.count());
+ const nstubs = @intCast(u32, self.stubs_table.lookup.count());
+ const ngot_entries = @intCast(u32, self.got_table.lookup.count());
const nindirectsyms = nstubs * 2 + ngot_entries;
const iextdefsym = ctx.nlocalsym;
const iundefsym = iextdefsym + ctx.nextdefsym;
@@ -3504,7 +3535,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
if (self.stubs_section_index) |sect_id| {
const stubs = &self.sections.items(.header)[sect_id];
stubs.reserved1 = 0;
- for (self.stubs.items) |entry| {
+ for (self.stubs_table.entries.items) |entry| {
if (entry.sym_index == 0) continue;
const target_sym = self.getSymbol(entry.target);
assert(target_sym.undf());
@@ -3515,7 +3546,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
if (self.got_section_index) |sect_id| {
const got = &self.sections.items(.header)[sect_id];
got.reserved1 = nstubs;
- for (self.got_entries.items) |entry| {
+ for (self.got_table.entries.items) |entry| {
if (entry.sym_index == 0) continue;
const target_sym = self.getSymbol(entry.target);
if (target_sym.undf()) {
@@ -3529,7 +3560,7 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
if (self.la_symbol_ptr_section_index) |sect_id| {
const la_symbol_ptr = &self.sections.items(.header)[sect_id];
la_symbol_ptr.reserved1 = nstubs + ngot_entries;
- for (self.stubs.items) |entry| {
+ for (self.stubs_table.entries.items) |entry| {
if (entry.sym_index == 0) continue;
const target_sym = self.getSymbol(entry.target);
assert(target_sym.undf());
@@ -3874,20 +3905,6 @@ pub fn getAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.In
return self.atom_by_index_table.get(sym_with_loc.sym_index);
}
-/// Returns GOT atom that references `sym_with_loc` if one exists.
-/// Returns null otherwise.
-pub fn getGotAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index {
- const got_index = self.got_entries_table.get(sym_with_loc) orelse return null;
- return self.got_entries.items[got_index].getAtomIndex(self);
-}
-
-/// Returns stubs atom that references `sym_with_loc` if one exists.
-/// Returns null otherwise.
-pub fn getStubsAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index {
- const stubs_index = self.stubs_table.get(sym_with_loc) orelse return null;
- return self.stubs.items[stubs_index].getAtomIndex(self);
-}
-
/// Returns symbol location corresponding to the set entrypoint.
/// Asserts output mode is executable.
pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {
@@ -4234,37 +4251,10 @@ pub fn logSymtab(self: *MachO) void {
}
log.debug("GOT entries:", .{});
- for (self.got_entries.items, 0..) |entry, i| {
- const atom_sym = entry.getSymbol(self);
- const target_sym = self.getSymbol(entry.target);
- if (target_sym.undf()) {
- log.debug(" {d}@{x} => import('{s}')", .{
- i,
- atom_sym.n_value,
- self.getSymbolName(entry.target),
- });
- } else {
- log.debug(" {d}@{x} => local(%{d}) in object({?d}) {s}", .{
- i,
- atom_sym.n_value,
- entry.target.sym_index,
- entry.target.file,
- logSymAttributes(target_sym, &buf),
- });
- }
- }
+ log.debug("{}", .{self.got_table.fmtDebug(self)});
log.debug("stubs entries:", .{});
- for (self.stubs.items, 0..) |entry, i| {
- const target_sym = self.getSymbol(entry.target);
- const atom_sym = entry.getSymbol(self);
- assert(target_sym.undf());
- log.debug(" {d}@{x} => import('{s}')", .{
- i,
- atom_sym.n_value,
- self.getSymbolName(entry.target),
- });
- }
+ log.debug("{}", .{self.stubs_table.fmtDebug(self)});
}
pub fn logAtoms(self: *MachO) void {