| author | |
| committer | |
| log | 7a96907b9233cd1385472a03ff75530d3a02556f |
| tree | 6ab7e0ca09fb13cbde775f282a381dbbf03de5ff |
| parent | 89d4ac628959fe301ee93b88fdc66ab1988d5f33 |
3 files changed, 97 insertions(+), 15 deletions(-)
src/link/Elf.zig+56| ... | @@ -1323,6 +1323,11 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1323,6 +1323,11 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1323 | } | 1323 | } |
| 1324 | } | 1324 | } |
| 1325 | 1325 | ||
| 1326 | self.checkDuplicates() catch |err| switch (err) { | ||
| 1327 | error.HasDuplicates => return error.FlushFailure, | ||
| 1328 | else => |e| return e, | ||
| 1329 | }; | ||
| 1330 | |||
| 1326 | try self.initOutputSections(); | 1331 | try self.initOutputSections(); |
| 1327 | try self.addLinkerDefinedSymbols(); | 1332 | try self.addLinkerDefinedSymbols(); |
| 1328 | self.claimUnresolved(); | 1333 | self.claimUnresolved(); |
| ... | @@ -3491,6 +3496,27 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3491,6 +3496,27 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3491 | } | 3496 | } |
| 3492 | } | 3497 | } |
| 3493 | 3498 | ||
| 3499 | fn checkDuplicates(self: *Elf) !void { | ||
| 3500 | const gpa = self.base.comp.gpa; | ||
| 3501 | |||
| 3502 | var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa); | ||
| 3503 | defer { | ||
| 3504 | for (dupes.values()) |*list| { | ||
| 3505 | list.deinit(gpa); | ||
| 3506 | } | ||
| 3507 | dupes.deinit(); | ||
| 3508 | } | ||
| 3509 | |||
| 3510 | if (self.zigObjectPtr()) |zig_object| { | ||
| 3511 | try zig_object.checkDuplicates(&dupes, self); | ||
| 3512 | } | ||
| 3513 | for (self.objects.items) |index| { | ||
| 3514 | try self.file(index).?.object.checkDuplicates(&dupes, self); | ||
| 3515 | } | ||
| 3516 | |||
| 3517 | try self.reportDuplicates(dupes); | ||
| 3518 | } | ||
| 3519 | |||
| 3494 | fn initOutputSections(self: *Elf) !void { | 3520 | fn initOutputSections(self: *Elf) !void { |
| 3495 | for (self.objects.items) |index| { | 3521 | for (self.objects.items) |index| { |
| 3496 | try self.file(index).?.object.initOutputSections(self); | 3522 | try self.file(index).?.object.initOutputSections(self); |
| ... | @@ -6164,6 +6190,36 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { | ... | @@ -6164,6 +6190,36 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { |
| 6164 | } | 6190 | } |
| 6165 | } | 6191 | } |
| 6166 | 6192 | ||
| 6193 | fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void { | ||
| 6194 | const max_notes = 3; | ||
| 6195 | var has_dupes = false; | ||
| 6196 | var it = dupes.iterator(); | ||
| 6197 | while (it.next()) |entry| { | ||
| 6198 | const sym = self.symbol(entry.key_ptr.*); | ||
| 6199 | const notes = entry.value_ptr.*; | ||
| 6200 | const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); | ||
| 6201 | |||
| 6202 | var err = try self.addErrorWithNotes(nnotes + 1); | ||
| 6203 | try err.addMsg(self, "duplicate symbol definition: {s}", .{sym.name(self)}); | ||
| 6204 | try err.addNote(self, "defined by {}", .{sym.file(self).?.fmtPath()}); | ||
| 6205 | |||
| 6206 | var inote: usize = 0; | ||
| 6207 | while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { | ||
| 6208 | const file_ptr = self.file(notes.items[inote]).?; | ||
| 6209 | try err.addNote(self, "defined by {}", .{file_ptr.fmtPath()}); | ||
| 6210 | } | ||
| 6211 | |||
| 6212 | if (notes.items.len > max_notes) { | ||
| 6213 | const remaining = notes.items.len - max_notes; | ||
| 6214 | try err.addNote(self, "defined {d} more times", .{remaining}); | ||
| 6215 | } | ||
| 6216 | |||
| 6217 | has_dupes = true; | ||
| 6218 | } | ||
| 6219 | |||
| 6220 | if (has_dupes) return error.HasDuplicates; | ||
| 6221 | } | ||
| 6222 | |||
| 6167 | fn reportMissingLibraryError( | 6223 | fn reportMissingLibraryError( |
| 6168 | self: *Elf, | 6224 | self: *Elf, |
| 6169 | checked_paths: []const []const u8, | 6225 | checked_paths: []const []const u8, |
src/link/Elf/Object.zig+15-15| ... | @@ -581,30 +581,30 @@ pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void { | ... | @@ -581,30 +581,30 @@ pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void { |
| 581 | } | 581 | } |
| 582 | } | 582 | } |
| 583 | 583 | ||
| 584 | pub fn checkDuplicates(self: *Object, elf_file: *Elf) void { | 584 | pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void { |
| 585 | const first_global = self.first_global orelse return; | 585 | const first_global = self.first_global orelse return; |
| 586 | for (self.globals(), 0..) |index, i| { | 586 | for (self.globals(), 0..) |index, i| { |
| 587 | const sym_idx = @as(u32, @intCast(first_global + i)); | 587 | const sym_idx = first_global + i; |
| 588 | const this_sym = self.symtab.items[sym_idx]; | 588 | const sym = self.symtab.items[sym_idx]; |
| 589 | const global = elf_file.symbol(index); | 589 | const global = elf_file.symbol(index); |
| 590 | const global_file = global.getFile(elf_file) orelse continue; | 590 | const global_file = global.file(elf_file) orelse continue; |
| 591 | 591 | ||
| 592 | if (self.index == global_file.getIndex() or | 592 | if (self.index == global_file.index() or |
| 593 | this_sym.st_shndx == elf.SHN_UNDEF or | 593 | sym.st_shndx == elf.SHN_UNDEF or |
| 594 | this_sym.st_bind() == elf.STB_WEAK or | 594 | sym.st_bind() == elf.STB_WEAK or |
| 595 | this_sym.st_shndx == elf.SHN_COMMON) continue; | 595 | sym.st_shndx == elf.SHN_COMMON) continue; |
| 596 | 596 | ||
| 597 | if (this_sym.st_shndx != elf.SHN_ABS) { | 597 | if (sym.st_shndx != elf.SHN_ABS) { |
| 598 | const atom_index = self.atoms.items[this_sym.st_shndx]; | 598 | const atom_index = self.atoms.items[sym.st_shndx]; |
| 599 | const atom = elf_file.atom(atom_index) orelse continue; | 599 | const atom = elf_file.atom(atom_index) orelse continue; |
| 600 | if (!atom.flags.alive) continue; | 600 | if (!atom.flags.alive) continue; |
| 601 | } | 601 | } |
| 602 | 602 | ||
| 603 | elf_file.base.fatal("multiple definition: {}: {}: {s}", .{ | 603 | const gop = try dupes.getOrPut(index); |
| 604 | self.fmtPath(), | 604 | if (!gop.found_existing) { |
| 605 | global_file.fmtPath(), | 605 | gop.value_ptr.* = .{}; |
| 606 | global.getName(elf_file), | 606 | } |
| 607 | }); | 607 | try gop.value_ptr.append(elf_file.base.comp.gpa, self.index); |
| 608 | } | 608 | } |
| 609 | } | 609 | } |
| 610 | 610 |
src/link/Elf/ZigObject.zig+26| ... | @@ -451,6 +451,32 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void { | ... | @@ -451,6 +451,32 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void { |
| 451 | } | 451 | } |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void { | ||
| 455 | for (self.globals(), 0..) |index, i| { | ||
| 456 | const esym = self.global_esyms.items(.elf_sym)[i]; | ||
| 457 | const shndx = self.global_esyms.items(.shndx)[i]; | ||
| 458 | const global = elf_file.symbol(index); | ||
| 459 | const global_file = global.file(elf_file) orelse continue; | ||
| 460 | |||
| 461 | if (self.index == global_file.index() or | ||
| 462 | esym.st_shndx == elf.SHN_UNDEF or | ||
| 463 | esym.st_bind() == elf.STB_WEAK or | ||
| 464 | esym.st_shndx == elf.SHN_COMMON) continue; | ||
| 465 | |||
| 466 | if (esym.st_shndx == SHN_ATOM) { | ||
| 467 | const atom_index = self.atoms.items[shndx]; | ||
| 468 | const atom = elf_file.atom(atom_index) orelse continue; | ||
| 469 | if (!atom.flags.alive) continue; | ||
| 470 | } | ||
| 471 | |||
| 472 | const gop = try dupes.getOrPut(index); | ||
| 473 | if (!gop.found_existing) { | ||
| 474 | gop.value_ptr.* = .{}; | ||
| 475 | } | ||
| 476 | try gop.value_ptr.append(elf_file.base.comp.gpa, self.index); | ||
| 477 | } | ||
| 478 | } | ||
| 479 | |||
| 454 | /// This is just a temporary helper function that allows us to re-read what we wrote to file into a buffer. | 480 | /// This is just a temporary helper function that allows us to re-read what we wrote to file into a buffer. |
| 455 | /// We need this so that we can write to an archive. | 481 | /// We need this so that we can write to an archive. |
| 456 | /// TODO implement writing ZigObject data directly to a buffer instead. | 482 | /// TODO implement writing ZigObject data directly to a buffer instead. |