diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b2646d11d8..02b463ff16 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -843,6 +843,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { sym.name_offset = name_off; esym.st_name = name_off; esym.st_info |= elf.STT_FILE; + esym.st_shndx = elf.SHN_ABS; } } } @@ -1299,22 +1300,19 @@ fn parseObject(self: *Elf, in_file: std.fs.File, path: []const u8, ctx: *ParseEr const gpa = self.base.allocator; const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32)); - const index = @as(File.Index, @intCast(self.files.slice().len)); - - var object = Object{ + const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); + self.files.set(index, .{ .object = .{ .path = path, .data = data, .index = index, - }; - errdefer object.deinit(gpa); + } }); + try self.objects.append(gpa, index); + + const object = self.file(index).?.object; try object.parse(self); ctx.detected_cpu_arch = object.header.?.e_machine.toTargetCpuArch().?; if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch; - - _ = try self.files.addOne(gpa); - self.files.set(index, .{ .object = object }); - try self.objects.append(gpa, index); } fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { @@ -2690,12 +2688,14 @@ pub fn updateDeclExports( break :blk sym_index; }; const sym = self.symbol(sym_index); + sym.flags.@"export" = true; sym.value = decl_sym.value; sym.atom_index = decl_sym.atom_index; sym.output_section_index = decl_sym.output_section_index; const esym = zig_module.sourceSymbol(sym_index, self); esym.* = decl_esym; esym.st_info = (stb_bits << 4) | stt_bits; + _ = self.unresolved.swapRemove(sym_index); } } @@ -3468,13 +3468,8 @@ pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index { pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 { _ = lib_name; - const gpa = self.base.allocator; - const name_off = try self.strtab.insert(gpa, name); - const gop = try self.getOrPutGlobal(name_off); - if (!gop.found_existing) { - try self.unresolved.putNoClobber(gpa, gop.index, {}); - } - return gop.index; + const zig_module = self.file(self.zig_module_index.?).?.zig_module; + return zig_module.addGlobal(name, self); } const GetOrCreateComdatGroupOwnerResult = struct { @@ -3519,42 +3514,83 @@ fn reportUndefined(self: *Elf) !void { try self.misc_errors.ensureUnusedCapacity(gpa, self.unresolved.keys().len); - for (self.unresolved.keys()) |sym_index| { - const undef_sym = self.symbol(sym_index); + const CollectStruct = struct { + notes: [max_notes]link.File.ErrorMsg = [_]link.File.ErrorMsg{.{ .msg = undefined }} ** max_notes, + notes_len: u3 = 0, + notes_count: usize = 0, + }; - var all_notes: usize = 0; - var notes = try std.ArrayList(link.File.ErrorMsg).initCapacity(gpa, max_notes + 1); - defer notes.deinit(); + const collect: []CollectStruct = try gpa.alloc(CollectStruct, self.unresolved.keys().len); + defer gpa.free(collect); + @memset(collect, .{}); - // Collect all references across all input files - if (self.zig_module_index) |index| { - const zig_module = self.file(index).?.zig_module; - for (zig_module.atoms.keys()) |atom_index| { - const atom_ptr = self.atom(atom_index).?; - if (!atom_ptr.alive) continue; + // Collect all references across all input files + if (self.zig_module_index) |index| { + const zig_module = self.file(index).?.zig_module; + for (zig_module.atoms.keys()) |atom_index| { + const atom_ptr = self.atom(atom_index).?; + if (!atom_ptr.alive) continue; - for (atom_ptr.relocs(self)) |rel| { - if (sym_index == rel.r_sym()) { - const note = try std.fmt.allocPrint(gpa, "referenced by {s}:{s}", .{ - zig_module.path, - atom_ptr.name(self), - }); - notes.appendAssumeCapacity(.{ .msg = note }); - all_notes += 1; - break; + for (atom_ptr.relocs(self)) |rel| { + if (self.unresolved.getIndex(rel.r_sym())) |bin_index| { + const note = try std.fmt.allocPrint(gpa, "referenced by {s}:{s}", .{ + zig_module.path, + atom_ptr.name(self), + }); + const bin = &collect[bin_index]; + if (bin.notes_len < max_notes) { + bin.notes[bin.notes_len] = .{ .msg = note }; + bin.notes_len += 1; } + bin.notes_count += 1; } } } + } - if (all_notes > max_notes) { - const remaining = all_notes - max_notes; + for (self.objects.items) |index| { + const object = self.file(index).?.object; + for (object.atoms.items) |atom_index| { + const atom_ptr = self.atom(atom_index) orelse continue; + if (!atom_ptr.alive) continue; + + for (atom_ptr.relocs(self)) |rel| { + const sym_index = object.symbols.items[rel.r_sym()]; + if (self.unresolved.getIndex(sym_index)) |bin_index| { + const note = try std.fmt.allocPrint(gpa, "referenced by {}:{s}", .{ + object.fmtPath(), + atom_ptr.name(self), + }); + const bin = &collect[bin_index]; + if (bin.notes_len < max_notes) { + bin.notes[bin.notes_len] = .{ .msg = note }; + bin.notes_len += 1; + } + bin.notes_count += 1; + } + } + } + } + + // Generate error notes + for (self.unresolved.keys(), 0..) |sym_index, bin_index| { + const collected = &collect[bin_index]; + + var notes = try std.ArrayList(link.File.ErrorMsg).initCapacity(gpa, max_notes + 1); + defer notes.deinit(); + + for (collected.notes[0..collected.notes_len]) |note| { + notes.appendAssumeCapacity(note); + } + + if (collected.notes_count > max_notes) { + const remaining = collected.notes_count - max_notes; const note = try std.fmt.allocPrint(gpa, "referenced {d} more times", .{remaining}); notes.appendAssumeCapacity(.{ .msg = note }); } var err_msg = link.File.ErrorMsg{ - .msg = try std.fmt.allocPrint(gpa, "undefined symbol: {s}", .{undef_sym.name(self)}), + .msg = try std.fmt.allocPrint(gpa, "undefined symbol: {s}", .{self.symbol(sym_index).name(self)}), }; err_msg.notes = try notes.toOwnedSlice(); diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index 98b5ff563e..0c6666e8bb 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -46,15 +46,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void { } } -// pub fn resetGlobals(self: *LinkerDefined, elf_file: *Elf) void { -// for (self.symbols.items) |index| { -// const global = elf_file.getSymbol(index); -// const name = global.name; -// global.* = .{}; -// global.name = name; -// } -// } - pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void { for (self.globals()) |global_index| { const global = elf_file.symbol(global_index); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index e4a1f432b6..aff1fa9182 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -187,6 +187,7 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8, atom.name_offset = try elf_file.strtab.insert(elf_file.base.allocator, name); atom.file_index = self.index; atom.input_section_index = shndx; + atom.alive = true; self.atoms.items[shndx] = atom_index; if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { @@ -244,6 +245,10 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void { const off = try elf_file.strtab.insert(gpa, name); const gop = try elf_file.getOrPutGlobal(off); self.symbols.addOneAssumeCapacity().* = gop.index; + + if (sym.st_shndx == elf.SHN_UNDEF) { + try elf_file.unresolved.put(gpa, gop.index, {}); + } } } @@ -394,6 +399,8 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void { if (!atom.alive) continue; } + _ = elf_file.unresolved.swapRemove(index); + const global = elf_file.symbol(index); if (self.asFile().symbolRank(this_sym, !self.alive) < global.symbolRank(elf_file)) { const atom = switch (this_sym.st_shndx) { @@ -598,7 +605,7 @@ pub fn globals(self: *Object) []const u32 { return self.symbols.items[start..]; } -pub inline fn shdrContents(self: *Object, index: u32) []const u8 { +pub fn shdrContents(self: *Object, index: u32) []const u8 { assert(index < self.shdrs.items.len); const shdr = self.shdrs.items[index]; return self.data[shdr.sh_offset..][0..shdr.sh_size]; diff --git a/src/link/Elf/ZigModule.zig b/src/link/Elf/ZigModule.zig index 72c3ca0132..cf14fcc169 100644 --- a/src/link/Elf/ZigModule.zig +++ b/src/link/Elf/ZigModule.zig @@ -58,7 +58,7 @@ pub fn addLocal(self: *ZigModule, elf_file: *Elf) !Symbol.Index { return symbol_index; } -pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.Index { +pub fn addGlobal(self: *ZigModule, name: []const u8, elf_file: *Elf) !Symbol.Index { const gpa = elf_file.base.allocator; try self.elf_global_symbols.ensureUnusedCapacity(gpa, 1); try self.global_symbols.ensureUnusedCapacity(gpa, 1); @@ -69,10 +69,12 @@ pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.I esym.st_name = off; esym.st_info = elf.STB_GLOBAL << 4; const gop = try elf_file.getOrPutGlobal(off); + if (!gop.found_existing) { + try elf_file.unresolved.putNoClobber(gpa, gop.index, {}); + } const sym = elf_file.symbol(gop.index); sym.file_index = self.index; sym.esym_index = esym_index; - sym.flags.@"export" = true; self.global_symbols.putAssumeCapacityNoClobber(gop.index, {}); return gop.index; }