| author | |
| committer | |
| log | 3dddb881bfefbcd64aae7775ed72c42e37503674 |
| tree | d3a8523750581848381b796a3de59fc05b66c64f |
| parent | 852e7e24b5f15b489463bdabb0039e2a424e5ee6 |
| parent | b1ffc2b8b353f64362c27df2ecc44436db234a29 |
| signature |
elf: report duplicate symbol definitions5 files changed, 131 insertions(+), 50 deletions(-)
lib/std/Build/Step/Compile.zig+2-3| ... | ... | @@ -1077,9 +1077,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1077 | 1077 | .exe => return step.fail("cannot link with an executable build artifact", .{}), |
| 1078 | 1078 | .@"test" => return step.fail("cannot link with a test", .{}), |
| 1079 | 1079 | .obj => { |
| 1080 | const included_in_lib = !my_responsibility and | |
| 1081 | compile.kind == .lib and other.kind == .obj; | |
| 1082 | if (!already_linked and !included_in_lib) { | |
| 1080 | const included_in_lib_or_obj = !my_responsibility and (compile.kind == .lib or compile.kind == .obj); | |
| 1081 | if (!already_linked and !included_in_lib_or_obj) { | |
| 1083 | 1082 | try zig_args.append(other.getEmittedBin().getPath(b)); |
| 1084 | 1083 | total_linker_objects += 1; |
| 1085 | 1084 | } |
src/link/Elf.zig+56| ... | ... | @@ -1302,6 +1302,11 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1302 | 1302 | } |
| 1303 | 1303 | } |
| 1304 | 1304 | |
| 1305 | self.checkDuplicates() catch |err| switch (err) { | |
| 1306 | error.HasDuplicates => return error.FlushFailure, | |
| 1307 | else => |e| return e, | |
| 1308 | }; | |
| 1309 | ||
| 1305 | 1310 | try self.initOutputSections(); |
| 1306 | 1311 | try self.addLinkerDefinedSymbols(); |
| 1307 | 1312 | self.claimUnresolved(); |
| ... | ... | @@ -3428,6 +3433,27 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3428 | 3433 | } |
| 3429 | 3434 | } |
| 3430 | 3435 | |
| 3436 | fn checkDuplicates(self: *Elf) !void { | |
| 3437 | const gpa = self.base.comp.gpa; | |
| 3438 | ||
| 3439 | var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa); | |
| 3440 | defer { | |
| 3441 | for (dupes.values()) |*list| { | |
| 3442 | list.deinit(gpa); | |
| 3443 | } | |
| 3444 | dupes.deinit(); | |
| 3445 | } | |
| 3446 | ||
| 3447 | if (self.zigObjectPtr()) |zig_object| { | |
| 3448 | try zig_object.checkDuplicates(&dupes, self); | |
| 3449 | } | |
| 3450 | for (self.objects.items) |index| { | |
| 3451 | try self.file(index).?.object.checkDuplicates(&dupes, self); | |
| 3452 | } | |
| 3453 | ||
| 3454 | try self.reportDuplicates(dupes); | |
| 3455 | } | |
| 3456 | ||
| 3431 | 3457 | fn initOutputSections(self: *Elf) !void { |
| 3432 | 3458 | for (self.objects.items) |index| { |
| 3433 | 3459 | try self.file(index).?.object.initOutputSections(self); |
| ... | ... | @@ -6101,6 +6127,36 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { |
| 6101 | 6127 | } |
| 6102 | 6128 | } |
| 6103 | 6129 | |
| 6130 | fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void { | |
| 6131 | const max_notes = 3; | |
| 6132 | var has_dupes = false; | |
| 6133 | var it = dupes.iterator(); | |
| 6134 | while (it.next()) |entry| { | |
| 6135 | const sym = self.symbol(entry.key_ptr.*); | |
| 6136 | const notes = entry.value_ptr.*; | |
| 6137 | const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); | |
| 6138 | ||
| 6139 | var err = try self.addErrorWithNotes(nnotes + 1); | |
| 6140 | try err.addMsg(self, "duplicate symbol definition: {s}", .{sym.name(self)}); | |
| 6141 | try err.addNote(self, "defined by {}", .{sym.file(self).?.fmtPath()}); | |
| 6142 | ||
| 6143 | var inote: usize = 0; | |
| 6144 | while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { | |
| 6145 | const file_ptr = self.file(notes.items[inote]).?; | |
| 6146 | try err.addNote(self, "defined by {}", .{file_ptr.fmtPath()}); | |
| 6147 | } | |
| 6148 | ||
| 6149 | if (notes.items.len > max_notes) { | |
| 6150 | const remaining = notes.items.len - max_notes; | |
| 6151 | try err.addNote(self, "defined {d} more times", .{remaining}); | |
| 6152 | } | |
| 6153 | ||
| 6154 | has_dupes = true; | |
| 6155 | } | |
| 6156 | ||
| 6157 | if (has_dupes) return error.HasDuplicates; | |
| 6158 | } | |
| 6159 | ||
| 6104 | 6160 | fn reportMissingLibraryError( |
| 6105 | 6161 | self: *Elf, |
| 6106 | 6162 | 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 | 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 | 585 | const first_global = self.first_global orelse return; |
| 586 | 586 | for (self.globals(), 0..) |index, i| { |
| 587 | const sym_idx = @as(u32, @intCast(first_global + i)); | |
| 588 | const this_sym = self.symtab.items[sym_idx]; | |
| 587 | const sym_idx = first_global + i; | |
| 588 | const sym = self.symtab.items[sym_idx]; | |
| 589 | 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 | |
| 593 | this_sym.st_shndx == elf.SHN_UNDEF or | |
| 594 | this_sym.st_bind() == elf.STB_WEAK or | |
| 595 | this_sym.st_shndx == elf.SHN_COMMON) continue; | |
| 592 | if (self.index == global_file.index() or | |
| 593 | sym.st_shndx == elf.SHN_UNDEF or | |
| 594 | sym.st_bind() == elf.STB_WEAK or | |
| 595 | sym.st_shndx == elf.SHN_COMMON) continue; | |
| 596 | 596 | |
| 597 | if (this_sym.st_shndx != elf.SHN_ABS) { | |
| 598 | const atom_index = self.atoms.items[this_sym.st_shndx]; | |
| 597 | if (sym.st_shndx != elf.SHN_ABS) { | |
| 598 | const atom_index = self.atoms.items[sym.st_shndx]; | |
| 599 | 599 | const atom = elf_file.atom(atom_index) orelse continue; |
| 600 | 600 | if (!atom.flags.alive) continue; |
| 601 | 601 | } |
| 602 | 602 | |
| 603 | elf_file.base.fatal("multiple definition: {}: {}: {s}", .{ | |
| 604 | self.fmtPath(), | |
| 605 | global_file.fmtPath(), | |
| 606 | global.getName(elf_file), | |
| 607 | }); | |
| 603 | const gop = try dupes.getOrPut(index); | |
| 604 | if (!gop.found_existing) { | |
| 605 | gop.value_ptr.* = .{}; | |
| 606 | } | |
| 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 | 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 | 480 | /// This is just a temporary helper function that allows us to re-read what we wrote to file into a buffer. |
| 455 | 481 | /// We need this so that we can write to an archive. |
| 456 | 482 | /// TODO implement writing ZigObject data directly to a buffer instead. |
test/link/elf.zig+32-32| ... | ... | @@ -695,41 +695,41 @@ fn testDsoUndef(b: *Build, opts: Options) *Step { |
| 695 | 695 | fn testEmitRelocatable(b: *Build, opts: Options) *Step { |
| 696 | 696 | const test_step = addTestStep(b, "emit-relocatable", opts); |
| 697 | 697 | |
| 698 | const obj1 = addObject(b, opts, .{ | |
| 699 | .name = "obj1", | |
| 700 | .zig_source_bytes = | |
| 701 | \\const std = @import("std"); | |
| 702 | \\extern var bar: i32; | |
| 703 | \\export fn foo() i32 { | |
| 704 | \\ return bar; | |
| 705 | \\} | |
| 706 | \\export fn printFoo() void { | |
| 707 | \\ std.debug.print("foo={d}\n", .{foo()}); | |
| 708 | \\} | |
| 709 | , | |
| 710 | .c_source_bytes = | |
| 711 | \\#include <stdio.h> | |
| 712 | \\int bar = 42; | |
| 713 | \\void printBar() { | |
| 714 | \\ fprintf(stderr, "bar=%d\n", bar); | |
| 715 | \\} | |
| 716 | , | |
| 698 | const a_o = addObject(b, opts, .{ .name = "a", .zig_source_bytes = | |
| 699 | \\const std = @import("std"); | |
| 700 | \\extern var bar: i32; | |
| 701 | \\export fn foo() i32 { | |
| 702 | \\ return bar; | |
| 703 | \\} | |
| 704 | \\export fn printFoo() void { | |
| 705 | \\ std.debug.print("foo={d}\n", .{foo()}); | |
| 706 | \\} | |
| 717 | 707 | }); |
| 718 | obj1.linkLibC(); | |
| 708 | a_o.linkLibC(); | |
| 719 | 709 | |
| 720 | const exe = addExecutable(b, opts, .{ | |
| 721 | .name = "test", | |
| 722 | .zig_source_bytes = | |
| 723 | \\const std = @import("std"); | |
| 724 | \\extern fn printFoo() void; | |
| 725 | \\extern fn printBar() void; | |
| 726 | \\pub fn main() void { | |
| 727 | \\ printFoo(); | |
| 728 | \\ printBar(); | |
| 729 | \\} | |
| 730 | , | |
| 710 | const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes = | |
| 711 | \\#include <stdio.h> | |
| 712 | \\int bar = 42; | |
| 713 | \\void printBar() { | |
| 714 | \\ fprintf(stderr, "bar=%d\n", bar); | |
| 715 | \\} | |
| 731 | 716 | }); |
| 732 | exe.addObject(obj1); | |
| 717 | b_o.linkLibC(); | |
| 718 | ||
| 719 | const c_o = addObject(b, opts, .{ .name = "c" }); | |
| 720 | c_o.addObject(a_o); | |
| 721 | c_o.addObject(b_o); | |
| 722 | ||
| 723 | const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes = | |
| 724 | \\const std = @import("std"); | |
| 725 | \\extern fn printFoo() void; | |
| 726 | \\extern fn printBar() void; | |
| 727 | \\pub fn main() void { | |
| 728 | \\ printFoo(); | |
| 729 | \\ printBar(); | |
| 730 | \\} | |
| 731 | }); | |
| 732 | exe.addObject(c_o); | |
| 733 | 733 | exe.linkLibC(); |
| 734 | 734 | |
| 735 | 735 | const run = addRunArtifact(exe); |