From 962b46148d573f62146a2752a0ab8cfd5f8da132 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 12 Sep 2023 14:36:55 +0200 Subject: [PATCH] elf: add simplistic symbol resolution --- src/link/Elf.zig | 17 ++++++++++++++++- src/link/Elf/Atom.zig | 4 ++-- src/link/Elf/Object.zig | 37 ++++++++++++++----------------------- src/link/Elf/Symbol.zig | 7 ++++--- src/link/Elf/ZigModule.zig | 31 +++++++++++++++++++++++++++---- src/link/Elf/file.zig | 12 ------------ 6 files changed, 63 insertions(+), 45 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b1051a7fe4..cde8243d57 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1045,6 +1045,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node try self.addLinkerDefinedSymbols(); + // Resolve symbols + self.resolveSymbols(); + if (self.unresolved.keys().len > 0) try self.reportUndefined(); self.allocateLinkerDefinedSymbols(); @@ -1321,6 +1324,18 @@ fn parseObject(self: *Elf, in_file: std.fs.File, path: []const u8, ctx: *ParseEr if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch; } +fn resolveSymbols(self: *Elf) void { + if (self.zig_module_index) |index| { + const zig_module = self.file(index).?.zig_module; + zig_module.resolveSymbols(self); + } + + for (self.objects.items) |index| { + const object = self.file(index).?.object; + object.resolveSymbols(self); + } +} + fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); @@ -2697,7 +2712,7 @@ pub fn updateDeclExports( const name_off = try self.strtab.insert(gpa, exp_name); const esym = &zig_module.global_esyms.items[sym_index]; esym.st_value = decl_sym.value; - esym.st_shndx = decl_sym.output_section_index; + esym.st_shndx = decl_sym.atom_index; esym.st_info = (stb_bits << 4) | stt_bits; esym.st_name = name_off; diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index c163aa8ecc..6a029d97a2 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -17,7 +17,7 @@ alignment: u8 = 0, input_section_index: Index = 0, /// Index of the output section. -output_section_index: u16 = 0, +output_section_index: Index = 0, /// Index of the input section containing this atom's relocs. relocs_section_index: Index = 0, @@ -484,7 +484,7 @@ fn format2( } } -pub const Index = u32; +pub const Index = u16; const std = @import("std"); const assert = std.debug.assert; diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 868ccb33c4..e2b45f45e4 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -245,10 +245,6 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void { const off = try elf_file.strtab.insert(gpa, name); const gop = try elf_file.getOrPutGlobal(off); self.symbols.addOneAssumeCapacity().* = gop.index; - - if (sym.st_shndx == elf.SHN_UNDEF) { - try elf_file.unresolved.put(gpa, gop.index, {}); - } } } @@ -388,34 +384,29 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf) !void { pub fn resolveSymbols(self: *Object, elf_file: *Elf) 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[sym_idx]; + const esym_index = @as(Symbol.Index, @intCast(first_global + i)); + const esym = self.symtab[esym_index]; - if (this_sym.st_shndx == elf.SHN_UNDEF) continue; + if (esym.st_shndx == elf.SHN_UNDEF) continue; - if (this_sym.st_shndx != elf.SHN_ABS and this_sym.st_shndx != elf.SHN_COMMON) { - const atom_index = self.atoms.items[this_sym.st_shndx]; + if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { + const atom_index = self.atoms.items[esym.st_shndx]; const atom = elf_file.atom(atom_index) orelse continue; if (!atom.alive) continue; } - _ = elf_file.unresolved.swapRemove(index); - const global = elf_file.symbol(index); - if (self.asFile().symbolRank(this_sym, !self.alive) < global.symbolRank(elf_file)) { - const atom = switch (this_sym.st_shndx) { + if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) { + const atom_index = switch (esym.st_shndx) { elf.SHN_ABS, elf.SHN_COMMON => 0, - else => self.atoms.items[this_sym.st_shndx], + else => self.atoms.items[esym.st_shndx], }; - global.* = .{ - .value = this_sym.st_value, - .name = global.name, - .atom = atom, - .sym_idx = sym_idx, - .file = self.index, - .ver_idx = elf_file.default_sym_version, - }; - if (this_sym.st_bind() == elf.STB_WEAK) global.flags.weak = true; + global.value = esym.st_value; + global.atom_index = atom_index; + global.esym_index = esym_index; + global.file_index = self.index; + global.version_index = elf_file.default_sym_version; + if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true; } } } diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 0f9c574555..22d3376b31 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -70,9 +70,10 @@ pub fn sourceSymbol(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym { const file_ptr = symbol.file(elf_file).?; switch (file_ptr) { .zig_module => |x| { - const is_global = x.globals_lookup.contains(symbol.name_offset); - if (is_global) return x.global_esyms.items[symbol.esym_index]; - return x.local_esyms.items[symbol.esym_index]; + const is_global = symbol.esym_index & 0x10000000 != 0; + const esym_index = symbol.esym_index & 0x0fffffff; + if (is_global) return x.global_esyms.items[esym_index]; + return x.local_esyms.items[esym_index]; }, .linker_defined => |x| return x.symtab.items[symbol.esym_index], .object => |x| return x.symtab[symbol.esym_index], diff --git a/src/link/Elf/ZigModule.zig b/src/link/Elf/ZigModule.zig index 8951894638..8a4e712310 100644 --- a/src/link/Elf/ZigModule.zig +++ b/src/link/Elf/ZigModule.zig @@ -62,7 +62,7 @@ pub fn addAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Sym const esym_index = try self.addLocalEsym(gpa); const esym = &self.local_esyms.items[esym_index]; - esym.st_shndx = output_section_index; + esym.st_shndx = atom_index; symbol_ptr.esym_index = esym_index; const relocs_index = @as(Atom.Index, @intCast(self.relocs.items.len)); @@ -74,9 +74,32 @@ pub fn addAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Sym } pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void { - _ = self; - _ = elf_file; - @panic("TODO"); + for (self.globals(), 0..) |index, i| { + const esym_index = @as(Symbol.Index, @intCast(i)) | 0x10000000; + const esym = self.global_esyms.items[i]; + + if (esym.st_shndx == elf.SHN_UNDEF) continue; + + if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { + const atom_index = self.atoms.keys()[esym.st_shndx]; + const atom = elf_file.atom(atom_index) orelse continue; + if (!atom.alive) continue; + } + + const global = elf_file.symbol(index); + if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) { + const atom_index = switch (esym.st_shndx) { + elf.SHN_ABS, elf.SHN_COMMON => 0, + else => self.atoms.keys()[esym.st_shndx], + }; + global.value = esym.st_value; + global.atom_index = atom_index; + global.esym_index = esym_index; + global.file_index = self.index; + global.version_index = elf_file.default_sym_version; + if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true; + } + } } pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void { diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index 828d4f4c1f..e7fb789217 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -30,18 +30,6 @@ pub const File = union(enum) { } } - pub fn resolveSymbols(file: File, elf_file: *Elf) void { - switch (file) { - inline else => |x| x.resolveSymbols(elf_file), - } - } - - // pub fn resetGlobals(file: File, elf_file: *Elf) void { - // switch (file) { - // inline else => |x| x.resetGlobals(elf_file), - // } - // } - pub fn isAlive(file: File) bool { return switch (file) { .zig_module => true,