diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-08-01 22:28:28 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-08-07 10:21:02 +0200 |
| commit | 41e9b8b6c84a1787ffa647fc42980dcce4942b7d (patch) | |
| tree | b50e763ea1b13fb6afd36e1e169991e2ad6592fb /src/link | |
| parent | deeaa1bb0cb8a8c7ccebb23cc68be64e4b013ab2 (diff) | |
| download | zig-41e9b8b6c84a1787ffa647fc42980dcce4942b7d.tar.gz zig-41e9b8b6c84a1787ffa647fc42980dcce4942b7d.zip | |
elf: fix compile errors
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/Elf.zig | 131 | ||||
| -rw-r--r-- | src/link/Elf/Atom.zig | 109 | ||||
| -rw-r--r-- | src/link/Elf/LinkerDefined.zig | 74 | ||||
| -rw-r--r-- | src/link/Elf/Object.zig | 79 | ||||
| -rw-r--r-- | src/link/Elf/SharedObject.zig | 37 | ||||
| -rw-r--r-- | src/link/Elf/Symbol.zig | 11 | ||||
| -rw-r--r-- | src/link/Elf/ZigObject.zig | 161 | ||||
| -rw-r--r-- | src/link/Elf/eh_frame.zig | 15 | ||||
| -rw-r--r-- | src/link/Elf/file.zig | 23 | ||||
| -rw-r--r-- | src/link/Elf/gc.zig | 139 | ||||
| -rw-r--r-- | src/link/Elf/relocatable.zig | 4 | ||||
| -rw-r--r-- | src/link/Elf/synthetic_sections.zig | 255 | ||||
| -rw-r--r-- | src/link/Elf/thunks.zig | 40 |
13 files changed, 597 insertions, 481 deletions
diff --git a/src/link/Elf.zig b/src/link/Elf.zig index f2dc7b563f..987d108567 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2013,11 +2013,10 @@ fn claimUnresolved(self: *Elf) void { fn scanRelocs(self: *Elf) !void { const gpa = self.base.comp.gpa; - var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa); + var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa); defer { - var it = undefs.iterator(); - while (it.next()) |entry| { - entry.value_ptr.deinit(); + for (undefs.values()) |*refs| { + refs.deinit(); } undefs.deinit(); } @@ -2028,7 +2027,18 @@ fn scanRelocs(self: *Elf) !void { objects.appendSliceAssumeCapacity(self.objects.items); var has_reloc_errors = false; - for (objects.items) |index| { + if (self.zigObjectPtr()) |zo| { + zo.asFile().scanRelocs(self, &undefs) catch |err| switch (err) { + error.RelaxFailure => unreachable, + error.UnsupportedCpuArch => { + try self.reportUnsupportedCpuArch(); + return error.FlushFailure; + }, + error.RelocFailure => has_reloc_errors = true, + else => |e| return e, + }; + } + for (self.objects.items) |index| { self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) { error.RelaxFailure => unreachable, error.UnsupportedCpuArch => { @@ -2044,47 +2054,12 @@ fn scanRelocs(self: *Elf) !void { if (has_reloc_errors) return error.FlushFailure; - for (self.symbols.items, 0..) |*sym, i| { - const index = @as(u32, @intCast(i)); - if (!sym.isLocal(self) and !sym.flags.has_dynamic) { - log.debug("'{s}' is non-local", .{sym.name(self)}); - try self.dynsym.addSymbol(index, self); - } - if (sym.flags.needs_got) { - log.debug("'{s}' needs GOT", .{sym.name(self)}); - _ = try self.got.addGotSymbol(index, self); - } - if (sym.flags.needs_plt) { - if (sym.flags.is_canonical) { - log.debug("'{s}' needs CPLT", .{sym.name(self)}); - sym.flags.@"export" = true; - try self.plt.addSymbol(index, self); - } else if (sym.flags.needs_got) { - log.debug("'{s}' needs PLTGOT", .{sym.name(self)}); - try self.plt_got.addSymbol(index, self); - } else { - log.debug("'{s}' needs PLT", .{sym.name(self)}); - try self.plt.addSymbol(index, self); - } - } - if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) { - log.debug("'{s}' needs COPYREL", .{sym.name(self)}); - try self.copy_rel.addSymbol(index, self); - } - if (sym.flags.needs_tlsgd) { - log.debug("'{s}' needs TLSGD", .{sym.name(self)}); - try self.got.addTlsGdSymbol(index, self); - } - if (sym.flags.needs_gottp) { - log.debug("'{s}' needs GOTTP", .{sym.name(self)}); - try self.got.addGotTpSymbol(index, self); - } - if (sym.flags.needs_tlsdesc) { - log.debug("'{s}' needs TLSDESC", .{sym.name(self)}); - try self.got.addTlsDescSymbol(index, self); - } + if (self.zigObjectPtr()) |zo| { + try zo.asFile().createSymbolIndirection(self); + } + for (self.objects.items) |index| { + try self.file(index).?.createSymbolIndirection(self); } - if (self.got.flags.needs_tlsld) { log.debug("program needs TLSLD", .{}); try self.got.addTlsLdSymbol(self); @@ -2861,8 +2836,8 @@ pub fn writeElfHeader(self: *Elf) !void { index += 4; const e_entry: u64 = if (self.linkerDefinedPtr()) |obj| blk: { - const entry_index = obj.entry_index orelse break :blk 0; - break :blk @intCast(self.symbol(entry_index).address(.{}, self)); + const entry_sym = obj.entrySymbol(self) orelse break :blk 0; + break :blk @intCast(entry_sym.address(.{}, self)); } else 0; const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0; switch (self.ptr_width) { @@ -2993,7 +2968,7 @@ pub fn deleteExport( fn checkDuplicates(self: *Elf) !void { const gpa = self.base.comp.gpa; - var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa); + var dupes = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)).init(gpa); defer { for (dupes.values()) |*list| { list.deinit(gpa); @@ -3301,7 +3276,7 @@ fn initSyntheticSections(self: *Elf) !void { }); const needs_versions = for (self.dynsym.entries.items) |entry| { - const sym = self.symbol(entry.symbol_index); + const sym = self.symbol(entry.ref).?; if (sym.flags.import and sym.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) break true; } else false; if (needs_versions) { @@ -3515,7 +3490,7 @@ fn setVersionSymtab(self: *Elf) !void { try self.versym.resize(gpa, self.dynsym.count()); self.versym.items[0] = elf.VER_NDX_LOCAL; for (self.dynsym.entries.items, 1..) |entry, i| { - const sym = self.symbol(entry.symbol_index); + const sym = self.symbol(entry.ref).?; self.versym.items[i] = sym.version_index; } @@ -4307,11 +4282,10 @@ fn allocateSpecialPhdrs(self: *Elf) void { fn writeAtoms(self: *Elf) !void { const gpa = self.base.comp.gpa; - var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa); + var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa); defer { - var it = undefs.iterator(); - while (it.next()) |entry| { - entry.value_ptr.deinit(); + for (undefs.values()) |*refs| { + refs.deinit(); } undefs.deinit(); } @@ -5261,7 +5235,7 @@ pub fn calcNumIRelativeRelocs(self: *Elf) usize { for (self.got.entries.items) |entry| { if (entry.tag != .got) continue; - const sym = self.symbol(entry.symbol_index); + const sym = self.symbol(entry.ref).?; if (sym.isIFunc(self)) count += 1; } @@ -5443,36 +5417,34 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { try self.base.comp.link_errors.ensureUnusedCapacity(gpa, undefs.count()); - var it = undefs.iterator(); - while (it.next()) |entry| { - const undef_index = entry.key_ptr.*; - const atoms = entry.value_ptr.*.items; - const natoms = @min(atoms.len, max_notes); - const nnotes = natoms + @intFromBool(atoms.len > max_notes); + for (undefs.keys(), undefs.values()) |key, refs| { + const undef_sym = self.resolver.keys.items[key - 1]; + const nrefs = @min(refs.items.len, max_notes); + const nnotes = nrefs + @intFromBool(refs.items.len > max_notes); var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes); - try err.addMsg("undefined symbol: {s}", .{self.symbol(undef_index).name(self)}); + try err.addMsg("undefined symbol: {s}", .{undef_sym.name(self)}); - for (atoms[0..natoms]) |ref| { + for (refs.items[0..nrefs]) |ref| { const atom_ptr = self.atom(ref).?; - const file_ptr = self.file(ref.file).?; + const file_ptr = atom_ptr.file(self).?; try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) }); } - if (atoms.len > max_notes) { - const remaining = atoms.len - max_notes; + if (refs.items.len > max_notes) { + const remaining = refs.items.len - max_notes; try err.addNote("referenced {d} more times", .{remaining}); } } } fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void { + if (dupes.keys().len == 0) return; // Nothing to do + const max_notes = 3; - var has_dupes = false; - var it = dupes.iterator(); - while (it.next()) |entry| { - const sym = self.symbol(entry.key_ptr.*); - const notes = entry.value_ptr.*; + + for (dupes.keys(), dupes.values()) |key, notes| { + const sym = self.resolver.keys.items[key - 1]; const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); var err = try self.base.addErrorWithNotes(nnotes + 1); @@ -5489,11 +5461,9 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor const remaining = notes.items.len - max_notes; try err.addNote("defined {d} more times", .{remaining}); } - - has_dupes = true; } - if (has_dupes) return error.HasDuplicates; + return error.HasDuplicates; } fn reportMissingLibraryError( @@ -5918,7 +5888,7 @@ pub const SymbolResolver = struct { elf_file: *Elf, ) !Result { const adapter = Adapter{ .keys = resolver.keys.items, .elf_file = elf_file }; - const key = Key{ .index = ref.index, .file = ref.file }; + const key = Key{ .index = ref.index, .file_index = ref.file }; const gop = try resolver.table.getOrPutAdapted(allocator, key, adapter); if (!gop.found_existing) { try resolver.keys.append(allocator, key); @@ -5944,16 +5914,15 @@ pub const SymbolResolver = struct { const Key = struct { index: Symbol.Index, - file: File.Index, + file_index: File.Index, fn name(key: Key, elf_file: *Elf) [:0]const u8 { - const ref = Ref{ .index = key.index, .file = key.file }; - return ref.symbol(elf_file).?.name(elf_file); + const ref = Ref{ .index = key.index, .file = key.file_index }; + return elf_file.symbol(ref).?.name(elf_file); } - pub fn file(key: Key, elf_file: *Elf) ?File { - const ref = Ref{ .index = key.index, .file = key.file }; - return ref.file(elf_file); + fn file(key: Key, elf_file: *Elf) ?File { + return elf_file.file(key.file_index); } fn eql(key: Key, other: Key, elf_file: *Elf) bool { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 0f1ea4b6e3..f2757f570b 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -326,12 +326,8 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El const cpu_arch = elf_file.getTarget().cpu.arch; const file_ptr = self.file(elf_file).?; for (self.relocs(elf_file)) |rel| { - const target_index = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, - }; - const target = elf_file.symbol(target_index); + const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target = elf_file.symbol(target_ref).?; const r_type = rel.r_type(); const r_offset: u64 = @intCast(self.value + @as(i64, @intCast(rel.r_offset))); var r_addend = rel.r_addend; @@ -422,12 +418,21 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype const r_kind = relocation.decode(rel.r_type(), cpu_arch); if (r_kind == .none) continue; - const symbol_index = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, + const symbol_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const symbol = elf_file.symbol(symbol_ref) orelse { + const sym_name = switch (file_ptr) { + .zig_object => |x| x.symbol(rel.r_sym()).name(elf_file), + inline else => |x| x.symbols.items[rel.r_sym()].name(elf_file), + }; + // Violation of One Definition Rule for COMDATs. + // TODO convert into an error + log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ + file_ptr.fmtPath(), + self.name(elf_file), + sym_name, + }); + continue; }; - const symbol = elf_file.symbol(symbol_index); const is_synthetic_symbol = switch (file_ptr) { .zig_object => false, // TODO: implement this once we support merge sections in ZigObject @@ -435,19 +440,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype else => unreachable, }; - // Check for violation of One Definition Rule for COMDATs. - if (symbol.file(elf_file) == null) { - // TODO convert into an error - log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ - file_ptr.fmtPath(), - self.name(elf_file), - symbol.name(elf_file), - }); - continue; - } - // Report an undefined symbol. - if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs))) + if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, symbol, rel, undefs))) continue; if (symbol.isIFunc(elf_file)) { @@ -694,16 +688,15 @@ fn reportUndefined( self: Atom, elf_file: *Elf, sym: *const Symbol, - sym_index: Symbol.Index, rel: elf.Elf64_Rela, undefs: anytype, ) !bool { const comp = elf_file.base.comp; const gpa = comp.gpa; - const rel_esym = switch (self.file(elf_file).?) { - .zig_object => |x| x.elfSym(rel.r_sym()).*, - .object => |x| x.symtab.items[rel.r_sym()], - else => unreachable, + const file_ptr = self.file(elf_file).?; + const rel_esym = switch (file_ptr) { + .zig_object => |x| x.symbol(rel.r_sym()).elfSym(elf_file), + inline else => |x| x.symtab.items[rel.r_sym()], }; const esym = sym.elfSym(elf_file); if (rel_esym.st_shndx == elf.SHN_UNDEF and @@ -712,7 +705,12 @@ fn reportUndefined( !sym.flags.import and esym.st_shndx == elf.SHN_UNDEF) { - const gop = try undefs.getOrPut(sym_index); + const idx = switch (file_ptr) { + .zig_object => |x| x.symbols_resolver.items[rel.r_sym() & ZigObject.symbol_mask], + .object => |x| x.symbols_resolver.items[rel.r_sym() - x.first_global.?], + inline else => |x| x.symbols_resolver.items[rel.r_sym()], + }; + const gop = try undefs.getOrPut(idx); if (!gop.found_existing) { gop.value_ptr.* = std.ArrayList(Elf.Ref).init(gpa); } @@ -737,11 +735,8 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi const r_kind = relocation.decode(rel.r_type(), cpu_arch); if (r_kind == .none) continue; - const target = switch (file_ptr) { - .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())), - .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]), - else => unreachable, - }; + const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target = elf_file.symbol(target_ref).?; const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; // We will use equation format to resolve relocations: @@ -923,31 +918,29 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; - const target_index = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, - }; - const target = elf_file.symbol(target_index); - const is_synthetic_symbol = switch (file_ptr) { - .zig_object => false, // TODO: implement this once we support merge sections in ZigObject - .object => |x| rel.r_sym() >= x.symtab.items.len, - else => unreachable, - }; - - // Check for violation of One Definition Rule for COMDATs. - if (target.file(elf_file) == null) { + const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target = elf_file.symbol(target_ref) orelse { + const sym_name = switch (file_ptr) { + .zig_object => |x| x.symbol(rel.r_sym()).name(elf_file), + inline else => |x| x.symbols.items[rel.r_sym()].name(elf_file), + }; + // Violation of One Definition Rule for COMDATs. // TODO convert into an error log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ file_ptr.fmtPath(), self.name(elf_file), - target.name(elf_file), + sym_name, }); continue; - } + }; + const is_synthetic_symbol = switch (file_ptr) { + .zig_object => false, // TODO: implement this once we support merge sections in ZigObject + .object => |x| rel.r_sym() >= x.symtab.items.len, + else => unreachable, + }; // Report an undefined symbol. - if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, target, target_index, rel, undefs))) + if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, target, rel, undefs))) continue; // We will use equation format to resolve relocations: @@ -1766,11 +1759,7 @@ const aarch64 = struct { => { const disp: i28 = math.cast(i28, S + A - P) orelse blk: { const th = atom.thunk(elf_file); - const target_index = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, - }; + const target_index = file_ptr.resolveSymbol(rel.r_sym(), elf_file); const S_ = th.targetAddress(target_index, elf_file); break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; }; @@ -2106,11 +2095,8 @@ const riscv = struct { return error.RelocFailure; }; it.pos = pos; - const target_ = switch (file_ptr) { - .zig_object => |x| elf_file.symbol(x.symbol(pair.r_sym())), - .object => |x| elf_file.symbol(x.symbols.items[pair.r_sym()]), - else => unreachable, - }; + const target_ref_ = file_ptr.resolveSymbol(pair.r_sym(), elf_file); + const target_ = elf_file.symbol(target_ref_).?; const S_ = target_.address(.{}, elf_file); const A_ = pair.r_addend; const P_ = atom_addr + @as(i64, @intCast(pair.r_offset)); @@ -2313,4 +2299,5 @@ const File = @import("file.zig").File; const Object = @import("Object.zig"); const Symbol = @import("Symbol.zig"); const Thunk = @import("thunks.zig").Thunk; +const ZigObject = @import("ZigObject.zig"); const dev = @import("../../dev.zig"); diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index 89e56a7e16..ee9a1e2956 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -44,7 +44,7 @@ pub fn init(self: *LinkerDefined, allocator: Allocator) !void { pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { const newSymbolAssumeCapacity = struct { - fn newSymbolAssumeCapacity(ld: *LinkerDefined, name_off: u32) Symbol.Index { + fn newSymbolAssumeCapacity(ld: *LinkerDefined, name_off: u32, ef: *Elf) Symbol.Index { const esym_index: u32 = @intCast(ld.symtab.items.len); const esym = ld.symtab.addOneAssumeCapacity(); esym.* = .{ @@ -61,7 +61,8 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { symbol.extra_index = ld.addSymbolExtraAssumeCapacity(.{}); symbol.ref = .{ .index = 0, .file = 0 }; symbol.esym_index = esym_index; - symbol.version_index = elf_file.default_sym_version; + symbol.version_index = ef.default_sym_version; + return index; } }.newSymbolAssumeCapacity; @@ -111,31 +112,31 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { @memset(self.symbols_resolver.items, 0); if (elf_file.entry_name) |name| { - self.entry_index = newSymbolAssumeCapacity(self, try self.addString(gpa, name)); + self.entry_index = newSymbolAssumeCapacity(self, try self.addString(gpa, name), elf_file); } - self.dynamic_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_DYNAMIC")); - self.ehdr_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__ehdr_start")); - self.init_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_start")); - self.init_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_end")); - self.fini_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_start")); - self.fini_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_end")); - self.preinit_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_start")); - self.preinit_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_end")); - self.got_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_")); - self.plt_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_")); - self.end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_end")); + self.dynamic_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_DYNAMIC"), elf_file); + self.ehdr_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__ehdr_start"), elf_file); + self.init_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_start"), elf_file); + self.init_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_end"), elf_file); + self.fini_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_start"), elf_file); + self.fini_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_end"), elf_file); + self.preinit_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_start"), elf_file); + self.preinit_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_end"), elf_file); + self.got_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_"), elf_file); + self.plt_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_"), elf_file); + self.end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_end"), elf_file); if (elf_file.base.comp.link_eh_frame_hdr) { - self.gnu_eh_frame_hdr_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__GNU_EH_FRAME_HDR")); + self.gnu_eh_frame_hdr_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__GNU_EH_FRAME_HDR"), elf_file); } - self.dso_handle_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__dso_handle")); - self.rela_iplt_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_start")); - self.rela_iplt_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_end")); + self.dso_handle_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__dso_handle"), elf_file); + self.rela_iplt_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_start"), elf_file); + self.rela_iplt_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_end"), elf_file); if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) { - self.global_pointer_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__global_pointer$")); + self.global_pointer_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__global_pointer$"), elf_file); } for (elf_file.objects.items) |index| { @@ -145,8 +146,8 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { defer gpa.free(start_name); const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name}); defer gpa.free(stop_name); - const start = newSymbolAssumeCapacity(self, try self.addString(gpa, start_name)); - const stop = newSymbolAssumeCapacity(self, try self.addString(gpa, stop_name)); + const start = newSymbolAssumeCapacity(self, try self.addString(gpa, start_name), elf_file); + const stop = newSymbolAssumeCapacity(self, try self.addString(gpa, stop_name), elf_file); self.start_stop_indexes.appendSliceAssumeCapacity(&.{ start, stop }); } } @@ -268,7 +269,7 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void { for (elf_file.shdrs.items, 0..) |shdr, shndx| { if (shdr.sh_flags & elf.SHF_ALLOC != 0) { value = shdr.sh_addr + shdr.sh_size; - osec = shndx; + osec = @intCast(shndx); } } allocSymbol(self, self.end_index.?, value, osec, elf_file); @@ -287,10 +288,10 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void { { var index: usize = 0; while (index < self.start_stop_indexes.items.len) : (index += 2) { - const start_ref = self.resolveSymbol(self.start_stop_indexes.items[index]); + const start_ref = self.resolveSymbol(self.start_stop_indexes.items[index], elf_file); const start = elf_file.symbol(start_ref).?; const name = start.name(elf_file); - const stop_ref = self.resolveSymbol(self.start_stop_indexes.items[index + 1]); + const stop_ref = self.resolveSymbol(self.start_stop_indexes.items[index + 1], elf_file); const stop = elf_file.symbol(stop_ref).?; const shndx = elf_file.sectionByName(name["__start_".len..]).?; const shdr = &elf_file.shdrs.items[shndx]; @@ -334,6 +335,18 @@ pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf) void { } } +pub fn dynamicSymbol(self: LinkerDefined, elf_file: *Elf) ?*Symbol { + const index = self.dynamic_index orelse return null; + const resolv = self.resolveSymbol(index, elf_file); + return elf_file.symbol(resolv); +} + +pub fn entrySymbol(self: LinkerDefined, elf_file: *Elf) ?*Symbol { + const index = self.entry_index orelse return null; + const resolv = self.resolveSymbol(index, elf_file); + return elf_file.symbol(resolv); +} + pub fn asFile(self: *LinkerDefined) File { return .{ .linker_defined = self }; } @@ -356,8 +369,12 @@ pub fn resolveSymbol(self: LinkerDefined, index: Symbol.Index, elf_file: *Elf) E return elf_file.resolver.get(resolv).?; } -pub fn addSymbol(self: *LinkerDefined, allocator: Allocator) !Symbol.Index { +fn addSymbol(self: *LinkerDefined, allocator: Allocator) !Symbol.Index { try self.symbols.ensureUnusedCapacity(allocator, 1); + return self.addSymbolAssumeCapacity(); +} + +fn addSymbolAssumeCapacity(self: *LinkerDefined) Symbol.Index { const index: Symbol.Index = @intCast(self.symbols.items.len); self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); return index; @@ -425,10 +442,11 @@ fn formatSymtab( ) !void { _ = unused_fmt_string; _ = options; + const self = ctx.self; + const elf_file = ctx.elf_file; try writer.writeAll(" globals\n"); - for (ctx.self.globals()) |index| { - const global = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); + for (self.symbols.items) |sym| { + try writer.print(" {}\n", .{sym.fmt(elf_file)}); } } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index feb70776d5..47c74967eb 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -394,10 +394,9 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void { sym_ptr.value = @intCast(sym.st_value); sym_ptr.name_offset = sym.st_name; sym_ptr.esym_index = @intCast(i); - sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{ - .weak = sym.st_bind() == elf.STB_WEAK, - }); + sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{}); sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else elf.VER_NDX_LOCAL; + sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK; if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) { sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index }; } @@ -548,7 +547,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { for (self.cies.items) |cie| { for (cie.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(self.resolveSymbol(rel.r_sym())); + const sym = elf_file.symbol(self.resolveSymbol(rel.r_sym(), elf_file)).?; if (sym.flags.import) { if (sym.type(elf_file) != elf.STT_FUNC) // TODO convert into an error @@ -562,6 +561,51 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { } } +pub fn createSymbolIndirection(self: *Object, elf_file: *Elf) !void { + for (self.symbols.items, 0..) |*sym, i| { + const ref = self.resolveSymbol(@intCast(i), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; + if (!sym.isLocal(elf_file) and !sym.flags.has_dynamic) { + log.debug("'{s}' is non-local", .{sym.name(elf_file)}); + try elf_file.dynsym.addSymbol(ref, elf_file); + } + if (sym.flags.needs_got) { + log.debug("'{s}' needs GOT", .{sym.name(elf_file)}); + _ = try elf_file.got.addGotSymbol(ref, elf_file); + } + if (sym.flags.needs_plt) { + if (sym.flags.is_canonical) { + log.debug("'{s}' needs CPLT", .{sym.name(elf_file)}); + sym.flags.@"export" = true; + try elf_file.plt.addSymbol(ref, elf_file); + } else if (sym.flags.needs_got) { + log.debug("'{s}' needs PLTGOT", .{sym.name(elf_file)}); + try elf_file.plt_got.addSymbol(ref, elf_file); + } else { + log.debug("'{s}' needs PLT", .{sym.name(elf_file)}); + try elf_file.plt.addSymbol(ref, elf_file); + } + } + if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) { + log.debug("'{s}' needs COPYREL", .{sym.name(elf_file)}); + try elf_file.copy_rel.addSymbol(ref, elf_file); + } + if (sym.flags.needs_tlsgd) { + log.debug("'{s}' needs TLSGD", .{sym.name(elf_file)}); + try elf_file.got.addTlsGdSymbol(ref, elf_file); + } + if (sym.flags.needs_gottp) { + log.debug("'{s}' needs GOTTP", .{sym.name(elf_file)}); + try elf_file.got.addGotTpSymbol(ref, elf_file); + } + if (sym.flags.needs_tlsdesc) { + log.debug("'{s}' needs TLSDESC", .{sym.name(elf_file)}); + try elf_file.got.addTlsDescSymbol(ref, elf_file); + } + } +} + pub fn resolveSymbols(self: *Object, elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; @@ -643,7 +687,7 @@ pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void { sym.file_index = self.index; const idx = self.symbols_resolver.items[i]; - elf_file.resolver.items[idx - 1] = .{ .index = esym_index, .file = self.index }; + elf_file.resolver.values.items[idx - 1] = .{ .index = esym_index, .file = self.index }; } } @@ -1120,7 +1164,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void { } for (self.globals(), self.symbols_resolver.items) |*global, resolv| { - const ref = elf_file.resolver.items[resolv]; + const ref = elf_file.resolver.values.items[resolv]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; if (!isAlive(global, elf_file)) continue; @@ -1136,7 +1180,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void { } } -pub fn writeSymtab(self: Object, elf_file: *Elf) void { +pub fn writeSymtab(self: *Object, elf_file: *Elf) void { for (self.locals()) |local| { const idx = local.outputSymtabIndex(elf_file) orelse continue; const out_sym = &elf_file.symtab.items[idx]; @@ -1147,7 +1191,7 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void { } for (self.globals(), self.symbols_resolver.items) |global, resolv| { - const ref = elf_file.resolver.items[resolv]; + const ref = elf_file.resolver.values.items[resolv]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; const idx = global.outputSymtabIndex(elf_file) orelse continue; @@ -1199,7 +1243,7 @@ fn locals(self: *Object) []Symbol { return self.symbols.items[0..end]; } -fn globals(self: *Object) []Symbol { +pub fn globals(self: *Object) []Symbol { if (self.symbols.items.len == 0) return &[0]Symbol{}; assert(self.symbols.items.len >= self.symtab.items.len); const start = self.first_global orelse self.symtab.items.len; @@ -1214,8 +1258,12 @@ pub fn resolveSymbol(self: Object, index: Symbol.Index, elf_file: *Elf) Elf.Ref return elf_file.resolver.get(resolv).?; } -pub fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index { +fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index { try self.symbols.ensureUnusedCapacity(allocator, 1); + return self.addSymbolAssumeCapacity(); +} + +fn addSymbolAssumeCapacity(self: *Object) Symbol.Index { const index: Symbol.Index = @intCast(self.symbols.items.len); self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); return index; @@ -1430,15 +1478,14 @@ fn formatSymtab( _ = unused_fmt_string; _ = options; const object = ctx.object; + const elf_file = ctx.elf_file; try writer.writeAll(" locals\n"); - for (object.locals()) |index| { - const local = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{local.fmt(ctx.elf_file)}); + for (object.locals()) |sym| { + try writer.print(" {}\n", .{sym.fmt(elf_file)}); } try writer.writeAll(" globals\n"); - for (object.globals()) |index| { - const global = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); + for (object.globals()) |sym| { + try writer.print(" {}\n", .{sym.fmt(elf_file)}); } } diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index aff07e4469..3c360c3c46 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -286,8 +286,8 @@ pub fn markImportExports(self: *SharedObject, elf_file: *Elf) void { for (0..self.symbols.items.len) |i| { const ref = self.resolveSymbol(@intCast(i), elf_file); const ref_sym = elf_file.symbol(ref) orelse continue; - const ref_file = ref_sym.file(self).?; - const vis = @as(elf.STV, @enumFromInt(ref_sym.elfSym(self).st_other)); + const ref_file = ref_sym.file(elf_file).?; + const vis = @as(elf.STV, @enumFromInt(ref_sym.elfSym(elf_file).st_other)); if (ref_file != .shared_object and vis != .HIDDEN) ref_sym.flags.@"export" = true; } } @@ -349,9 +349,12 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { assert(self.aliases == null); const SortAlias = struct { - pub fn lessThan(ctx: *Elf, lhs: Symbol.Index, rhs: Symbol.Index) bool { - const lhs_sym = ctx.symbol(lhs).elfSym(ctx); - const rhs_sym = ctx.symbol(rhs).elfSym(ctx); + so: *SharedObject, + ef: *Elf, + + pub fn lessThan(ctx: @This(), lhs: Symbol.Index, rhs: Symbol.Index) bool { + const lhs_sym = ctx.so.symbols.items[lhs].elfSym(ctx.ef); + const rhs_sym = ctx.so.symbols.items[rhs].elfSym(ctx.ef); return lhs_sym.st_value < rhs_sym.st_value; } }; @@ -362,14 +365,14 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { defer aliases.deinit(); try aliases.ensureTotalCapacityPrecise(self.symbols.items.len); - for (self.symbols_resolvers.items, 0..) |resolv, index| { + for (self.symbols_resolver.items, 0..) |resolv, index| { const ref = elf_file.resolver.get(resolv).?; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; - aliases.appendAssumeCapacity(index); + aliases.appendAssumeCapacity(@intCast(index)); } - std.mem.sort(u32, aliases.items, elf_file, SortAlias.lessThan); + std.mem.sort(u32, aliases.items, SortAlias{ .so = self, .ef = elf_file }, SortAlias.lessThan); self.aliases = aliases.moveToUnmanaged(); } @@ -377,16 +380,16 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u32 { assert(self.aliases != null); - const symbol = self.symbol(index).elfSym(elf_file); + const symbol = self.symbols.items[index].elfSym(elf_file); const aliases = self.aliases.?; const start = for (aliases.items, 0..) |alias, i| { - const alias_sym = self.symbol(alias).elfSym(elf_file); + const alias_sym = self.symbols.items[alias].elfSym(elf_file); if (symbol.st_value == alias_sym.st_value) break i; } else aliases.items.len; const end = for (aliases.items[start..], 0..) |alias, i| { - const alias_sym = self.symbol(alias).elfSym(elf_file); + const alias_sym = self.symbols.items[alias].elfSym(elf_file); if (symbol.st_value < alias_sym.st_value) break i + start; } else aliases.items.len; @@ -403,8 +406,12 @@ pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) El return elf_file.resolver.get(resolv).?; } -pub fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index { +fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index { try self.symbols.ensureUnusedCapacity(allocator, 1); + return self.addSymbolAssumeCapacity(); +} + +fn addSymbolAssumeCapacity(self: *SharedObject) Symbol.Index { const index: Symbol.Index = @intCast(self.symbols.items.len); self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); return index; @@ -486,10 +493,10 @@ fn formatSymtab( _ = unused_fmt_string; _ = options; const shared = ctx.shared; + const elf_file = ctx.elf_file; try writer.writeAll(" globals\n"); - for (shared.symbols.items) |index| { - const global = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); + for (shared.symbols.items) |sym| { + try writer.print(" {}\n", .{sym.fmt(elf_file)}); } } diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index ba5c8f4986..ce6b94a185 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -86,6 +86,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File { pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym { return switch (symbol.file(elf_file).?) { + .zig_object => |x| x.symtab.items(.elf_sym)[symbol.esym_index], inline else => |x| x.symtab.items[symbol.esym_index], }; } @@ -261,7 +262,7 @@ const AddExtraOpts = struct { zig_got: ?u32 = null, }; -pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void { +pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void { var extras = symbol.extra(elf_file); inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { if (@field(opts, field.name)) |x| { @@ -272,11 +273,15 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void { } pub fn extra(symbol: Symbol, elf_file: *Elf) Extra { - return elf_file.symbolExtra(symbol.extra_index); + return switch (symbol.file(elf_file).?) { + inline else => |x| x.symbolExtra(symbol.extra_index), + }; } pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void { - elf_file.setSymbolExtra(symbol.extra_index, extras); + return switch (symbol.file(elf_file).?) { + inline else => |x| x.setSymbolExtra(symbol.extra_index, extras), + }; } pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index fb41cd2c97..1970ab5701 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -89,19 +89,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { try self.strtab.buffer.append(gpa, 0); const name_off = try self.strtab.insert(gpa, self.path); - const symbol_index = try elf_file.addSymbol(); - try self.local_symbols.append(gpa, symbol_index); - const symbol_ptr = elf_file.symbol(symbol_index); - symbol_ptr.file_index = self.index; - symbol_ptr.name_offset = name_off; - symbol_ptr.extra_index = try elf_file.addSymbolExtra(.{}); - - const esym_index = try self.addLocalEsym(gpa); - const esym = &self.local_esyms.items(.elf_sym)[esym_index]; - esym.st_name = name_off; + const symbol_index = try self.newLocalSymbol(gpa, name_off); + const sym = self.symbol(symbol_index); + const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; esym.st_info = elf.STT_FILE; esym.st_shndx = elf.SHN_ABS; - symbol_ptr.esym_index = esym_index; switch (comp.config.debug_format) { .strip => {}, @@ -275,7 +267,7 @@ fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) const index = self.addSymbolAssumeCapacity(); const sym = &self.symbols.items[index]; sym.name_offset = name_off; - sym.extra = self.addSymbolExtraAssumeCapacity(.{}); + sym.extra_index = self.addSymbolExtraAssumeCapacity(.{}); const esym_idx: u32 = @intCast(self.symtab.addOneAssumeCapacity()); const esym = ElfSym{ .elf_sym = .{ @@ -377,7 +369,7 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) !void { continue; } - if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) { + if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) { gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index }; } } @@ -428,7 +420,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void { global.file_index = self.index; const idx = self.symbols_resolver.items[i]; - elf_file.resolver.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index }; + elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index }; } } @@ -450,6 +442,64 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void { } } +pub fn createSymbolIndirection(self: *ZigObject, elf_file: *Elf) !void { + const impl = struct { + fn impl(sym: *Symbol, ref: Elf.Ref, ef: *Elf) !void { + if (!sym.isLocal(ef) and !sym.flags.has_dynamic) { + log.debug("'{s}' is non-local", .{sym.name(ef)}); + try ef.dynsym.addSymbol(ref, ef); + } + if (sym.flags.needs_got) { + log.debug("'{s}' needs GOT", .{sym.name(ef)}); + _ = try ef.got.addGotSymbol(ref, ef); + } + if (sym.flags.needs_plt) { + if (sym.flags.is_canonical) { + log.debug("'{s}' needs CPLT", .{sym.name(ef)}); + sym.flags.@"export" = true; + try ef.plt.addSymbol(ref, ef); + } else if (sym.flags.needs_got) { + log.debug("'{s}' needs PLTGOT", .{sym.name(ef)}); + try ef.plt_got.addSymbol(ref, ef); + } else { + log.debug("'{s}' needs PLT", .{sym.name(ef)}); + try ef.plt.addSymbol(ref, ef); + } + } + if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) { + log.debug("'{s}' needs COPYREL", .{sym.name(ef)}); + try ef.copy_rel.addSymbol(ref, ef); + } + if (sym.flags.needs_tlsgd) { + log.debug("'{s}' needs TLSGD", .{sym.name(ef)}); + try ef.got.addTlsGdSymbol(ref, ef); + } + if (sym.flags.needs_gottp) { + log.debug("'{s}' needs GOTTP", .{sym.name(ef)}); + try ef.got.addGotTpSymbol(ref, ef); + } + if (sym.flags.needs_tlsdesc) { + log.debug("'{s}' needs TLSDESC", .{sym.name(ef)}); + try ef.got.addTlsDescSymbol(ref, ef); + } + } + }.impl; + for (self.local_symbols.items, 0..) |index, i| { + const sym = &self.symbols.items[index]; + const ref = self.resolveSymbol(@intCast(i), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; + try impl(sym, ref, elf_file); + } + for (self.global_symbols.items, 0..) |index, i| { + const sym = &self.symbols.items[index]; + const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; + try impl(sym, ref, elf_file); + } +} + pub fn markLive(self: *ZigObject, elf_file: *Elf) void { for (self.global_symbols.items, 0..) |index, i| { const global = self.symbols.items[index]; @@ -468,7 +518,7 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void { } } -pub fn markImportsExports(self: *Object, elf_file: *Elf) void { +pub fn markImportsExports(self: *ZigObject, elf_file: *Elf) void { for (0..self.global_symbols.items.len) |i| { const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file); const sym = elf_file.symbol(ref) orelse continue; @@ -604,7 +654,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| { const global = &self.symbols.items[index]; - const ref = elf_file.resolver.items[resolv]; + const ref = elf_file.resolver.values.items[resolv]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue; @@ -633,7 +683,7 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void { for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| { const global = self.symbols.items[index]; - const ref = elf_file.resolver.items[resolv]; + const ref = elf_file.resolver.values.items[resolv]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; const idx = global.outputSymtabIndex(elf_file) orelse continue; @@ -678,13 +728,13 @@ pub fn getDeclVAddr( reloc_info: link.File.RelocInfo, ) !u64 { const this_sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index); - const this_sym = elf_file.symbol(this_sym_index); + const this_sym = self.symbol(this_sym_index); const vaddr = this_sym.address(.{}, elf_file); - const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?; + const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?; const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch); try parent_atom.addReloc(elf_file, .{ .r_offset = reloc_info.offset, - .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | r_type, + .r_info = (@as(u64, @intCast(this_sym_index)) << 32) | r_type, .r_addend = reloc_info.addend, }); return @intCast(vaddr); @@ -697,13 +747,13 @@ pub fn getAnonDeclVAddr( reloc_info: link.File.RelocInfo, ) !u64 { const sym_index = self.anon_decls.get(decl_val).?.symbol_index; - const sym = elf_file.symbol(sym_index); + const sym = self.symbol(sym_index); const vaddr = sym.address(.{}, elf_file); - const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?; + const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?; const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch); try parent_atom.addReloc(elf_file, .{ .r_offset = reloc_info.offset, - .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | r_type, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, .r_addend = reloc_info.addend, }); return @intCast(vaddr); @@ -725,7 +775,7 @@ pub fn lowerAnonDecl( else => explicit_alignment, }; if (self.anon_decls.get(decl_val)) |metadata| { - const existing_alignment = elf_file.symbol(metadata.symbol_index).atom(elf_file).?.alignment; + const existing_alignment = self.symbol(metadata.symbol_index).atom(elf_file).?.alignment; if (decl_alignment.order(existing_alignment).compare(.lte)) return .ok; } @@ -811,11 +861,10 @@ fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.De } fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void { - _ = self; - const sym = elf_file.symbol(sym_index); + const sym = self.symbol(sym_index); sym.atom(elf_file).?.free(elf_file); log.debug("adding %{d} to local symbols free list", .{sym_index}); - elf_file.symbols.items[sym_index] = .{}; + self.symbols.items[sym_index] = .{}; // TODO free GOT entry here } @@ -940,8 +989,8 @@ fn updateDeclCode( target_util.minFunctionAlignment(mod.getTarget()), ); - const sym = elf_file.symbol(sym_index); - const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index]; + const sym = self.symbol(sym_index); + const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; const atom_ptr = sym.atom(elf_file).?; const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip)); @@ -1038,8 +1087,8 @@ fn updateTlv( const required_alignment = decl.getAlignment(pt); - const sym = elf_file.symbol(sym_index); - const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index]; + const sym = self.symbol(sym_index); + const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; const atom_ptr = sym.atom(elf_file).?; const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip)); @@ -1264,9 +1313,9 @@ fn updateLazySymbol( .code => elf_file.zig_text_section_index.?, .const_data => elf_file.zig_data_rel_ro_section_index.?, }; - const local_sym = elf_file.symbol(symbol_index); + const local_sym = self.symbol(symbol_index); local_sym.name_offset = name_str_index; - const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index]; + const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index]; local_esym.st_name = name_str_index; local_esym.st_info |= elf.STT_OBJECT; local_esym.st_size = code.len; @@ -1372,7 +1421,7 @@ fn lowerConst( }; const local_sym = self.symbol(sym_index); - const local_esym = local_sym.elfSym(elf_file); + const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index]; local_esym.st_info |= elf.STT_OBJECT; local_esym.st_size = code.len; const atom_ptr = local_sym.atom(elf_file).?; @@ -1473,9 +1522,9 @@ pub fn updateExports( const global_sym = self.symbol(global_sym_index); global_sym.value = value; global_sym.flags.weak = exp.opts.linkage == .weak; - global_sym.version_index = elf_file.default_version_index; + global_sym.version_index = elf_file.default_sym_version; global_sym.ref = .{ .index = esym_shndx, .file = self.index }; - const global_esym = global_sym.elfSym(elf_file); + const global_esym = &self.symtab.items(.elf_sym)[global_sym.esym_index]; global_esym.st_value = @intCast(value); global_esym.st_shndx = esym.st_shndx; global_esym.st_info = (stb_bits << 4) | stt_bits; @@ -1517,16 +1566,16 @@ pub fn deleteExport( const exp_name = name.toSlice(&mod.intern_pool); const esym_index = metadata.@"export"(self, exp_name) orelse return; log.debug("deleting export '{s}'", .{exp_name}); - const esym = &self.global_esyms.items(.elf_sym)[esym_index.*]; + const esym = &self.symtab.items(.elf_sym)[esym_index.*]; _ = self.globals_lookup.remove(esym.st_name); - const sym_index = elf_file.resolver.get(esym.st_name).?; - const sym = elf_file.symbol(sym_index); - if (sym.file_index == self.index) { - _ = elf_file.resolver.swapRemove(esym.st_name); - sym.* = .{}; - } + // const sym_index = elf_file.resolver.get(esym.st_name).?; + // const sym = elf_file.symbol(sym_index); + // if (sym.file_index == self.index) { + // _ = elf_file.resolver.swapRemove(esym.st_name); + // sym.* = .{}; + // } esym.* = Elf.null_sym; - self.global_esyms.items(.shndx)[esym_index.*] = elf.SHN_UNDEF; + self.symtab.items(.shndx)[esym_index.*] = elf.SHN_UNDEF; } pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 { @@ -1535,7 +1584,7 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n const off = try self.strtab.insert(gpa, name); const lookup_gop = try self.globals_lookup.getOrPut(gpa, off); if (!lookup_gop.found_existing) { - lookup_gop.value_ptr.* = try self.newSymbol(gpa, off); + lookup_gop.value_ptr.* = try self.newGlobalSymbol(gpa, off); } return lookup_gop.value_ptr.*; } @@ -1636,8 +1685,12 @@ pub fn resolveSymbol(self: ZigObject, index: Symbol.Index, elf_file: *Elf) Elf.R return .{ .index = index, .file = self.index }; } -pub fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index { +fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index { try self.symbols.ensureUnusedCapacity(allocator, 1); + return self.addSymbolAssumeCapacity(); +} + +fn addSymbolAssumeCapacity(self: *ZigObject) Symbol.Index { const index: Symbol.Index = @intCast(self.symbols.items.len); self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); return index; @@ -1705,15 +1758,17 @@ fn formatSymtab( ) !void { _ = unused_fmt_string; _ = options; + const self = ctx.self; + const elf_file = ctx.elf_file; try writer.writeAll(" locals\n"); - for (ctx.self.locals()) |index| { - const local = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{local.fmt(ctx.elf_file)}); + for (self.local_symbols.items) |index| { + const local = self.symbols.items[index]; + try writer.print(" {}\n", .{local.fmt(elf_file)}); } try writer.writeAll(" globals\n"); - for (ctx.self.globals()) |index| { - const global = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); + for (ctx.self.global_symbols.items) |index| { + const global = self.symbols.items[index]; + try writer.print(" {}\n", .{global.fmt(elf_file)}); } } @@ -1759,7 +1814,7 @@ const DeclMetadata = struct { fn @"export"(m: DeclMetadata, zo: *ZigObject, name: []const u8) ?*u32 { for (m.exports.items) |*exp| { - const exp_name = zo.getString(zo.symbol(exp.*).name_off); + const exp_name = zo.getString(zo.symbol(exp.*).name_offset); if (mem.eql(u8, name, exp_name)) return exp; } return null; diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index 1ca1b90906..30f35b16d8 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -339,7 +339,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { const contents = cie.data(elf_file); for (cie.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const sym = elf_file.symbol(ref).?; resolveReloc(cie, sym, rel, elf_file, contents) catch |err| switch (err) { error.RelocFailure => has_reloc_errors = true, else => |e| return e, @@ -366,7 +367,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { ); for (fde.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const sym = elf_file.symbol(ref).?; resolveReloc(fde, sym, rel, elf_file, contents) catch |err| switch (err) { error.RelocFailure => has_reloc_errors = true, else => |e| return e, @@ -452,7 +454,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { for (object.cies.items) |cie| { if (!cie.alive) continue; for (cie.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const sym = elf_file.symbol(ref).?; const out_rel = emitReloc(elf_file, cie, sym, rel); try writer.writeStruct(out_rel); } @@ -461,7 +464,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { for (object.fdes.items) |fde| { if (!fde.alive) continue; for (fde.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const sym = elf_file.symbol(ref).?; const out_rel = emitReloc(elf_file, fde, sym, rel); try writer.writeStruct(out_rel); } @@ -513,7 +517,8 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { const relocs = fde.relocs(elf_file); assert(relocs.len > 0); // Should this be an error? Things are completely broken anyhow if this trips... const rel = relocs[0]; - const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const sym = elf_file.symbol(ref).?; const P = @as(i64, @intCast(fde.address(elf_file))); const S = @as(i64, @intCast(sym.address(.{}, elf_file))); const A = rel.r_addend; diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index 9c7cd27626..32a540ce39 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -61,10 +61,10 @@ pub const File = union(enum) { return (@as(u32, base) << 24) + file.index(); } - pub fn resolveSymbols(file: File, elf_file: *Elf) void { - switch (file) { + pub fn resolveSymbols(file: File, elf_file: *Elf) !void { + return switch (file) { inline else => |x| x.resolveSymbols(elf_file), - } + }; } pub fn resetGlobals(file: File, elf_file: *Elf) void { @@ -100,6 +100,13 @@ pub const File = union(enum) { } } + pub fn createSymbolIndirection(file: File, elf_file: *Elf) !void { + return switch (file) { + .linker_defined, .shared_object => unreachable, + inline else => |x| x.createSymbolIndirection(elf_file), + }; + } + pub fn atom(file: File, atom_index: Atom.Index) ?*Atom { return switch (file) { .shared_object => unreachable, @@ -146,10 +153,16 @@ pub const File = union(enum) { }; } - pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index { + pub fn resolveSymbol(file: File, ind: Symbol.Index, elf_file: *Elf) Elf.Ref { + return switch (file) { + inline else => |x| x.resolveSymbol(ind, elf_file), + }; + } + + pub fn symbol(file: File, ind: Symbol.Index) *Symbol { return switch (file) { .zig_object => |x| x.symbol(ind), - inline else => |x| x.symbols.items[ind], + inline else => |x| &x.symbols.items[ind], }; } diff --git a/src/link/Elf/gc.zig b/src/link/Elf/gc.zig index de2d43f738..e0680d5db6 100644 --- a/src/link/Elf/gc.zig +++ b/src/link/Elf/gc.zig @@ -1,71 +1,84 @@ pub fn gcAtoms(elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; - const num_files = elf_file.objects.items.len + @intFromBool(elf_file.zig_object_index != null); - var files = try std.ArrayList(File.Index).initCapacity(gpa, num_files); - defer files.deinit(); - if (elf_file.zig_object_index) |index| files.appendAssumeCapacity(index); - for (elf_file.objects.items) |index| files.appendAssumeCapacity(index); - var roots = std.ArrayList(*Atom).init(gpa); defer roots.deinit(); - try collectRoots(&roots, files.items, elf_file); - + try collectRoots(&roots, elf_file); mark(roots, elf_file); - prune(files.items, elf_file); + prune(elf_file); } -fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_file: *Elf) !void { +fn collectRoots(roots: *std.ArrayList(*Atom), elf_file: *Elf) !void { if (elf_file.linkerDefinedPtr()) |obj| { - if (obj.entry_index) |index| { - const global = elf_file.symbol(index); - try markSymbol(global, roots, elf_file); + if (obj.entrySymbol(elf_file)) |sym| { + try markSymbol(sym, roots, elf_file); } } - for (files) |index| { - for (elf_file.file(index).?.globals()) |global_index| { - const global = elf_file.symbol(global_index); - if (global.file(elf_file)) |file| { - if (file.index() == index and global.flags.@"export") - try markSymbol(global, roots, elf_file); + if (elf_file.zigObjectPtr()) |zo| { + for (0..zo.global_symbols.items.len) |i| { + const ref = zo.resolveSymbol(@intCast(i | ZigObject.global_symbol_bit), elf_file); + const sym = elf_file.symbol(ref) orelse continue; + if (sym.file(elf_file).?.index() != zo.index) continue; + if (sym.flags.@"export") { + try markSymbol(sym, roots, elf_file); } } } - for (files) |index| { - const file = elf_file.file(index).?; - - for (file.atoms()) |atom_index| { - const atom = file.atom(atom_index) orelse continue; - if (!atom.alive) continue; - - const shdr = atom.inputShdr(elf_file); - const name = atom.name(elf_file); - const is_gc_root = blk: { - if (shdr.sh_flags & elf.SHF_GNU_RETAIN != 0) break :blk true; - if (shdr.sh_type == elf.SHT_NOTE) break :blk true; - if (shdr.sh_type == elf.SHT_PREINIT_ARRAY) break :blk true; - if (shdr.sh_type == elf.SHT_INIT_ARRAY) break :blk true; - if (shdr.sh_type == elf.SHT_FINI_ARRAY) break :blk true; - if (mem.startsWith(u8, name, ".ctors")) break :blk true; - if (mem.startsWith(u8, name, ".dtors")) break :blk true; - if (mem.startsWith(u8, name, ".init")) break :blk true; - if (mem.startsWith(u8, name, ".fini")) break :blk true; - if (Elf.isCIdentifier(name)) break :blk true; - break :blk false; - }; - if (is_gc_root and markAtom(atom)) try roots.append(atom); - if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.visited = true; + for (elf_file.objects.items) |index| { + const object = elf_file.file(index).?.object; + for (0..object.globals().len) |i| { + const ref = object.resolveSymbol(@intCast(i), elf_file); + const sym = elf_file.symbol(ref) orelse continue; + if (sym.file(elf_file).?.index() != object.index) continue; + if (sym.flags.@"export") { + try markSymbol(sym, roots, elf_file); + } } + } - // Mark every atom referenced by CIE as alive. - for (file.cies()) |cie| { - for (cie.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(file.symbol(rel.r_sym())); - try markSymbol(sym, roots, elf_file); + const atomRoots = struct { + fn atomRoots(file: File, rs: anytype, ef: *Elf) !void { + for (file.atoms()) |atom_index| { + const atom = file.atom(atom_index) orelse continue; + if (!atom.alive) continue; + + const shdr = atom.inputShdr(ef); + const name = atom.name(ef); + const is_gc_root = blk: { + if (shdr.sh_flags & elf.SHF_GNU_RETAIN != 0) break :blk true; + if (shdr.sh_type == elf.SHT_NOTE) break :blk true; + if (shdr.sh_type == elf.SHT_PREINIT_ARRAY) break :blk true; + if (shdr.sh_type == elf.SHT_INIT_ARRAY) break :blk true; + if (shdr.sh_type == elf.SHT_FINI_ARRAY) break :blk true; + if (mem.startsWith(u8, name, ".ctors")) break :blk true; + if (mem.startsWith(u8, name, ".dtors")) break :blk true; + if (mem.startsWith(u8, name, ".init")) break :blk true; + if (mem.startsWith(u8, name, ".fini")) break :blk true; + if (Elf.isCIdentifier(name)) break :blk true; + break :blk false; + }; + if (is_gc_root and markAtom(atom)) try rs.append(atom); + if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.visited = true; + } + + // Mark every atom referenced by CIE as alive. + for (file.cies()) |cie| { + for (cie.relocs(ef)) |rel| { + const ref = file.resolveSymbol(rel.r_sym(), ef); + const sym = ef.symbol(ref) orelse continue; + try markSymbol(sym, rs, ef); + } } } + }.atomRoots; + + if (elf_file.zigObjectPtr()) |zo| { + try atomRoots(zo.asFile(), roots, elf_file); + } + for (elf_file.objects.items) |index| { + try atomRoots(elf_file.file(index).?, roots, elf_file); } } @@ -92,7 +105,8 @@ fn markLive(atom: *Atom, elf_file: *Elf) void { for (atom.fdes(elf_file)) |fde| { for (fde.relocs(elf_file)[1..]) |rel| { - const target_sym = elf_file.symbol(file.symbol(rel.r_sym())); + const ref = file.resolveSymbol(rel.r_sym(), elf_file); + const target_sym = elf_file.symbol(ref) orelse continue; const target_atom = target_sym.atom(elf_file) orelse continue; target_atom.alive = true; gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index }); @@ -101,7 +115,8 @@ fn markLive(atom: *Atom, elf_file: *Elf) void { } for (atom.relocs(elf_file)) |rel| { - const target_sym = elf_file.symbol(file.symbol(rel.r_sym())); + const ref = file.resolveSymbol(rel.r_sym(), elf_file); + const target_sym = elf_file.symbol(ref) orelse continue; if (target_sym.mergeSubsection(elf_file)) |msub| { msub.alive = true; continue; @@ -120,16 +135,23 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void { } } -fn prune(files: []const File.Index, elf_file: *Elf) void { - for (files) |index| { - const file = elf_file.file(index).?; - for (file.atoms()) |atom_index| { - const atom = file.atom(atom_index) orelse continue; - if (atom.alive and !atom.visited) { - atom.alive = false; - atom.markFdesDead(elf_file); +fn prune(elf_file: *Elf) void { + const pruneInFile = struct { + fn pruneInFile(file: File, ef: *Elf) void { + for (file.atoms()) |atom_index| { + const atom = file.atom(atom_index) orelse continue; + if (atom.alive and !atom.visited) { + atom.alive = false; + atom.markFdesDead(ef); + } } } + }.pruneInFile; + if (elf_file.zigObjectPtr()) |zo| { + pruneInFile(zo.asFile(), elf_file); + } + for (elf_file.objects.items) |index| { + pruneInFile(elf_file.file(index).?, elf_file); } } @@ -181,3 +203,4 @@ const Atom = @import("Atom.zig"); const Elf = @import("../Elf.zig"); const File = @import("file.zig").File; const Symbol = @import("Symbol.zig"); +const ZigObject = @import("ZigObject.zig"); diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index ce65b8eb72..92eace8501 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -37,7 +37,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co // First, we flush relocatable object file generated with our backends. if (elf_file.zigObjectPtr()) |zig_object| { - zig_object.resolveSymbols(elf_file); + try zig_object.resolveSymbols(elf_file); try elf_file.addCommentString(); try elf_file.finalizeMergeSections(); zig_object.claimUnresolvedObject(elf_file); @@ -383,7 +383,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void { shdr.sh_size = cg.size(elf_file); shdr.sh_link = elf_file.symtab_section_index.?; - const sym = elf_file.symbol(cg.symbol(elf_file)); + const sym = cg.symbol(elf_file); shdr.sh_info = sym.outputSymtabIndex(elf_file) orelse elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx(elf_file).?); } diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index df98b753b3..c767fb093c 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -251,15 +251,16 @@ pub const ZigGotSection = struct { pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index { const comp = elf_file.base.comp; const gpa = comp.gpa; + const zo = elf_file.zigObjectPtr().?; const index = try zig_got.allocateEntry(gpa); const entry = &zig_got.entries.items[index]; entry.* = sym_index; - const symbol = elf_file.symbol(sym_index); + const symbol = zo.symbol(sym_index); symbol.flags.has_zig_got = true; if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) { zig_got.flags.needs_rela = true; } - try symbol.addExtra(.{ .zig_got = index }, elf_file); + symbol.addExtra(.{ .zig_got = index }, elf_file); return index; } @@ -282,6 +283,7 @@ pub const ZigGotSection = struct { } pub fn writeOne(zig_got: *ZigGotSection, elf_file: *Elf, index: Index) !void { + const zo = elf_file.zigObjectPtr().?; if (zig_got.flags.dirty) { const needed_size = zig_got.size(elf_file); try elf_file.growAllocSection(elf_file.zig_got_section_index.?, needed_size); @@ -293,7 +295,7 @@ pub const ZigGotSection = struct { const off = zig_got.entryOffset(index, elf_file); const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file)); const entry = zig_got.entries.items[index]; - const value = elf_file.symbol(entry).address(.{}, elf_file); + const value = zo.symbol(entry).address(.{}, elf_file); switch (entry_size) { 2 => { var buf: [2]u8 = undefined; @@ -336,8 +338,9 @@ pub const ZigGotSection = struct { } pub fn writeAll(zig_got: ZigGotSection, elf_file: *Elf, writer: anytype) !void { + const zo = elf_file.zigObjectPtr().?; for (zig_got.entries.items) |entry| { - const symbol = elf_file.symbol(entry); + const symbol = zo.symbol(entry); const value = symbol.address(.{ .plt = false }, elf_file); try writeInt(value, elf_file, writer); } @@ -351,9 +354,10 @@ pub const ZigGotSection = struct { const comp = elf_file.base.comp; const gpa = comp.gpa; const cpu_arch = elf_file.getTarget().cpu.arch; + const zo = elf_file.zigObjectPtr().?; try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela()); for (zig_got.entries.items) |entry| { - const symbol = elf_file.symbol(entry); + const symbol = zo.symbol(entry); const offset = symbol.zigGotAddress(elf_file); elf_file.addRelaDynAssumeCapacity(.{ .offset = @intCast(offset), @@ -364,16 +368,18 @@ pub const ZigGotSection = struct { } pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void { + const zo = elf_file.zigObjectPtr().?; zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len)); for (zig_got.entries.items) |entry| { - const name = elf_file.symbol(entry).name(elf_file); + const name = zo.symbol(entry).name(elf_file); zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1; } } pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void { + const zo = elf_file.zigObjectPtr().?; for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| { - const symbol = elf_file.symbol(entry); + const symbol = zo.symbol(entry); const symbol_name = symbol.name(elf_file); const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(symbol_name); @@ -409,15 +415,18 @@ pub const ZigGotSection = struct { ) !void { _ = options; _ = unused_fmt_string; + const zig_got = ctx.zig_got; + const elf_file = ctx.elf_file; + const zo = elf_file.zigObjectPtr().?; try writer.writeAll(".zig.got\n"); - for (ctx.zig_got.entries.items, 0..) |entry, index| { - const symbol = ctx.elf_file.symbol(entry); + for (zig_got.entries.items, 0..) |entry, index| { + const symbol = zo.symbol(entry); try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ index, - ctx.zig_got.entryAddress(@intCast(index), ctx.elf_file), + zig_got.entryAddress(@intCast(index), elf_file), entry, - symbol.address(.{}, ctx.elf_file), - symbol.name(ctx.elf_file), + symbol.address(.{}, elf_file), + symbol.name(elf_file), }); } } @@ -446,7 +455,7 @@ pub const GotSection = struct { const Entry = struct { tag: Tag, - symbol_index: Symbol.Index, + ref: Elf.Ref, cell_index: Index, /// Returns how many indexes in the GOT this entry uses. @@ -477,25 +486,25 @@ pub const GotSection = struct { const last = got.entries.items[index - 1]; break :blk last.cell_index + @as(Index, @intCast(last.len())); } else 0; - entry.* = .{ .tag = undefined, .symbol_index = undefined, .cell_index = cell_index }; + entry.* = .{ .tag = undefined, .ref = undefined, .cell_index = cell_index }; return index; } - pub fn addGotSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index { + pub fn addGotSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !Index { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = try got.allocateEntry(gpa); const entry = &got.entries.items[index]; entry.tag = .got; - entry.symbol_index = sym_index; - const symbol = elf_file.symbol(sym_index); + entry.ref = ref; + const symbol = elf_file.symbol(ref).?; symbol.flags.has_got = true; if (symbol.flags.import or symbol.isIFunc(elf_file) or ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and !symbol.isAbs(elf_file))) { got.flags.needs_rela = true; } - try symbol.addExtra(.{ .got = index }, elf_file); + symbol.addExtra(.{ .got = index }, elf_file); return index; } @@ -506,48 +515,48 @@ pub const GotSection = struct { const index = try got.allocateEntry(gpa); const entry = &got.entries.items[index]; entry.tag = .tlsld; - entry.symbol_index = undefined; // unused + entry.ref = .{ .index = 0, .file = 0 }; // unused got.flags.needs_rela = true; got.tlsld_index = index; } - pub fn addTlsGdSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addTlsGdSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = try got.allocateEntry(gpa); const entry = &got.entries.items[index]; entry.tag = .tlsgd; - entry.symbol_index = sym_index; - const symbol = elf_file.symbol(sym_index); + entry.ref = ref; + const symbol = elf_file.symbol(ref).?; symbol.flags.has_tlsgd = true; if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true; - try symbol.addExtra(.{ .tlsgd = index }, elf_file); + symbol.addExtra(.{ .tlsgd = index }, elf_file); } - pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addGotTpSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = try got.allocateEntry(gpa); const entry = &got.entries.items[index]; entry.tag = .gottp; - entry.symbol_index = sym_index; - const symbol = elf_file.symbol(sym_index); + entry.ref = ref; + const symbol = elf_file.symbol(ref).?; symbol.flags.has_gottp = true; if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true; - try symbol.addExtra(.{ .gottp = index }, elf_file); + symbol.addExtra(.{ .gottp = index }, elf_file); } - pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addTlsDescSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = try got.allocateEntry(gpa); const entry = &got.entries.items[index]; entry.tag = .tlsdesc; - entry.symbol_index = sym_index; - const symbol = elf_file.symbol(sym_index); + entry.ref = ref; + const symbol = elf_file.symbol(ref).?; symbol.flags.has_tlsdesc = true; got.flags.needs_rela = true; - try symbol.addExtra(.{ .tlsdesc = index }, elf_file); + symbol.addExtra(.{ .tlsdesc = index }, elf_file); } pub fn size(got: GotSection, elf_file: *Elf) usize { @@ -564,10 +573,7 @@ pub const GotSection = struct { const apply_relocs = true; // TODO add user option for this for (got.entries.items) |entry| { - const symbol = switch (entry.tag) { - .tlsld => null, - inline else => elf_file.symbol(entry.symbol_index), - }; + const symbol = elf_file.symbol(entry.ref); switch (entry.tag) { .got => { const value = blk: { @@ -637,10 +643,7 @@ pub const GotSection = struct { try elf_file.rela_dyn.ensureUnusedCapacity(gpa, got.numRela(elf_file)); for (got.entries.items) |entry| { - const symbol = switch (entry.tag) { - .tlsld => null, - inline else => elf_file.symbol(entry.symbol_index), - }; + const symbol = elf_file.symbol(entry.ref); const extra = if (symbol) |s| s.extra(elf_file) else null; switch (entry.tag) { @@ -740,10 +743,7 @@ pub const GotSection = struct { const is_dyn_lib = elf_file.isEffectivelyDynLib(); var num: usize = 0; for (got.entries.items) |entry| { - const symbol = switch (entry.tag) { - .tlsld => null, - inline else => elf_file.symbol(entry.symbol_index), - }; + const symbol = elf_file.symbol(entry.ref); switch (entry.tag) { .got => if (symbol.?.flags.import or symbol.?.isIFunc(elf_file) or ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and @@ -775,24 +775,15 @@ pub const GotSection = struct { pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void { got.output_symtab_ctx.nlocals = @as(u32, @intCast(got.entries.items.len)); for (got.entries.items) |entry| { - const symbol_name = switch (entry.tag) { - .tlsld => "", - inline else => elf_file.symbol(entry.symbol_index).name(elf_file), - }; + const symbol_name = if (elf_file.symbol(entry.ref)) |sym| sym.name(elf_file) else ""; got.output_symtab_ctx.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1; } } pub fn writeSymtab(got: GotSection, elf_file: *Elf) void { for (got.entries.items, got.output_symtab_ctx.ilocal..) |entry, ilocal| { - const symbol = switch (entry.tag) { - .tlsld => null, - inline else => elf_file.symbol(entry.symbol_index), - }; - const symbol_name = switch (entry.tag) { - .tlsld => "", - inline else => symbol.?.name(elf_file), - }; + const symbol = elf_file.symbol(entry.ref); + const symbol_name = if (symbol) |s| s.name(elf_file) else ""; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(symbol_name); elf_file.strtab.appendAssumeCapacity('$'); @@ -828,36 +819,38 @@ pub const GotSection = struct { ) !void { _ = options; _ = unused_fmt_string; + const got = ctx.got; + const elf_file = ctx.elf_file; try writer.writeAll("GOT\n"); - for (ctx.got.entries.items) |entry| { - const symbol = ctx.elf_file.symbol(entry.symbol_index); - try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ + for (got.entries.items) |entry| { + const symbol = elf_file.symbol(entry.ref).?; + try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{ entry.cell_index, - entry.address(ctx.elf_file), - entry.symbol_index, - symbol.address(.{}, ctx.elf_file), - symbol.name(ctx.elf_file), + entry.address(elf_file), + entry.ref, + symbol.address(.{}, elf_file), + symbol.name(elf_file), }); } } }; pub const PltSection = struct { - symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, + symbols: std.ArrayListUnmanaged(Elf.Ref) = .{}, output_symtab_ctx: Elf.SymtabCtx = .{}, pub fn deinit(plt: *PltSection, allocator: Allocator) void { plt.symbols.deinit(allocator); } - pub fn addSymbol(plt: *PltSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addSymbol(plt: *PltSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = @as(u32, @intCast(plt.symbols.items.len)); - const symbol = elf_file.symbol(sym_index); + const symbol = elf_file.symbol(ref).?; symbol.flags.has_plt = true; - try symbol.addExtra(.{ .plt = index }, elf_file); - try plt.symbols.append(gpa, sym_index); + symbol.addExtra(.{ .plt = index }, elf_file); + try plt.symbols.append(gpa, ref); } pub fn size(plt: PltSection, elf_file: *Elf) usize { @@ -895,8 +888,8 @@ pub const PltSection = struct { const gpa = comp.gpa; const cpu_arch = elf_file.getTarget().cpu.arch; try elf_file.rela_plt.ensureUnusedCapacity(gpa, plt.numRela()); - for (plt.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (plt.symbols.items) |ref| { + const sym = elf_file.symbol(ref).?; assert(sym.flags.import); const extra = sym.extra(elf_file); const r_offset: u64 = @intCast(sym.gotPltAddress(elf_file)); @@ -916,16 +909,16 @@ pub const PltSection = struct { pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void { plt.output_symtab_ctx.nlocals = @as(u32, @intCast(plt.symbols.items.len)); - for (plt.symbols.items) |sym_index| { - const name = elf_file.symbol(sym_index).name(elf_file); + for (plt.symbols.items) |ref| { + const name = elf_file.symbol(ref).?.name(elf_file); plt.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1; } } pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void { const cpu_arch = elf_file.getTarget().cpu.arch; - for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |sym_index, ilocal| { - const sym = elf_file.symbol(sym_index); + for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |ref, ilocal| { + const sym = elf_file.symbol(ref).?; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file)); elf_file.strtab.appendSliceAssumeCapacity("$plt"); @@ -958,15 +951,17 @@ pub const PltSection = struct { ) !void { _ = options; _ = unused_fmt_string; + const plt = ctx.plt; + const elf_file = ctx.elf_file; try writer.writeAll("PLT\n"); - for (ctx.plt.symbols.items, 0..) |symbol_index, i| { - const symbol = ctx.elf_file.symbol(symbol_index); - try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ + for (plt.symbols.items, 0..) |ref, i| { + const symbol = elf_file.symbol(ref).?; + try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{ i, - symbol.pltAddress(ctx.elf_file), - symbol_index, - symbol.address(.{}, ctx.elf_file), - symbol.name(ctx.elf_file), + symbol.pltAddress(elf_file), + ref, + symbol.address(.{}, elf_file), + symbol.name(elf_file), }); } } @@ -988,8 +983,8 @@ pub const PltSection = struct { try writer.writeAll(&preamble); try writer.writeByteNTimes(0xcc, preambleSize(.x86_64) - preamble.len); - for (plt.symbols.items, 0..) |sym_index, i| { - const sym = elf_file.symbol(sym_index); + for (plt.symbols.items, 0..) |ref, i| { + const sym = elf_file.symbol(ref).?; const target_addr = sym.gotPltAddress(elf_file); const source_addr = sym.pltAddress(elf_file); disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4; @@ -1037,8 +1032,8 @@ pub const PltSection = struct { } } - for (plt.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (plt.symbols.items) |ref| { + const sym = elf_file.symbol(ref).?; const target_addr = sym.gotPltAddress(elf_file); const source_addr = sym.pltAddress(elf_file); const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); @@ -1075,7 +1070,7 @@ pub const GotPltSection = struct { _ = got_plt; { // [0]: _DYNAMIC - const symbol = elf_file.symbol(elf_file.linkerDefinedPtr().?.dynamic_index.?); + const symbol = elf_file.linkerDefinedPtr().?.dynamicSymbol(elf_file).?; try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little); } // [1]: 0x0 @@ -1093,22 +1088,22 @@ pub const GotPltSection = struct { }; pub const PltGotSection = struct { - symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, + symbols: std.ArrayListUnmanaged(Elf.Ref) = .{}, output_symtab_ctx: Elf.SymtabCtx = .{}, pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void { plt_got.symbols.deinit(allocator); } - pub fn addSymbol(plt_got: *PltGotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addSymbol(plt_got: *PltGotSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = @as(u32, @intCast(plt_got.symbols.items.len)); - const symbol = elf_file.symbol(sym_index); + const symbol = elf_file.symbol(ref).?; symbol.flags.has_plt = true; symbol.flags.has_got = true; - try symbol.addExtra(.{ .plt_got = index }, elf_file); - try plt_got.symbols.append(gpa, sym_index); + symbol.addExtra(.{ .plt_got = index }, elf_file); + try plt_got.symbols.append(gpa, ref); } pub fn size(plt_got: PltGotSection, elf_file: *Elf) usize { @@ -1134,15 +1129,15 @@ pub const PltGotSection = struct { pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void { plt_got.output_symtab_ctx.nlocals = @as(u32, @intCast(plt_got.symbols.items.len)); - for (plt_got.symbols.items) |sym_index| { - const name = elf_file.symbol(sym_index).name(elf_file); + for (plt_got.symbols.items) |ref| { + const name = elf_file.symbol(ref).?.name(elf_file); plt_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1; } } pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf) void { - for (plt_got.symbols.items, plt_got.output_symtab_ctx.ilocal..) |sym_index, ilocal| { - const sym = elf_file.symbol(sym_index); + for (plt_got.symbols.items, plt_got.output_symtab_ctx.ilocal..) |ref, ilocal| { + const sym = elf_file.symbol(ref).?; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file)); elf_file.strtab.appendSliceAssumeCapacity("$pltgot"); @@ -1160,8 +1155,8 @@ pub const PltGotSection = struct { const x86_64 = struct { pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { - for (plt_got.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (plt_got.symbols.items) |ref| { + const sym = elf_file.symbol(ref).?; const target_addr = sym.gotAddress(elf_file); const source_addr = sym.pltGotAddress(elf_file); const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 6)) - 4; @@ -1178,8 +1173,8 @@ pub const PltGotSection = struct { const aarch64 = struct { fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { - for (plt_got.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (plt_got.symbols.items) |ref| { + const sym = elf_file.symbol(ref).?; const target_addr = sym.gotAddress(elf_file); const source_addr = sym.pltGotAddress(elf_file); const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); @@ -1204,56 +1199,56 @@ pub const PltGotSection = struct { }; pub const CopyRelSection = struct { - symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, + symbols: std.ArrayListUnmanaged(Elf.Ref) = .{}, pub fn deinit(copy_rel: *CopyRelSection, allocator: Allocator) void { copy_rel.symbols.deinit(allocator); } - pub fn addSymbol(copy_rel: *CopyRelSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addSymbol(copy_rel: *CopyRelSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = @as(u32, @intCast(copy_rel.symbols.items.len)); - const symbol = elf_file.symbol(sym_index); + const symbol = elf_file.symbol(ref).?; symbol.flags.import = true; symbol.flags.@"export" = true; symbol.flags.has_copy_rel = true; symbol.flags.weak = false; - try symbol.addExtra(.{ .copy_rel = index }, elf_file); - try copy_rel.symbols.append(gpa, sym_index); + symbol.addExtra(.{ .copy_rel = index }, elf_file); + try copy_rel.symbols.append(gpa, ref); const shared_object = symbol.file(elf_file).?.shared_object; if (shared_object.aliases == null) { try shared_object.initSymbolAliases(elf_file); } - const aliases = shared_object.symbolAliases(sym_index, elf_file); + const aliases = shared_object.symbolAliases(ref.index, elf_file); for (aliases) |alias| { - if (alias == sym_index) continue; - const alias_sym = elf_file.symbol(alias); + if (alias == ref.index) continue; + const alias_sym = &shared_object.symbols.items[alias]; alias_sym.flags.import = true; alias_sym.flags.@"export" = true; alias_sym.flags.has_copy_rel = true; alias_sym.flags.needs_copy_rel = true; alias_sym.flags.weak = false; - try elf_file.dynsym.addSymbol(alias, elf_file); + try elf_file.dynsym.addSymbol(.{ .index = alias, .file = shared_object.index }, elf_file); } } pub fn updateSectionSize(copy_rel: CopyRelSection, shndx: u32, elf_file: *Elf) !void { const shdr = &elf_file.shdrs.items[shndx]; - for (copy_rel.symbols.items) |sym_index| { - const symbol = elf_file.symbol(sym_index); + for (copy_rel.symbols.items) |ref| { + const symbol = elf_file.symbol(ref).?; const shared_object = symbol.file(elf_file).?.shared_object; const alignment = try symbol.dsoAlignment(elf_file); symbol.value = @intCast(mem.alignForward(u64, shdr.sh_size, alignment)); shdr.sh_addralign = @max(shdr.sh_addralign, alignment); shdr.sh_size = @as(u64, @intCast(symbol.value)) + symbol.elfSym(elf_file).st_size; - const aliases = shared_object.symbolAliases(sym_index, elf_file); + const aliases = shared_object.symbolAliases(ref.index, elf_file); for (aliases) |alias| { - if (alias == sym_index) continue; - const alias_sym = elf_file.symbol(alias); + if (alias == ref.index) continue; + const alias_sym = &shared_object.symbols.items[alias]; alias_sym.value = symbol.value; } } @@ -1264,8 +1259,8 @@ pub const CopyRelSection = struct { const gpa = comp.gpa; const cpu_arch = elf_file.getTarget().cpu.arch; try elf_file.rela_dyn.ensureUnusedCapacity(gpa, copy_rel.numRela()); - for (copy_rel.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (copy_rel.symbols.items) |ref| { + const sym = elf_file.symbol(ref).?; assert(sym.flags.import and sym.flags.has_copy_rel); const extra = sym.extra(elf_file); elf_file.addRelaDynAssumeCapacity(.{ @@ -1285,8 +1280,8 @@ pub const DynsymSection = struct { entries: std.ArrayListUnmanaged(Entry) = .{}, pub const Entry = struct { - /// Index of the symbol which gets privilege of getting a dynamic treatment - symbol_index: Symbol.Index, + /// Ref of the symbol which gets privilege of getting a dynamic treatment + ref: Elf.Ref, /// Offset into .dynstrtab off: u32, }; @@ -1295,22 +1290,22 @@ pub const DynsymSection = struct { dynsym.entries.deinit(allocator); } - pub fn addSymbol(dynsym: *DynsymSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addSymbol(dynsym: *DynsymSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = @as(u32, @intCast(dynsym.entries.items.len + 1)); - const sym = elf_file.symbol(sym_index); + const sym = elf_file.symbol(ref).?; sym.flags.has_dynamic = true; - try sym.addExtra(.{ .dynamic = index }, elf_file); + sym.addExtra(.{ .dynamic = index }, elf_file); const off = try elf_file.insertDynString(sym.name(elf_file)); - try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off }); + try dynsym.entries.append(gpa, .{ .ref = ref, .off = off }); } pub fn sort(dynsym: *DynsymSection, elf_file: *Elf) void { const Sort = struct { pub fn lessThan(ctx: *Elf, lhs: Entry, rhs: Entry) bool { - const lhs_sym = ctx.symbol(lhs.symbol_index); - const rhs_sym = ctx.symbol(rhs.symbol_index); + const lhs_sym = ctx.symbol(lhs.ref).?; + const rhs_sym = ctx.symbol(rhs.ref).?; if (lhs_sym.flags.@"export" != rhs_sym.flags.@"export") { return rhs_sym.flags.@"export"; @@ -1329,7 +1324,7 @@ pub const DynsymSection = struct { var num_exports: u32 = 0; for (dynsym.entries.items) |entry| { - const sym = elf_file.symbol(entry.symbol_index); + const sym = elf_file.symbol(entry.ref).?; if (sym.flags.@"export") num_exports += 1; } @@ -1338,7 +1333,7 @@ pub const DynsymSection = struct { std.mem.sort(Entry, dynsym.entries.items, elf_file, Sort.lessThan); for (dynsym.entries.items, 1..) |entry, index| { - const sym = elf_file.symbol(entry.symbol_index); + const sym = elf_file.symbol(entry.ref).?; var extra = sym.extra(elf_file); extra.dynamic = @as(u32, @intCast(index)); sym.setExtra(extra, elf_file); @@ -1356,7 +1351,7 @@ pub const DynsymSection = struct { pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: anytype) !void { try writer.writeStruct(Elf.null_sym); for (dynsym.entries.items) |entry| { - const sym = elf_file.symbol(entry.symbol_index); + const sym = elf_file.symbol(entry.ref).?; var out_sym: elf.Elf64_Sym = Elf.null_sym; sym.setOutputSym(elf_file, &out_sym); out_sym.st_name = entry.off; @@ -1429,7 +1424,7 @@ pub const GnuHashSection = struct { fn getExports(elf_file: *Elf) []const DynsymSection.Entry { const start = for (elf_file.dynsym.entries.items, 0..) |entry, i| { - const sym = elf_file.symbol(entry.symbol_index); + const sym = elf_file.symbol(entry.ref).?; if (sym.flags.@"export") break i; } else elf_file.dynsym.entries.items.len; return elf_file.dynsym.entries.items[start..]; @@ -1477,7 +1472,7 @@ pub const GnuHashSection = struct { @memset(bloom, 0); for (exports, 0..) |entry, i| { - const sym = elf_file.symbol(entry.symbol_index); + const sym = elf_file.symbol(entry.ref).?; const h = hasher(sym.name(elf_file)); hashes[i] = h; indices[i] = h % hash.num_buckets; @@ -1574,7 +1569,7 @@ pub const VerneedSection = struct { try verneed.ensureTotalCapacity(dynsyms.len); for (dynsyms, 1..) |entry, i| { - const symbol = elf_file.symbol(entry.symbol_index); + const symbol = elf_file.symbol(entry.ref).?; if (symbol.flags.import and symbol.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) { const shared_object = symbol.file(elf_file).?.shared_object; verneed.appendAssumeCapacity(.{ @@ -1677,11 +1672,11 @@ pub const ComdatGroupSection = struct { return cg_file.object.comdatGroup(cgs.cg_ref.index); } - pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index { + pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) *Symbol { const cg = cgs.comdatGroup(elf_file); const object = cg.file(elf_file).object; const shdr = object.shdrs.items[cg.shndx]; - return object.symbols.items[shdr.sh_info]; + return &object.symbols.items[shdr.sh_info]; } pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize { diff --git a/src/link/Elf/thunks.zig b/src/link/Elf/thunks.zig index 8353eea98a..c62c81bd38 100644 --- a/src/link/Elf/thunks.zig +++ b/src/link/Elf/thunks.zig @@ -43,11 +43,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { else => @panic("unsupported arch"), }; if (is_reachable) continue; - const target = switch (file) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, - }; + const target = file.resolveSymbol(rel.r_sym(), elf_file); try thunk.symbols.put(gpa, target, {}); } atom.addExtra(.{ .thunk = thunk_index }, elf_file); @@ -80,7 +76,7 @@ fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 { pub const Thunk = struct { value: i64 = 0, output_section_index: u32 = 0, - symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, + symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .{}, output_symtab_ctx: Elf.SymtabCtx = .{}, pub fn deinit(thunk: *Thunk, allocator: Allocator) void { @@ -97,9 +93,9 @@ pub const Thunk = struct { return @as(i64, @intCast(shdr.sh_addr)) + thunk.value; } - pub fn targetAddress(thunk: Thunk, sym_index: Symbol.Index, elf_file: *Elf) i64 { + pub fn targetAddress(thunk: Thunk, ref: Elf.Ref, elf_file: *Elf) i64 { const cpu_arch = elf_file.getTarget().cpu.arch; - return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(sym_index).? * trampolineSize(cpu_arch))); + return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(ref).? * trampolineSize(cpu_arch))); } pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { @@ -112,16 +108,16 @@ pub const Thunk = struct { pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void { thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len)); - for (thunk.symbols.keys()) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (thunk.symbols.keys()) |ref| { + const sym = elf_file.symbol(ref).?; thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1)); } } pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void { const cpu_arch = elf_file.getTarget().cpu.arch; - for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |sym_index, ilocal| { - const sym = elf_file.symbol(sym_index); + for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| { + const sym = elf_file.symbol(ref).?; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file)); elf_file.strtab.appendSliceAssumeCapacity("$thunk"); @@ -131,7 +127,7 @@ pub const Thunk = struct { .st_info = elf.STT_FUNC, .st_other = 0, .st_shndx = @intCast(thunk.output_section_index), - .st_value = @intCast(thunk.targetAddress(sym_index, elf_file)), + .st_value = @intCast(thunk.targetAddress(ref, elf_file)), .st_size = trampolineSize(cpu_arch), }; } @@ -181,9 +177,9 @@ pub const Thunk = struct { const thunk = ctx.thunk; const elf_file = ctx.elf_file; try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) }); - for (thunk.symbols.keys()) |index| { - const sym = elf_file.symbol(index); - try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.name(elf_file), sym.value }); + for (thunk.symbols.keys()) |ref| { + const sym = elf_file.symbol(ref).?; + try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value }); } } @@ -195,12 +191,8 @@ const aarch64 = struct { const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); if (r_type != .CALL26 and r_type != .JUMP26) return true; const file = atom.file(elf_file).?; - const target_index = switch (file) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, - }; - const target = elf_file.symbol(target_index); + const target_ref = file.resolveSymbol(rel.r_sym(), elf_file); + const target = elf_file.symbol(target_ref).?; if (target.flags.has_plt) return false; if (atom.output_section_index != target.output_section_index) return false; const target_atom = target.atom(elf_file).?; @@ -212,8 +204,8 @@ const aarch64 = struct { } fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { - for (thunk.symbols.keys(), 0..) |sym_index, i| { - const sym = elf_file.symbol(sym_index); + for (thunk.symbols.keys(), 0..) |ref, i| { + const sym = elf_file.symbol(ref).?; const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size)); const taddr = sym.address(.{}, elf_file); const pages = try util.calcNumberOfPages(saddr, taddr); |
