authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-08-01 08:50:01+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-08-07 10:21:02+02:00
logdeeaa1bb0cb8a8c7ccebb23cc68be64e4b013ab2
tree0b1e93cb77cff05de14485b646e985f7dcba9ecf
parentde80e4fec2a29c5aac70c8d72b11a90cb96feeaf

elf: redo symbol mgmt and ownership in ZigObject


7 files changed, 335 insertions(+), 278 deletions(-)

src/link/Elf.zig+17-61
...@@ -173,11 +173,7 @@ shstrtab_section_index: ?u32 = null,...@@ -173,11 +173,7 @@ shstrtab_section_index: ?u32 = null,
173strtab_section_index: ?u32 = null,173strtab_section_index: ?u32 = null,
174symtab_section_index: ?u32 = null,174symtab_section_index: ?u32 = null,
175175
176/// An array of symbols parsed across all input files.176resolver: SymbolResolver = .{},
177symbols: std.ArrayListUnmanaged(Symbol) = .{},
178symbols_extra: std.ArrayListUnmanaged(u32) = .{},
179
180resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
181177
182has_text_reloc: bool = false,178has_text_reloc: bool = false,
183num_ifunc_dynrelocs: usize = 0,179num_ifunc_dynrelocs: usize = 0,
...@@ -191,10 +187,6 @@ merge_sections: std.ArrayListUnmanaged(MergeSection) = .{},...@@ -191,10 +187,6 @@ merge_sections: std.ArrayListUnmanaged(MergeSection) = .{},
191/// Table of last atom index in a section and matching atom free list if any.187/// Table of last atom index in a section and matching atom free list if any.
192last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},188last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
193189
194/// Global string table used to provide quick access to global symbol resolvers
195/// such as `resolver`.
196strings: StringTable = .{},
197
198first_eflags: ?elf.Elf64_Word = null,190first_eflags: ?elf.Elf64_Word = null,
199191
200/// When allocating, the ideal_capacity is calculated by192/// When allocating, the ideal_capacity is calculated by
...@@ -455,8 +447,6 @@ pub fn deinit(self: *Elf) void {...@@ -455,8 +447,6 @@ pub fn deinit(self: *Elf) void {
455 self.shstrtab.deinit(gpa);447 self.shstrtab.deinit(gpa);
456 self.symtab.deinit(gpa);448 self.symtab.deinit(gpa);
457 self.strtab.deinit(gpa);449 self.strtab.deinit(gpa);
458 self.symbols.deinit(gpa);
459 self.symbols_extra.deinit(gpa);
460 self.resolver.deinit(gpa);450 self.resolver.deinit(gpa);
461451
462 for (self.thunks.items) |*th| {452 for (self.thunks.items) |*th| {
...@@ -472,8 +462,6 @@ pub fn deinit(self: *Elf) void {...@@ -472,8 +462,6 @@ pub fn deinit(self: *Elf) void {
472 }462 }
473 self.last_atom_and_free_list_table.deinit(gpa);463 self.last_atom_and_free_list_table.deinit(gpa);
474464
475 self.strings.deinit(gpa);
476
477 self.got.deinit(gpa);465 self.got.deinit(gpa);
478 self.plt.deinit(gpa);466 self.plt.deinit(gpa);
479 self.plt_got.deinit(gpa);467 self.plt_got.deinit(gpa);
...@@ -1916,20 +1904,17 @@ fn accessLibPath(...@@ -1916,20 +1904,17 @@ fn accessLibPath(
1916/// 6. Re-run symbol resolution on pruned objects and shared objects sets.1904/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1917pub fn resolveSymbols(self: *Elf) !void {1905pub fn resolveSymbols(self: *Elf) !void {
1918 // Resolve symbols in the ZigObject. For now, we assume that it's always live.1906 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
1919 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);1907 if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
1920 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).1908 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
1921 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);1909 for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
1922 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);1910 for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
1923 if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);1911 if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
19241912
1925 // Mark live objects.1913 // Mark live objects.
1926 self.markLive();1914 self.markLive();
19271915
1928 // Reset state of all globals after marking live objects.1916 // Reset state of all globals after marking live objects.
1929 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);1917 self.resolver.reset();
1930 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
1931 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
1932 if (self.linkerDefinedPtr()) |obj| obj.asFile().resetGlobals(self);
19331918
1934 // Prune dead objects and shared objects.1919 // Prune dead objects and shared objects.
1935 var i: usize = 0;1920 var i: usize = 0;
...@@ -1962,10 +1947,10 @@ pub fn resolveSymbols(self: *Elf) !void {...@@ -1962,10 +1947,10 @@ pub fn resolveSymbols(self: *Elf) !void {
1962 }1947 }
19631948
1964 // Re-resolve the symbols.1949 // Re-resolve the symbols.
1965 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);1950 if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
1966 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);1951 for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
1967 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);1952 for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
1968 if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);1953 if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
1969}1954}
19701955
1971/// Traverses all objects and shared objects marking any object referenced by1956/// Traverses all objects and shared objects marking any object referenced by
...@@ -1999,46 +1984,17 @@ fn convertCommonSymbols(self: *Elf) !void {...@@ -1999,46 +1984,17 @@ fn convertCommonSymbols(self: *Elf) !void {
1999}1984}
20001985
2001fn markImportsExports(self: *Elf) void {1986fn markImportsExports(self: *Elf) void {
2002 const mark = struct {1987 if (self.zigObjectPtr()) |zo| {
2003 fn mark(elf_file: *Elf, file_index: File.Index) void {1988 zo.markImportsExports(self);
2004 for (elf_file.file(file_index).?.globals()) |global_index| {1989 }
2005 const global = elf_file.symbol(global_index);1990 for (self.objects.items) |index| {
2006 if (global.version_index == elf.VER_NDX_LOCAL) continue;1991 self.file(index).?.object.markImportsExports(self);
2007 const file_ptr = global.file(elf_file) orelse continue;1992 }
2008 const vis = @as(elf.STV, @enumFromInt(global.elfSym(elf_file).st_other));
2009 if (vis == .HIDDEN) continue;
2010 if (file_ptr == .shared_object and !global.isAbs(elf_file)) {
2011 global.flags.import = true;
2012 continue;
2013 }
2014 if (file_ptr.index() == file_index) {
2015 global.flags.@"export" = true;
2016 if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
2017 global.flags.import = true;
2018 }
2019 }
2020 }
2021 }
2022 }.mark;
2023
2024 if (!self.isEffectivelyDynLib()) {1993 if (!self.isEffectivelyDynLib()) {
2025 for (self.shared_objects.items) |index| {1994 for (self.shared_objects.items) |index| {
2026 for (self.file(index).?.globals()) |global_index| {1995 self.file(index).?.shared_object.markImportExports(self);
2027 const global = self.symbol(global_index);
2028 const file_ptr = global.file(self) orelse continue;
2029 const vis = @as(elf.STV, @enumFromInt(global.elfSym(self).st_other));
2030 if (file_ptr != .shared_object and vis != .HIDDEN) global.flags.@"export" = true;
2031 }
2032 }1996 }
2033 }1997 }
2034
2035 if (self.zig_object_index) |index| {
2036 mark(self, index);
2037 }
2038
2039 for (self.objects.items) |index| {
2040 mark(self, index);
2041 }
2042}1998}
20431999
2044fn claimUnresolved(self: *Elf) void {2000fn claimUnresolved(self: *Elf) void {
src/link/Elf/LinkerDefined.zig+2-6
...@@ -302,12 +302,8 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -302,12 +302,8 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {
302 }302 }
303}303}
304304
305pub fn globals(self: *LinkerDefined) []Symbol {
306 return self.symbols.items;
307}
308
309pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {305pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {
310 for (self.globals(), self.symbols_resolver.items) |*global, resolv| {306 for (self.symbols.items, self.symbols_resolver.items) |*global, resolv| {
311 const ref = elf_file.resolver.get(resolv).?;307 const ref = elf_file.resolver.get(resolv).?;
312 const ref_sym = elf_file.symbol(ref) orelse continue;308 const ref_sym = elf_file.symbol(ref) orelse continue;
313 if (ref_sym.file(elf_file).?.index() != self.index) continue;309 if (ref_sym.file(elf_file).?.index() != self.index) continue;
...@@ -324,7 +320,7 @@ pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {...@@ -324,7 +320,7 @@ pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {
324}320}
325321
326pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf) void {322pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf) void {
327 for (self.globals(), self.symbols_resolver.items) |global, resolv| {323 for (self.symbols.items, self.symbols_resolver.items) |global, resolv| {
328 const ref = elf_file.resolver.get(resolv).?;324 const ref = elf_file.resolver.get(resolv).?;
329 const ref_sym = elf_file.symbol(ref) orelse continue;325 const ref_sym = elf_file.symbol(ref) orelse continue;
330 if (ref_sym.file(elf_file).?.index() != self.index) continue;326 if (ref_sym.file(elf_file).?.index() != self.index) continue;
src/link/Elf/Object.zig+25-2
...@@ -676,6 +676,29 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {...@@ -676,6 +676,29 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {
676 }676 }
677}677}
678678
679pub fn markImportsExports(self: *Object, elf_file: *Elf) void {
680 const first_global = self.first_global orelse return;
681 for (0..self.globals().len) |i| {
682 const idx = first_global + i;
683 const ref = self.resolveSymbol(@intCast(idx), elf_file);
684 const sym = elf_file.symbol(ref) orelse continue;
685 const file = sym.file(elf_file).?;
686 if (sym.version_index == elf.VER_NDX_LOCAL) continue;
687 const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
688 if (vis == .HIDDEN) continue;
689 if (file == .shared_object and !sym.isAbs(elf_file)) {
690 sym.flags.import = true;
691 continue;
692 }
693 if (file.index() == self.index) {
694 sym.flags.@"export" = true;
695 if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
696 sym.flags.import = true;
697 }
698 }
699 }
700}
701
679pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {702pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
680 const first_global = self.first_global orelse return;703 const first_global = self.first_global orelse return;
681 for (0..self.globals().len) |i| {704 for (0..self.globals().len) |i| {
...@@ -1169,14 +1192,14 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index...@@ -1169,14 +1192,14 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index
1169 return data;1192 return data;
1170}1193}
11711194
1172pub fn locals(self: *Object) []Symbol {1195fn locals(self: *Object) []Symbol {
1173 if (self.symbols.items.len == 0) return &[0]Symbol{};1196 if (self.symbols.items.len == 0) return &[0]Symbol{};
1174 assert(self.symbols.items.len >= self.symtab.items.len);1197 assert(self.symbols.items.len >= self.symtab.items.len);
1175 const end = self.first_global orelse self.symtab.items.len;1198 const end = self.first_global orelse self.symtab.items.len;
1176 return self.symbols.items[0..end];1199 return self.symbols.items[0..end];
1177}1200}
11781201
1179pub fn globals(self: *Object) []Symbol {1202fn globals(self: *Object) []Symbol {
1180 if (self.symbols.items.len == 0) return &[0]Symbol{};1203 if (self.symbols.items.len == 0) return &[0]Symbol{};
1181 assert(self.symbols.items.len >= self.symtab.items.len);1204 assert(self.symbols.items.len >= self.symtab.items.len);
1182 const start = self.first_global orelse self.symtab.items.len;1205 const start = self.first_global orelse self.symtab.items.len;
src/link/Elf/SharedObject.zig+11-5
...@@ -282,12 +282,18 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {...@@ -282,12 +282,18 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
282 }282 }
283}283}
284284
285pub fn globals(self: *SharedObject) []Symbol {285pub fn markImportExports(self: *SharedObject, elf_file: *Elf) void {
286 return self.symbols.items;286 for (0..self.symbols.items.len) |i| {
287 const ref = self.resolveSymbol(@intCast(i), elf_file);
288 const ref_sym = elf_file.symbol(ref) orelse continue;
289 const ref_file = ref_sym.file(self).?;
290 const vis = @as(elf.STV, @enumFromInt(ref_sym.elfSym(self).st_other));
291 if (ref_file != .shared_object and vis != .HIDDEN) ref_sym.flags.@"export" = true;
292 }
287}293}
288294
289pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void {295pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void {
290 for (self.globals(), self.symbols_resolver.items) |*global, resolv| {296 for (self.symbols.items, self.symbols_resolver.items) |*global, resolv| {
291 const ref = elf_file.resolver.get(resolv).?;297 const ref = elf_file.resolver.get(resolv).?;
292 const ref_sym = elf_file.symbol(ref) orelse continue;298 const ref_sym = elf_file.symbol(ref) orelse continue;
293 if (ref_sym.file(elf_file).?.index() != self.index) continue;299 if (ref_sym.file(elf_file).?.index() != self.index) continue;
...@@ -300,7 +306,7 @@ pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void {...@@ -300,7 +306,7 @@ pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void {
300}306}
301307
302pub fn writeSymtab(self: *SharedObject, elf_file: *Elf) void {308pub fn writeSymtab(self: *SharedObject, elf_file: *Elf) void {
303 for (self.globals(), self.symbols_resolver.items) |global, resolv| {309 for (self.symbols.items, self.symbols_resolver.items) |global, resolv| {
304 const ref = elf_file.resolver.get(resolv).?;310 const ref = elf_file.resolver.get(resolv).?;
305 const ref_sym = elf_file.symbol(ref) orelse continue;311 const ref_sym = elf_file.symbol(ref) orelse continue;
306 if (ref_sym.file(elf_file).?.index() != self.index) continue;312 if (ref_sym.file(elf_file).?.index() != self.index) continue;
...@@ -354,7 +360,7 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {...@@ -354,7 +360,7 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
354 const gpa = comp.gpa;360 const gpa = comp.gpa;
355 var aliases = std.ArrayList(Symbol.Index).init(gpa);361 var aliases = std.ArrayList(Symbol.Index).init(gpa);
356 defer aliases.deinit();362 defer aliases.deinit();
357 try aliases.ensureTotalCapacityPrecise(self.globals().len);363 try aliases.ensureTotalCapacityPrecise(self.symbols.items.len);
358364
359 for (self.symbols_resolvers.items, 0..) |resolv, index| {365 for (self.symbols_resolvers.items, 0..) |resolv, index| {
360 const ref = elf_file.resolver.get(resolv).?;366 const ref = elf_file.resolver.get(resolv).?;
src/link/Elf/Symbol.zig+2-12
...@@ -63,9 +63,7 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {...@@ -63,9 +63,7 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
63}63}
6464
65pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {65pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
66 if (symbol.flags.global) return elf_file.strings.getAssumeExists(symbol.name_offset);66 return switch (symbol.file(elf_file).?) {
67 const file_ptr = symbol.file(elf_file).?;
68 return switch (file_ptr) {
69 inline else => |x| x.getString(symbol.name_offset),67 inline else => |x| x.getString(symbol.name_offset),
70 };68 };
71}69}
...@@ -87,9 +85,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {...@@ -87,9 +85,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
87}85}
8886
89pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {87pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
90 const file_ptr = symbol.file(elf_file).?;88 return switch (symbol.file(elf_file).?) {
91 return switch (file_ptr) {
92 .zig_object => |x| x.elfSym(symbol.esym_index).*,
93 inline else => |x| x.symtab.items[symbol.esym_index],89 inline else => |x| x.symtab.items[symbol.esym_index],
94 };90 };
95}91}
...@@ -423,12 +419,6 @@ pub const Flags = packed struct {...@@ -423,12 +419,6 @@ pub const Flags = packed struct {
423 /// Whether this symbol is weak.419 /// Whether this symbol is weak.
424 weak: bool = false,420 weak: bool = false,
425421
426 /// Whether the symbol has its name interned in global symbol
427 /// resolver table.
428 /// This happens for any symbol that is considered a global
429 /// symbol, but is not necessarily an import or export.
430 global: bool = false,
431
432 /// Whether the symbol makes into the output symtab.422 /// Whether the symbol makes into the output symtab.
433 output_symtab: bool = false,423 output_symtab: bool = false,
434424
src/link/Elf/ZigObject.zig+278-179
...@@ -8,9 +8,11 @@ data: std.ArrayListUnmanaged(u8) = .{},...@@ -8,9 +8,11 @@ data: std.ArrayListUnmanaged(u8) = .{},
8path: []const u8,8path: []const u8,
9index: File.Index,9index: File.Index,
1010
11local_esyms: std.MultiArrayList(ElfSym) = .{},11symtab: std.MultiArrayList(ElfSym) = .{},
12global_esyms: std.MultiArrayList(ElfSym) = .{},
13strtab: StringTable = .{},12strtab: StringTable = .{},
13symbols: std.ArrayListUnmanaged(Symbol) = .{},
14symbols_extra: std.ArrayListUnmanaged(u32) = .{},
15symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
14local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},16local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
15global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},17global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
16globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},18globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
...@@ -113,9 +115,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -113,9 +115,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
113115
114pub fn deinit(self: *ZigObject, allocator: Allocator) void {116pub fn deinit(self: *ZigObject, allocator: Allocator) void {
115 self.data.deinit(allocator);117 self.data.deinit(allocator);
116 self.local_esyms.deinit(allocator);118 self.symtab.deinit(allocator);
117 self.global_esyms.deinit(allocator);
118 self.strtab.deinit(allocator);119 self.strtab.deinit(allocator);
120 self.symbols.deinit(allocator);
121 self.symbols_extra.deinit(allocator);
122 self.symbols_resolver.deinit(allocator);
119 self.local_symbols.deinit(allocator);123 self.local_symbols.deinit(allocator);
120 self.global_symbols.deinit(allocator);124 self.global_symbols.deinit(allocator);
121 self.globals_lookup.deinit(allocator);125 self.globals_lookup.deinit(allocator);
...@@ -263,51 +267,73 @@ fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {...@@ -263,51 +267,73 @@ fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
263 }267 }
264}268}
265269
266pub fn addLocalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {270fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) !Symbol.Index {
267 try self.local_esyms.ensureUnusedCapacity(allocator, 1);271 try self.symtab.ensureUnusedCapacity(allocator, 1);
268 const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));272 try self.symbols.ensureUnusedCapacity(allocator, 1);
269 var esym = ElfSym{ .elf_sym = Elf.null_sym };273 try self.symbols_extra.ensureUnusedCapacity(allocator, @sizeOf(Symbol.Extra));
270 esym.elf_sym.st_info = elf.STB_LOCAL << 4;274
271 self.local_esyms.set(index, esym);275 const index = self.addSymbolAssumeCapacity();
276 const sym = &self.symbols.items[index];
277 sym.name_offset = name_off;
278 sym.extra = self.addSymbolExtraAssumeCapacity(.{});
279
280 const esym_idx: u32 = @intCast(self.symtab.addOneAssumeCapacity());
281 const esym = ElfSym{ .elf_sym = .{
282 .st_value = 0,
283 .st_name = name_off,
284 .st_info = @as(u8, @intCast(st_bind)) << 4,
285 .st_other = 0,
286 .st_size = 0,
287 .st_shndx = 0,
288 } };
289 self.symtab.set(index, esym);
290 sym.esym_index = esym_idx;
291
272 return index;292 return index;
273}293}
274294
275pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {295fn newLocalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
276 try self.global_esyms.ensureUnusedCapacity(allocator, 1);296 try self.local_symbols.ensureUnusedCapacity(allocator, 1);
277 const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity()));297 const fake_index: Symbol.Index = @intCast(self.local_symbols.items.len);
278 var esym = ElfSym{ .elf_sym = Elf.null_sym };298 const index = try self.newSymbol(allocator, name_off, elf.STB_LOCAL);
279 esym.elf_sym.st_info = elf.STB_GLOBAL << 4;299 self.local_symbols.appendAssumeCapacity(index);
280 self.global_esyms.set(index, esym);300 return fake_index;
281 return index | global_symbol_bit;
282}301}
283302
284pub fn newAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {303fn newGlobalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
285 const gpa = elf_file.base.comp.gpa;304 try self.global_symbols.ensureUnusedCapacity(allocator, 1);
286 const atom_index = try self.addAtom(gpa);305 const fake_index: Symbol.Index = @intCast(self.global_symbols.items.len);
287 const symbol_index = try elf_file.addSymbol();306 const index = try self.newSymbol(allocator, name_off, elf.STB_GLOBAL);
288 const esym_index = try self.addLocalEsym(gpa);307 self.global_symbols.appendAssumeCapacity(index);
289308 return fake_index | global_symbol_bit;
290 try self.atoms_indexes.append(gpa, atom_index);309}
291 try self.local_symbols.append(gpa, symbol_index);
292
293 const symbol_ptr = elf_file.symbol(symbol_index);
294 symbol_ptr.file_index = self.index;
295 symbol_ptr.ref = .{ .index = atom_index, .file = self.index };
296 symbol_ptr.extra_index = try elf_file.addSymbolExtra(.{});
297310
298 self.local_esyms.items(.shndx)[esym_index] = atom_index;311fn newAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Atom.Index {
299 self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;312 try self.atoms.ensureUnusedCapacity(allocator, 1);
300 symbol_ptr.esym_index = esym_index;313 try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
314 try self.atoms_indexes.ensureUnusedCapacity(allocator, 1);
315 try self.relocs.ensureUnusedCapacity(allocator, 1);
301316
302 // TODO I'm thinking that maybe we shouldn' set this value unless it's actually needed?317 const index = self.addAtomAssumeCapacity();
303 const relocs_index = @as(u32, @intCast(self.relocs.items.len));318 self.atoms_indexes.appendAssumeCapacity(index);
304 const relocs = try self.relocs.addOne(gpa);319 const atom_ptr = self.atom(index).?;
305 relocs.* = .{};320 atom_ptr.name_offset = name_off;
306321
307 const atom_ptr = self.atom(atom_index).?;322 const relocs_index: u32 = @intCast(self.relocs.items.len);
323 self.relocs.addOneAssumeCapacity().* = .{};
308 atom_ptr.relocs_section_index = relocs_index;324 atom_ptr.relocs_section_index = relocs_index;
309325
310 return symbol_index;326 return index;
327}
328
329fn newSymbolWithAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
330 const atom_index = try self.newAtom(allocator, name_off);
331 const sym_index = try self.newLocalSymbol(allocator, name_off);
332 const sym = self.symbol(sym_index);
333 sym.ref = .{ .index = atom_index, .file = self.index };
334 self.symtab.items(.shndx)[sym.esym_index] = atom_index;
335 self.symtab.items(.elf_sym)[sym.esym_index].st_shndx = SHN_ATOM;
336 return sym_index;
311}337}
312338
313/// TODO actually create fake input shdrs and return that instead.339/// 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...@@ -322,48 +348,47 @@ pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.E
322 return shdr;348 return shdr;
323}349}
324350
325pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {351pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) !void {
326 for (self.globals(), 0..) |index, i| {352 const gpa = elf_file.base.comp.gpa;
327 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
328 const esym = self.global_esyms.items(.elf_sym)[i];
329 const shndx = self.global_esyms.items(.shndx)[i];
330
331 if (esym.st_shndx == elf.SHN_UNDEF) continue;
332353
354 for (self.global_symbols.items, 0..) |index, i| {
355 const global = &self.symbols.items[index];
356 const esym = global.elfSym(elf_file);
357 const shndx = self.symtab.items(.shndx)[global.esym_index];
333 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {358 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
334 assert(esym.st_shndx == SHN_ATOM);359 assert(esym.st_shndx == SHN_ATOM);
335 const atom_ptr = self.atom(shndx) orelse continue;360 const atom_ptr = self.atom(shndx) orelse continue;
336 if (!atom_ptr.alive) continue;361 if (!atom_ptr.alive) continue;
337 }362 }
338363
339 const global = elf_file.symbol(index);364 const resolv = &self.symbols_resolver.items[i];
340 if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {365 const gop = try elf_file.resolver.getOrPut(gpa, .{
341 const atom_index = switch (esym.st_shndx) {366 .index = @intCast(i | global_symbol_bit),
342 elf.SHN_ABS, elf.SHN_COMMON => 0,367 .file = self.index,
343 SHN_ATOM => shndx,368 }, elf_file);
344 else => unreachable,369 if (!gop.found_existing) {
345 };370 gop.ref.* = .{ .index = 0, .file = 0 };
346 global.value = @intCast(esym.st_value);371 }
347 global.ref = .{ .index = atom_index, .file = self.index };372 resolv.* = gop.index;
348 global.esym_index = esym_index;373
349 global.file_index = self.index;374 if (esym.st_shndx == elf.SHN_UNDEF) continue;
350 global.version_index = elf_file.default_sym_version;375 if (elf_file.symbol(gop.ref.*) == null) {
351 if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;376 gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
377 continue;
378 }
379
380 if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
381 gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
352 }382 }
353 }383 }
354}384}
355385
356pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {386pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
357 for (self.globals(), 0..) |index, i| {387 for (self.global_symbols.items, 0..) |index, i| {
358 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;388 const global = &self.symbols.items[index];
359 const esym = self.global_esyms.items(.elf_sym)[i];389 const esym = self.symtab.items(.elf_sym)[index];
360
361 if (esym.st_shndx != elf.SHN_UNDEF) continue;390 if (esym.st_shndx != elf.SHN_UNDEF) continue;
362391 if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue;
363 const global = elf_file.symbol(index);
364 if (global.file(elf_file)) |_| {
365 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue;
366 }
367392
368 const is_import = blk: {393 const is_import = blk: {
369 if (!elf_file.isEffectivelyDynLib()) break :blk false;394 if (!elf_file.isEffectivelyDynLib()) break :blk false;
...@@ -374,29 +399,36 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {...@@ -374,29 +399,36 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
374399
375 global.value = 0;400 global.value = 0;
376 global.ref = .{ .index = 0, .file = 0 };401 global.ref = .{ .index = 0, .file = 0 };
377 global.esym_index = esym_index;402 global.esym_index = @intCast(index);
378 global.file_index = self.index;403 global.file_index = self.index;
379 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;404 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
380 global.flags.import = is_import;405 global.flags.import = is_import;
406
407 const idx = self.symbols_resolver.items[i];
408 elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
381 }409 }
382}410}
383411
384pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {412pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
385 for (self.globals(), 0..) |index, i| {413 for (self.global_symbols.items, 0..) |index, i| {
386 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;414 const global = &self.symbols.items[index];
387 const esym = self.global_esyms.items(.elf_sym)[i];415 const esym = self.symtab.items(.elf_sym)[index];
388
389 if (esym.st_shndx != elf.SHN_UNDEF) continue;416 if (esym.st_shndx != elf.SHN_UNDEF) continue;
417 if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue;
390418
391 const global = elf_file.symbol(index);419 // TODO: audit this
392 if (global.file(elf_file)) |file| {420 // const global = elf_file.symbol(index);
393 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;421 // if (global.file(elf_file)) |file| {
394 }422 // if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
423 // }
395424
396 global.value = 0;425 global.value = 0;
397 global.ref = .{ .index = 0, .file = 0 };426 global.ref = .{ .index = 0, .file = 0 };
398 global.esym_index = esym_index;427 global.esym_index = @intCast(index);
399 global.file_index = self.index;428 global.file_index = self.index;
429
430 const idx = self.symbols_resolver.items[i];
431 elf_file.resolver.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
400 }432 }
401}433}
402434
...@@ -419,12 +451,14 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {...@@ -419,12 +451,14 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
419}451}
420452
421pub fn markLive(self: *ZigObject, elf_file: *Elf) void {453pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
422 for (self.globals(), 0..) |index, i| {454 for (self.global_symbols.items, 0..) |index, i| {
423 const esym = self.global_esyms.items(.elf_sym)[i];455 const global = self.symbols.items[index];
456 const esym = self.symtab.items(.elf_sym)[index];
424 if (esym.st_bind() == elf.STB_WEAK) continue;457 if (esym.st_bind() == elf.STB_WEAK) continue;
425458
426 const global = elf_file.symbol(index);459 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
427 const file = global.file(elf_file) orelse continue;460 const sym = elf_file.symbol(ref) orelse continue;
461 const file = sym.file(elf_file).?;
428 const should_keep = esym.st_shndx == elf.SHN_UNDEF or462 const should_keep = esym.st_shndx == elf.SHN_UNDEF or
429 (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);463 (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
430 if (should_keep and !file.isAlive()) {464 if (should_keep and !file.isAlive()) {
...@@ -434,14 +468,36 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {...@@ -434,14 +468,36 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
434 }468 }
435}469}
436470
437pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {471pub fn markImportsExports(self: *Object, elf_file: *Elf) void {
438 for (self.globals(), 0..) |index, i| {472 for (0..self.global_symbols.items.len) |i| {
439 const esym = self.global_esyms.items(.elf_sym)[i];473 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
440 const shndx = self.global_esyms.items(.shndx)[i];474 const sym = elf_file.symbol(ref) orelse continue;
441 const global = elf_file.symbol(index);475 const file = sym.file(elf_file).?;
442 const global_file = global.file(elf_file) orelse continue;476 if (sym.version_index == elf.VER_NDX_LOCAL) continue;
477 const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
478 if (vis == .HIDDEN) continue;
479 if (file == .shared_object and !sym.isAbs(elf_file)) {
480 sym.flags.import = true;
481 continue;
482 }
483 if (file.index() == self.index) {
484 sym.flags.@"export" = true;
485 if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
486 sym.flags.import = true;
487 }
488 }
489 }
490}
443491
444 if (self.index == global_file.index() or492pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
493 for (self.global_symbols.items, 0..) |index, i| {
494 const esym = self.symtab.items(.elf_sym)[index];
495 const shndx = self.symtab.items(.shndx)[index];
496 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
497 const ref_sym = elf_file.symbol(ref) orelse continue;
498 const ref_file = ref_sym.file(elf_file).?;
499
500 if (self.index == ref_file.index() or
445 esym.st_shndx == elf.SHN_UNDEF or501 esym.st_shndx == elf.SHN_UNDEF or
446 esym.st_bind() == elf.STB_WEAK or502 esym.st_bind() == elf.STB_WEAK or
447 esym.st_shndx == elf.SHN_COMMON) continue;503 esym.st_shndx == elf.SHN_COMMON) continue;
...@@ -451,7 +507,7 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O...@@ -451,7 +507,7 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O
451 if (!atom_ptr.alive) continue;507 if (!atom_ptr.alive) continue;
452 }508 }
453509
454 const gop = try dupes.getOrPut(index);510 const gop = try dupes.getOrPut(self.symbols_resolver.items[i]);
455 if (!gop.found_existing) {511 if (!gop.found_existing) {
456 gop.value_ptr.* = .{};512 gop.value_ptr.* = .{};
457 }513 }
...@@ -483,12 +539,13 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {...@@ -483,12 +539,13 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {
483pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {539pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {
484 const gpa = elf_file.base.comp.gpa;540 const gpa = elf_file.base.comp.gpa;
485541
486 try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len);542 try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.global_symbols.items.len);
487543
488 for (self.globals()) |global_index| {544 for (self.global_symbols.items, 0..) |index, i| {
489 const global = elf_file.symbol(global_index);545 const global = self.symbols.items[index];
490 const file_ptr = global.file(elf_file).?;546 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
491 assert(file_ptr.index() == self.index);547 const sym = elf_file.symbol(ref).?;
548 assert(sym.file(elf_file).?.index() == self.index);
492 if (global.outputShndx(elf_file) == null) continue;549 if (global.outputShndx(elf_file) == null) continue;
493550
494 const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));551 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 {...@@ -530,33 +587,9 @@ pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
530 }587 }
531}588}
532589
533inline fn isGlobal(index: Symbol.Index) bool {
534 return index & global_symbol_bit != 0;
535}
536
537pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index {
538 const actual_index = index & symbol_mask;
539 if (isGlobal(index)) return self.globals()[actual_index];
540 return self.locals()[actual_index];
541}
542
543pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
544 const actual_index = index & symbol_mask;
545 if (isGlobal(index)) return &self.global_esyms.items(.elf_sym)[actual_index];
546 return &self.local_esyms.items(.elf_sym)[actual_index];
547}
548
549pub fn locals(self: ZigObject) []const Symbol.Index {
550 return self.local_symbols.items;
551}
552
553pub fn globals(self: ZigObject) []const Symbol.Index {
554 return self.global_symbols.items;
555}
556
557pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {590pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
558 for (self.locals()) |local_index| {591 for (self.local_symbols.items) |index| {
559 const local = elf_file.symbol(local_index);592 const local = &self.symbols.items[index];
560 if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;593 if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
561 const esym = local.elfSym(elf_file);594 const esym = local.elfSym(elf_file);
562 switch (esym.st_type()) {595 switch (esym.st_type()) {
...@@ -564,22 +597,23 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {...@@ -564,22 +597,23 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
564 else => {},597 else => {},
565 }598 }
566 local.flags.output_symtab = true;599 local.flags.output_symtab = true;
567 try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);600 local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
568 self.output_symtab_ctx.nlocals += 1;601 self.output_symtab_ctx.nlocals += 1;
569 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;602 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
570 }603 }
571604
572 for (self.globals()) |global_index| {605 for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| {
573 const global = elf_file.symbol(global_index);606 const global = &self.symbols.items[index];
574 const file_ptr = global.file(elf_file) orelse continue;607 const ref = elf_file.resolver.items[resolv];
575 if (file_ptr.index() != self.index) continue;608 const ref_sym = elf_file.symbol(ref) orelse continue;
609 if (ref_sym.file(elf_file).?.index() != self.index) continue;
576 if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;610 if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
577 global.flags.output_symtab = true;611 global.flags.output_symtab = true;
578 if (global.isLocal(elf_file)) {612 if (global.isLocal(elf_file)) {
579 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);613 global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
580 self.output_symtab_ctx.nlocals += 1;614 self.output_symtab_ctx.nlocals += 1;
581 } else {615 } else {
582 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);616 global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
583 self.output_symtab_ctx.nglobals += 1;617 self.output_symtab_ctx.nglobals += 1;
584 }618 }
585 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;619 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 {...@@ -587,8 +621,8 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
587}621}
588622
589pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {623pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
590 for (self.locals()) |local_index| {624 for (self.local_symbols.items) |index| {
591 const local = elf_file.symbol(local_index);625 const local = &self.symbols.items[index];
592 const idx = local.outputSymtabIndex(elf_file) orelse continue;626 const idx = local.outputSymtabIndex(elf_file) orelse continue;
593 const out_sym = &elf_file.symtab.items[idx];627 const out_sym = &elf_file.symtab.items[idx];
594 out_sym.st_name = @intCast(elf_file.strtab.items.len);628 out_sym.st_name = @intCast(elf_file.strtab.items.len);
...@@ -597,10 +631,11 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {...@@ -597,10 +631,11 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
597 local.setOutputSym(elf_file, out_sym);631 local.setOutputSym(elf_file, out_sym);
598 }632 }
599633
600 for (self.globals()) |global_index| {634 for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| {
601 const global = elf_file.symbol(global_index);635 const global = self.symbols.items[index];
602 const file_ptr = global.file(elf_file) orelse continue;636 const ref = elf_file.resolver.items[resolv];
603 if (file_ptr.index() != self.index) continue;637 const ref_sym = elf_file.symbol(ref) orelse continue;
638 if (ref_sym.file(elf_file).?.index() != self.index) continue;
604 const idx = global.outputSymtabIndex(elf_file) orelse continue;639 const idx = global.outputSymtabIndex(elf_file) orelse continue;
605 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));640 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
606 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));641 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
...@@ -611,10 +646,6 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {...@@ -611,10 +646,6 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
611 }646 }
612}647}
613648
614pub fn asFile(self: *ZigObject) File {
615 return .{ .zig_object = self };
616}
617
618/// Returns atom's code.649/// Returns atom's code.
619/// Caller owns the memory.650/// Caller owns the memory.
620pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {651pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
...@@ -755,8 +786,8 @@ pub fn getOrCreateMetadataForLazySymbol(...@@ -755,8 +786,8 @@ pub fn getOrCreateMetadataForLazySymbol(
755 };786 };
756 switch (metadata.state.*) {787 switch (metadata.state.*) {
757 .unused => {788 .unused => {
758 const symbol_index = try self.newAtom(elf_file);789 const symbol_index = try self.newSymbolWithAtom(gpa, 0);
759 const sym = elf_file.symbol(symbol_index);790 const sym = self.symbol(symbol_index);
760 sym.flags.needs_zig_got = true;791 sym.flags.needs_zig_got = true;
761 metadata.symbol_index.* = symbol_index;792 metadata.symbol_index.* = symbol_index;
762 },793 },
...@@ -817,10 +848,10 @@ pub fn getOrCreateMetadataForDecl(...@@ -817,10 +848,10 @@ pub fn getOrCreateMetadataForDecl(
817 const gop = try self.decls.getOrPut(gpa, decl_index);848 const gop = try self.decls.getOrPut(gpa, decl_index);
818 if (!gop.found_existing) {849 if (!gop.found_existing) {
819 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;850 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
820 const symbol_index = try self.newAtom(elf_file);851 const symbol_index = try self.newSymbolWithAtom(gpa, 0);
821 const mod = elf_file.base.comp.module.?;852 const mod = elf_file.base.comp.module.?;
822 const decl = mod.declPtr(decl_index);853 const decl = mod.declPtr(decl_index);
823 const sym = elf_file.symbol(symbol_index);854 const sym = self.symbol(symbol_index);
824 if (decl.getOwnedVariable(mod)) |variable| {855 if (decl.getOwnedVariable(mod)) |variable| {
825 if (variable.is_threadlocal and any_non_single_threaded) {856 if (variable.is_threadlocal and any_non_single_threaded) {
826 sym.flags.is_tls = true;857 sym.flags.is_tls = true;
...@@ -1064,7 +1095,7 @@ pub fn updateFunc(...@@ -1064,7 +1095,7 @@ pub fn updateFunc(
10641095
1065 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);1096 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
1066 self.freeUnnamedConsts(elf_file, decl_index);1097 self.freeUnnamedConsts(elf_file, decl_index);
1067 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);1098 self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
10681099
1069 var code_buffer = std.ArrayList(u8).init(gpa);1100 var code_buffer = std.ArrayList(u8).init(gpa);
1070 defer code_buffer.deinit();1101 defer code_buffer.deinit();
...@@ -1096,7 +1127,7 @@ pub fn updateFunc(...@@ -1096,7 +1127,7 @@ pub fn updateFunc(
1096 try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_FUNC);1127 try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_FUNC);
10971128
1098 if (decl_state) |*ds| {1129 if (decl_state) |*ds| {
1099 const sym = elf_file.symbol(sym_index);1130 const sym = self.symbol(sym_index);
1100 try self.dwarf.?.commitDeclState(1131 try self.dwarf.?.commitDeclState(
1101 pt,1132 pt,
1102 decl_index,1133 decl_index,
...@@ -1130,13 +1161,13 @@ pub fn updateDecl(...@@ -1130,13 +1161,13 @@ pub fn updateDecl(
1130 const variable = decl.getOwnedVariable(mod).?;1161 const variable = decl.getOwnedVariable(mod).?;
1131 const name = decl.name.toSlice(&mod.intern_pool);1162 const name = decl.name.toSlice(&mod.intern_pool);
1132 const lib_name = variable.lib_name.toSlice(&mod.intern_pool);1163 const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
1133 const esym_index = try self.getGlobalSymbol(elf_file, name, lib_name);1164 const sym_index = try self.getGlobalSymbol(elf_file, name, lib_name);
1134 elf_file.symbol(self.symbol(esym_index)).flags.needs_got = true;1165 self.symbol(sym_index).flags.needs_got = true;
1135 return;1166 return;
1136 }1167 }
11371168
1138 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);1169 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
1139 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);1170 self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
11401171
1141 const gpa = elf_file.base.comp.gpa;1172 const gpa = elf_file.base.comp.gpa;
1142 var code_buffer = std.ArrayList(u8).init(gpa);1173 var code_buffer = std.ArrayList(u8).init(gpa);
...@@ -1174,7 +1205,7 @@ pub fn updateDecl(...@@ -1174,7 +1205,7 @@ pub fn updateDecl(
1174 try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_OBJECT);1205 try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_OBJECT);
11751206
1176 if (decl_state) |*ds| {1207 if (decl_state) |*ds| {
1177 const sym = elf_file.symbol(sym_index);1208 const sym = self.symbol(sym_index);
1178 try self.dwarf.?.commitDeclState(1209 try self.dwarf.?.commitDeclState(
1179 pt,1210 pt,
1180 decl_index,1211 decl_index,
...@@ -1323,7 +1354,8 @@ fn lowerConst(...@@ -1323,7 +1354,8 @@ fn lowerConst(
1323 var code_buffer = std.ArrayList(u8).init(gpa);1354 var code_buffer = std.ArrayList(u8).init(gpa);
1324 defer code_buffer.deinit();1355 defer code_buffer.deinit();
13251356
1326 const sym_index = try self.newAtom(elf_file);1357 const name_off = try self.addString(gpa, name);
1358 const sym_index = try self.newSymbolWithAtom(gpa, name_off);
13271359
1328 const res = try codegen.generateSymbol(1360 const res = try codegen.generateSymbol(
1329 &elf_file.base,1361 &elf_file.base,
...@@ -1339,27 +1371,19 @@ fn lowerConst(...@@ -1339,27 +1371,19 @@ fn lowerConst(
1339 .fail => |em| return .{ .fail = em },1371 .fail => |em| return .{ .fail = em },
1340 };1372 };
13411373
1342 const local_sym = elf_file.symbol(sym_index);1374 const local_sym = self.symbol(sym_index);
1343 const name_str_index = try self.strtab.insert(gpa, name);1375 const local_esym = local_sym.elfSym(elf_file);
1344 local_sym.name_offset = name_str_index;
1345 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
1346 local_esym.st_name = name_str_index;
1347 local_esym.st_info |= elf.STT_OBJECT;1376 local_esym.st_info |= elf.STT_OBJECT;
1348 local_esym.st_size = code.len;1377 local_esym.st_size = code.len;
1349 const atom_ptr = local_sym.atom(elf_file).?;1378 const atom_ptr = local_sym.atom(elf_file).?;
1350 atom_ptr.alive = true;1379 atom_ptr.alive = true;
1351 atom_ptr.name_offset = name_str_index;
1352 atom_ptr.alignment = required_alignment;1380 atom_ptr.alignment = required_alignment;
1353 atom_ptr.size = code.len;1381 atom_ptr.size = code.len;
1354 atom_ptr.output_section_index = output_section_index;1382 atom_ptr.output_section_index = output_section_index;
13551383
1356 try atom_ptr.allocate(elf_file);1384 try atom_ptr.allocate(elf_file);
1357 // TODO rename and re-audit this method
1358 errdefer self.freeDeclMetadata(elf_file, sym_index);1385 errdefer self.freeDeclMetadata(elf_file, sym_index);
13591386
1360 local_sym.value = 0;
1361 local_esym.st_value = 0;
1362
1363 const shdr = elf_file.shdrs.items[output_section_index];1387 const shdr = elf_file.shdrs.items[output_section_index];
1364 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));1388 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1365 try elf_file.base.file.?.pwriteAll(code, file_offset);1389 try elf_file.base.file.?.pwriteAll(code, file_offset);
...@@ -1401,9 +1425,9 @@ pub fn updateExports(...@@ -1401,9 +1425,9 @@ pub fn updateExports(
1401 },1425 },
1402 };1426 };
1403 const sym_index = metadata.symbol_index;1427 const sym_index = metadata.symbol_index;
1404 const esym_index = elf_file.symbol(sym_index).esym_index;1428 const esym_index = self.symbol(sym_index).esym_index;
1405 const esym = self.local_esyms.items(.elf_sym)[esym_index];1429 const esym = self.symtab.items(.elf_sym)[esym_index];
1406 const esym_shndx = self.local_esyms.items(.shndx)[esym_index];1430 const esym_shndx = self.symtab.items(.shndx)[esym_index];
14071431
1408 for (export_indices) |export_idx| {1432 for (export_indices) |export_idx| {
1409 const exp = mod.all_exports.items[export_idx];1433 const exp = mod.all_exports.items[export_idx];
...@@ -1437,22 +1461,27 @@ pub fn updateExports(...@@ -1437,22 +1461,27 @@ pub fn updateExports(
1437 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));1461 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
1438 const exp_name = exp.opts.name.toSlice(&mod.intern_pool);1462 const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
1439 const name_off = try self.strtab.insert(gpa, exp_name);1463 const name_off = try self.strtab.insert(gpa, exp_name);
1440 const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index|1464 const global_sym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
1441 exp_index.*1465 exp_index.*
1442 else blk: {1466 else blk: {
1443 const global_esym_index = try self.getGlobalSymbol(elf_file, exp_name, null);1467 const global_sym_index = try self.getGlobalSymbol(elf_file, exp_name, null);
1444 try metadata.exports.append(gpa, global_esym_index);1468 try metadata.exports.append(gpa, global_sym_index);
1445 break :blk global_esym_index;1469 break :blk global_sym_index;
1446 };1470 };
14471471
1448 const actual_esym_index = global_esym_index & symbol_mask;1472 const value = self.symbol(sym_index).value;
1449 const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index];1473 const global_sym = self.symbol(global_sym_index);
1450 global_esym.st_value = @intCast(elf_file.symbol(sym_index).value);1474 global_sym.value = value;
1475 global_sym.flags.weak = exp.opts.linkage == .weak;
1476 global_sym.version_index = elf_file.default_version_index;
1477 global_sym.ref = .{ .index = esym_shndx, .file = self.index };
1478 const global_esym = global_sym.elfSym(elf_file);
1479 global_esym.st_value = @intCast(value);
1451 global_esym.st_shndx = esym.st_shndx;1480 global_esym.st_shndx = esym.st_shndx;
1452 global_esym.st_info = (stb_bits << 4) | stt_bits;1481 global_esym.st_info = (stb_bits << 4) | stt_bits;
1453 global_esym.st_name = name_off;1482 global_esym.st_name = name_off;
1454 global_esym.st_size = esym.st_size;1483 global_esym.st_size = esym.st_size;
1455 self.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;1484 self.symtab.items(.shndx)[global_sym.esym_index] = esym_shndx;
1456 }1485 }
1457}1486}
14581487
...@@ -1506,16 +1535,19 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n...@@ -1506,16 +1535,19 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n
1506 const off = try self.strtab.insert(gpa, name);1535 const off = try self.strtab.insert(gpa, name);
1507 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);1536 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
1508 if (!lookup_gop.found_existing) {1537 if (!lookup_gop.found_existing) {
1509 const esym_index = try self.addGlobalEsym(gpa);1538 lookup_gop.value_ptr.* = try self.newSymbol(gpa, off);
1510 const esym = self.elfSym(esym_index);
1511 esym.st_name = off;
1512 lookup_gop.value_ptr.* = esym_index;
1513 const gop = try elf_file.getOrPutGlobal(name);
1514 try self.global_symbols.append(gpa, gop.index);
1515 }1539 }
1516 return lookup_gop.value_ptr.*;1540 return lookup_gop.value_ptr.*;
1517}1541}
15181542
1543pub fn asFile(self: *ZigObject) File {
1544 return .{ .zig_object = self };
1545}
1546
1547fn addString(self: *ZigObject, allocator: Allocator, string: []const u8) !u32 {
1548 return self.strtab.insert(allocator, string);
1549}
1550
1519pub fn getString(self: ZigObject, off: u32) [:0]const u8 {1551pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
1520 return self.strtab.getAssumeExists(off);1552 return self.strtab.getAssumeExists(off);
1521}1553}
...@@ -1586,6 +1618,73 @@ pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {...@@ -1586,6 +1618,73 @@ pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {
1586 }1618 }
1587}1619}
15881620
1621inline fn isGlobal(index: Symbol.Index) bool {
1622 return index & global_symbol_bit != 0;
1623}
1624
1625pub fn symbol(self: *ZigObject, index: Symbol.Index) *Symbol {
1626 const actual_index = index & symbol_mask;
1627 if (isGlobal(index)) return &self.symbols.items[self.global_symbols.items[actual_index]];
1628 return &self.symbols.items[self.local_symbols.items[actual_index]];
1629}
1630
1631pub fn resolveSymbol(self: ZigObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
1632 if (isGlobal(index)) {
1633 const resolv = self.symbols_resolver.items[index & symbol_mask];
1634 return elf_file.resolver.get(resolv).?;
1635 }
1636 return .{ .index = index, .file = self.index };
1637}
1638
1639pub fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index {
1640 try self.symbols.ensureUnusedCapacity(allocator, 1);
1641 const index: Symbol.Index = @intCast(self.symbols.items.len);
1642 self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
1643 return index;
1644}
1645
1646pub fn addSymbolExtra(self: *ZigObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
1647 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1648 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
1649 return self.addSymbolExtraAssumeCapacity(extra);
1650}
1651
1652pub fn addSymbolExtraAssumeCapacity(self: *ZigObject, extra: Symbol.Extra) u32 {
1653 const index = @as(u32, @intCast(self.symbols_extra.items.len));
1654 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1655 inline for (fields) |field| {
1656 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
1657 u32 => @field(extra, field.name),
1658 else => @compileError("bad field type"),
1659 });
1660 }
1661 return index;
1662}
1663
1664pub fn symbolExtra(self: *ZigObject, index: u32) Symbol.Extra {
1665 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1666 var i: usize = index;
1667 var result: Symbol.Extra = undefined;
1668 inline for (fields) |field| {
1669 @field(result, field.name) = switch (field.type) {
1670 u32 => self.symbols_extra.items[i],
1671 else => @compileError("bad field type"),
1672 };
1673 i += 1;
1674 }
1675 return result;
1676}
1677
1678pub fn setSymbolExtra(self: *ZigObject, index: u32, extra: Symbol.Extra) void {
1679 const fields = @typeInfo(Symbol.Extra).Struct.fields;
1680 inline for (fields, 0..) |field, i| {
1681 self.symbols_extra.items[index + i] = switch (field.type) {
1682 u32 => @field(extra, field.name),
1683 else => @compileError("bad field type"),
1684 };
1685 }
1686}
1687
1589pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {1688pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
1590 return .{ .data = .{1689 return .{ .data = .{
1591 .self = self,1690 .self = self,
...@@ -1658,9 +1757,9 @@ const DeclMetadata = struct {...@@ -1658,9 +1757,9 @@ const DeclMetadata = struct {
1658 /// A list of all exports aliases of this Decl.1757 /// A list of all exports aliases of this Decl.
1659 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},1758 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
16601759
1661 fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {1760 fn @"export"(m: DeclMetadata, zo: *ZigObject, name: []const u8) ?*u32 {
1662 for (m.exports.items) |*exp| {1761 for (m.exports.items) |*exp| {
1663 const exp_name = zig_object.getString(zig_object.elfSym(exp.*).st_name);1762 const exp_name = zo.getString(zo.symbol(exp.*).name_off);
1664 if (mem.eql(u8, name, exp_name)) return exp;1763 if (mem.eql(u8, name, exp_name)) return exp;
1665 }1764 }
1666 return null;1765 return null;
src/link/Elf/file.zig-13
...@@ -153,19 +153,6 @@ pub const File = union(enum) {...@@ -153,19 +153,6 @@ pub const File = union(enum) {
153 };153 };
154 }154 }
155155
156 pub fn locals(file: File) []const Symbol.Index {
157 return switch (file) {
158 .linker_defined, .shared_object => &[0]Symbol.Index{},
159 inline else => |x| x.locals(),
160 };
161 }
162
163 pub fn globals(file: File) []const Symbol.Index {
164 return switch (file) {
165 inline else => |x| x.globals(),
166 };
167 }
168
169 pub fn getString(file: File, off: u32) [:0]const u8 {156 pub fn getString(file: File, off: u32) [:0]const u8 {
170 return switch (file) {157 return switch (file) {
171 inline else => |x| x.getString(off),158 inline else => |x| x.getString(off),