authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-11 13:17:31+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-11 16:02:21+02:00
log65b9597c07ddc6328c9725e0731ae838666d9e20
treeec7e6918e418396157e35c8572bfacffdfffee00
parent7a9eba2f8597a94e4a6def62253e9bf5220a46af

elf: report undefined symbols as errors


2 files changed, 57 insertions(+), 2 deletions(-)

src/link.zig+1
...@@ -849,6 +849,7 @@ pub const File = struct {...@@ -849,6 +849,7 @@ pub const File = struct {
849849
850 pub fn miscErrors(base: *File) []const ErrorMsg {850 pub fn miscErrors(base: *File) []const ErrorMsg {
851 switch (base.tag) {851 switch (base.tag) {
852 .elf => return @fieldParentPtr(Elf, "base", base).misc_errors.items,
852 .macho => return @fieldParentPtr(MachO, "base", base).misc_errors.items,853 .macho => return @fieldParentPtr(MachO, "base", base).misc_errors.items,
853 else => return &.{},854 else => return &.{},
854 }855 }
src/link/Elf.zig+56-2
...@@ -87,7 +87,7 @@ start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},...@@ -87,7 +87,7 @@ start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
87symbols: std.ArrayListUnmanaged(Symbol) = .{},87symbols: std.ArrayListUnmanaged(Symbol) = .{},
88symbols_extra: std.ArrayListUnmanaged(u32) = .{},88symbols_extra: std.ArrayListUnmanaged(u32) = .{},
89resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},89resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
90unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{},90unresolved: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},
91symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},91symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
9292
93phdr_table_dirty: bool = false,93phdr_table_dirty: bool = false,
...@@ -102,6 +102,7 @@ debug_info_header_dirty: bool = false,...@@ -102,6 +102,7 @@ debug_info_header_dirty: bool = false,
102debug_line_header_dirty: bool = false,102debug_line_header_dirty: bool = false,
103103
104error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},104error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},
105misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
105106
106/// Table of tracked LazySymbols.107/// Table of tracked LazySymbols.
107lazy_syms: LazySymbolTable = .{},108lazy_syms: LazySymbolTable = .{},
...@@ -292,6 +293,8 @@ pub fn deinit(self: *Elf) void {...@@ -292,6 +293,8 @@ pub fn deinit(self: *Elf) void {
292 if (self.dwarf) |*dw| {293 if (self.dwarf) |*dw| {
293 dw.deinit();294 dw.deinit();
294 }295 }
296
297 self.misc_errors.deinit(gpa);
295}298}
296299
297pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {300pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
...@@ -1015,6 +1018,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1015,6 +1018,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10151018
1016 try self.addLinkerDefinedSymbols();1019 try self.addLinkerDefinedSymbols();
10171020
1021 if (self.unresolved.keys().len > 0) try self.reportUndefined();
1022
1018 self.allocateLinkerDefinedSymbols();1023 self.allocateLinkerDefinedSymbols();
10191024
1020 // Beyond this point, everything has been allocated a virtual address and we can resolve1025 // Beyond this point, everything has been allocated a virtual address and we can resolve
...@@ -3392,11 +3397,60 @@ pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32...@@ -3392,11 +3397,60 @@ pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32
3392 const name_off = try self.strtab.insert(gpa, name);3397 const name_off = try self.strtab.insert(gpa, name);
3393 const gop = try self.getOrPutGlobal(name_off);3398 const gop = try self.getOrPutGlobal(name_off);
3394 if (!gop.found_existing) {3399 if (!gop.found_existing) {
3395 try self.unresolved.putNoClobber(gpa, name_off, {});3400 try self.unresolved.putNoClobber(gpa, gop.index, {});
3396 }3401 }
3397 return gop.index;3402 return gop.index;
3398}3403}
33993404
3405fn reportUndefined(self: *Elf) !void {
3406 const gpa = self.base.allocator;
3407 const max_notes = 4;
3408
3409 try self.misc_errors.ensureUnusedCapacity(gpa, self.unresolved.keys().len);
3410
3411 for (self.unresolved.keys()) |sym_index| {
3412 const undef_sym = self.symbol(sym_index);
3413
3414 var all_notes: usize = 0;
3415 var notes = try std.ArrayList(link.File.ErrorMsg).initCapacity(gpa, max_notes + 1);
3416 defer notes.deinit();
3417
3418 // Collect all references across all input files
3419 if (self.zig_module_index) |index| {
3420 const zig_module = self.file(index).?.zig_module;
3421 for (zig_module.atoms.keys()) |atom_index| {
3422 const atom_ptr = self.atom(atom_index).?;
3423 if (!atom_ptr.alive) continue;
3424
3425 for (atom_ptr.relocs(self)) |rel| {
3426 if (sym_index == rel.r_sym()) {
3427 const note = try std.fmt.allocPrint(gpa, "referenced by {s}:{s}", .{
3428 zig_module.path,
3429 atom_ptr.name(self),
3430 });
3431 notes.appendAssumeCapacity(.{ .msg = note });
3432 all_notes += 1;
3433 break;
3434 }
3435 }
3436 }
3437 }
3438
3439 if (all_notes > max_notes) {
3440 const remaining = all_notes - max_notes;
3441 const note = try std.fmt.allocPrint(gpa, "referenced {d} more times", .{remaining});
3442 notes.appendAssumeCapacity(.{ .msg = note });
3443 }
3444
3445 var err_msg = link.File.ErrorMsg{
3446 .msg = try std.fmt.allocPrint(gpa, "undefined symbol: {s}", .{undef_sym.name(self)}),
3447 };
3448 err_msg.notes = try notes.toOwnedSlice();
3449
3450 self.misc_errors.appendAssumeCapacity(err_msg);
3451 }
3452}
3453
3400fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) {3454fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) {
3401 return .{ .data = self };3455 return .{ .data = self };
3402}3456}