authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-12 00:10:54+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-12 00:10:54+02:00
log00787885f4f99a92d85b496ff9e03993d69b1cf6
treeff86e3d84ec68c39a8db90bb2388b613a570534d
parent67d458370dfc87753e9938e7af94cb86e3bc98cc

elf: report undefined symbols in objects


4 files changed, 88 insertions(+), 52 deletions(-)

src/link/Elf.zig+76-40
...@@ -843,6 +843,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -843,6 +843,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
843 sym.name_offset = name_off;843 sym.name_offset = name_off;
844 esym.st_name = name_off;844 esym.st_name = name_off;
845 esym.st_info |= elf.STT_FILE;845 esym.st_info |= elf.STT_FILE;
846 esym.st_shndx = elf.SHN_ABS;
846 }847 }
847 }848 }
848}849}
...@@ -1299,22 +1300,19 @@ fn parseObject(self: *Elf, in_file: std.fs.File, path: []const u8, ctx: *ParseEr...@@ -1299,22 +1300,19 @@ fn parseObject(self: *Elf, in_file: std.fs.File, path: []const u8, ctx: *ParseEr
12991300
1300 const gpa = self.base.allocator;1301 const gpa = self.base.allocator;
1301 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));1302 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
1302 const index = @as(File.Index, @intCast(self.files.slice().len));1303 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
13031304 self.files.set(index, .{ .object = .{
1304 var object = Object{
1305 .path = path,1305 .path = path,
1306 .data = data,1306 .data = data,
1307 .index = index,1307 .index = index,
1308 };1308 } });
1309 errdefer object.deinit(gpa);1309 try self.objects.append(gpa, index);
1310
1311 const object = self.file(index).?.object;
1310 try object.parse(self);1312 try object.parse(self);
13111313
1312 ctx.detected_cpu_arch = object.header.?.e_machine.toTargetCpuArch().?;1314 ctx.detected_cpu_arch = object.header.?.e_machine.toTargetCpuArch().?;
1313 if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;1315 if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
1314
1315 _ = try self.files.addOne(gpa);
1316 self.files.set(index, .{ .object = object });
1317 try self.objects.append(gpa, index);
1318}1316}
13191317
1320fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {1318fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
...@@ -2690,12 +2688,14 @@ pub fn updateDeclExports(...@@ -2690,12 +2688,14 @@ pub fn updateDeclExports(
2690 break :blk sym_index;2688 break :blk sym_index;
2691 };2689 };
2692 const sym = self.symbol(sym_index);2690 const sym = self.symbol(sym_index);
2691 sym.flags.@"export" = true;
2693 sym.value = decl_sym.value;2692 sym.value = decl_sym.value;
2694 sym.atom_index = decl_sym.atom_index;2693 sym.atom_index = decl_sym.atom_index;
2695 sym.output_section_index = decl_sym.output_section_index;2694 sym.output_section_index = decl_sym.output_section_index;
2696 const esym = zig_module.sourceSymbol(sym_index, self);2695 const esym = zig_module.sourceSymbol(sym_index, self);
2697 esym.* = decl_esym;2696 esym.* = decl_esym;
2698 esym.st_info = (stb_bits << 4) | stt_bits;2697 esym.st_info = (stb_bits << 4) | stt_bits;
2698 _ = self.unresolved.swapRemove(sym_index);
2699 }2699 }
2700}2700}
27012701
...@@ -3468,13 +3468,8 @@ pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {...@@ -3468,13 +3468,8 @@ pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {
34683468
3469pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {3469pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
3470 _ = lib_name;3470 _ = lib_name;
3471 const gpa = self.base.allocator;3471 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3472 const name_off = try self.strtab.insert(gpa, name);3472 return zig_module.addGlobal(name, self);
3473 const gop = try self.getOrPutGlobal(name_off);
3474 if (!gop.found_existing) {
3475 try self.unresolved.putNoClobber(gpa, gop.index, {});
3476 }
3477 return gop.index;
3478}3473}
34793474
3480const GetOrCreateComdatGroupOwnerResult = struct {3475const GetOrCreateComdatGroupOwnerResult = struct {
...@@ -3519,42 +3514,83 @@ fn reportUndefined(self: *Elf) !void {...@@ -3519,42 +3514,83 @@ fn reportUndefined(self: *Elf) !void {
35193514
3520 try self.misc_errors.ensureUnusedCapacity(gpa, self.unresolved.keys().len);3515 try self.misc_errors.ensureUnusedCapacity(gpa, self.unresolved.keys().len);
35213516
3522 for (self.unresolved.keys()) |sym_index| {3517 const CollectStruct = struct {
3523 const undef_sym = self.symbol(sym_index);3518 notes: [max_notes]link.File.ErrorMsg = [_]link.File.ErrorMsg{.{ .msg = undefined }} ** max_notes,
3519 notes_len: u3 = 0,
3520 notes_count: usize = 0,
3521 };
35243522
3525 var all_notes: usize = 0;3523 const collect: []CollectStruct = try gpa.alloc(CollectStruct, self.unresolved.keys().len);
3526 var notes = try std.ArrayList(link.File.ErrorMsg).initCapacity(gpa, max_notes + 1);3524 defer gpa.free(collect);
3527 defer notes.deinit();3525 @memset(collect, .{});
35283526
3529 // Collect all references across all input files3527 // Collect all references across all input files
3530 if (self.zig_module_index) |index| {3528 if (self.zig_module_index) |index| {
3531 const zig_module = self.file(index).?.zig_module;3529 const zig_module = self.file(index).?.zig_module;
3532 for (zig_module.atoms.keys()) |atom_index| {3530 for (zig_module.atoms.keys()) |atom_index| {
3533 const atom_ptr = self.atom(atom_index).?;3531 const atom_ptr = self.atom(atom_index).?;
3534 if (!atom_ptr.alive) continue;3532 if (!atom_ptr.alive) continue;
35353533
3536 for (atom_ptr.relocs(self)) |rel| {3534 for (atom_ptr.relocs(self)) |rel| {
3537 if (sym_index == rel.r_sym()) {3535 if (self.unresolved.getIndex(rel.r_sym())) |bin_index| {
3538 const note = try std.fmt.allocPrint(gpa, "referenced by {s}:{s}", .{3536 const note = try std.fmt.allocPrint(gpa, "referenced by {s}:{s}", .{
3539 zig_module.path,3537 zig_module.path,
3540 atom_ptr.name(self),3538 atom_ptr.name(self),
3541 });3539 });
3542 notes.appendAssumeCapacity(.{ .msg = note });3540 const bin = &collect[bin_index];
3543 all_notes += 1;3541 if (bin.notes_len < max_notes) {
3544 break;3542 bin.notes[bin.notes_len] = .{ .msg = note };
3543 bin.notes_len += 1;
3545 }3544 }
3545 bin.notes_count += 1;
3546 }3546 }
3547 }3547 }
3548 }3548 }
3549 }
3550
3551 for (self.objects.items) |index| {
3552 const object = self.file(index).?.object;
3553 for (object.atoms.items) |atom_index| {
3554 const atom_ptr = self.atom(atom_index) orelse continue;
3555 if (!atom_ptr.alive) continue;
3556
3557 for (atom_ptr.relocs(self)) |rel| {
3558 const sym_index = object.symbols.items[rel.r_sym()];
3559 if (self.unresolved.getIndex(sym_index)) |bin_index| {
3560 const note = try std.fmt.allocPrint(gpa, "referenced by {}:{s}", .{
3561 object.fmtPath(),
3562 atom_ptr.name(self),
3563 });
3564 const bin = &collect[bin_index];
3565 if (bin.notes_len < max_notes) {
3566 bin.notes[bin.notes_len] = .{ .msg = note };
3567 bin.notes_len += 1;
3568 }
3569 bin.notes_count += 1;
3570 }
3571 }
3572 }
3573 }
3574
3575 // Generate error notes
3576 for (self.unresolved.keys(), 0..) |sym_index, bin_index| {
3577 const collected = &collect[bin_index];
3578
3579 var notes = try std.ArrayList(link.File.ErrorMsg).initCapacity(gpa, max_notes + 1);
3580 defer notes.deinit();
3581
3582 for (collected.notes[0..collected.notes_len]) |note| {
3583 notes.appendAssumeCapacity(note);
3584 }
35493585
3550 if (all_notes > max_notes) {3586 if (collected.notes_count > max_notes) {
3551 const remaining = all_notes - max_notes;3587 const remaining = collected.notes_count - max_notes;
3552 const note = try std.fmt.allocPrint(gpa, "referenced {d} more times", .{remaining});3588 const note = try std.fmt.allocPrint(gpa, "referenced {d} more times", .{remaining});
3553 notes.appendAssumeCapacity(.{ .msg = note });3589 notes.appendAssumeCapacity(.{ .msg = note });
3554 }3590 }
35553591
3556 var err_msg = link.File.ErrorMsg{3592 var err_msg = link.File.ErrorMsg{
3557 .msg = try std.fmt.allocPrint(gpa, "undefined symbol: {s}", .{undef_sym.name(self)}),3593 .msg = try std.fmt.allocPrint(gpa, "undefined symbol: {s}", .{self.symbol(sym_index).name(self)}),
3558 };3594 };
3559 err_msg.notes = try notes.toOwnedSlice();3595 err_msg.notes = try notes.toOwnedSlice();
35603596
src/link/Elf/LinkerDefined.zig-9
...@@ -46,15 +46,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -46,15 +46,6 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
46 }46 }
47}47}
4848
49// pub fn resetGlobals(self: *LinkerDefined, elf_file: *Elf) void {
50// for (self.symbols.items) |index| {
51// const global = elf_file.getSymbol(index);
52// const name = global.name;
53// global.* = .{};
54// global.name = name;
55// }
56// }
57
58pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {49pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {
59 for (self.globals()) |global_index| {50 for (self.globals()) |global_index| {
60 const global = elf_file.symbol(global_index);51 const global = elf_file.symbol(global_index);
src/link/Elf/Object.zig+8-1
...@@ -187,6 +187,7 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8,...@@ -187,6 +187,7 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8,
187 atom.name_offset = try elf_file.strtab.insert(elf_file.base.allocator, name);187 atom.name_offset = try elf_file.strtab.insert(elf_file.base.allocator, name);
188 atom.file_index = self.index;188 atom.file_index = self.index;
189 atom.input_section_index = shndx;189 atom.input_section_index = shndx;
190 atom.alive = true;
190 self.atoms.items[shndx] = atom_index;191 self.atoms.items[shndx] = atom_index;
191192
192 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {193 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
...@@ -244,6 +245,10 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void {...@@ -244,6 +245,10 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void {
244 const off = try elf_file.strtab.insert(gpa, name);245 const off = try elf_file.strtab.insert(gpa, name);
245 const gop = try elf_file.getOrPutGlobal(off);246 const gop = try elf_file.getOrPutGlobal(off);
246 self.symbols.addOneAssumeCapacity().* = gop.index;247 self.symbols.addOneAssumeCapacity().* = gop.index;
248
249 if (sym.st_shndx == elf.SHN_UNDEF) {
250 try elf_file.unresolved.put(gpa, gop.index, {});
251 }
247 }252 }
248}253}
249254
...@@ -394,6 +399,8 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {...@@ -394,6 +399,8 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
394 if (!atom.alive) continue;399 if (!atom.alive) continue;
395 }400 }
396401
402 _ = elf_file.unresolved.swapRemove(index);
403
397 const global = elf_file.symbol(index);404 const global = elf_file.symbol(index);
398 if (self.asFile().symbolRank(this_sym, !self.alive) < global.symbolRank(elf_file)) {405 if (self.asFile().symbolRank(this_sym, !self.alive) < global.symbolRank(elf_file)) {
399 const atom = switch (this_sym.st_shndx) {406 const atom = switch (this_sym.st_shndx) {
...@@ -598,7 +605,7 @@ pub fn globals(self: *Object) []const u32 {...@@ -598,7 +605,7 @@ pub fn globals(self: *Object) []const u32 {
598 return self.symbols.items[start..];605 return self.symbols.items[start..];
599}606}
600607
601pub inline fn shdrContents(self: *Object, index: u32) []const u8 {608pub fn shdrContents(self: *Object, index: u32) []const u8 {
602 assert(index < self.shdrs.items.len);609 assert(index < self.shdrs.items.len);
603 const shdr = self.shdrs.items[index];610 const shdr = self.shdrs.items[index];
604 return self.data[shdr.sh_offset..][0..shdr.sh_size];611 return self.data[shdr.sh_offset..][0..shdr.sh_size];
src/link/Elf/ZigModule.zig+4-2
...@@ -58,7 +58,7 @@ pub fn addLocal(self: *ZigModule, elf_file: *Elf) !Symbol.Index {...@@ -58,7 +58,7 @@ pub fn addLocal(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
58 return symbol_index;58 return symbol_index;
59}59}
6060
61pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.Index {61pub fn addGlobal(self: *ZigModule, name: []const u8, elf_file: *Elf) !Symbol.Index {
62 const gpa = elf_file.base.allocator;62 const gpa = elf_file.base.allocator;
63 try self.elf_global_symbols.ensureUnusedCapacity(gpa, 1);63 try self.elf_global_symbols.ensureUnusedCapacity(gpa, 1);
64 try self.global_symbols.ensureUnusedCapacity(gpa, 1);64 try self.global_symbols.ensureUnusedCapacity(gpa, 1);
...@@ -69,10 +69,12 @@ pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.I...@@ -69,10 +69,12 @@ pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.I
69 esym.st_name = off;69 esym.st_name = off;
70 esym.st_info = elf.STB_GLOBAL << 4;70 esym.st_info = elf.STB_GLOBAL << 4;
71 const gop = try elf_file.getOrPutGlobal(off);71 const gop = try elf_file.getOrPutGlobal(off);
72 if (!gop.found_existing) {
73 try elf_file.unresolved.putNoClobber(gpa, gop.index, {});
74 }
72 const sym = elf_file.symbol(gop.index);75 const sym = elf_file.symbol(gop.index);
73 sym.file_index = self.index;76 sym.file_index = self.index;
74 sym.esym_index = esym_index;77 sym.esym_index = esym_index;
75 sym.flags.@"export" = true;
76 self.global_symbols.putAssumeCapacityNoClobber(gop.index, {});78 self.global_symbols.putAssumeCapacityNoClobber(gop.index, {});
77 return gop.index;79 return gop.index;
78}80}