authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-16 21:13:57+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-18 09:13:09+02:00
log34f34dbe3246547d4586d284cf44510e3f8feaa2
tree05602e26db6b788edc0e74eaa7b70ac98346de64
parentd19aab2e872df58c56a17ca7b9ee1ea9aab82b99

macho: reinstate duplicate definition checking


5 files changed, 86 insertions(+), 69 deletions(-)

src/link/MachO.zig+30-29
......@@ -26,6 +26,7 @@ resolver: SymbolResolver = .{},
2626/// This table will be populated after `scanRelocs` has run.
2727/// Key is symbol index.
2828undefs: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(Ref)) = .{},
29dupes: std.AutoHashMapUnmanaged(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)) = .{},
2930
3031dyld_info_cmd: macho.dyld_info_command = .{},
3132symtab_cmd: macho.symtab_command = .{},
......@@ -311,6 +312,13 @@ pub fn deinit(self: *MachO) void {
311312 }
312313 self.undefs.deinit(gpa);
313314 }
315 {
316 var it = self.dupes.iterator();
317 while (it.next()) |entry| {
318 entry.value_ptr.deinit(gpa);
319 }
320 self.dupes.deinit(gpa);
321 }
314322
315323 self.symtab.deinit(gpa);
316324 self.strtab.deinit(gpa);
......@@ -518,14 +526,13 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
518526 try dead_strip.gcAtoms(self);
519527 }
520528
521 // TODO
522 // self.checkDuplicates() catch |err| switch (err) {
523 // error.HasDuplicates => return error.FlushFailure,
524 // else => |e| {
525 // try self.reportUnexpectedError("unexpected error while checking for duplicate symbol definitions", .{});
526 // return e;
527 // },
528 // };
529 self.checkDuplicates() catch |err| switch (err) {
530 error.HasDuplicates => return error.FlushFailure,
531 else => |e| {
532 try self.reportUnexpectedError("unexpected error while checking for duplicate symbol definitions", .{});
533 return e;
534 },
535 };
529536
530537 self.markImportsAndExports();
531538 self.deadStripDylibs();
......@@ -1434,25 +1441,16 @@ fn claimUnresolved(self: *MachO) void {
14341441}
14351442
14361443fn checkDuplicates(self: *MachO) !void {
1437 const gpa = self.base.comp.gpa;
1438
1439 var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa);
1440 defer {
1441 for (dupes.values()) |*list| {
1442 list.deinit(gpa);
1443 }
1444 dupes.deinit();
1445 }
1446
14471444 if (self.getZigObject()) |zo| {
1448 try zo.checkDuplicates(&dupes, self);
1445 try zo.asFile().checkDuplicates(self);
14491446 }
1450
14511447 for (self.objects.items) |index| {
1452 try self.getFile(index).?.object.checkDuplicates(&dupes, self);
1448 try self.getFile(index).?.checkDuplicates(self);
14531449 }
1454
1455 try self.reportDuplicates(dupes);
1450 if (self.getInternalObject()) |obj| {
1451 try obj.asFile().checkDuplicates(self);
1452 }
1453 try self.reportDuplicates();
14561454}
14571455
14581456fn markImportsAndExports(self: *MachO) void {
......@@ -3737,22 +3735,23 @@ pub fn reportUnexpectedError(self: *MachO, comptime format: []const u8, args: an
37373735 try err.addNote(self, "please report this as a linker bug on https://github.com/ziglang/zig/issues/new/choose", .{});
37383736}
37393737
3740fn reportDuplicates(self: *MachO, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void {
3738fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
37413739 const tracy = trace(@src());
37423740 defer tracy.end();
37433741
37443742 const max_notes = 3;
37453743
37463744 var has_dupes = false;
3747 var it = dupes.iterator();
3745 var it = self.dupes.iterator();
37483746 while (it.next()) |entry| {
3749 const sym = self.getSymbol(entry.key_ptr.*);
3747 const sym = self.resolver.keys.items[entry.key_ptr.* - 1];
37503748 const notes = entry.value_ptr.*;
37513749 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
37523750
37533751 var err = try self.addErrorWithNotes(nnotes + 1);
37543752 try err.addMsg(self, "duplicate symbol definition: {s}", .{sym.getName(self)});
37553753 try err.addNote(self, "defined by {}", .{sym.getFile(self).?.fmtPath()});
3754 has_dupes = true;
37563755
37573756 var inote: usize = 0;
37583757 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
......@@ -3764,10 +3763,7 @@ fn reportDuplicates(self: *MachO, dupes: anytype) error{ HasDuplicates, OutOfMem
37643763 const remaining = notes.items.len - max_notes;
37653764 try err.addNote(self, "defined {d} more times", .{remaining});
37663765 }
3767
3768 has_dupes = true;
37693766 }
3770
37713767 if (has_dupes) return error.HasDuplicates;
37723768}
37733769
......@@ -4452,6 +4448,11 @@ pub const SymbolResolver = struct {
44524448 return ref.getSymbol(macho_file).?.getName(macho_file);
44534449 }
44544450
4451 pub fn getFile(key: Key, macho_file: *MachO) ?File {
4452 const ref = Ref{ .index = key.index, .file = key.file };
4453 return ref.getFile(macho_file);
4454 }
4455
44554456 fn eql(key: Key, other: Key, macho_file: *MachO) bool {
44564457 const key_name = key.getName(macho_file);
44574458 const other_name = other.getName(macho_file);
src/link/MachO/Object.zig-19
......@@ -1550,25 +1550,6 @@ pub fn mergeSymbolVisibility(self: *Object, macho_file: *MachO) void {
15501550 }
15511551}
15521552
1553// TODO
1554// pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{OutOfMemory}!void {
1555// for (self.symbols.items, 0..) |index, nlist_idx| {
1556// const sym = macho_file.getSymbol(index);
1557// if (sym.visibility != .global) continue;
1558// const file = sym.getFile(macho_file) orelse continue;
1559// if (file.getIndex() == self.index) continue;
1560
1561// const nlist = self.symtab.items(.nlist)[nlist_idx];
1562// if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) {
1563// const gop = try dupes.getOrPut(index);
1564// if (!gop.found_existing) {
1565// gop.value_ptr.* = .{};
1566// }
1567// try gop.value_ptr.append(macho_file.base.comp.gpa, self.index);
1568// }
1569// }
1570// }
1571
15721553pub fn scanRelocs(self: *Object, macho_file: *MachO) !void {
15731554 const tracy = trace(@src());
15741555 defer tracy.end();
src/link/MachO/ZigObject.zig-19
......@@ -308,25 +308,6 @@ pub fn mergeSymbolVisibility(self: *ZigObject, macho_file: *MachO) void {
308308 }
309309}
310310
311// TODO
312// pub fn checkDuplicates(self: *ZigObject, dupes: anytype, macho_file: *MachO) !void {
313// for (self.symbols.items, 0..) |index, nlist_idx| {
314// const sym = macho_file.getSymbol(index);
315// if (sym.visibility != .global) continue;
316// const file = sym.getFile(macho_file) orelse continue;
317// if (file.getIndex() == self.index) continue;
318
319// const nlist = self.symtab.items(.nlist)[nlist_idx];
320// if (!nlist.undf() and !nlist.tentative() and !(nlist.weakDef() or nlist.pext())) {
321// const gop = try dupes.getOrPut(index);
322// if (!gop.found_existing) {
323// gop.value_ptr.* = .{};
324// }
325// try gop.value_ptr.append(macho_file.base.comp.gpa, self.index);
326// }
327// }
328// }
329
330311pub fn resolveLiterals(self: *ZigObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void {
331312 _ = self;
332313 _ = lp;
src/link/MachO/file.zig+24-2
......@@ -24,7 +24,7 @@ pub const File = union(enum) {
2424 _ = options;
2525 switch (file) {
2626 .zig_object => |x| try writer.writeAll(x.path),
27 .internal => try writer.writeAll(""),
27 .internal => try writer.writeAll("internal"),
2828 .object => |x| try writer.print("{}", .{x.fmtPath()}),
2929 .dylib => |x| try writer.writeAll(x.path),
3030 }
......@@ -57,7 +57,7 @@ pub const File = union(enum) {
5757 weak: bool = false,
5858 tentative: bool = false,
5959 }) u32 {
60 if (file == .object and !args.archive) {
60 if (file != .dylib and !args.archive) {
6161 const base: u32 = blk: {
6262 if (args.tentative) break :blk 3;
6363 break :blk if (args.weak) 2 else 1;
......@@ -254,6 +254,28 @@ pub const File = union(enum) {
254254 }
255255 }
256256
257 pub fn checkDuplicates(file: File, macho_file: *MachO) !void {
258 const tracy = trace(@src());
259 defer tracy.end();
260
261 const gpa = macho_file.base.comp.gpa;
262
263 for (file.getSymbols(), file.getNlists(), 0..) |sym, nlist, i| {
264 if (sym.visibility != .global) continue;
265 if (sym.flags.weak) continue;
266 if (nlist.undf()) continue;
267 const ref = file.getSymbolRef(@intCast(i), macho_file);
268 const ref_file = ref.getFile(macho_file) orelse continue;
269 if (ref_file.getIndex() == file.getIndex()) continue;
270
271 const gop = try macho_file.dupes.getOrPut(gpa, file.getGlobals()[i]);
272 if (!gop.found_existing) {
273 gop.value_ptr.* = .{};
274 }
275 try gop.value_ptr.append(gpa, file.getIndex());
276 }
277 }
278
257279 pub fn initOutputSections(file: File, macho_file: *MachO) !void {
258280 const tracy = trace(@src());
259281 defer tracy.end();
test/link/macho.zig+32
......@@ -30,6 +30,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
3030
3131 // Exercise linker with LLVM backend
3232 macho_step.dependOn(testDeadStrip(b, .{ .target = default_target }));
33 macho_step.dependOn(testDuplicateDefinitions(b, .{ .target = default_target }));
3334 macho_step.dependOn(testEmptyObject(b, .{ .target = default_target }));
3435 macho_step.dependOn(testEmptyZig(b, .{ .target = default_target }));
3536 macho_step.dependOn(testEntryPoint(b, .{ .target = default_target }));
......@@ -182,6 +183,37 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {
182183 return test_step;
183184}
184185
186fn testDuplicateDefinitions(b: *Build, opts: Options) *Step {
187 const test_step = addTestStep(b, "duplicate-definitions", opts);
188
189 const obj = addObject(b, opts, .{ .name = "a", .zig_source_bytes =
190 \\var x: usize = 1;
191 \\export fn strong() void { x += 1; }
192 \\export fn weak() void { x += 1; }
193 });
194
195 const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes =
196 \\var x: usize = 1;
197 \\export fn strong() void { x += 1; }
198 \\comptime { @export(weakImpl, .{ .name = "weak", .linkage = .weak }); }
199 \\fn weakImpl() callconv(.C) void { x += 1; }
200 \\extern fn weak() void;
201 \\pub fn main() void {
202 \\ weak();
203 \\ strong();
204 \\}
205 });
206 exe.addObject(obj);
207
208 expectLinkErrors(exe, test_step, .{ .exact = &.{
209 "error: duplicate symbol definition: _strong",
210 "note: defined by /?/a.o",
211 "note: defined by /?/main.o",
212 } });
213
214 return test_step;
215}
216
185217fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
186218 const test_step = addTestStep(b, "dead-strip-dylibs", opts);
187219