authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-28 07:53:03+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-29 11:40:20+02:00
log68dc1a3e3fc8ab739cb34ed536c71a02727b3825
treed2dc4f02055667163af318520600d8da9b9be865
parent0f02a1fcb0ea82c98de509e7ba9b7b8768f0d4ee

macho: report symbol collision as compiler error


2 files changed, 50 insertions(+), 18 deletions(-)

src/link/MachO.zig+46-17
...@@ -428,11 +428,14 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -428,11 +428,14 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
428 var actions = std.ArrayList(ResolveAction).init(self.base.allocator);428 var actions = std.ArrayList(ResolveAction).init(self.base.allocator);
429 defer actions.deinit();429 defer actions.deinit();
430 try self.resolveSymbols(&actions);430 try self.resolveSymbols(&actions);
431 try self.reportUndefined();
432431
433 if (self.getEntryPoint() == null) {432 if (self.getEntryPoint() == null) {
434 self.error_flags.no_entry_point_found = true;433 self.error_flags.no_entry_point_found = true;
435 }434 }
435 if (self.unresolved.count() > 0) {
436 try self.reportUndefined();
437 return error.FlushFailure;
438 }
436439
437 for (actions.items) |action| switch (action.kind) {440 for (actions.items) |action| switch (action.kind) {
438 .none => {},441 .none => {},
...@@ -1642,13 +1645,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {...@@ -1642,13 +1645,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
1642 // TODO redo this logic with corresponding logic in updateDeclExports to avoid this1645 // TODO redo this logic with corresponding logic in updateDeclExports to avoid this
1643 // ugly check.1646 // ugly check.
1644 if (self.mode == .zld) {1647 if (self.mode == .zld) {
1645 log.err("symbol '{s}' defined multiple times", .{sym_name});1648 try self.reportSymbolCollision(global, current);
1646 if (global.getFile()) |file| {
1647 log.err(" first definition in '{s}'", .{self.objects.items[file].name});
1648 }
1649 if (current.getFile()) |file| {
1650 log.err(" next definition in '{s}'", .{self.objects.items[file].name});
1651 }
1652 }1649 }
1653 return error.MultipleSymbolDefinitions;1650 return error.MultipleSymbolDefinitions;
1654 }1651 }
...@@ -1714,7 +1711,13 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u32) !void {...@@ -1714,7 +1711,13 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u32) !void {
1714 continue;1711 continue;
1715 }1712 }
17161713
1717 try self.resolveGlobalSymbol(.{ .sym_index = sym_index, .file = object_id + 1 });1714 self.resolveGlobalSymbol(.{
1715 .sym_index = sym_index,
1716 .file = object_id + 1,
1717 }) catch |err| switch (err) {
1718 error.MultipleSymbolDefinitions => return error.FlushFailure,
1719 else => |e| return e,
1720 };
1718 }1721 }
1719}1722}
17201723
...@@ -4833,20 +4836,16 @@ pub fn getSectionPrecedence(header: macho.section_64) u8 {...@@ -4833,20 +4836,16 @@ pub fn getSectionPrecedence(header: macho.section_64) u8 {
4833 return (@as(u8, @intCast(segment_precedence)) << 4) + section_precedence;4836 return (@as(u8, @intCast(segment_precedence)) << 4) + section_precedence;
4834}4837}
48354838
4836pub fn reportUndefined(self: *MachO) !void {4839pub fn reportUndefined(self: *MachO) error{OutOfMemory}!void {
4837 const count = self.unresolved.count();
4838 if (count == 0) return;
4839
4840 const gpa = self.base.allocator;4840 const gpa = self.base.allocator;
48414841 const count = self.unresolved.count();
4842 try self.misc_errors.ensureUnusedCapacity(gpa, count);4842 try self.misc_errors.ensureUnusedCapacity(gpa, count);
48434843
4844 for (self.unresolved.keys()) |global_index| {4844 for (self.unresolved.keys()) |global_index| {
4845 const global = self.globals.items[global_index];4845 const global = self.globals.items[global_index];
4846 const sym_name = self.getSymbolName(global);4846 const sym_name = self.getSymbolName(global);
48474847
4848 const nnotes: usize = if (global.getFile() == null) @as(usize, 0) else 1;4848 var notes = try std.ArrayList(File.ErrorMsg).initCapacity(gpa, 1);
4849 var notes = try std.ArrayList(File.ErrorMsg).initCapacity(gpa, nnotes);
4850 defer notes.deinit();4849 defer notes.deinit();
48514850
4852 if (global.getFile()) |file| {4851 if (global.getFile()) |file| {
...@@ -4863,8 +4862,38 @@ pub fn reportUndefined(self: *MachO) !void {...@@ -4863,8 +4862,38 @@ pub fn reportUndefined(self: *MachO) !void {
48634862
4864 self.misc_errors.appendAssumeCapacity(err_msg);4863 self.misc_errors.appendAssumeCapacity(err_msg);
4865 }4864 }
4865}
4866
4867fn reportSymbolCollision(
4868 self: *MachO,
4869 first: SymbolWithLoc,
4870 other: SymbolWithLoc,
4871) error{OutOfMemory}!void {
4872 const gpa = self.base.allocator;
4873 try self.misc_errors.ensureUnusedCapacity(gpa, 1);
4874
4875 var notes = try std.ArrayList(File.ErrorMsg).initCapacity(gpa, 2);
4876 defer notes.deinit();
4877
4878 if (first.getFile()) |file| {
4879 const note = try std.fmt.allocPrint(gpa, "first definition in {s}", .{
4880 self.objects.items[file].name,
4881 });
4882 notes.appendAssumeCapacity(.{ .msg = note });
4883 }
4884 if (other.getFile()) |file| {
4885 const note = try std.fmt.allocPrint(gpa, "next definition in {s}", .{
4886 self.objects.items[file].name,
4887 });
4888 notes.appendAssumeCapacity(.{ .msg = note });
4889 }
4890
4891 var err_msg = File.ErrorMsg{ .msg = try std.fmt.allocPrint(gpa, "symbol {s} defined multiple times", .{
4892 self.getSymbolName(first),
4893 }) };
4894 err_msg.notes = try notes.toOwnedSlice();
48664895
4867 return error.FlushFailure;4896 self.misc_errors.appendAssumeCapacity(err_msg);
4868}4897}
48694898
4870/// Binary search4899/// Binary search
src/link/MachO/zld.zig+4-1
...@@ -388,7 +388,10 @@ pub fn linkWithZld(...@@ -388,7 +388,10 @@ pub fn linkWithZld(
388 var actions = std.ArrayList(MachO.ResolveAction).init(gpa);388 var actions = std.ArrayList(MachO.ResolveAction).init(gpa);
389 defer actions.deinit();389 defer actions.deinit();
390 try macho_file.resolveSymbols(&actions);390 try macho_file.resolveSymbols(&actions);
391 try macho_file.reportUndefined();391 if (macho_file.unresolved.count() > 0) {
392 try macho_file.reportUndefined();
393 return error.FlushFailure;
394 }
392395
393 for (macho_file.objects.items, 0..) |*object, object_id| {396 for (macho_file.objects.items, 0..) |*object, object_id| {
394 try object.splitIntoAtoms(macho_file, @as(u32, @intCast(object_id)));397 try object.splitIntoAtoms(macho_file, @as(u32, @intCast(object_id)));