| ... | @@ -6,6 +6,9 @@ ptr_width: PtrWidth, | ... | @@ -6,6 +6,9 @@ ptr_width: PtrWidth, |
| 6 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. | 6 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. |
| 7 | llvm_object: ?*LlvmObject = null, | 7 | llvm_object: ?*LlvmObject = null, |
| 8 | | 8 | |
| | 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. |
| 9 | files: std.MultiArrayList(File.Entry) = .{}, | 12 | files: std.MultiArrayList(File.Entry) = .{}, |
| 10 | zig_module_index: ?File.Index = null, | 13 | zig_module_index: ?File.Index = null, |
| 11 | linker_defined_index: ?File.Index = null, | 14 | linker_defined_index: ?File.Index = null, |
| ... | @@ -47,6 +50,7 @@ shstrtab: StringTable(.strtab) = .{}, | ... | @@ -47,6 +50,7 @@ shstrtab: StringTable(.strtab) = .{}, |
| 47 | /// .strtab buffer | 50 | /// .strtab buffer |
| 48 | strtab: StringTable(.strtab) = .{}, | 51 | strtab: StringTable(.strtab) = .{}, |
| 49 | | 52 | |
| | 53 | /// Representation of the GOT table as committed to the file. |
| 50 | got: GotSection = .{}, | 54 | got: GotSection = .{}, |
| 51 | | 55 | |
| 52 | text_section_index: ?u16 = null, | 56 | text_section_index: ?u16 = null, |
| ... | @@ -86,10 +90,10 @@ rela_iplt_start_index: ?Symbol.Index = null, | ... | @@ -86,10 +90,10 @@ rela_iplt_start_index: ?Symbol.Index = null, |
| 86 | rela_iplt_end_index: ?Symbol.Index = null, | 90 | rela_iplt_end_index: ?Symbol.Index = null, |
| 87 | start_stop_indexes: std.ArrayListUnmanaged(u32) = .{}, | 91 | start_stop_indexes: std.ArrayListUnmanaged(u32) = .{}, |
| 88 | | 92 | |
| | 93 | /// An array of symbols parsed across all input files. |
| 89 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, | 94 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, |
| 90 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, | 95 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 91 | resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{}, | 96 | resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{}, |
| 92 | unresolved: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, | | |
| 93 | symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 97 | symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 94 | | 98 | |
| 95 | phdr_table_dirty: bool = false, | 99 | phdr_table_dirty: bool = false, |
| ... | @@ -271,7 +275,6 @@ pub fn deinit(self: *Elf) void { | ... | @@ -271,7 +275,6 @@ pub fn deinit(self: *Elf) void { |
| 271 | self.symbols_free_list.deinit(gpa); | 275 | self.symbols_free_list.deinit(gpa); |
| 272 | self.got.deinit(gpa); | 276 | self.got.deinit(gpa); |
| 273 | self.resolver.deinit(gpa); | 277 | self.resolver.deinit(gpa); |
| 274 | self.unresolved.deinit(gpa); | | |
| 275 | self.start_stop_indexes.deinit(gpa); | 278 | self.start_stop_indexes.deinit(gpa); |
| 276 | | 279 | |
| 277 | { | 280 | { |
| ... | @@ -316,7 +319,7 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link. | ... | @@ -316,7 +319,7 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link. |
| 316 | const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?; | 319 | const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?; |
| 317 | try parent_atom.addReloc(self, .{ | 320 | try parent_atom.addReloc(self, .{ |
| 318 | .r_offset = reloc_info.offset, | 321 | .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, |
| 320 | .r_addend = reloc_info.addend, | 323 | .r_addend = reloc_info.addend, |
| 321 | }); | 324 | }); |
| 322 | | 325 | |
| ... | @@ -997,12 +1000,16 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -997,12 +1000,16 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 997 | }; | 1000 | }; |
| 998 | _ = compiler_rt_path; | 1001 | _ = compiler_rt_path; |
| 999 | | 1002 | |
| 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. |
| 1001 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); | 1005 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); |
| 1002 | defer positionals.deinit(); | 1006 | defer positionals.deinit(); |
| 1003 | try positionals.ensureUnusedCapacity(self.base.options.objects.len); | 1007 | try positionals.ensureUnusedCapacity(self.base.options.objects.len); |
| 1004 | positionals.appendSliceAssumeCapacity(self.base.options.objects); | 1008 | positionals.appendSliceAssumeCapacity(self.base.options.objects); |
| 1005 | | 1009 | |
| | 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. |
| 1006 | for (comp.c_object_table.keys()) |key| { | 1013 | for (comp.c_object_table.keys()) |key| { |
| 1007 | try positionals.append(.{ .path = key.status.success.object_path }); | 1014 | try positionals.append(.{ .path = key.status.success.object_path }); |
| 1008 | } | 1015 | } |
| ... | @@ -1016,6 +1023,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1016,6 +1023,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1016 | try self.handleAndReportParseError(obj.path, err, &parse_ctx); | 1023 | try self.handleAndReportParseError(obj.path, err, &parse_ctx); |
| 1017 | } | 1024 | } |
| 1018 | | 1025 | |
| | 1026 | // Handle any lazy symbols that were emitted by incremental compilation. |
| 1019 | if (self.lazy_syms.getPtr(.none)) |metadata| { | 1027 | if (self.lazy_syms.getPtr(.none)) |metadata| { |
| 1020 | // Most lazy symbols can be updated on first use, but | 1028 | // Most lazy symbols can be updated on first use, but |
| 1021 | // anyerror needs to wait for everything to be flushed. | 1029 | // 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 | ... | @@ -1046,27 +1054,34 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1046 | try dw.flushModule(module); | 1054 | try dw.flushModule(module); |
| 1047 | } | 1055 | } |
| 1048 | | 1056 | |
| | 1057 | // If we haven't already, create a linker-generated input file comprising of |
| | 1058 | // linker-defined synthetic symbols only such as `_DYNAMIC`, etc. |
| 1049 | if (self.linker_defined_index == null) { | 1059 | if (self.linker_defined_index == null) { |
| 1050 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | 1060 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 1051 | self.files.set(index, .{ .linker_defined = .{ .index = index } }); | 1061 | self.files.set(index, .{ .linker_defined = .{ .index = index } }); |
| 1052 | self.linker_defined_index = index; | 1062 | self.linker_defined_index = index; |
| 1053 | } | 1063 | } |
| 1054 | | | |
| 1055 | // Symbol resolution happens here | | |
| 1056 | try self.addLinkerDefinedSymbols(); | 1064 | 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. |
| 1057 | self.resolveSymbols(); | 1071 | self.resolveSymbols(); |
| 1058 | self.markImportsExports(); | 1072 | self.markImportsExports(); |
| 1059 | self.claimUnresolved(); | 1073 | self.claimUnresolved(); |
| 1060 | | 1074 | |
| 1061 | // Scan and create missing synthetic entries such as GOT indirection | 1075 | // Scan and create missing synthetic entries such as GOT indirection. |
| 1062 | try self.scanRelocs(); | 1076 | try self.scanRelocs(); |
| 1063 | | 1077 | |
| 1064 | // Allocate atoms parsed from input object files | 1078 | // Allocate atoms parsed from input object files, followed by allocating |
| | 1079 | // linker-defined synthetic symbols. |
| 1065 | try self.allocateObjects(); | 1080 | try self.allocateObjects(); |
| 1066 | self.allocateLinkerDefinedSymbols(); | 1081 | self.allocateLinkerDefinedSymbols(); |
| 1067 | | 1082 | |
| 1068 | // Beyond this point, everything has been allocated a virtual address and we can resolve | 1083 | // 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. |
| 1070 | if (self.zig_module_index) |index| { | 1085 | if (self.zig_module_index) |index| { |
| 1071 | for (self.file(index).?.zig_module.atoms.keys()) |atom_index| { | 1086 | for (self.file(index).?.zig_module.atoms.keys()) |atom_index| { |
| 1072 | const atom_ptr = self.atom(atom_index).?; | 1087 | const atom_ptr = self.atom(atom_index).?; |
| ... | @@ -1083,9 +1098,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1083,9 +1098,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1083 | } | 1098 | } |
| 1084 | try self.writeObjects(); | 1099 | try self.writeObjects(); |
| 1085 | | 1100 | |
| | 1101 | // Generate and emit the symbol table. |
| 1086 | try self.updateSymtabSize(); | 1102 | try self.updateSymtabSize(); |
| 1087 | try self.writeSymtab(); | 1103 | try self.writeSymtab(); |
| 1088 | | 1104 | |
| | 1105 | // Dump the state for easy debugging. |
| | 1106 | // State can be dumped via `--debug-log link_state`. |
| 1089 | if (build_options.enable_logging) { | 1107 | if (build_options.enable_logging) { |
| 1090 | state_log.debug("{}", .{self.dumpState()}); | 1108 | state_log.debug("{}", .{self.dumpState()}); |
| 1091 | } | 1109 | } |
| ... | @@ -1393,17 +1411,32 @@ fn claimUnresolved(self: *Elf) void { | ... | @@ -1393,17 +1411,32 @@ fn claimUnresolved(self: *Elf) void { |
| 1393 | } | 1411 | } |
| 1394 | } | 1412 | } |
| 1395 | | 1413 | |
| | 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. |
| 1396 | fn scanRelocs(self: *Elf) !void { | 1418 | fn 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 | |
| 1397 | if (self.zig_module_index) |index| { | 1430 | if (self.zig_module_index) |index| { |
| 1398 | const zig_module = self.file(index).?.zig_module; | 1431 | const zig_module = self.file(index).?.zig_module; |
| 1399 | try zig_module.scanRelocs(self); | 1432 | try zig_module.scanRelocs(self, &undefs); |
| 1400 | } | 1433 | } |
| 1401 | for (self.objects.items) |index| { | 1434 | for (self.objects.items) |index| { |
| 1402 | const object = self.file(index).?.object; | 1435 | const object = self.file(index).?.object; |
| 1403 | try object.scanRelocs(self); | 1436 | try object.scanRelocs(self, &undefs); |
| 1404 | } | 1437 | } |
| 1405 | | 1438 | |
| 1406 | // try self.reportUndefined(); | 1439 | try self.reportUndefined(&undefs); |
| 1407 | | 1440 | |
| 1408 | for (self.symbols.items) |*sym| { | 1441 | for (self.symbols.items) |*sym| { |
| 1409 | if (sym.flags.needs_got) { | 1442 | if (sym.flags.needs_got) { |
| ... | @@ -1433,8 +1466,10 @@ fn allocateObjects(self: *Elf) !void { | ... | @@ -1433,8 +1466,10 @@ fn allocateObjects(self: *Elf) !void { |
| 1433 | | 1466 | |
| 1434 | for (object.globals()) |global_index| { | 1467 | for (object.globals()) |global_index| { |
| 1435 | const global = self.symbol(global_index); | 1468 | const global = self.symbol(global_index); |
| | 1469 | const atom_ptr = global.atom(self) orelse continue; |
| | 1470 | if (!atom_ptr.alive) continue; |
| 1436 | if (global.file_index == index) { | 1471 | if (global.file_index == index) { |
| 1437 | global.value = global.atom(self).?.value; | 1472 | global.value = atom_ptr.value; |
| 1438 | } | 1473 | } |
| 1439 | } | 1474 | } |
| 1440 | } | 1475 | } |
| ... | @@ -2829,21 +2864,23 @@ pub fn updateDeclExports( | ... | @@ -2829,21 +2864,23 @@ pub fn updateDeclExports( |
| 2829 | }; | 2864 | }; |
| 2830 | const stt_bits: u8 = @as(u4, @truncate(decl_esym.st_info)); | 2865 | const stt_bits: u8 = @as(u4, @truncate(decl_esym.st_info)); |
| 2831 | | 2866 | |
| | 2867 | const name_off = try self.strtab.insert(gpa, exp_name); |
| 2832 | const sym_index = if (decl_metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: { | 2868 | const sym_index = if (decl_metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: { |
| 2833 | const sym_index = try zig_module.addGlobalEsym(gpa); | 2869 | 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; |
| 2835 | try decl_metadata.exports.append(gpa, sym_index); | 2874 | 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); |
| 2836 | break :blk sym_index; | 2877 | break :blk sym_index; |
| 2837 | }; | 2878 | }; |
| 2838 | const name_off = try self.strtab.insert(gpa, exp_name); | 2879 | const esym = &zig_module.global_esyms.items[sym_index & 0x0fffffff]; |
| 2839 | const esym = &zig_module.global_esyms.items[sym_index]; | | |
| 2840 | esym.st_value = decl_sym.value; | 2880 | esym.st_value = decl_sym.value; |
| 2841 | esym.st_shndx = decl_sym.atom_index; | 2881 | esym.st_shndx = decl_sym.atom_index; |
| 2842 | esym.st_info = (stb_bits << 4) | stt_bits; | 2882 | esym.st_info = (stb_bits << 4) | stt_bits; |
| 2843 | esym.st_name = name_off; | 2883 | esym.st_name = name_off; |
| 2844 | | | |
| 2845 | const gop = try self.getOrPutGlobal(name_off); | | |
| 2846 | zig_module.global_symbols.items[sym_index] = gop.index; | | |
| 2847 | } | 2884 | } |
| 2848 | } | 2885 | } |
| 2849 | | 2886 | |
| ... | @@ -3636,16 +3673,17 @@ pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 | ... | @@ -3636,16 +3673,17 @@ pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 |
| 3636 | _ = lib_name; | 3673 | _ = lib_name; |
| 3637 | const gpa = self.base.allocator; | 3674 | const gpa = self.base.allocator; |
| 3638 | const off = try self.strtab.insert(gpa, name); | 3675 | const off = try self.strtab.insert(gpa, name); |
| 3639 | const gop = try self.getOrPutGlobal(off); | | |
| 3640 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; | 3676 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 3641 | const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, off); | 3677 | const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, off); |
| 3642 | if (!lookup_gop.found_existing) { | 3678 | if (!lookup_gop.found_existing) { |
| 3643 | const esym_index = try zig_module.addGlobalEsym(gpa); | 3679 | 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); |
| 3645 | esym.st_name = off; | 3681 | esym.st_name = off; |
| 3646 | lookup_gop.value_ptr.* = esym_index; | 3682 | lookup_gop.value_ptr.* = esym_index; |
| | 3683 | const gop = try self.getOrPutGlobal(off); |
| | 3684 | try zig_module.global_symbols.append(gpa, gop.index); |
| 3647 | } | 3685 | } |
| 3648 | return gop.index; | 3686 | return lookup_gop.value_ptr.*; |
| 3649 | } | 3687 | } |
| 3650 | | 3688 | |
| 3651 | const GetOrCreateComdatGroupOwnerResult = struct { | 3689 | const GetOrCreateComdatGroupOwnerResult = struct { |
| ... | @@ -3684,89 +3722,39 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO | ... | @@ -3684,89 +3722,39 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO |
| 3684 | return &self.comdat_groups_owners.items[index]; | 3722 | return &self.comdat_groups_owners.items[index]; |
| 3685 | } | 3723 | } |
| 3686 | | 3724 | |
| 3687 | fn reportUndefined(self: *Elf) !void { | 3725 | fn reportUndefined(self: *Elf, undefs: anytype) !void { |
| 3688 | const gpa = self.base.allocator; | 3726 | const gpa = self.base.allocator; |
| 3689 | const max_notes = 4; | 3727 | const max_notes = 4; |
| 3690 | | 3728 | |
| 3691 | try self.misc_errors.ensureUnusedCapacity(gpa, self.unresolved.keys().len); | 3729 | try self.misc_errors.ensureUnusedCapacity(gpa, undefs.count()); |
| 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; | | |
| 3732 | | 3730 | |
| 3733 | for (atom_ptr.relocs(self)) |rel| { | 3731 | var it = undefs.iterator(); |
| 3734 | const sym_index = object.symbols.items[rel.r_sym()]; | 3732 | while (it.next()) |entry| { |
| 3735 | if (self.unresolved.getIndex(sym_index)) |bin_index| { | 3733 | const undef_index = entry.key_ptr.*; |
| 3736 | const note = try std.fmt.allocPrint(gpa, "referenced by {}:{s}", .{ | 3734 | const atoms = entry.value_ptr.*.items; |
| 3737 | object.fmtPath(), | 3735 | const nnotes = @min(atoms.len, max_notes); |
| 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]; | | |
| 3754 | | 3736 | |
| 3755 | var notes = try std.ArrayList(link.File.ErrorMsg).initCapacity(gpa, max_notes + 1); | 3737 | var notes = try std.ArrayList(link.File.ErrorMsg).initCapacity(gpa, max_notes + 1); |
| 3756 | defer notes.deinit(); | 3738 | defer notes.deinit(); |
| 3757 | | 3739 | |
| 3758 | for (collected.notes[0..collected.notes_len]) |note| { | 3740 | for (atoms[0..nnotes]) |atom_index| { |
| 3759 | notes.appendAssumeCapacity(note); | 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 }); |
| 3760 | } | 3748 | } |
| 3761 | | 3749 | |
| 3762 | if (collected.notes_count > max_notes) { | 3750 | if (atoms.len > max_notes) { |
| 3763 | const remaining = collected.notes_count - max_notes; | 3751 | const remaining = atoms.len - max_notes; |
| 3764 | const note = try std.fmt.allocPrint(gpa, "referenced {d} more times", .{remaining}); | 3752 | const note = try std.fmt.allocPrint(gpa, "referenced {d} more times", .{remaining}); |
| 3765 | notes.appendAssumeCapacity(.{ .msg = note }); | 3753 | notes.appendAssumeCapacity(.{ .msg = note }); |
| 3766 | } | 3754 | } |
| 3767 | | 3755 | |
| 3768 | var err_msg = link.File.ErrorMsg{ | 3756 | 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)}), |
| 3770 | }; | 3758 | }; |
| 3771 | err_msg.notes = try notes.toOwnedSlice(); | 3759 | err_msg.notes = try notes.toOwnedSlice(); |
| 3772 | | 3760 | |
| ... | @@ -3931,7 +3919,7 @@ const DeclMetadata = struct { | ... | @@ -3931,7 +3919,7 @@ const DeclMetadata = struct { |
| 3931 | fn @"export"(m: DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 { | 3919 | fn @"export"(m: DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 { |
| 3932 | const zig_module = elf_file.file(elf_file.zig_module_index.?).?.zig_module; | 3920 | const zig_module = elf_file.file(elf_file.zig_module_index.?).?.zig_module; |
| 3933 | for (m.exports.items) |*exp| { | 3921 | 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); |
| 3935 | if (mem.eql(u8, name, exp_name)) return exp; | 3923 | if (mem.eql(u8, name, exp_name)) return exp; |
| 3936 | } | 3924 | } |
| 3937 | return null; | 3925 | return null; |