mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
Merge pull request #18560 from ziglang/elf-report-dupes
elf: report duplicate symbol definitions
This commit is contained in:
commit
3dddb881bf
@ -1077,9 +1077,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||
.exe => return step.fail("cannot link with an executable build artifact", .{}),
|
||||
.@"test" => return step.fail("cannot link with a test", .{}),
|
||||
.obj => {
|
||||
const included_in_lib = !my_responsibility and
|
||||
compile.kind == .lib and other.kind == .obj;
|
||||
if (!already_linked and !included_in_lib) {
|
||||
const included_in_lib_or_obj = !my_responsibility and (compile.kind == .lib or compile.kind == .obj);
|
||||
if (!already_linked and !included_in_lib_or_obj) {
|
||||
try zig_args.append(other.getEmittedBin().getPath(b));
|
||||
total_linker_objects += 1;
|
||||
}
|
||||
|
||||
@ -1302,6 +1302,11 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
|
||||
}
|
||||
}
|
||||
|
||||
self.checkDuplicates() catch |err| switch (err) {
|
||||
error.HasDuplicates => return error.FlushFailure,
|
||||
else => |e| return e,
|
||||
};
|
||||
|
||||
try self.initOutputSections();
|
||||
try self.addLinkerDefinedSymbols();
|
||||
self.claimUnresolved();
|
||||
@ -3428,6 +3433,27 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
|
||||
}
|
||||
}
|
||||
|
||||
fn checkDuplicates(self: *Elf) !void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
|
||||
var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa);
|
||||
defer {
|
||||
for (dupes.values()) |*list| {
|
||||
list.deinit(gpa);
|
||||
}
|
||||
dupes.deinit();
|
||||
}
|
||||
|
||||
if (self.zigObjectPtr()) |zig_object| {
|
||||
try zig_object.checkDuplicates(&dupes, self);
|
||||
}
|
||||
for (self.objects.items) |index| {
|
||||
try self.file(index).?.object.checkDuplicates(&dupes, self);
|
||||
}
|
||||
|
||||
try self.reportDuplicates(dupes);
|
||||
}
|
||||
|
||||
fn initOutputSections(self: *Elf) !void {
|
||||
for (self.objects.items) |index| {
|
||||
try self.file(index).?.object.initOutputSections(self);
|
||||
@ -6101,6 +6127,36 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void {
|
||||
const max_notes = 3;
|
||||
var has_dupes = false;
|
||||
var it = dupes.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const sym = self.symbol(entry.key_ptr.*);
|
||||
const notes = entry.value_ptr.*;
|
||||
const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
|
||||
|
||||
var err = try self.addErrorWithNotes(nnotes + 1);
|
||||
try err.addMsg(self, "duplicate symbol definition: {s}", .{sym.name(self)});
|
||||
try err.addNote(self, "defined by {}", .{sym.file(self).?.fmtPath()});
|
||||
|
||||
var inote: usize = 0;
|
||||
while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
|
||||
const file_ptr = self.file(notes.items[inote]).?;
|
||||
try err.addNote(self, "defined by {}", .{file_ptr.fmtPath()});
|
||||
}
|
||||
|
||||
if (notes.items.len > max_notes) {
|
||||
const remaining = notes.items.len - max_notes;
|
||||
try err.addNote(self, "defined {d} more times", .{remaining});
|
||||
}
|
||||
|
||||
has_dupes = true;
|
||||
}
|
||||
|
||||
if (has_dupes) return error.HasDuplicates;
|
||||
}
|
||||
|
||||
fn reportMissingLibraryError(
|
||||
self: *Elf,
|
||||
checked_paths: []const []const u8,
|
||||
|
||||
@ -581,30 +581,30 @@ pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {
|
||||
pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
|
||||
const first_global = self.first_global orelse return;
|
||||
for (self.globals(), 0..) |index, i| {
|
||||
const sym_idx = @as(u32, @intCast(first_global + i));
|
||||
const this_sym = self.symtab.items[sym_idx];
|
||||
const sym_idx = first_global + i;
|
||||
const sym = self.symtab.items[sym_idx];
|
||||
const global = elf_file.symbol(index);
|
||||
const global_file = global.getFile(elf_file) orelse continue;
|
||||
const global_file = global.file(elf_file) orelse continue;
|
||||
|
||||
if (self.index == global_file.getIndex() or
|
||||
this_sym.st_shndx == elf.SHN_UNDEF or
|
||||
this_sym.st_bind() == elf.STB_WEAK or
|
||||
this_sym.st_shndx == elf.SHN_COMMON) continue;
|
||||
if (self.index == global_file.index() or
|
||||
sym.st_shndx == elf.SHN_UNDEF or
|
||||
sym.st_bind() == elf.STB_WEAK or
|
||||
sym.st_shndx == elf.SHN_COMMON) continue;
|
||||
|
||||
if (this_sym.st_shndx != elf.SHN_ABS) {
|
||||
const atom_index = self.atoms.items[this_sym.st_shndx];
|
||||
if (sym.st_shndx != elf.SHN_ABS) {
|
||||
const atom_index = self.atoms.items[sym.st_shndx];
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
}
|
||||
|
||||
elf_file.base.fatal("multiple definition: {}: {}: {s}", .{
|
||||
self.fmtPath(),
|
||||
global_file.fmtPath(),
|
||||
global.getName(elf_file),
|
||||
});
|
||||
const gop = try dupes.getOrPut(index);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{};
|
||||
}
|
||||
try gop.value_ptr.append(elf_file.base.comp.gpa, self.index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -451,6 +451,32 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
|
||||
for (self.globals(), 0..) |index, i| {
|
||||
const esym = self.global_esyms.items(.elf_sym)[i];
|
||||
const shndx = self.global_esyms.items(.shndx)[i];
|
||||
const global = elf_file.symbol(index);
|
||||
const global_file = global.file(elf_file) orelse continue;
|
||||
|
||||
if (self.index == global_file.index() or
|
||||
esym.st_shndx == elf.SHN_UNDEF or
|
||||
esym.st_bind() == elf.STB_WEAK or
|
||||
esym.st_shndx == elf.SHN_COMMON) continue;
|
||||
|
||||
if (esym.st_shndx == SHN_ATOM) {
|
||||
const atom_index = self.atoms.items[shndx];
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
}
|
||||
|
||||
const gop = try dupes.getOrPut(index);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{};
|
||||
}
|
||||
try gop.value_ptr.append(elf_file.base.comp.gpa, self.index);
|
||||
}
|
||||
}
|
||||
|
||||
/// This is just a temporary helper function that allows us to re-read what we wrote to file into a buffer.
|
||||
/// We need this so that we can write to an archive.
|
||||
/// TODO implement writing ZigObject data directly to a buffer instead.
|
||||
|
||||
@ -695,41 +695,41 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
|
||||
fn testEmitRelocatable(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "emit-relocatable", opts);
|
||||
|
||||
const obj1 = addObject(b, opts, .{
|
||||
.name = "obj1",
|
||||
.zig_source_bytes =
|
||||
\\const std = @import("std");
|
||||
\\extern var bar: i32;
|
||||
\\export fn foo() i32 {
|
||||
\\ return bar;
|
||||
\\}
|
||||
\\export fn printFoo() void {
|
||||
\\ std.debug.print("foo={d}\n", .{foo()});
|
||||
\\}
|
||||
,
|
||||
.c_source_bytes =
|
||||
\\#include <stdio.h>
|
||||
\\int bar = 42;
|
||||
\\void printBar() {
|
||||
\\ fprintf(stderr, "bar=%d\n", bar);
|
||||
\\}
|
||||
,
|
||||
const a_o = addObject(b, opts, .{ .name = "a", .zig_source_bytes =
|
||||
\\const std = @import("std");
|
||||
\\extern var bar: i32;
|
||||
\\export fn foo() i32 {
|
||||
\\ return bar;
|
||||
\\}
|
||||
\\export fn printFoo() void {
|
||||
\\ std.debug.print("foo={d}\n", .{foo()});
|
||||
\\}
|
||||
});
|
||||
obj1.linkLibC();
|
||||
a_o.linkLibC();
|
||||
|
||||
const exe = addExecutable(b, opts, .{
|
||||
.name = "test",
|
||||
.zig_source_bytes =
|
||||
\\const std = @import("std");
|
||||
\\extern fn printFoo() void;
|
||||
\\extern fn printBar() void;
|
||||
\\pub fn main() void {
|
||||
\\ printFoo();
|
||||
\\ printBar();
|
||||
\\}
|
||||
,
|
||||
const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes =
|
||||
\\#include <stdio.h>
|
||||
\\int bar = 42;
|
||||
\\void printBar() {
|
||||
\\ fprintf(stderr, "bar=%d\n", bar);
|
||||
\\}
|
||||
});
|
||||
exe.addObject(obj1);
|
||||
b_o.linkLibC();
|
||||
|
||||
const c_o = addObject(b, opts, .{ .name = "c" });
|
||||
c_o.addObject(a_o);
|
||||
c_o.addObject(b_o);
|
||||
|
||||
const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes =
|
||||
\\const std = @import("std");
|
||||
\\extern fn printFoo() void;
|
||||
\\extern fn printBar() void;
|
||||
\\pub fn main() void {
|
||||
\\ printFoo();
|
||||
\\ printBar();
|
||||
\\}
|
||||
});
|
||||
exe.addObject(c_o);
|
||||
exe.linkLibC();
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user