diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2023-02-03 12:49:40 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-02-03 12:49:40 -0700 |
| commit | fab9b7110ed1fa7bb082aad5e095047441db2b24 (patch) | |
| tree | 81fef60aa45e7980dab8f3e23e5b5e92b40ee0a9 /src/link/MachO.zig | |
| parent | d20d69b59e6b65a99f45cb6a45c14e887034dd18 (diff) | |
| parent | 60935decd318498529a016eeb1379d943a7e830d (diff) | |
| download | zig-fab9b7110ed1fa7bb082aad5e095047441db2b24.tar.gz zig-fab9b7110ed1fa7bb082aad5e095047441db2b24.zip | |
Merge remote-tracking branch 'origin/master' into llvm16
Diffstat (limited to 'src/link/MachO.zig')
| -rw-r--r-- | src/link/MachO.zig | 765 |
1 files changed, 385 insertions, 380 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index e6924a6717..24ef275c5b 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -66,7 +66,7 @@ const Section = struct { // TODO is null here necessary, or can we do away with tracking via section // size in incremental context? - last_atom: ?*Atom = null, + last_atom_index: ?Atom.Index = null, /// A list of atoms that have surplus capacity. This list can have false /// positives, as functions grow and shrink over time, only sometimes being added @@ -83,7 +83,7 @@ const Section = struct { /// overcapacity can be negative. A simple way to have negative overcapacity is to /// allocate a fresh atom, which will have ideal capacity, and then grow it /// by 1 byte. It will then have -1 overcapacity. - free_list: std.ArrayListUnmanaged(*Atom) = .{}, + free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, }; base: File, @@ -140,8 +140,8 @@ locals_free_list: std.ArrayListUnmanaged(u32) = .{}, globals_free_list: std.ArrayListUnmanaged(u32) = .{}, dyld_stub_binder_index: ?u32 = null, -dyld_private_atom: ?*Atom = null, -stub_helper_preamble_atom: ?*Atom = null, +dyld_private_atom_index: ?Atom.Index = null, +stub_helper_preamble_atom_index: ?Atom.Index = null, strtab: StringTable(.strtab) = .{}, @@ -164,10 +164,10 @@ segment_table_dirty: bool = false, cold_start: bool = true, /// List of atoms that are either synthetic or map directly to the Zig source program. -managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, +atoms: std.ArrayListUnmanaged(Atom) = .{}, /// Table of atoms indexed by the symbol index. -atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, +atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{}, /// Table of unnamed constants associated with a parent `Decl`. /// We store them here so that we can free the constants whenever the `Decl` @@ -210,11 +210,36 @@ bindings: BindingTable = .{}, /// this will be a table indexed by index into the list of Atoms. lazy_bindings: BindingTable = .{}, -/// Table of Decls that are currently alive. -/// We store them here so that we can properly dispose of any allocated -/// memory within the atom in the incremental linker. -/// TODO consolidate this. -decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, ?u8) = .{}, +/// Table of tracked Decls. +decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, + +const DeclMetadata = struct { + atom: Atom.Index, + section: u8, + /// A list of all exports aliases of this Decl. + /// TODO do we actually need this at all? + exports: std.ArrayListUnmanaged(u32) = .{}, + + fn getExport(m: DeclMetadata, macho_file: *const MachO, name: []const u8) ?u32 { + for (m.exports.items) |exp| { + if (mem.eql(u8, name, macho_file.getSymbolName(.{ + .sym_index = exp, + .file = null, + }))) return exp; + } + return null; + } + + fn getExportPtr(m: *DeclMetadata, macho_file: *MachO, name: []const u8) ?*u32 { + for (m.exports.items) |*exp| { + if (mem.eql(u8, name, macho_file.getSymbolName(.{ + .sym_index = exp.*, + .file = null, + }))) return exp; + } + return null; + } +}; const Entry = struct { target: SymbolWithLoc, @@ -229,8 +254,8 @@ const Entry = struct { return macho_file.getSymbolPtr(.{ .sym_index = entry.sym_index, .file = null }); } - pub fn getAtom(entry: Entry, macho_file: *MachO) ?*Atom { - return macho_file.getAtomForSymbol(.{ .sym_index = entry.sym_index, .file = null }); + pub fn getAtomIndex(entry: Entry, macho_file: *MachO) ?Atom.Index { + return macho_file.getAtomIndexForSymbol(.{ .sym_index = entry.sym_index, .file = null }); } pub fn getName(entry: Entry, macho_file: *MachO) []const u8 { @@ -238,10 +263,10 @@ const Entry = struct { } }; -const BindingTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Atom.Binding)); -const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); -const RebaseTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32)); -const RelocationTable = std.AutoArrayHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Relocation)); +const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding)); +const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); +const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); +const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); const PendingUpdate = union(enum) { resolve_undef: u32, @@ -286,10 +311,6 @@ pub const default_pagezero_vmsize: u64 = 0x100000000; /// potential future extensions. pub const default_headerpad_size: u32 = 0x1000; -pub const Export = struct { - sym_index: ?u32 = null, -}; - pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { assert(options.target.ofmt == .macho); @@ -547,8 +568,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try self.allocateSpecialSymbols(); - for (self.relocs.keys()) |atom| { - try atom.resolveRelocations(self); + for (self.relocs.keys()) |atom_index| { + try Atom.resolveRelocations(self, atom_index); } if (build_options.enable_logging) { @@ -999,18 +1020,19 @@ pub fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs: } } -pub fn writeAtom(self: *MachO, atom: *Atom, code: []const u8) !void { +pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []const u8) !void { + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const section = self.sections.get(sym.n_sect - 1); const file_offset = section.header.offset + sym.n_value - section.header.addr; log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset }); try self.base.file.?.pwriteAll(code, file_offset); - try atom.resolveRelocations(self); + try Atom.resolveRelocations(self, atom_index); } -fn writePtrWidthAtom(self: *MachO, atom: *Atom) !void { +fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void { var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); - try self.writeAtom(atom, &buffer); + try self.writeAtom(atom_index, &buffer); } fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void { @@ -1026,7 +1048,8 @@ fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void { fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void { for (self.relocs.values()) |*relocs| { for (relocs.items) |*reloc| { - const target_atom = reloc.getTargetAtom(self) orelse continue; + const target_atom_index = reloc.getTargetAtomIndex(self) orelse continue; + const target_atom = self.getAtom(target_atom_index); const target_sym = target_atom.getSymbol(self); if (target_sym.n_value < addr) continue; reloc.dirty = true; @@ -1053,31 +1076,38 @@ pub fn allocateSpecialSymbols(self: *MachO) !void { } } -pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom { +pub fn createAtom(self: *MachO) !Atom.Index { const gpa = self.base.allocator; - + const atom_index = @intCast(Atom.Index, self.atoms.items.len); + const atom = try self.atoms.addOne(gpa); const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = @sizeOf(u64); - atom.alignment = @alignOf(u64); - break :blk atom; + try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); + atom.* = .{ + .sym_index = sym_index, + .file = null, + .size = 0, + .alignment = 0, + .prev_index = null, + .next_index = null, }; - errdefer gpa.destroy(atom); + log.debug("creating ATOM(%{d}) at index {d}", .{ sym_index, atom_index }); + return atom_index; +} - try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); +pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index { + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); + atom.size = @sizeOf(u64); + atom.alignment = @alignOf(u64); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; sym.n_sect = self.got_section_index.? + 1; - sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); + sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64)); log.debug("allocated GOT atom at 0x{x}", .{sym.n_value}); - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = switch (self.base.options.target.cpu.arch) { .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), @@ -1092,50 +1122,39 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !*Atom { const target_sym = self.getSymbol(target); if (target_sym.undf()) { - try atom.addBinding(self, .{ + try Atom.addBinding(self, atom_index, .{ .target = self.getGlobal(self.getSymbolName(target)).?, .offset = 0, }); } else { - try atom.addRebase(self, 0); + try Atom.addRebase(self, atom_index, 0); } - return atom; + return atom_index; } pub fn createDyldPrivateAtom(self: *MachO) !void { if (self.dyld_stub_binder_index == null) return; - if (self.dyld_private_atom != null) return; - - const gpa = self.base.allocator; + if (self.dyld_private_atom_index != null) return; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = @sizeOf(u64); - atom.alignment = @alignOf(u64); - break :blk atom; - }; - errdefer gpa.destroy(atom); + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); + atom.size = @sizeOf(u64); + atom.alignment = @alignOf(u64); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; sym.n_sect = self.data_section_index.? + 1; - self.dyld_private_atom = atom; + self.dyld_private_atom_index = atom_index; - try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); - - sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); + sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64)); log.debug("allocated dyld_private atom at 0x{x}", .{sym.n_value}); - try self.writePtrWidthAtom(atom); + try self.writePtrWidthAtom(atom_index); } pub fn createStubHelperPreambleAtom(self: *MachO) !void { if (self.dyld_stub_binder_index == null) return; - if (self.stub_helper_preamble_atom != null) return; + if (self.stub_helper_preamble_atom_index != null) return; const gpa = self.base.allocator; const arch = self.base.options.target.cpu.arch; @@ -1144,26 +1163,23 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { .aarch64 => 6 * @sizeOf(u32), else => unreachable, }; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = size; - atom.alignment = switch (arch) { - .x86_64 => 1, - .aarch64 => @alignOf(u32), - else => unreachable, - }; - break :blk atom; + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); + atom.size = size; + atom.alignment = switch (arch) { + .x86_64 => 1, + .aarch64 => @alignOf(u32), + else => unreachable, }; - errdefer gpa.destroy(atom); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; sym.n_sect = self.stub_helper_section_index.? + 1; - const dyld_private_sym_index = self.dyld_private_atom.?.sym_index; + const dyld_private_sym_index = if (self.dyld_private_atom_index) |dyld_index| + self.getAtom(dyld_index).getSymbolIndex().? + else + unreachable; const code = try gpa.alloc(u8, size); defer gpa.free(code); @@ -1182,7 +1198,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { code[9] = 0xff; code[10] = 0x25; - try atom.addRelocations(self, 2, .{ .{ + try Atom.addRelocations(self, atom_index, 2, .{ .{ .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), .target = .{ .sym_index = dyld_private_sym_index, .file = null }, .offset = 3, @@ -1222,7 +1238,7 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { // br x16 mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32()); - try atom.addRelocations(self, 4, .{ .{ + try Atom.addRelocations(self, atom_index, 4, .{ .{ .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), .target = .{ .sym_index = dyld_private_sym_index, .file = null }, .offset = 0, @@ -1255,17 +1271,14 @@ pub fn createStubHelperPreambleAtom(self: *MachO) !void { else => unreachable, } - self.stub_helper_preamble_atom = atom; - - try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); + self.stub_helper_preamble_atom_index = atom_index; - sym.n_value = try self.allocateAtom(atom, size, atom.alignment); + sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment); log.debug("allocated stub preamble atom at 0x{x}", .{sym.n_value}); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); } -pub fn createStubHelperAtom(self: *MachO) !*Atom { +pub fn createStubHelperAtom(self: *MachO) !Atom.Index { const gpa = self.base.allocator; const arch = self.base.options.target.cpu.arch; const size: u4 = switch (arch) { @@ -1273,20 +1286,14 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { .aarch64 => 3 * @sizeOf(u32), else => unreachable, }; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = size; - atom.alignment = switch (arch) { - .x86_64 => 1, - .aarch64 => @alignOf(u32), - else => unreachable, - }; - break :blk atom; + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); + atom.size = size; + atom.alignment = switch (arch) { + .x86_64 => 1, + .aarch64 => @alignOf(u32), + else => unreachable, }; - errdefer gpa.destroy(atom); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; @@ -1296,6 +1303,11 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { defer gpa.free(code); mem.set(u8, code, 0); + const stub_helper_preamble_atom_sym_index = if (self.stub_helper_preamble_atom_index) |stub_index| + self.getAtom(stub_index).getSymbolIndex().? + else + unreachable; + switch (arch) { .x86_64 => { // pushq @@ -1304,9 +1316,9 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { // jmpq code[5] = 0xe9; - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), - .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null }, + .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null }, .offset = 6, .addend = 0, .pcrel = true, @@ -1327,9 +1339,9 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(0).toU32()); // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26), - .target = .{ .sym_index = self.stub_helper_preamble_atom.?.sym_index, .file = null }, + .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null }, .offset = 4, .addend = 0, .pcrel = true, @@ -1339,34 +1351,24 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { else => unreachable, } - try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); - - sym.n_value = try self.allocateAtom(atom, size, atom.alignment); + sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment); log.debug("allocated stub helper atom at 0x{x}", .{sym.n_value}); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); - return atom; + return atom_index; } -pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !*Atom { - const gpa = self.base.allocator; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = @sizeOf(u64); - atom.alignment = @alignOf(u64); - break :blk atom; - }; - errdefer gpa.destroy(atom); +pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !Atom.Index { + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); + atom.size = @sizeOf(u64); + atom.alignment = @alignOf(u64); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; sym.n_sect = self.la_symbol_ptr_section_index.? + 1; - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = switch (self.base.options.target.cpu.arch) { .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), @@ -1378,23 +1380,20 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWi .pcrel = false, .length = 3, }); - try atom.addRebase(self, 0); - try atom.addLazyBinding(self, .{ + try Atom.addRebase(self, atom_index, 0); + try Atom.addLazyBinding(self, atom_index, .{ .target = self.getGlobal(self.getSymbolName(target)).?, .offset = 0, }); - try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); - - sym.n_value = try self.allocateAtom(atom, atom.size, @alignOf(u64)); + sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64)); log.debug("allocated lazy pointer atom at 0x{x} ({s})", .{ sym.n_value, self.getSymbolName(target) }); - try self.writePtrWidthAtom(atom); + try self.writePtrWidthAtom(atom_index); - return atom; + return atom_index; } -pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { +pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index { const gpa = self.base.allocator; const arch = self.base.options.target.cpu.arch; const size: u4 = switch (arch) { @@ -1402,21 +1401,15 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { .aarch64 => 3 * @sizeOf(u32), else => unreachable, // unhandled architecture type }; - const sym_index = try self.allocateSymbol(); - const atom = blk: { - const atom = try gpa.create(Atom); - atom.* = Atom.empty; - atom.sym_index = sym_index; - atom.size = size; - atom.alignment = switch (arch) { - .x86_64 => 1, - .aarch64 => @alignOf(u32), - else => unreachable, // unhandled architecture type + const atom_index = try self.createAtom(); + const atom = self.getAtomPtr(atom_index); + atom.size = size; + atom.alignment = switch (arch) { + .x86_64 => 1, + .aarch64 => @alignOf(u32), + else => unreachable, // unhandled architecture type - }; - break :blk atom; }; - errdefer gpa.destroy(atom); const sym = atom.getSymbolPtr(self); sym.n_type = macho.N_SECT; @@ -1432,7 +1425,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { code[0] = 0xff; code[1] = 0x25; - try atom.addRelocation(self, .{ + try Atom.addRelocation(self, atom_index, .{ .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), .target = .{ .sym_index = laptr_sym_index, .file = null }, .offset = 2, @@ -1453,7 +1446,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { // br x16 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32()); - try atom.addRelocations(self, 2, .{ + try Atom.addRelocations(self, atom_index, 2, .{ .{ .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), .target = .{ .sym_index = laptr_sym_index, .file = null }, @@ -1475,14 +1468,11 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { else => unreachable, } - try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom); - - sym.n_value = try self.allocateAtom(atom, size, atom.alignment); + sym.n_value = try self.allocateAtom(atom_index, size, atom.alignment); log.debug("allocated stub atom at 0x{x}", .{sym.n_value}); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); - return atom; + return atom_index; } pub fn createMhExecuteHeaderSymbol(self: *MachO) !void { @@ -1616,10 +1606,13 @@ pub fn resolveSymbolsInDylibs(self: *MachO) !void { if (self.stubs_table.contains(global)) break :blk; const stub_index = try self.allocateStubEntry(global); - const stub_helper_atom = try self.createStubHelperAtom(); - const laptr_atom = try self.createLazyPointerAtom(stub_helper_atom.sym_index, global); - const stub_atom = try self.createStubAtom(laptr_atom.sym_index); - self.stubs.items[stub_index].sym_index = stub_atom.sym_index; + 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().?, global); + 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.markRelocsDirtyByTarget(global); } @@ -1716,10 +1709,11 @@ pub fn resolveDyldStubBinder(self: *MachO) !void { // Add dyld_stub_binder as the final GOT entry. const got_index = try self.allocateGotEntry(global); - const got_atom = try self.createGotAtom(global); - self.got_entries.items[got_index].sym_index = got_atom.sym_index; + const got_atom_index = try self.createGotAtom(global); + const got_atom = self.getAtom(got_atom_index); + self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; - try self.writePtrWidthAtom(got_atom); + try self.writePtrWidthAtom(got_atom_index); } pub fn deinit(self: *MachO) void { @@ -1769,12 +1763,12 @@ pub fn deinit(self: *MachO) void { } self.sections.deinit(gpa); - for (self.managed_atoms.items) |atom| { - gpa.destroy(atom); - } - self.managed_atoms.deinit(gpa); + self.atoms.deinit(gpa); if (self.base.options.module) |_| { + for (self.decls.values()) |*m| { + m.exports.deinit(gpa); + } self.decls.deinit(gpa); } else { assert(self.decls.count() == 0); @@ -1808,12 +1802,14 @@ pub fn deinit(self: *MachO) void { self.lazy_bindings.deinit(gpa); } -fn freeAtom(self: *MachO, atom: *Atom) void { - log.debug("freeAtom {*}", .{atom}); +fn freeAtom(self: *MachO, atom_index: Atom.Index) void { + const gpa = self.base.allocator; + log.debug("freeAtom {d}", .{atom_index}); // Remove any relocs and base relocs associated with this Atom - self.freeRelocationsForAtom(atom); + Atom.freeRelocations(self, atom_index); + const atom = self.getAtom(atom_index); const sect_id = atom.getSymbol(self).n_sect - 1; const free_list = &self.sections.items(.free_list)[sect_id]; var already_have_free_list_node = false; @@ -1821,69 +1817,94 @@ fn freeAtom(self: *MachO, atom: *Atom) void { var i: usize = 0; // TODO turn free_list into a hash map while (i < free_list.items.len) { - if (free_list.items[i] == atom) { + if (free_list.items[i] == atom_index) { _ = free_list.swapRemove(i); continue; } - if (free_list.items[i] == atom.prev) { + if (free_list.items[i] == atom.prev_index) { already_have_free_list_node = true; } i += 1; } } - const maybe_last_atom = &self.sections.items(.last_atom)[sect_id]; - if (maybe_last_atom.*) |last_atom| { - if (last_atom == atom) { - if (atom.prev) |prev| { + const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id]; + if (maybe_last_atom_index.*) |last_atom_index| { + if (last_atom_index == atom_index) { + if (atom.prev_index) |prev_index| { // TODO shrink the section size here - maybe_last_atom.* = prev; + maybe_last_atom_index.* = prev_index; } else { - maybe_last_atom.* = null; + maybe_last_atom_index.* = null; } } } - if (atom.prev) |prev| { - prev.next = atom.next; + if (atom.prev_index) |prev_index| { + const prev = self.getAtomPtr(prev_index); + prev.next_index = atom.next_index; - if (!already_have_free_list_node and prev.freeListEligible(self)) { + if (!already_have_free_list_node and prev.*.freeListEligible(self)) { // The free list is heuristics, it doesn't have to be perfect, so we can ignore // the OOM here. - free_list.append(self.base.allocator, prev) catch {}; + free_list.append(gpa, prev_index) catch {}; } } else { - atom.prev = null; + self.getAtomPtr(atom_index).prev_index = null; } - if (atom.next) |next| { - next.prev = atom.prev; + if (atom.next_index) |next_index| { + self.getAtomPtr(next_index).prev_index = atom.prev_index; } else { - atom.next = null; + self.getAtomPtr(atom_index).next_index = null; } - if (self.d_sym) |*d_sym| { - d_sym.dwarf.freeAtom(&atom.dbg_info_atom); + // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. + const sym_index = atom.getSymbolIndex().?; + + 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); + } + + log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); } + + self.locals.items[sym_index].n_type = 0; + _ = self.atom_by_index_table.remove(sym_index); + log.debug(" adding local symbol index {d} to free list", .{sym_index}); + self.getAtomPtr(atom_index).sym_index = 0; } -fn shrinkAtom(self: *MachO, atom: *Atom, new_block_size: u64) void { +fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void { _ = self; - _ = atom; + _ = atom_index; _ = new_block_size; // TODO check the new capacity, and if it crosses the size threshold into a big enough // capacity, insert a free list node for it. } -fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !u64 { +fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 { + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const align_ok = mem.alignBackwardGeneric(u64, sym.n_value, alignment) == sym.n_value; const need_realloc = !align_ok or new_atom_size > atom.capacity(self); if (!need_realloc) return sym.n_value; - return self.allocateAtom(atom, new_atom_size, alignment); + return self.allocateAtom(atom_index, new_atom_size, alignment); } -fn allocateSymbol(self: *MachO) !u32 { +pub fn allocateSymbol(self: *MachO) !u32 { try self.locals.ensureUnusedCapacity(self.base.allocator, 1); const index = blk: { @@ -1975,16 +1996,6 @@ pub fn allocateStubEntry(self: *MachO, target: SymbolWithLoc) !u32 { return index; } -pub fn allocateDeclIndexes(self: *MachO, decl_index: Module.Decl.Index) !void { - if (self.llvm_object) |_| return; - const decl = self.base.options.module.?.declPtr(decl_index); - if (decl.link.macho.sym_index != 0) return; - - decl.link.macho.sym_index = try self.allocateSymbol(); - try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.macho.sym_index, &decl.link.macho); - try self.decls.putNoClobber(self.base.allocator, decl_index, null); -} - pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { if (build_options.skip_non_native and builtin.object_format != .macho) { @panic("Attempted to compile for object format that was disabled by build configuration"); @@ -1997,8 +2008,12 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv const decl_index = func.owner_decl; const decl = module.declPtr(decl_index); + + const atom_index = try self.getOrCreateAtomForDecl(decl_index); self.freeUnnamedConsts(decl_index); - self.freeRelocationsForAtom(&decl.link.macho); + Atom.freeRelocations(self, atom_index); + + const atom = self.getAtom(atom_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -2017,7 +2032,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); const code = switch (res) { - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -2028,13 +2043,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv const addr = try self.updateDeclCode(decl_index, code); if (decl_state) |*ds| { - try self.d_sym.?.dwarf.commitDeclState( - module, - decl_index, - addr, - decl.link.macho.size, - ds, - ); + try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds); } // Since we updated the vaddr and the size, each corresponding export symbol also @@ -2069,21 +2078,13 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu log.debug("allocating symbol indexes for {?s}", .{name}); - const atom = try gpa.create(Atom); - errdefer gpa.destroy(atom); - atom.* = Atom.empty; - - atom.sym_index = try self.allocateSymbol(); - - try self.managed_atoms.append(gpa, atom); - try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); + const atom_index = try self.createAtom(); const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{ - .parent_atom_index = atom.sym_index, + .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, }); const code = switch (res) { - .externally_managed => |x| x, - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -2093,26 +2094,27 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu }; const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); + const atom = self.getAtomPtr(atom_index); atom.size = code.len; atom.alignment = required_alignment; // TODO: work out logic for disambiguating functions from function pointers - // const sect_id = self.getDeclOutputSection(decl); + // const sect_id = self.getDeclOutputSection(decl_index); const sect_id = self.data_const_section_index.?; const symbol = atom.getSymbolPtr(self); symbol.n_strx = name_str_index; symbol.n_type = macho.N_SECT; symbol.n_sect = sect_id + 1; - symbol.n_value = try self.allocateAtom(atom, code.len, required_alignment); - errdefer self.freeAtom(atom); + symbol.n_value = try self.allocateAtom(atom_index, code.len, required_alignment); + errdefer self.freeAtom(atom_index); - try unnamed_consts.append(gpa, atom); + try unnamed_consts.append(gpa, atom_index); log.debug("allocated atom for {?s} at 0x{x}", .{ name, symbol.n_value }); log.debug(" (required alignment 0x{x})", .{required_alignment}); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); - return atom.sym_index; + return atom.getSymbolIndex().?; } pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { @@ -2137,7 +2139,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) } } - self.freeRelocationsForAtom(&decl.link.macho); + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + Atom.freeRelocations(self, atom_index); + const atom = self.getAtom(atom_index); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -2156,19 +2160,18 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) }, &code_buffer, .{ .dwarf = ds, }, .{ - .parent_atom_index = decl.link.macho.sym_index, + .parent_atom_index = atom.getSymbolIndex().?, }) else try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ .ty = decl.ty, .val = decl_val, }, &code_buffer, .none, .{ - .parent_atom_index = decl.link.macho.sym_index, + .parent_atom_index = atom.getSymbolIndex().?, }); const code = switch (res) { - .externally_managed => |x| x, - .appended => code_buffer.items, + .ok => code_buffer.items, .fail => |em| { decl.analysis = .codegen_failure; try module.failed_decls.put(module.gpa, decl_index, em); @@ -2178,13 +2181,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) const addr = try self.updateDeclCode(decl_index, code); if (decl_state) |*ds| { - try self.d_sym.?.dwarf.commitDeclState( - module, - decl_index, - addr, - decl.link.macho.size, - ds, - ); + try self.d_sym.?.dwarf.commitDeclState(module, decl_index, addr, atom.size, ds); } // Since we updated the vaddr and the size, each corresponding export symbol also @@ -2192,7 +2189,20 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); } -fn getDeclOutputSection(self: *MachO, decl: *Module.Decl) u8 { +pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index { + const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + if (!gop.found_existing) { + gop.value_ptr.* = .{ + .atom = try self.createAtom(), + .section = self.getDeclOutputSection(decl_index), + .exports = .{}, + }; + } + return gop.value_ptr.atom; +} + +fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { + const decl = self.base.options.module.?.declPtr(decl_index); const ty = decl.ty; const val = decl.val; const zig_ty = ty.zigTypeTag(); @@ -2339,17 +2349,15 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) const decl = mod.declPtr(decl_index); const required_alignment = decl.getAlignment(self.base.options.target); - assert(decl.link.macho.sym_index != 0); // Caller forgot to call allocateDeclIndexes() const sym_name = try decl.getFullyQualifiedName(mod); defer self.base.allocator.free(sym_name); - const atom = &decl.link.macho; - const decl_ptr = self.decls.getPtr(decl_index).?; - if (decl_ptr.* == null) { - decl_ptr.* = self.getDeclOutputSection(decl); - } - const sect_id = decl_ptr.*.?; + const decl_metadata = self.decls.get(decl_index).?; + const atom_index = decl_metadata.atom; + const atom = self.getAtom(atom_index); + const sym_index = atom.getSymbolIndex().?; + const sect_id = decl_metadata.section; const code_len = code.len; if (atom.size != 0) { @@ -2359,31 +2367,31 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) sym.n_sect = sect_id + 1; sym.n_desc = 0; - const capacity = decl.link.macho.capacity(self); + const capacity = atom.capacity(self); const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, sym.n_value, required_alignment); if (need_realloc) { - const vaddr = try self.growAtom(atom, code_len, required_alignment); + const vaddr = try self.growAtom(atom_index, code_len, required_alignment); log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, sym.n_value, vaddr }); log.debug(" (required alignment 0x{x})", .{required_alignment}); if (vaddr != sym.n_value) { sym.n_value = vaddr; log.debug(" (updating GOT entry)", .{}); - const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; - const got_atom = self.getGotAtomForSymbol(got_target).?; + const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; + const got_atom_index = self.getGotAtomIndexForSymbol(got_target).?; self.markRelocsDirtyByTarget(got_target); - try self.writePtrWidthAtom(got_atom); + try self.writePtrWidthAtom(got_atom_index); } } else if (code_len < atom.size) { - self.shrinkAtom(atom, code_len); - } else if (atom.next == null) { + self.shrinkAtom(atom_index, code_len); + } else if (atom.next_index == null) { const header = &self.sections.items(.header)[sect_id]; const segment = self.getSegment(sect_id); const needed_size = (sym.n_value + code_len) - segment.vmaddr; header.size = needed_size; } - atom.size = code_len; + self.getAtomPtr(atom_index).size = code_len; } else { const name_str_index = try self.strtab.insert(gpa, sym_name); const sym = atom.getSymbolPtr(self); @@ -2392,32 +2400,32 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []const u8) sym.n_sect = sect_id + 1; sym.n_desc = 0; - const vaddr = try self.allocateAtom(atom, code_len, required_alignment); - errdefer self.freeAtom(atom); + const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment); + errdefer self.freeAtom(atom_index); log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, vaddr }); log.debug(" (required alignment 0x{x})", .{required_alignment}); - atom.size = code_len; + self.getAtomPtr(atom_index).size = code_len; sym.n_value = vaddr; - const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; + const got_target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; const got_index = try self.allocateGotEntry(got_target); - const got_atom = try self.createGotAtom(got_target); - self.got_entries.items[got_index].sym_index = got_atom.sym_index; - try self.writePtrWidthAtom(got_atom); + const got_atom_index = try self.createGotAtom(got_target); + const got_atom = self.getAtom(got_atom_index); + self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?; + try self.writePtrWidthAtom(got_atom_index); } self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); - try self.writeAtom(atom, code); + try self.writeAtom(atom_index, code); return atom.getSymbol(self).n_value; } -pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void { - _ = module; +pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { if (self.d_sym) |*d_sym| { - try d_sym.dwarf.updateDeclLineNumber(decl); + try d_sym.dwarf.updateDeclLineNumber(module, decl_index); } } @@ -2434,14 +2442,17 @@ pub fn updateDeclExports( if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports); } + const tracy = trace(@src()); defer tracy.end(); const gpa = self.base.allocator; const decl = module.declPtr(decl_index); - if (decl.link.macho.sym_index == 0) return; - const decl_sym = decl.link.macho.getSymbol(self); + const atom_index = try self.getOrCreateAtomForDecl(decl_index); + const atom = self.getAtom(atom_index); + const decl_sym = atom.getSymbol(self); + const decl_metadata = self.decls.getPtr(decl_index).?; for (exports) |exp| { const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name}); @@ -2479,9 +2490,9 @@ pub fn updateDeclExports( continue; } - const sym_index = exp.link.macho.sym_index orelse blk: { + const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: { const sym_index = try self.allocateSymbol(); - exp.link.macho.sym_index = sym_index; + try decl_metadata.exports.append(gpa, sym_index); break :blk sym_index; }; const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; @@ -2529,16 +2540,18 @@ pub fn updateDeclExports( } } -pub fn deleteExport(self: *MachO, exp: Export) void { +pub fn deleteDeclExport(self: *MachO, decl_index: Module.Decl.Index, name: []const u8) Allocator.Error!void { if (self.llvm_object) |_| return; - const sym_index = exp.sym_index orelse return; + const metadata = self.decls.getPtr(decl_index) orelse return; const gpa = self.base.allocator; + const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{name}); + defer gpa.free(exp_name); + const sym_index = metadata.getExportPtr(self, exp_name) orelse return; - const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; + const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null }; const sym = self.getSymbolPtr(sym_loc); - const sym_name = self.getSymbolName(sym_loc); - log.debug("deleting export '{s}'", .{sym_name}); + log.debug("deleting export '{s}'", .{exp_name}); assert(sym.sect() and sym.ext()); sym.* = .{ .n_strx = 0, @@ -2547,9 +2560,9 @@ pub fn deleteExport(self: *MachO, exp: Export) void { .n_desc = 0, .n_value = 0, }; - self.locals_free_list.append(gpa, sym_index) catch {}; + self.locals_free_list.append(gpa, sym_index.*) catch {}; - if (self.resolver.fetchRemove(sym_name)) |entry| { + if (self.resolver.fetchRemove(exp_name)) |entry| { defer gpa.free(entry.key); self.globals_free_list.append(gpa, entry.value) catch {}; self.globals.items[entry.value] = .{ @@ -2557,17 +2570,8 @@ pub fn deleteExport(self: *MachO, exp: Export) void { .file = null, }; } -} -fn freeRelocationsForAtom(self: *MachO, atom: *Atom) void { - var removed_relocs = self.relocs.fetchOrderedRemove(atom); - if (removed_relocs) |*relocs| relocs.value.deinit(self.base.allocator); - var removed_rebases = self.rebases.fetchOrderedRemove(atom); - if (removed_rebases) |*rebases| rebases.value.deinit(self.base.allocator); - var removed_bindings = self.bindings.fetchOrderedRemove(atom); - if (removed_bindings) |*bindings| bindings.value.deinit(self.base.allocator); - var removed_lazy_bindings = self.lazy_bindings.fetchOrderedRemove(atom); - if (removed_lazy_bindings) |*lazy_bindings| lazy_bindings.value.deinit(self.base.allocator); + sym_index.* = 0; } fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void { @@ -2575,11 +2579,6 @@ fn freeUnnamedConsts(self: *MachO, decl_index: Module.Decl.Index) void { const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; for (unnamed_consts.items) |atom| { self.freeAtom(atom); - self.locals_free_list.append(gpa, atom.sym_index) catch {}; - self.locals.items[atom.sym_index].n_type = 0; - _ = self.atom_by_index_table.remove(atom.sym_index); - log.debug(" adding local symbol index {d} to free list", .{atom.sym_index}); - atom.sym_index = 0; } unnamed_consts.clearAndFree(gpa); } @@ -2593,67 +2592,37 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void { log.debug("freeDecl {*}", .{decl}); - const kv = self.decls.fetchSwapRemove(decl_index); - if (kv.?.value) |_| { - self.freeAtom(&decl.link.macho); + if (self.decls.fetchSwapRemove(decl_index)) |const_kv| { + var kv = const_kv; + self.freeAtom(kv.value.atom); self.freeUnnamedConsts(decl_index); - } - - // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. - const gpa = self.base.allocator; - const sym_index = decl.link.macho.sym_index; - if (sym_index != 0) { - 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); - } - - log.debug(" adding GOT index {d} to free list (target local@{d})", .{ got_index, sym_index }); - } - - self.locals.items[sym_index].n_type = 0; - _ = self.atom_by_index_table.remove(sym_index); - log.debug(" adding local symbol index {d} to free list", .{sym_index}); - decl.link.macho.sym_index = 0; + kv.value.exports.deinit(self.base.allocator); } if (self.d_sym) |*d_sym| { - d_sym.dwarf.freeDecl(decl); + d_sym.dwarf.freeDecl(decl_index); } } pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 { - const mod = self.base.options.module.?; - const decl = mod.declPtr(decl_index); - assert(self.llvm_object == null); - assert(decl.link.macho.sym_index != 0); - const atom = self.getAtomForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; - try atom.addRelocation(self, .{ + const this_atom_index = try self.getOrCreateAtomForDecl(decl_index); + const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?; + const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; + try Atom.addRelocation(self, atom_index, .{ .type = switch (self.base.options.target.cpu.arch) { .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), else => unreachable, }, - .target = .{ .sym_index = decl.link.macho.sym_index, .file = null }, + .target = .{ .sym_index = sym_index, .file = null }, .offset = @intCast(u32, reloc_info.offset), .addend = reloc_info.addend, .pcrel = false, .length = 3, }); - try atom.addRebase(self, @intCast(u32, reloc_info.offset)); + try Atom.addRebase(self, atom_index, @intCast(u32, reloc_info.offset)); return 0; } @@ -2885,34 +2854,36 @@ fn moveSectionInVirtualMemory(self: *MachO, sect_id: u8, needed_size: u64) !void // TODO: enforce order by increasing VM addresses in self.sections container. for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| { const index = @intCast(u8, sect_id + 1 + next_sect_id); - const maybe_last_atom = &self.sections.items(.last_atom)[index]; const next_segment = self.getSegmentPtr(index); next_header.addr += diff; next_segment.vmaddr += diff; - if (maybe_last_atom.*) |last_atom| { - var atom = last_atom; + const maybe_last_atom_index = &self.sections.items(.last_atom_index)[index]; + if (maybe_last_atom_index.*) |last_atom_index| { + var atom_index = last_atom_index; while (true) { + const atom = self.getAtom(atom_index); const sym = atom.getSymbolPtr(self); sym.n_value += diff; - if (atom.prev) |prev| { - atom = prev; + if (atom.prev_index) |prev_index| { + atom_index = prev_index; } else break; } } } } -fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !u64 { +fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment: u64) !u64 { const tracy = trace(@src()); defer tracy.end(); + const atom = self.getAtom(atom_index); const sect_id = atom.getSymbol(self).n_sect - 1; const segment = self.getSegmentPtr(sect_id); const header = &self.sections.items(.header)[sect_id]; const free_list = &self.sections.items(.free_list)[sect_id]; - const maybe_last_atom = &self.sections.items(.last_atom)[sect_id]; + const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sect_id]; const requires_padding = blk: { if (!header.isCode()) break :blk false; if (header.isSymbolStubs()) break :blk false; @@ -2926,7 +2897,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! // 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 = null; + var atom_placement: ?Atom.Index = null; var free_list_removal: ?usize = null; // First we look for an appropriately sized free list node. @@ -2934,7 +2905,8 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! var vaddr = blk: { var i: usize = 0; while (i < free_list.items.len) { - const big_atom = free_list.items[i]; + const big_atom_index = free_list.items[i]; + const big_atom = self.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 sym = big_atom.getSymbol(self); @@ -2962,30 +2934,35 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! const keep_free_list_node = remaining_capacity >= min_text_capacity; // Set up the metadata to be updated, after errors are no longer possible. - atom_placement = big_atom; + atom_placement = big_atom_index; if (!keep_free_list_node) { free_list_removal = i; } break :blk new_start_vaddr; - } else if (maybe_last_atom.*) |last| { + } else if (maybe_last_atom_index.*) |last_index| { + const last = self.getAtom(last_index); const last_symbol = last.getSymbol(self); const ideal_capacity = if (requires_padding) padToIdeal(last.size) else last.size; const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity; const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment); - atom_placement = last; + atom_placement = last_index; break :blk new_start_vaddr; } else { break :blk mem.alignForwardGeneric(u64, segment.vmaddr, alignment); } }; - const expand_section = atom_placement == null or atom_placement.?.next == null; + const expand_section = if (atom_placement) |placement_index| + self.getAtom(placement_index).next_index == null + else + true; if (expand_section) { const sect_capacity = self.allocatedSize(header.offset); const needed_size = (vaddr + new_atom_size) - segment.vmaddr; if (needed_size > sect_capacity) { const new_offset = self.findFreeSpace(needed_size, self.page_size); - const current_size = if (maybe_last_atom.*) |last_atom| blk: { + const current_size = if (maybe_last_atom_index.*) |last_atom_index| blk: { + const last_atom = self.getAtom(last_atom_index); const sym = last_atom.getSymbol(self); break :blk (sym.n_value + last_atom.size) - segment.vmaddr; } else 0; @@ -3017,7 +2994,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! header.size = needed_size; segment.filesize = mem.alignForwardGeneric(u64, needed_size, self.page_size); segment.vmsize = mem.alignForwardGeneric(u64, needed_size, self.page_size); - maybe_last_atom.* = atom; + maybe_last_atom_index.* = atom_index; self.segment_table_dirty = true; } @@ -3026,21 +3003,31 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! if (header.@"align" < align_pow) { header.@"align" = align_pow; } + { + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.size = new_atom_size; + atom_ptr.alignment = @intCast(u32, alignment); + } - if (atom.prev) |prev| { - prev.next = atom.next; + if (atom.prev_index) |prev_index| { + const prev = self.getAtomPtr(prev_index); + prev.next_index = atom.next_index; } - if (atom.next) |next| { - next.prev = atom.prev; + if (atom.next_index) |next_index| { + const next = self.getAtomPtr(next_index); + next.prev_index = atom.prev_index; } - if (atom_placement) |big_atom| { - atom.prev = big_atom; - atom.next = big_atom.next; - big_atom.next = atom; + if (atom_placement) |big_atom_index| { + const big_atom = self.getAtomPtr(big_atom_index); + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.prev_index = big_atom_index; + atom_ptr.next_index = big_atom.next_index; + big_atom.next_index = atom_index; } else { - atom.prev = null; - atom.next = null; + const atom_ptr = self.getAtomPtr(atom_index); + atom_ptr.prev_index = null; + atom_ptr.next_index = null; } if (free_list_removal) |i| { _ = free_list.swapRemove(i); @@ -3180,8 +3167,9 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void { const gpa = self.base.allocator; const slice = self.sections.slice(); - for (self.rebases.keys()) |atom, i| { - log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) }); + for (self.rebases.keys()) |atom_index, i| { + const atom = self.getAtom(atom_index); + log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) }); const sym = atom.getSymbol(self); const segment_index = slice.items(.segment_index)[sym.n_sect - 1]; @@ -3209,8 +3197,9 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void { const gpa = self.base.allocator; const slice = self.sections.slice(); - for (raw_bindings.keys()) |atom, i| { - log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) }); + for (raw_bindings.keys()) |atom_index, i| { + const atom = self.getAtom(atom_index); + log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) }); const sym = atom.getSymbol(self); const segment_index = slice.items(.segment_index)[sym.n_sect - 1]; @@ -3384,7 +3373,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void if (lazy_bind.size() == 0) return; const stub_helper_section_index = self.stub_helper_section_index.?; - assert(self.stub_helper_preamble_atom != null); + assert(self.stub_helper_preamble_atom_index != null); const section = self.sections.get(stub_helper_section_index); @@ -3394,10 +3383,11 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void else => unreachable, }; const header = section.header; - var atom = section.last_atom.?; + var atom_index = section.last_atom_index.?; var index: usize = lazy_bind.offsets.items.len; while (index > 0) : (index -= 1) { + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const file_offset = header.offset + sym.n_value - header.addr + stub_offset; const bind_offset = lazy_bind.offsets.items[index - 1]; @@ -3410,7 +3400,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void try self.base.file.?.pwriteAll(mem.asBytes(&bind_offset), file_offset); - atom = atom.prev.?; + atom_index = atom.prev_index.?; } } @@ -3853,25 +3843,35 @@ pub fn getOrPutGlobalPtr(self: *MachO, name: []const u8) !GetOrPutGlobalPtrResul return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr }; } +pub fn getAtom(self: *MachO, atom_index: Atom.Index) Atom { + assert(atom_index < self.atoms.items.len); + return self.atoms.items[atom_index]; +} + +pub fn getAtomPtr(self: *MachO, atom_index: Atom.Index) *Atom { + assert(atom_index < self.atoms.items.len); + return &self.atoms.items[atom_index]; +} + /// Returns atom if there is an atom referenced by the symbol described by `sym_with_loc` descriptor. /// Returns null on failure. -pub fn getAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { +pub fn getAtomIndexForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?Atom.Index { assert(sym_with_loc.file == null); 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 getGotAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { +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].getAtom(self); + 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 getStubsAtomForSymbol(self: *MachO, sym_with_loc: SymbolWithLoc) ?*Atom { +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].getAtom(self); + return self.stubs.items[stubs_index].getAtomIndex(self); } /// Returns symbol location corresponding to the set entrypoint. @@ -4257,30 +4257,35 @@ pub fn logAtoms(self: *MachO) void { log.debug("atoms:", .{}); const slice = self.sections.slice(); - for (slice.items(.last_atom)) |last, i| { - var atom = last orelse continue; + for (slice.items(.last_atom_index)) |last_atom_index, i| { + var atom_index = last_atom_index orelse continue; const header = slice.items(.header)[i]; - while (atom.prev) |prev| { - atom = prev; + while (true) { + const atom = self.getAtom(atom_index); + if (atom.prev_index) |prev_index| { + atom_index = prev_index; + } else break; } log.debug("{s},{s}", .{ header.segName(), header.sectName() }); while (true) { - self.logAtom(atom); - if (atom.next) |next| { - atom = next; + self.logAtom(atom_index); + const atom = self.getAtom(atom_index); + if (atom.next_index) |next_index| { + atom_index = next_index; } else break; } } } -pub fn logAtom(self: *MachO, atom: *const Atom) void { +pub fn logAtom(self: *MachO, atom_index: Atom.Index) void { + const atom = self.getAtom(atom_index); const sym = atom.getSymbol(self); const sym_name = atom.getName(self); - log.debug(" ATOM(%{d}, '{s}') @ {x} (sizeof({x}), alignof({x})) in object({?d}) in sect({d})", .{ - atom.sym_index, + log.debug(" ATOM(%{?d}, '{s}') @ {x} (sizeof({x}), alignof({x})) in object({?d}) in sect({d})", .{ + atom.getSymbolIndex(), sym_name, sym.n_value, atom.size, |
