| 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,9 +1077,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1077 | .exe => return step.fail("cannot link with an executable build artifact", .{}), | 1077 | .exe => return step.fail("cannot link with an executable build artifact", .{}), |
| 1078 | .@"test" => return step.fail("cannot link with a test", .{}), | 1078 | .@"test" => return step.fail("cannot link with a test", .{}), |
| 1079 | .obj => { | 1079 | .obj => { |
| 1080 | const included_in_lib = !my_responsibility and | 1080 | const included_in_lib_or_obj = !my_responsibility and (compile.kind == .lib or compile.kind == .obj); |
| 1081 | compile.kind == .lib and other.kind == .obj; | 1081 | if (!already_linked and !included_in_lib_or_obj) { |
| 1082 | if (!already_linked and !included_in_lib) { | ||
| 1083 | try zig_args.append(other.getEmittedBin().getPath(b)); | 1082 | try zig_args.append(other.getEmittedBin().getPath(b)); |
| 1084 | total_linker_objects += 1; | 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,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 | try self.initOutputSections(); | 1310 | try self.initOutputSections(); |
| 1306 | try self.addLinkerDefinedSymbols(); | 1311 | try self.addLinkerDefinedSymbols(); |
| 1307 | self.claimUnresolved(); | 1312 | self.claimUnresolved(); |
| ... | @@ -3428,6 +3433,27 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -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 | fn initOutputSections(self: *Elf) !void { | 3457 | fn initOutputSections(self: *Elf) !void { |
| 3432 | for (self.objects.items) |index| { | 3458 | for (self.objects.items) |index| { |
| 3433 | try self.file(index).?.object.initOutputSections(self); | 3459 | try self.file(index).?.object.initOutputSections(self); |
| ... | @@ -6101,6 +6127,36 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { | ... | @@ -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 | fn reportMissingLibraryError( | 6160 | fn reportMissingLibraryError( |
| 6105 | self: *Elf, | 6161 | self: *Elf, |
| 6106 | checked_paths: []const []const u8, | 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,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. |
test/link/elf.zig+32-32| ... | @@ -695,41 +695,41 @@ fn testDsoUndef(b: *Build, opts: Options) *Step { | ... | @@ -695,41 +695,41 @@ fn testDsoUndef(b: *Build, opts: Options) *Step { |
| 695 | fn testEmitRelocatable(b: *Build, opts: Options) *Step { | 695 | fn testEmitRelocatable(b: *Build, opts: Options) *Step { |
| 696 | const test_step = addTestStep(b, "emit-relocatable", opts); | 696 | const test_step = addTestStep(b, "emit-relocatable", opts); |
| 697 | 697 | ||
| 698 | const obj1 = addObject(b, opts, .{ | 698 | const a_o = addObject(b, opts, .{ .name = "a", .zig_source_bytes = |
| 699 | .name = "obj1", | 699 | \\const std = @import("std"); |
| 700 | .zig_source_bytes = | 700 | \\extern var bar: i32; |
| 701 | \\const std = @import("std"); | 701 | \\export fn foo() i32 { |
| 702 | \\extern var bar: i32; | 702 | \\ return bar; |
| 703 | \\export fn foo() i32 { | 703 | \\} |
| 704 | \\ return bar; | 704 | \\export fn printFoo() void { |
| 705 | \\} | 705 | \\ std.debug.print("foo={d}\n", .{foo()}); |
| 706 | \\export fn printFoo() void { | 706 | \\} |
| 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 | , | ||
| 717 | }); | 707 | }); |
| 718 | obj1.linkLibC(); | 708 | a_o.linkLibC(); |
| 719 | 709 | ||
| 720 | const exe = addExecutable(b, opts, .{ | 710 | const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes = |
| 721 | .name = "test", | 711 | \\#include <stdio.h> |
| 722 | .zig_source_bytes = | 712 | \\int bar = 42; |
| 723 | \\const std = @import("std"); | 713 | \\void printBar() { |
| 724 | \\extern fn printFoo() void; | 714 | \\ fprintf(stderr, "bar=%d\n", bar); |
| 725 | \\extern fn printBar() void; | 715 | \\} |
| 726 | \\pub fn main() void { | ||
| 727 | \\ printFoo(); | ||
| 728 | \\ printBar(); | ||
| 729 | \\} | ||
| 730 | , | ||
| 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 | exe.linkLibC(); | 733 | exe.linkLibC(); |
| 734 | 734 | ||
| 735 | const run = addRunArtifact(exe); | 735 | const run = addRunArtifact(exe); |