Commit deeaa1bb0c
Changed files (7)
src/link/Elf/file.zig
@@ -153,19 +153,6 @@ pub const File = union(enum) {
};
}
- pub fn locals(file: File) []const Symbol.Index {
- return switch (file) {
- .linker_defined, .shared_object => &[0]Symbol.Index{},
- inline else => |x| x.locals(),
- };
- }
-
- pub fn globals(file: File) []const Symbol.Index {
- return switch (file) {
- inline else => |x| x.globals(),
- };
- }
-
pub fn getString(file: File, off: u32) [:0]const u8 {
return switch (file) {
inline else => |x| x.getString(off),
src/link/Elf/LinkerDefined.zig
@@ -302,12 +302,8 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {
}
}
-pub fn globals(self: *LinkerDefined) []Symbol {
- return self.symbols.items;
-}
-
pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {
- for (self.globals(), self.symbols_resolver.items) |*global, resolv| {
+ for (self.symbols.items, self.symbols_resolver.items) |*global, resolv| {
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;
@@ -324,7 +320,7 @@ pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {
}
pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf) void {
- for (self.globals(), self.symbols_resolver.items) |global, resolv| {
+ for (self.symbols.items, self.symbols_resolver.items) |global, resolv| {
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;
src/link/Elf/Object.zig
@@ -676,6 +676,29 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {
}
}
+pub fn markImportsExports(self: *Object, elf_file: *Elf) void {
+ const first_global = self.first_global orelse return;
+ for (0..self.globals().len) |i| {
+ const idx = first_global + i;
+ const ref = self.resolveSymbol(@intCast(idx), elf_file);
+ const sym = elf_file.symbol(ref) orelse continue;
+ const file = sym.file(elf_file).?;
+ if (sym.version_index == elf.VER_NDX_LOCAL) continue;
+ const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
+ if (vis == .HIDDEN) continue;
+ if (file == .shared_object and !sym.isAbs(elf_file)) {
+ sym.flags.import = true;
+ continue;
+ }
+ if (file.index() == self.index) {
+ sym.flags.@"export" = true;
+ if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
+ sym.flags.import = true;
+ }
+ }
+ }
+}
+
pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
const first_global = self.first_global orelse return;
for (0..self.globals().len) |i| {
@@ -1169,14 +1192,14 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index
return data;
}
-pub fn locals(self: *Object) []Symbol {
+fn locals(self: *Object) []Symbol {
if (self.symbols.items.len == 0) return &[0]Symbol{};
assert(self.symbols.items.len >= self.symtab.items.len);
const end = self.first_global orelse self.symtab.items.len;
return self.symbols.items[0..end];
}
-pub fn globals(self: *Object) []Symbol {
+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;
src/link/Elf/Symbol.zig
@@ -63,9 +63,7 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
}
pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
- if (symbol.flags.global) return elf_file.strings.getAssumeExists(symbol.name_offset);
- const file_ptr = symbol.file(elf_file).?;
- return switch (file_ptr) {
+ return switch (symbol.file(elf_file).?) {
inline else => |x| x.getString(symbol.name_offset),
};
}
@@ -87,9 +85,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
}
pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
- const file_ptr = symbol.file(elf_file).?;
- return switch (file_ptr) {
- .zig_object => |x| x.elfSym(symbol.esym_index).*,
+ return switch (symbol.file(elf_file).?) {
inline else => |x| x.symtab.items[symbol.esym_index],
};
}
@@ -423,12 +419,6 @@ pub const Flags = packed struct {
/// Whether this symbol is weak.
weak: bool = false,
- /// Whether the symbol has its name interned in global symbol
- /// resolver table.
- /// This happens for any symbol that is considered a global
- /// symbol, but is not necessarily an import or export.
- global: bool = false,
-
/// Whether the symbol makes into the output symtab.
output_symtab: bool = false,
src/link/Elf/ZigObject.zig
@@ -8,9 +8,11 @@ data: std.ArrayListUnmanaged(u8) = .{},
path: []const u8,
index: File.Index,
-local_esyms: std.MultiArrayList(ElfSym) = .{},
-global_esyms: std.MultiArrayList(ElfSym) = .{},
+symtab: std.MultiArrayList(ElfSym) = .{},
strtab: StringTable = .{},
+symbols: std.ArrayListUnmanaged(Symbol) = .{},
+symbols_extra: std.ArrayListUnmanaged(u32) = .{},
+symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
@@ -113,9 +115,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
pub fn deinit(self: *ZigObject, allocator: Allocator) void {
self.data.deinit(allocator);
- self.local_esyms.deinit(allocator);
- self.global_esyms.deinit(allocator);
+ self.symtab.deinit(allocator);
self.strtab.deinit(allocator);
+ self.symbols.deinit(allocator);
+ self.symbols_extra.deinit(allocator);
+ self.symbols_resolver.deinit(allocator);
self.local_symbols.deinit(allocator);
self.global_symbols.deinit(allocator);
self.globals_lookup.deinit(allocator);
@@ -263,51 +267,73 @@ fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
}
}
-pub fn addLocalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
- try self.local_esyms.ensureUnusedCapacity(allocator, 1);
- const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));
- var esym = ElfSym{ .elf_sym = Elf.null_sym };
- esym.elf_sym.st_info = elf.STB_LOCAL << 4;
- self.local_esyms.set(index, esym);
+fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) !Symbol.Index {
+ try self.symtab.ensureUnusedCapacity(allocator, 1);
+ try self.symbols.ensureUnusedCapacity(allocator, 1);
+ try self.symbols_extra.ensureUnusedCapacity(allocator, @sizeOf(Symbol.Extra));
+
+ const index = self.addSymbolAssumeCapacity();
+ const sym = &self.symbols.items[index];
+ sym.name_offset = name_off;
+ sym.extra = self.addSymbolExtraAssumeCapacity(.{});
+
+ const esym_idx: u32 = @intCast(self.symtab.addOneAssumeCapacity());
+ const esym = ElfSym{ .elf_sym = .{
+ .st_value = 0,
+ .st_name = name_off,
+ .st_info = @as(u8, @intCast(st_bind)) << 4,
+ .st_other = 0,
+ .st_size = 0,
+ .st_shndx = 0,
+ } };
+ self.symtab.set(index, esym);
+ sym.esym_index = esym_idx;
+
return index;
}
-pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
- try self.global_esyms.ensureUnusedCapacity(allocator, 1);
- const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity()));
- var esym = ElfSym{ .elf_sym = Elf.null_sym };
- esym.elf_sym.st_info = elf.STB_GLOBAL << 4;
- self.global_esyms.set(index, esym);
- return index | global_symbol_bit;
+fn newLocalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
+ try self.local_symbols.ensureUnusedCapacity(allocator, 1);
+ const fake_index: Symbol.Index = @intCast(self.local_symbols.items.len);
+ const index = try self.newSymbol(allocator, name_off, elf.STB_LOCAL);
+ self.local_symbols.appendAssumeCapacity(index);
+ return fake_index;
}
-pub fn newAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
- const gpa = elf_file.base.comp.gpa;
- const atom_index = try self.addAtom(gpa);
- const symbol_index = try elf_file.addSymbol();
- const esym_index = try self.addLocalEsym(gpa);
-
- try self.atoms_indexes.append(gpa, atom_index);
- try self.local_symbols.append(gpa, symbol_index);
-
- const symbol_ptr = elf_file.symbol(symbol_index);
- symbol_ptr.file_index = self.index;
- symbol_ptr.ref = .{ .index = atom_index, .file = self.index };
- symbol_ptr.extra_index = try elf_file.addSymbolExtra(.{});
+fn newGlobalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
+ try self.global_symbols.ensureUnusedCapacity(allocator, 1);
+ const fake_index: Symbol.Index = @intCast(self.global_symbols.items.len);
+ const index = try self.newSymbol(allocator, name_off, elf.STB_GLOBAL);
+ self.global_symbols.appendAssumeCapacity(index);
+ return fake_index | global_symbol_bit;
+}
- self.local_esyms.items(.shndx)[esym_index] = atom_index;
- self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;
- symbol_ptr.esym_index = esym_index;
+fn newAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Atom.Index {
+ try self.atoms.ensureUnusedCapacity(allocator, 1);
+ try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
+ try self.atoms_indexes.ensureUnusedCapacity(allocator, 1);
+ try self.relocs.ensureUnusedCapacity(allocator, 1);
- // TODO I'm thinking that maybe we shouldn' set this value unless it's actually needed?
- const relocs_index = @as(u32, @intCast(self.relocs.items.len));
- const relocs = try self.relocs.addOne(gpa);
- relocs.* = .{};
+ const index = self.addAtomAssumeCapacity();
+ self.atoms_indexes.appendAssumeCapacity(index);
+ const atom_ptr = self.atom(index).?;
+ atom_ptr.name_offset = name_off;
- const atom_ptr = self.atom(atom_index).?;
+ const relocs_index: u32 = @intCast(self.relocs.items.len);
+ self.relocs.addOneAssumeCapacity().* = .{};
atom_ptr.relocs_section_index = relocs_index;
- return symbol_index;
+ return index;
+}
+
+fn newSymbolWithAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
+ const atom_index = try self.newAtom(allocator, name_off);
+ const sym_index = try self.newLocalSymbol(allocator, name_off);
+ const sym = self.symbol(sym_index);
+ sym.ref = .{ .index = atom_index, .file = self.index };
+ self.symtab.items(.shndx)[sym.esym_index] = atom_index;
+ self.symtab.items(.elf_sym)[sym.esym_index].st_shndx = SHN_ATOM;
+ return sym_index;
}
/// TODO actually create fake input shdrs and return that instead.
@@ -322,48 +348,47 @@ pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.E
return shdr;
}
-pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
- for (self.globals(), 0..) |index, i| {
- const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
- const esym = self.global_esyms.items(.elf_sym)[i];
- const shndx = self.global_esyms.items(.shndx)[i];
-
- if (esym.st_shndx == elf.SHN_UNDEF) continue;
+pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) !void {
+ const gpa = elf_file.base.comp.gpa;
+ for (self.global_symbols.items, 0..) |index, i| {
+ const global = &self.symbols.items[index];
+ const esym = global.elfSym(elf_file);
+ const shndx = self.symtab.items(.shndx)[global.esym_index];
if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
assert(esym.st_shndx == SHN_ATOM);
const atom_ptr = self.atom(shndx) orelse continue;
if (!atom_ptr.alive) continue;
}
- const global = elf_file.symbol(index);
- if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {
- const atom_index = switch (esym.st_shndx) {
- elf.SHN_ABS, elf.SHN_COMMON => 0,
- SHN_ATOM => shndx,
- else => unreachable,
- };
- global.value = @intCast(esym.st_value);
- global.ref = .{ .index = atom_index, .file = self.index };
- global.esym_index = esym_index;
- global.file_index = self.index;
- global.version_index = elf_file.default_sym_version;
- if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;
+ const resolv = &self.symbols_resolver.items[i];
+ const gop = try elf_file.resolver.getOrPut(gpa, .{
+ .index = @intCast(i | global_symbol_bit),
+ .file = self.index,
+ }, elf_file);
+ if (!gop.found_existing) {
+ gop.ref.* = .{ .index = 0, .file = 0 };
+ }
+ resolv.* = gop.index;
+
+ if (esym.st_shndx == elf.SHN_UNDEF) continue;
+ if (elf_file.symbol(gop.ref.*) == null) {
+ gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
+ continue;
+ }
+
+ if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
+ gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
}
}
}
-pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
- for (self.globals(), 0..) |index, i| {
- const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
- const esym = self.global_esyms.items(.elf_sym)[i];
-
+pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
+ for (self.global_symbols.items, 0..) |index, i| {
+ const global = &self.symbols.items[index];
+ const esym = self.symtab.items(.elf_sym)[index];
if (esym.st_shndx != elf.SHN_UNDEF) continue;
-
- const global = elf_file.symbol(index);
- if (global.file(elf_file)) |_| {
- if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue;
- }
+ if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue;
const is_import = blk: {
if (!elf_file.isEffectivelyDynLib()) break :blk false;
@@ -374,29 +399,36 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
global.value = 0;
global.ref = .{ .index = 0, .file = 0 };
- global.esym_index = esym_index;
+ global.esym_index = @intCast(index);
global.file_index = self.index;
global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
global.flags.import = is_import;
+
+ const idx = self.symbols_resolver.items[i];
+ elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
}
}
pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
- for (self.globals(), 0..) |index, i| {
- const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
- const esym = self.global_esyms.items(.elf_sym)[i];
-
+ for (self.global_symbols.items, 0..) |index, i| {
+ const global = &self.symbols.items[index];
+ const esym = self.symtab.items(.elf_sym)[index];
if (esym.st_shndx != elf.SHN_UNDEF) continue;
+ if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue;
- const global = elf_file.symbol(index);
- if (global.file(elf_file)) |file| {
- if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
- }
+ // TODO: audit this
+ // const global = elf_file.symbol(index);
+ // if (global.file(elf_file)) |file| {
+ // if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
+ // }
global.value = 0;
global.ref = .{ .index = 0, .file = 0 };
- global.esym_index = esym_index;
+ global.esym_index = @intCast(index);
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 };
}
}
@@ -419,12 +451,14 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
}
pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
- for (self.globals(), 0..) |index, i| {
- const esym = self.global_esyms.items(.elf_sym)[i];
+ for (self.global_symbols.items, 0..) |index, i| {
+ const global = self.symbols.items[index];
+ const esym = self.symtab.items(.elf_sym)[index];
if (esym.st_bind() == elf.STB_WEAK) continue;
- const global = elf_file.symbol(index);
- const file = global.file(elf_file) orelse continue;
+ const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
+ const sym = elf_file.symbol(ref) orelse continue;
+ const file = sym.file(elf_file).?;
const should_keep = esym.st_shndx == elf.SHN_UNDEF or
(esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
if (should_keep and !file.isAlive()) {
@@ -434,14 +468,36 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
}
}
-pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
- for (self.globals(), 0..) |index, i| {
- const esym = self.global_esyms.items(.elf_sym)[i];
- const shndx = self.global_esyms.items(.shndx)[i];
- const global = elf_file.symbol(index);
- const global_file = global.file(elf_file) orelse continue;
+pub fn markImportsExports(self: *Object, 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;
+ const file = sym.file(elf_file).?;
+ if (sym.version_index == elf.VER_NDX_LOCAL) continue;
+ const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
+ if (vis == .HIDDEN) continue;
+ if (file == .shared_object and !sym.isAbs(elf_file)) {
+ sym.flags.import = true;
+ continue;
+ }
+ if (file.index() == self.index) {
+ sym.flags.@"export" = true;
+ if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
+ sym.flags.import = true;
+ }
+ }
+ }
+}
- if (self.index == global_file.index() or
+pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
+ for (self.global_symbols.items, 0..) |index, i| {
+ const esym = self.symtab.items(.elf_sym)[index];
+ const shndx = self.symtab.items(.shndx)[index];
+ const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
+ const ref_sym = elf_file.symbol(ref) orelse continue;
+ const ref_file = ref_sym.file(elf_file).?;
+
+ if (self.index == ref_file.index() or
esym.st_shndx == elf.SHN_UNDEF or
esym.st_bind() == elf.STB_WEAK or
esym.st_shndx == elf.SHN_COMMON) continue;
@@ -451,7 +507,7 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O
if (!atom_ptr.alive) continue;
}
- const gop = try dupes.getOrPut(index);
+ const gop = try dupes.getOrPut(self.symbols_resolver.items[i]);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
@@ -483,12 +539,13 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {
pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {
const gpa = elf_file.base.comp.gpa;
- try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len);
+ try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.global_symbols.items.len);
- for (self.globals()) |global_index| {
- const global = elf_file.symbol(global_index);
- const file_ptr = global.file(elf_file).?;
- assert(file_ptr.index() == self.index);
+ for (self.global_symbols.items, 0..) |index, i| {
+ const global = self.symbols.items[index];
+ const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
+ const sym = elf_file.symbol(ref).?;
+ assert(sym.file(elf_file).?.index() == self.index);
if (global.outputShndx(elf_file) == null) continue;
const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));
@@ -530,33 +587,9 @@ pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
}
}
-inline fn isGlobal(index: Symbol.Index) bool {
- return index & global_symbol_bit != 0;
-}
-
-pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index {
- const actual_index = index & symbol_mask;
- if (isGlobal(index)) return self.globals()[actual_index];
- return self.locals()[actual_index];
-}
-
-pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
- const actual_index = index & symbol_mask;
- if (isGlobal(index)) return &self.global_esyms.items(.elf_sym)[actual_index];
- return &self.local_esyms.items(.elf_sym)[actual_index];
-}
-
-pub fn locals(self: ZigObject) []const Symbol.Index {
- return self.local_symbols.items;
-}
-
-pub fn globals(self: ZigObject) []const Symbol.Index {
- return self.global_symbols.items;
-}
-
pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
- for (self.locals()) |local_index| {
- const local = elf_file.symbol(local_index);
+ for (self.local_symbols.items) |index| {
+ const local = &self.symbols.items[index];
if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
const esym = local.elfSym(elf_file);
switch (esym.st_type()) {
@@ -564,22 +597,23 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
else => {},
}
local.flags.output_symtab = true;
- try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
+ local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
self.output_symtab_ctx.nlocals += 1;
self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
}
- for (self.globals()) |global_index| {
- const global = elf_file.symbol(global_index);
- const file_ptr = global.file(elf_file) orelse continue;
- if (file_ptr.index() != self.index) continue;
+ 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_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;
global.flags.output_symtab = true;
if (global.isLocal(elf_file)) {
- try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
+ global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
self.output_symtab_ctx.nlocals += 1;
} else {
- try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
+ global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
self.output_symtab_ctx.nglobals += 1;
}
self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
@@ -587,8 +621,8 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
}
pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
- for (self.locals()) |local_index| {
- const local = elf_file.symbol(local_index);
+ for (self.local_symbols.items) |index| {
+ const local = &self.symbols.items[index];
const idx = local.outputSymtabIndex(elf_file) orelse continue;
const out_sym = &elf_file.symtab.items[idx];
out_sym.st_name = @intCast(elf_file.strtab.items.len);
@@ -597,10 +631,11 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
local.setOutputSym(elf_file, out_sym);
}
- for (self.globals()) |global_index| {
- const global = elf_file.symbol(global_index);
- const file_ptr = global.file(elf_file) orelse continue;
- if (file_ptr.index() != self.index) continue;
+ 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_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;
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
@@ -611,10 +646,6 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
}
}
-pub fn asFile(self: *ZigObject) File {
- return .{ .zig_object = self };
-}
-
/// Returns atom's code.
/// Caller owns the memory.
pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
@@ -755,8 +786,8 @@ pub fn getOrCreateMetadataForLazySymbol(
};
switch (metadata.state.*) {
.unused => {
- const symbol_index = try self.newAtom(elf_file);
- const sym = elf_file.symbol(symbol_index);
+ const symbol_index = try self.newSymbolWithAtom(gpa, 0);
+ const sym = self.symbol(symbol_index);
sym.flags.needs_zig_got = true;
metadata.symbol_index.* = symbol_index;
},
@@ -817,10 +848,10 @@ pub fn getOrCreateMetadataForDecl(
const gop = try self.decls.getOrPut(gpa, decl_index);
if (!gop.found_existing) {
const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
- const symbol_index = try self.newAtom(elf_file);
+ const symbol_index = try self.newSymbolWithAtom(gpa, 0);
const mod = elf_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
- const sym = elf_file.symbol(symbol_index);
+ const sym = self.symbol(symbol_index);
if (decl.getOwnedVariable(mod)) |variable| {
if (variable.is_threadlocal and any_non_single_threaded) {
sym.flags.is_tls = true;
@@ -1064,7 +1095,7 @@ pub fn updateFunc(
const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
self.freeUnnamedConsts(elf_file, decl_index);
- elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
+ self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
@@ -1096,7 +1127,7 @@ pub fn updateFunc(
try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_FUNC);
if (decl_state) |*ds| {
- const sym = elf_file.symbol(sym_index);
+ const sym = self.symbol(sym_index);
try self.dwarf.?.commitDeclState(
pt,
decl_index,
@@ -1130,13 +1161,13 @@ pub fn updateDecl(
const variable = decl.getOwnedVariable(mod).?;
const name = decl.name.toSlice(&mod.intern_pool);
const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
- const esym_index = try self.getGlobalSymbol(elf_file, name, lib_name);
- elf_file.symbol(self.symbol(esym_index)).flags.needs_got = true;
+ const sym_index = try self.getGlobalSymbol(elf_file, name, lib_name);
+ self.symbol(sym_index).flags.needs_got = true;
return;
}
const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
- elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
+ self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
const gpa = elf_file.base.comp.gpa;
var code_buffer = std.ArrayList(u8).init(gpa);
@@ -1174,7 +1205,7 @@ pub fn updateDecl(
try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_OBJECT);
if (decl_state) |*ds| {
- const sym = elf_file.symbol(sym_index);
+ const sym = self.symbol(sym_index);
try self.dwarf.?.commitDeclState(
pt,
decl_index,
@@ -1323,7 +1354,8 @@ fn lowerConst(
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
- const sym_index = try self.newAtom(elf_file);
+ const name_off = try self.addString(gpa, name);
+ const sym_index = try self.newSymbolWithAtom(gpa, name_off);
const res = try codegen.generateSymbol(
&elf_file.base,
@@ -1339,27 +1371,19 @@ fn lowerConst(
.fail => |em| return .{ .fail = em },
};
- const local_sym = elf_file.symbol(sym_index);
- const name_str_index = try self.strtab.insert(gpa, name);
- local_sym.name_offset = name_str_index;
- const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
- local_esym.st_name = name_str_index;
+ const local_sym = self.symbol(sym_index);
+ const local_esym = local_sym.elfSym(elf_file);
local_esym.st_info |= elf.STT_OBJECT;
local_esym.st_size = code.len;
const atom_ptr = local_sym.atom(elf_file).?;
atom_ptr.alive = true;
- atom_ptr.name_offset = name_str_index;
atom_ptr.alignment = required_alignment;
atom_ptr.size = code.len;
atom_ptr.output_section_index = output_section_index;
try atom_ptr.allocate(elf_file);
- // TODO rename and re-audit this method
errdefer self.freeDeclMetadata(elf_file, sym_index);
- local_sym.value = 0;
- local_esym.st_value = 0;
-
const shdr = elf_file.shdrs.items[output_section_index];
const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
try elf_file.base.file.?.pwriteAll(code, file_offset);
@@ -1401,9 +1425,9 @@ pub fn updateExports(
},
};
const sym_index = metadata.symbol_index;
- const esym_index = elf_file.symbol(sym_index).esym_index;
- const esym = self.local_esyms.items(.elf_sym)[esym_index];
- const esym_shndx = self.local_esyms.items(.shndx)[esym_index];
+ const esym_index = self.symbol(sym_index).esym_index;
+ const esym = self.symtab.items(.elf_sym)[esym_index];
+ const esym_shndx = self.symtab.items(.shndx)[esym_index];
for (export_indices) |export_idx| {
const exp = mod.all_exports.items[export_idx];
@@ -1437,22 +1461,27 @@ pub fn updateExports(
const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
const name_off = try self.strtab.insert(gpa, exp_name);
- const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
+ const global_sym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
exp_index.*
else blk: {
- const global_esym_index = try self.getGlobalSymbol(elf_file, exp_name, null);
- try metadata.exports.append(gpa, global_esym_index);
- break :blk global_esym_index;
+ const global_sym_index = try self.getGlobalSymbol(elf_file, exp_name, null);
+ try metadata.exports.append(gpa, global_sym_index);
+ break :blk global_sym_index;
};
- const actual_esym_index = global_esym_index & symbol_mask;
- const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index];
- global_esym.st_value = @intCast(elf_file.symbol(sym_index).value);
+ const value = self.symbol(sym_index).value;
+ 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.ref = .{ .index = esym_shndx, .file = self.index };
+ const global_esym = global_sym.elfSym(elf_file);
+ global_esym.st_value = @intCast(value);
global_esym.st_shndx = esym.st_shndx;
global_esym.st_info = (stb_bits << 4) | stt_bits;
global_esym.st_name = name_off;
global_esym.st_size = esym.st_size;
- self.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;
+ self.symtab.items(.shndx)[global_sym.esym_index] = esym_shndx;
}
}
@@ -1506,16 +1535,19 @@ 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) {
- const esym_index = try self.addGlobalEsym(gpa);
- const esym = self.elfSym(esym_index);
- esym.st_name = off;
- lookup_gop.value_ptr.* = esym_index;
- const gop = try elf_file.getOrPutGlobal(name);
- try self.global_symbols.append(gpa, gop.index);
+ lookup_gop.value_ptr.* = try self.newSymbol(gpa, off);
}
return lookup_gop.value_ptr.*;
}
+pub fn asFile(self: *ZigObject) File {
+ return .{ .zig_object = self };
+}
+
+fn addString(self: *ZigObject, allocator: Allocator, string: []const u8) !u32 {
+ return self.strtab.insert(allocator, string);
+}
+
pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
return self.strtab.getAssumeExists(off);
}
@@ -1586,6 +1618,73 @@ pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {
}
}
+inline fn isGlobal(index: Symbol.Index) bool {
+ return index & global_symbol_bit != 0;
+}
+
+pub fn symbol(self: *ZigObject, index: Symbol.Index) *Symbol {
+ const actual_index = index & symbol_mask;
+ if (isGlobal(index)) return &self.symbols.items[self.global_symbols.items[actual_index]];
+ return &self.symbols.items[self.local_symbols.items[actual_index]];
+}
+
+pub fn resolveSymbol(self: ZigObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
+ if (isGlobal(index)) {
+ const resolv = self.symbols_resolver.items[index & symbol_mask];
+ return elf_file.resolver.get(resolv).?;
+ }
+ return .{ .index = index, .file = self.index };
+}
+
+pub fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index {
+ try self.symbols.ensureUnusedCapacity(allocator, 1);
+ const index: Symbol.Index = @intCast(self.symbols.items.len);
+ self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
+ return index;
+}
+
+pub fn addSymbolExtra(self: *ZigObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
+ const fields = @typeInfo(Symbol.Extra).Struct.fields;
+ try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
+ return self.addSymbolExtraAssumeCapacity(extra);
+}
+
+pub fn addSymbolExtraAssumeCapacity(self: *ZigObject, extra: Symbol.Extra) u32 {
+ const index = @as(u32, @intCast(self.symbols_extra.items.len));
+ const fields = @typeInfo(Symbol.Extra).Struct.fields;
+ inline for (fields) |field| {
+ self.symbols_extra.appendAssumeCapacity(switch (field.type) {
+ u32 => @field(extra, field.name),
+ else => @compileError("bad field type"),
+ });
+ }
+ return index;
+}
+
+pub fn symbolExtra(self: *ZigObject, index: u32) Symbol.Extra {
+ const fields = @typeInfo(Symbol.Extra).Struct.fields;
+ var i: usize = index;
+ var result: Symbol.Extra = undefined;
+ inline for (fields) |field| {
+ @field(result, field.name) = switch (field.type) {
+ u32 => self.symbols_extra.items[i],
+ else => @compileError("bad field type"),
+ };
+ i += 1;
+ }
+ return result;
+}
+
+pub fn setSymbolExtra(self: *ZigObject, index: u32, extra: Symbol.Extra) void {
+ const fields = @typeInfo(Symbol.Extra).Struct.fields;
+ inline for (fields, 0..) |field, i| {
+ self.symbols_extra.items[index + i] = switch (field.type) {
+ u32 => @field(extra, field.name),
+ else => @compileError("bad field type"),
+ };
+ }
+}
+
pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
return .{ .data = .{
.self = self,
@@ -1658,9 +1757,9 @@ const DeclMetadata = struct {
/// A list of all exports aliases of this Decl.
exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
- fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
+ fn @"export"(m: DeclMetadata, zo: *ZigObject, name: []const u8) ?*u32 {
for (m.exports.items) |*exp| {
- const exp_name = zig_object.getString(zig_object.elfSym(exp.*).st_name);
+ const exp_name = zo.getString(zo.symbol(exp.*).name_off);
if (mem.eql(u8, name, exp_name)) return exp;
}
return null;
src/link/Elf.zig
@@ -173,11 +173,7 @@ shstrtab_section_index: ?u32 = null,
strtab_section_index: ?u32 = null,
symtab_section_index: ?u32 = null,
-/// An array of symbols parsed across all input files.
-symbols: std.ArrayListUnmanaged(Symbol) = .{},
-symbols_extra: std.ArrayListUnmanaged(u32) = .{},
-
-resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
+resolver: SymbolResolver = .{},
has_text_reloc: bool = false,
num_ifunc_dynrelocs: usize = 0,
@@ -191,10 +187,6 @@ merge_sections: std.ArrayListUnmanaged(MergeSection) = .{},
/// Table of last atom index in a section and matching atom free list if any.
last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
-/// Global string table used to provide quick access to global symbol resolvers
-/// such as `resolver`.
-strings: StringTable = .{},
-
first_eflags: ?elf.Elf64_Word = null,
/// When allocating, the ideal_capacity is calculated by
@@ -455,8 +447,6 @@ pub fn deinit(self: *Elf) void {
self.shstrtab.deinit(gpa);
self.symtab.deinit(gpa);
self.strtab.deinit(gpa);
- self.symbols.deinit(gpa);
- self.symbols_extra.deinit(gpa);
self.resolver.deinit(gpa);
for (self.thunks.items) |*th| {
@@ -472,8 +462,6 @@ pub fn deinit(self: *Elf) void {
}
self.last_atom_and_free_list_table.deinit(gpa);
- self.strings.deinit(gpa);
-
self.got.deinit(gpa);
self.plt.deinit(gpa);
self.plt_got.deinit(gpa);
@@ -1916,20 +1904,17 @@ fn accessLibPath(
/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
pub fn resolveSymbols(self: *Elf) !void {
// Resolve symbols in the ZigObject. For now, we assume that it's always live.
- if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
+ if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
// Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
- for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
- for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
- if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);
+ for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
+ for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
+ if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
// Mark live objects.
self.markLive();
// Reset state of all globals after marking live objects.
- if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);
- for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
- for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
- if (self.linkerDefinedPtr()) |obj| obj.asFile().resetGlobals(self);
+ self.resolver.reset();
// Prune dead objects and shared objects.
var i: usize = 0;
@@ -1962,10 +1947,10 @@ pub fn resolveSymbols(self: *Elf) !void {
}
// Re-resolve the symbols.
- if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
- for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
- for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
- if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);
+ if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
+ for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
+ for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
+ if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
}
/// Traverses all objects and shared objects marking any object referenced by
@@ -1999,46 +1984,17 @@ fn convertCommonSymbols(self: *Elf) !void {
}
fn markImportsExports(self: *Elf) void {
- const mark = struct {
- fn mark(elf_file: *Elf, file_index: File.Index) void {
- for (elf_file.file(file_index).?.globals()) |global_index| {
- const global = elf_file.symbol(global_index);
- if (global.version_index == elf.VER_NDX_LOCAL) continue;
- const file_ptr = global.file(elf_file) orelse continue;
- const vis = @as(elf.STV, @enumFromInt(global.elfSym(elf_file).st_other));
- if (vis == .HIDDEN) continue;
- if (file_ptr == .shared_object and !global.isAbs(elf_file)) {
- global.flags.import = true;
- continue;
- }
- if (file_ptr.index() == file_index) {
- global.flags.@"export" = true;
- if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
- global.flags.import = true;
- }
- }
- }
- }
- }.mark;
-
+ if (self.zigObjectPtr()) |zo| {
+ zo.markImportsExports(self);
+ }
+ for (self.objects.items) |index| {
+ self.file(index).?.object.markImportsExports(self);
+ }
if (!self.isEffectivelyDynLib()) {
for (self.shared_objects.items) |index| {
- for (self.file(index).?.globals()) |global_index| {
- const global = self.symbol(global_index);
- const file_ptr = global.file(self) orelse continue;
- const vis = @as(elf.STV, @enumFromInt(global.elfSym(self).st_other));
- if (file_ptr != .shared_object and vis != .HIDDEN) global.flags.@"export" = true;
- }
+ self.file(index).?.shared_object.markImportExports(self);
}
}
-
- if (self.zig_object_index) |index| {
- mark(self, index);
- }
-
- for (self.objects.items) |index| {
- mark(self, index);
- }
}
fn claimUnresolved(self: *Elf) void {