authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-12 23:27:11+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-12 23:27:14+02:00
log1a6d12ea92eb9033aed686c88b53ff406ec2fbe7
tree00700d4647d1551641a3694e315bd9423d3f3687
parent9719fa7412371243aaac6f307f80d783c7ac50cb

elf: clean up and unify symbol ref handling in relocs

Also, this lets us re-enable proper undefined symbols tracking.

6 files changed, 146 insertions(+), 107 deletions(-)

src/link/Elf.zig+79-91
......@@ -6,6 +6,9 @@ ptr_width: PtrWidth,
66/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
77llvm_object: ?*LlvmObject = null,
88
9/// A list of all input files.
10/// Index of each input file also encodes the priority or precedence of one input file
11/// over another.
912files: std.MultiArrayList(File.Entry) = .{},
1013zig_module_index: ?File.Index = null,
1114linker_defined_index: ?File.Index = null,
......@@ -47,6 +50,7 @@ shstrtab: StringTable(.strtab) = .{},
4750/// .strtab buffer
4851strtab: StringTable(.strtab) = .{},
4952
53/// Representation of the GOT table as committed to the file.
5054got: GotSection = .{},
5155
5256text_section_index: ?u16 = null,
......@@ -86,10 +90,10 @@ rela_iplt_start_index: ?Symbol.Index = null,
8690rela_iplt_end_index: ?Symbol.Index = null,
8791start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
8892
93/// An array of symbols parsed across all input files.
8994symbols: std.ArrayListUnmanaged(Symbol) = .{},
9095symbols_extra: std.ArrayListUnmanaged(u32) = .{},
9196resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
92unresolved: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},
9397symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
9498
9599phdr_table_dirty: bool = false,
......@@ -271,7 +275,6 @@ pub fn deinit(self: *Elf) void {
271275 self.symbols_free_list.deinit(gpa);
272276 self.got.deinit(gpa);
273277 self.resolver.deinit(gpa);
274 self.unresolved.deinit(gpa);
275278 self.start_stop_indexes.deinit(gpa);
276279
277280 {
......@@ -316,7 +319,7 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.
316319 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
317320 try parent_atom.addReloc(self, .{
318321 .r_offset = reloc_info.offset,
319 .r_info = (@as(u64, @intCast(this_sym_index)) << 32) | elf.R_X86_64_64,
322 .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | elf.R_X86_64_64,
320323 .r_addend = reloc_info.addend,
321324 });
322325
......@@ -997,12 +1000,16 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
9971000 };
9981001 _ = compiler_rt_path;
9991002
1000 // Parse input files
1003 // Here we will parse input positional and library files (if referenced).
1004 // This will roughly match in any linker backend we support.
10011005 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
10021006 defer positionals.deinit();
10031007 try positionals.ensureUnusedCapacity(self.base.options.objects.len);
10041008 positionals.appendSliceAssumeCapacity(self.base.options.objects);
10051009
1010 // This is a set of object files emitted by clang in a single `build-exe` invocation.
1011 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
1012 // in this set.
10061013 for (comp.c_object_table.keys()) |key| {
10071014 try positionals.append(.{ .path = key.status.success.object_path });
10081015 }
......@@ -1016,6 +1023,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10161023 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
10171024 }
10181025
1026 // Handle any lazy symbols that were emitted by incremental compilation.
10191027 if (self.lazy_syms.getPtr(.none)) |metadata| {
10201028 // Most lazy symbols can be updated on first use, but
10211029 // anyerror needs to wait for everything to be flushed.
......@@ -1046,27 +1054,34 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10461054 try dw.flushModule(module);
10471055 }
10481056
1057 // If we haven't already, create a linker-generated input file comprising of
1058 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
10491059 if (self.linker_defined_index == null) {
10501060 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
10511061 self.files.set(index, .{ .linker_defined = .{ .index = index } });
10521062 self.linker_defined_index = index;
10531063 }
1054
1055 // Symbol resolution happens here
10561064 try self.addLinkerDefinedSymbols();
1065
1066 // Now, we are ready to resolve the symbols across all input files.
1067 // We will first resolve the files in the ZigModule, next in the parsed
1068 // input Object files.
1069 // Any qualifing unresolved symbol will be upgraded to an absolute, weak
1070 // symbol for potential resolution at load-time.
10571071 self.resolveSymbols();
10581072 self.markImportsExports();
10591073 self.claimUnresolved();
10601074
1061 // Scan and create missing synthetic entries such as GOT indirection
1075 // Scan and create missing synthetic entries such as GOT indirection.
10621076 try self.scanRelocs();
10631077
1064 // Allocate atoms parsed from input object files
1078 // Allocate atoms parsed from input object files, followed by allocating
1079 // linker-defined synthetic symbols.
10651080 try self.allocateObjects();
10661081 self.allocateLinkerDefinedSymbols();
10671082
10681083 // Beyond this point, everything has been allocated a virtual address and we can resolve
1069 // the relocations.
1084 // the relocations, and commit objects to file.
10701085 if (self.zig_module_index) |index| {
10711086 for (self.file(index).?.zig_module.atoms.keys()) |atom_index| {
10721087 const atom_ptr = self.atom(atom_index).?;
......@@ -1083,9 +1098,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10831098 }
10841099 try self.writeObjects();
10851100
1101 // Generate and emit the symbol table.
10861102 try self.updateSymtabSize();
10871103 try self.writeSymtab();
10881104
1105 // Dump the state for easy debugging.
1106 // State can be dumped via `--debug-log link_state`.
10891107 if (build_options.enable_logging) {
10901108 state_log.debug("{}", .{self.dumpState()});
10911109 }
......@@ -1393,17 +1411,32 @@ fn claimUnresolved(self: *Elf) void {
13931411 }
13941412}
13951413
1414/// In scanRelocs we will go over all live atoms and scan their relocs.
1415/// This will help us work out what synthetics to emit, GOT indirection, etc.
1416/// This is also the point where we will report undefined symbols for any
1417/// alloc sections.
13961418fn scanRelocs(self: *Elf) !void {
1419 const gpa = self.base.allocator;
1420
1421 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Atom.Index)).init(gpa);
1422 defer {
1423 var it = undefs.iterator();
1424 while (it.next()) |entry| {
1425 entry.value_ptr.deinit();
1426 }
1427 undefs.deinit();
1428 }
1429
13971430 if (self.zig_module_index) |index| {
13981431 const zig_module = self.file(index).?.zig_module;
1399 try zig_module.scanRelocs(self);
1432 try zig_module.scanRelocs(self, &undefs);
14001433 }
14011434 for (self.objects.items) |index| {
14021435 const object = self.file(index).?.object;
1403 try object.scanRelocs(self);
1436 try object.scanRelocs(self, &undefs);
14041437 }
14051438
1406 // try self.reportUndefined();
1439 try self.reportUndefined(&undefs);
14071440
14081441 for (self.symbols.items) |*sym| {
14091442 if (sym.flags.needs_got) {
......@@ -1433,8 +1466,10 @@ fn allocateObjects(self: *Elf) !void {
14331466
14341467 for (object.globals()) |global_index| {
14351468 const global = self.symbol(global_index);
1469 const atom_ptr = global.atom(self) orelse continue;
1470 if (!atom_ptr.alive) continue;
14361471 if (global.file_index == index) {
1437 global.value = global.atom(self).?.value;
1472 global.value = atom_ptr.value;
14381473 }
14391474 }
14401475 }
......@@ -2829,21 +2864,23 @@ pub fn updateDeclExports(
28292864 };
28302865 const stt_bits: u8 = @as(u4, @truncate(decl_esym.st_info));
28312866
2867 const name_off = try self.strtab.insert(gpa, exp_name);
28322868 const sym_index = if (decl_metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {
28332869 const sym_index = try zig_module.addGlobalEsym(gpa);
2834 _ = try zig_module.global_symbols.addOne(gpa);
2870 const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, name_off);
2871 const esym = zig_module.elfSym(sym_index);
2872 esym.st_name = name_off;
2873 lookup_gop.value_ptr.* = sym_index;
28352874 try decl_metadata.exports.append(gpa, sym_index);
2875 const gop = try self.getOrPutGlobal(name_off);
2876 try zig_module.global_symbols.append(gpa, gop.index);
28362877 break :blk sym_index;
28372878 };
2838 const name_off = try self.strtab.insert(gpa, exp_name);
2839 const esym = &zig_module.global_esyms.items[sym_index];
2879 const esym = &zig_module.global_esyms.items[sym_index & 0x0fffffff];
28402880 esym.st_value = decl_sym.value;
28412881 esym.st_shndx = decl_sym.atom_index;
28422882 esym.st_info = (stb_bits << 4) | stt_bits;
28432883 esym.st_name = name_off;
2844
2845 const gop = try self.getOrPutGlobal(name_off);
2846 zig_module.global_symbols.items[sym_index] = gop.index;
28472884 }
28482885}
28492886
......@@ -3636,16 +3673,17 @@ pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32
36363673 _ = lib_name;
36373674 const gpa = self.base.allocator;
36383675 const off = try self.strtab.insert(gpa, name);
3639 const gop = try self.getOrPutGlobal(off);
36403676 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
36413677 const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, off);
36423678 if (!lookup_gop.found_existing) {
36433679 const esym_index = try zig_module.addGlobalEsym(gpa);
3644 const esym = &zig_module.global_esyms.items[esym_index];
3680 const esym = zig_module.elfSym(esym_index);
36453681 esym.st_name = off;
36463682 lookup_gop.value_ptr.* = esym_index;
3683 const gop = try self.getOrPutGlobal(off);
3684 try zig_module.global_symbols.append(gpa, gop.index);
36473685 }
3648 return gop.index;
3686 return lookup_gop.value_ptr.*;
36493687}
36503688
36513689const GetOrCreateComdatGroupOwnerResult = struct {
......@@ -3684,89 +3722,39 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO
36843722 return &self.comdat_groups_owners.items[index];
36853723}
36863724
3687fn reportUndefined(self: *Elf) !void {
3725fn reportUndefined(self: *Elf, undefs: anytype) !void {
36883726 const gpa = self.base.allocator;
36893727 const max_notes = 4;
36903728
3691 try self.misc_errors.ensureUnusedCapacity(gpa, self.unresolved.keys().len);
3692
3693 const CollectStruct = struct {
3694 notes: [max_notes]link.File.ErrorMsg = [_]link.File.ErrorMsg{.{ .msg = undefined }} ** max_notes,
3695 notes_len: u3 = 0,
3696 notes_count: usize = 0,
3697 };
3698
3699 const collect: []CollectStruct = try gpa.alloc(CollectStruct, self.unresolved.keys().len);
3700 defer gpa.free(collect);
3701 @memset(collect, .{});
3702
3703 // Collect all references across all input files
3704 if (self.zig_module_index) |index| {
3705 const zig_module = self.file(index).?.zig_module;
3706 for (zig_module.atoms.keys()) |atom_index| {
3707 const atom_ptr = self.atom(atom_index).?;
3708 if (!atom_ptr.alive) continue;
3709
3710 for (atom_ptr.relocs(self)) |rel| {
3711 if (self.unresolved.getIndex(rel.r_sym())) |bin_index| {
3712 const note = try std.fmt.allocPrint(gpa, "referenced by {s}:{s}", .{
3713 zig_module.path,
3714 atom_ptr.name(self),
3715 });
3716 const bin = &collect[bin_index];
3717 if (bin.notes_len < max_notes) {
3718 bin.notes[bin.notes_len] = .{ .msg = note };
3719 bin.notes_len += 1;
3720 }
3721 bin.notes_count += 1;
3722 }
3723 }
3724 }
3725 }
3726
3727 for (self.objects.items) |index| {
3728 const object = self.file(index).?.object;
3729 for (object.atoms.items) |atom_index| {
3730 const atom_ptr = self.atom(atom_index) orelse continue;
3731 if (!atom_ptr.alive) continue;
3729 try self.misc_errors.ensureUnusedCapacity(gpa, undefs.count());
37323730
3733 for (atom_ptr.relocs(self)) |rel| {
3734 const sym_index = object.symbols.items[rel.r_sym()];
3735 if (self.unresolved.getIndex(sym_index)) |bin_index| {
3736 const note = try std.fmt.allocPrint(gpa, "referenced by {}:{s}", .{
3737 object.fmtPath(),
3738 atom_ptr.name(self),
3739 });
3740 const bin = &collect[bin_index];
3741 if (bin.notes_len < max_notes) {
3742 bin.notes[bin.notes_len] = .{ .msg = note };
3743 bin.notes_len += 1;
3744 }
3745 bin.notes_count += 1;
3746 }
3747 }
3748 }
3749 }
3750
3751 // Generate error notes
3752 for (self.unresolved.keys(), 0..) |sym_index, bin_index| {
3753 const collected = &collect[bin_index];
3731 var it = undefs.iterator();
3732 while (it.next()) |entry| {
3733 const undef_index = entry.key_ptr.*;
3734 const atoms = entry.value_ptr.*.items;
3735 const nnotes = @min(atoms.len, max_notes);
37543736
37553737 var notes = try std.ArrayList(link.File.ErrorMsg).initCapacity(gpa, max_notes + 1);
37563738 defer notes.deinit();
37573739
3758 for (collected.notes[0..collected.notes_len]) |note| {
3759 notes.appendAssumeCapacity(note);
3740 for (atoms[0..nnotes]) |atom_index| {
3741 const atom_ptr = self.atom(atom_index).?;
3742 const file_ptr = self.file(atom_ptr.file_index).?;
3743 const note = try std.fmt.allocPrint(gpa, "referenced by {s}:{s}", .{
3744 file_ptr.fmtPath(),
3745 atom_ptr.name(self),
3746 });
3747 notes.appendAssumeCapacity(.{ .msg = note });
37603748 }
37613749
3762 if (collected.notes_count > max_notes) {
3763 const remaining = collected.notes_count - max_notes;
3750 if (atoms.len > max_notes) {
3751 const remaining = atoms.len - max_notes;
37643752 const note = try std.fmt.allocPrint(gpa, "referenced {d} more times", .{remaining});
37653753 notes.appendAssumeCapacity(.{ .msg = note });
37663754 }
37673755
37683756 var err_msg = link.File.ErrorMsg{
3769 .msg = try std.fmt.allocPrint(gpa, "undefined symbol: {s}", .{self.symbol(sym_index).name(self)}),
3757 .msg = try std.fmt.allocPrint(gpa, "undefined symbol: {s}", .{self.symbol(undef_index).name(self)}),
37703758 };
37713759 err_msg.notes = try notes.toOwnedSlice();
37723760
......@@ -3931,7 +3919,7 @@ const DeclMetadata = struct {
39313919 fn @"export"(m: DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 {
39323920 const zig_module = elf_file.file(elf_file.zig_module_index.?).?.zig_module;
39333921 for (m.exports.items) |*exp| {
3934 const exp_name = elf_file.strtab.getAssumeExists(zig_module.global_esyms.items[exp.*].st_name);
3922 const exp_name = elf_file.strtab.getAssumeExists(zig_module.elfSym(exp.*).st_name);
39353923 if (mem.eql(u8, name, exp_name)) return exp;
39363924 }
39373925 return null;
src/link/Elf/Atom.zig+40-3
......@@ -312,7 +312,7 @@ pub fn freeRelocs(self: Atom, elf_file: *Elf) void {
312312 zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity();
313313}
314314
315pub fn scanRelocs(self: Atom, elf_file: *Elf) !void {
315pub fn scanRelocs(self: Atom, elf_file: *Elf, undefs: anytype) !void {
316316 const file_ptr = elf_file.file(self.file_index).?;
317317 const rels = self.relocs(elf_file);
318318 var i: usize = 0;
......@@ -322,11 +322,25 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf) !void {
322322 if (rel.r_type() == elf.R_X86_64_NONE) continue;
323323
324324 const symbol = switch (file_ptr) {
325 .zig_module => elf_file.symbol(rel.r_sym()),
325 .zig_module => |x| elf_file.symbol(x.symbol(rel.r_sym())),
326326 .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
327327 else => unreachable,
328328 };
329329
330 // Check for violation of One Definition Rule for COMDATs.
331 if (symbol.file(elf_file) == null) {
332 // TODO convert into an error
333 log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
334 file_ptr.fmtPath(),
335 self.name(elf_file),
336 symbol.name(elf_file),
337 });
338 continue;
339 }
340
341 // Report an undefined symbol.
342 try self.reportUndefined(elf_file, symbol, rel, undefs);
343
330344 // While traversing relocations, mark symbols that require special handling such as
331345 // pointer indirection via GOT, or a stub trampoline via PLT.
332346 switch (rel.r_type()) {
......@@ -363,6 +377,28 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf) !void {
363377 }
364378}
365379
380// This function will report any undefined non-weak symbols that are not imports.
381fn reportUndefined(self: Atom, elf_file: *Elf, sym: *const Symbol, rel: elf.Elf64_Rela, undefs: anytype) !void {
382 const rel_esym = switch (elf_file.file(self.file_index).?) {
383 .zig_module => |x| x.elfSym(rel.r_sym()).*,
384 .object => |x| x.symtab[rel.r_sym()],
385 else => unreachable,
386 };
387 const esym = sym.elfSym(elf_file);
388 if (rel_esym.st_shndx == elf.SHN_UNDEF and
389 rel_esym.st_bind() == elf.STB_GLOBAL and
390 sym.esym_index > 0 and
391 !sym.flags.import and
392 esym.st_shndx == elf.SHN_UNDEF)
393 {
394 const gop = try undefs.getOrPut(sym.index);
395 if (!gop.found_existing) {
396 gop.value_ptr.* = std.ArrayList(Atom.Index).init(elf_file.base.allocator);
397 }
398 try gop.value_ptr.append(self.atom_index);
399 }
400}
401
366402/// TODO mark relocs dirty
367403pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void {
368404 relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
......@@ -376,7 +412,7 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void {
376412 if (r_type == elf.R_X86_64_NONE) continue;
377413
378414 const target = switch (file_ptr) {
379 .zig_module => elf_file.symbol(rel.r_sym()),
415 .zig_module => |x| elf_file.symbol(x.symbol(rel.r_sym())),
380416 .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
381417 else => unreachable,
382418 };
......@@ -564,3 +600,4 @@ const Allocator = std.mem.Allocator;
564600const Atom = @This();
565601const Elf = @import("../Elf.zig");
566602const File = @import("file.zig").File;
603const Symbol = @import("Symbol.zig");
src/link/Elf/Object.zig+2-2
......@@ -392,14 +392,14 @@ fn filterRelocs(
392392 return .{ .start = f_start, .len = f_len };
393393}
394394
395pub fn scanRelocs(self: *Object, elf_file: *Elf) !void {
395pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
396396 for (self.atoms.items) |atom_index| {
397397 const atom = elf_file.atom(atom_index) orelse continue;
398398 if (!atom.alive) continue;
399399 const shdr = atom.inputShdr(elf_file);
400400 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
401401 if (shdr.sh_type == elf.SHT_NOBITS) continue;
402 try atom.scanRelocs(elf_file);
402 try atom.scanRelocs(elf_file, undefs);
403403 }
404404
405405 for (self.cies.items) |cie| {
src/link/Elf/Symbol.zig+2-7
......@@ -43,7 +43,7 @@ pub fn isLocal(symbol: Symbol) bool {
4343 return !(symbol.flags.import or symbol.flags.@"export");
4444}
4545
46pub inline fn isIFunc(symbol: Symbol, elf_file: *Elf) bool {
46pub fn isIFunc(symbol: Symbol, elf_file: *Elf) bool {
4747 return symbol.type(elf_file) == elf.STT_GNU_IFUNC;
4848}
4949
......@@ -69,12 +69,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
6969pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
7070 const file_ptr = symbol.file(elf_file).?;
7171 switch (file_ptr) {
72 .zig_module => |x| {
73 const is_global = symbol.esym_index & 0x10000000 != 0;
74 const esym_index = symbol.esym_index & 0x0fffffff;
75 if (is_global) return x.global_esyms.items[esym_index];
76 return x.local_esyms.items[esym_index];
77 },
72 .zig_module => |x| return x.elfSym(symbol.esym_index).*,
7873 .linker_defined => |x| return x.symtab.items[symbol.esym_index],
7974 .object => |x| return x.symtab[symbol.esym_index],
8075 }
src/link/Elf/ZigModule.zig+22-3
......@@ -1,3 +1,8 @@
1//! ZigModule encapsulates the state of the incrementally compiled Zig module.
2//! It stores the associated input local and global symbols, allocated atoms,
3//! and any relocations that may have been emitted.
4//! Think about this as fake in-memory Object file for the Zig module.
5
16/// Path is owned by Module and lives as long as *Module.
27path: []const u8,
38index: File.Index,
......@@ -41,7 +46,7 @@ pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
4146 const esym = self.global_esyms.addOneAssumeCapacity();
4247 esym.* = Elf.null_sym;
4348 esym.st_info = elf.STB_GLOBAL << 4;
44 return index;
49 return index | 0x10000000;
4550}
4651
4752pub fn addAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index {
......@@ -135,11 +140,11 @@ pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {
135140 }
136141}
137142
138pub fn scanRelocs(self: *ZigModule, elf_file: *Elf) !void {
143pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {
139144 for (self.atoms.keys()) |atom_index| {
140145 const atom = elf_file.atom(atom_index) orelse continue;
141146 if (!atom.alive) continue;
142 try atom.scanRelocs(elf_file);
147 try atom.scanRelocs(elf_file, undefs);
143148 }
144149}
145150
......@@ -197,6 +202,20 @@ pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void {
197202 }
198203}
199204
205pub fn symbol(self: *ZigModule, index: Symbol.Index) Symbol.Index {
206 const is_global = index & 0x10000000 != 0;
207 const actual_index = index & 0x0fffffff;
208 if (is_global) return self.global_symbols.items[actual_index];
209 return self.local_symbols.items[actual_index];
210}
211
212pub fn elfSym(self: *ZigModule, index: Symbol.Index) *elf.Elf64_Sym {
213 const is_global = index & 0x10000000 != 0;
214 const actual_index = index & 0x0fffffff;
215 if (is_global) return &self.global_esyms.items[actual_index];
216 return &self.local_esyms.items[actual_index];
217}
218
200219pub fn locals(self: *ZigModule) []const Symbol.Index {
201220 return self.local_symbols.items;
202221}
src/link/Elf/file.zig+1-1
......@@ -23,7 +23,7 @@ pub const File = union(enum) {
2323 _ = unused_fmt_string;
2424 _ = options;
2525 switch (file) {
26 .zig_module => try writer.writeAll("(zig module)"),
26 .zig_module => |x| try writer.print("{s}", .{x.path}),
2727 .linker_defined => try writer.writeAll("(linker defined)"),
2828 .object => |x| try writer.print("{}", .{x.fmtPath()}),
2929 // .shared_object => |x| try writer.writeAll(x.path),