From c654f3b0ee8d02d809bb458e1e006b4aa7c3cbc6 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 12 Sep 2023 15:44:16 +0200 Subject: [PATCH] elf: claim unresolved dangling symbols that can be claimed --- src/link/Elf.zig | 72 ++++++++++++++++++++------------------ src/link/Elf/Object.zig | 32 +++++++++++++++-- src/link/Elf/ZigModule.zig | 28 +++++++++++++++ src/link/Elf/file.zig | 6 ++++ 4 files changed, 101 insertions(+), 37 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 24140cd1d0..efd3dc9d54 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1048,6 +1048,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // Resolve symbols self.resolveSymbols(); self.markImportsExports(); + self.claimUnresolved(); if (self.unresolved.keys().len > 0) try self.reportUndefined(); @@ -1338,48 +1339,45 @@ fn resolveSymbols(self: *Elf) void { } fn markImportsExports(self: *Elf) void { - const is_dyn_lib = self.base.options.output_mode == .Lib and self.base.options.link_mode == .Dynamic; - - if (self.zig_module_index) |index| { - const zig_module = self.file(index).?.zig_module; - for (zig_module.globals()) |global_index| { - const global = self.symbol(global_index); - if (global.version_index == elf.VER_NDX_LOCAL) continue; - const file_ptr = global.file(self) orelse continue; - const vis = @as(elf.STV, @enumFromInt(global.elfSym(self).st_other)); - if (vis == .HIDDEN) continue; - // if (file == .shared and !global.isAbs(self)) { - // global.flags.import = true; - // continue; - // } - if (file_ptr.index() == index) { - global.flags.@"export" = true; - if (is_dyn_lib and vis != .PROTECTED) { - global.flags.import = true; + const mark = struct { + fn mark(elf_file: *Elf, file_index: File.Index) void { + for (elf_file.file(file_index).?.globals()) |global_index| { + const global = elf_file.symbol(global_index); + if (global.version_index == elf.VER_NDX_LOCAL) continue; + const file_ptr = global.file(elf_file) orelse continue; + const vis = @as(elf.STV, @enumFromInt(global.elfSym(elf_file).st_other)); + if (vis == .HIDDEN) continue; + // if (file == .shared and !global.isAbs(self)) { + // global.flags.import = true; + // continue; + // } + if (file_ptr.index() == file_index) { + global.flags.@"export" = true; + if (elf_file.isDynLib() and vis != .PROTECTED) { + global.flags.import = true; + } } } } + }.mark; + + if (self.zig_module_index) |index| { + mark(self, index); } + for (self.objects.items) |index| { + mark(self, index); + } +} + +fn claimUnresolved(self: *Elf) void { + if (self.zig_module_index) |index| { + const zig_module = self.file(index).?.zig_module; + zig_module.claimUnresolved(self); + } for (self.objects.items) |index| { const object = self.file(index).?.object; - for (object.globals()) |global_index| { - const global = self.symbol(global_index); - if (global.version_index == elf.VER_NDX_LOCAL) continue; - const file_ptr = global.file(self) orelse continue; - const vis = @as(elf.STV, @enumFromInt(global.elfSym(self).st_other)); - if (vis == .HIDDEN) continue; - // if (file == .shared and !global.isAbs(self)) { - // global.flags.import = true; - // continue; - // } - if (file_ptr.index() == index) { - global.flags.@"export" = true; - if (is_dyn_lib and vis != .PROTECTED) { - global.flags.import = true; - } - } - } + object.claimUnresolved(self); } } @@ -3423,6 +3421,10 @@ pub fn defaultEntryAddress(self: Elf) u64 { }; } +pub fn isDynLib(self: Elf) bool { + return self.base.options.output_mode == .Lib and self.base.options.link_mode == .Dynamic; +} + pub fn sectionByName(self: *Elf, name: [:0]const u8) ?u16 { for (self.shdrs.items, 0..) |*shdr, i| { const this_name = self.shstrtab.getAssumeExists(shdr.sh_name); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 7d85509901..e99f7c63f8 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -411,6 +411,34 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void { } } +pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { + const first_global = self.first_global orelse return; + for (self.globals(), 0..) |index, i| { + const esym_index = @as(u32, @intCast(first_global + i)); + const esym = self.symtab[esym_index]; + if (esym.st_shndx != elf.SHN_UNDEF) continue; + + const global = elf_file.symbol(index); + if (global.file(elf_file)) |_| { + if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue; + } + + const is_import = blk: { + if (!elf_file.isDynLib()) break :blk false; + const vis = @as(elf.STV, @enumFromInt(esym.st_other)); + if (vis == .HIDDEN) break :blk false; + break :blk true; + }; + + global.value = 0; + global.atom_index = 0; + global.esym_index = esym_index; + global.file_index = self.index; + global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version; + global.flags.import = is_import; + } +} + pub fn resetGlobals(self: *Object, elf_file: *Elf) void { for (self.globals()) |index| { const global = elf_file.symbol(index); @@ -576,12 +604,12 @@ pub fn writeSymtab(self: *Object, elf_file: *Elf, ctx: anytype) void { } } -pub fn locals(self: *Object) []const u32 { +pub fn locals(self: *Object) []const Symbol.Index { const end = self.first_global orelse self.symbols.items.len; return self.symbols.items[0..end]; } -pub fn globals(self: *Object) []const u32 { +pub fn globals(self: *Object) []const Symbol.Index { const start = self.first_global orelse self.symbols.items.len; return self.symbols.items[start..]; } diff --git a/src/link/Elf/ZigModule.zig b/src/link/Elf/ZigModule.zig index f9df0d33ea..75fd3842e2 100644 --- a/src/link/Elf/ZigModule.zig +++ b/src/link/Elf/ZigModule.zig @@ -102,6 +102,34 @@ pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void { } } +pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void { + 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; + + const global = elf_file.symbol(index); + if (global.file(elf_file)) |_| { + if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue; + } + + const is_import = blk: { + if (!elf_file.isDynLib()) break :blk false; + const vis = @as(elf.STV, @enumFromInt(esym.st_other)); + if (vis == .HIDDEN) break :blk false; + break :blk true; + }; + + global.value = 0; + global.atom_index = 0; + global.esym_index = esym_index; + global.file_index = self.index; + global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version; + global.flags.import = is_import; + } +} + pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void { for (self.locals()) |local_index| { const local = elf_file.symbol(local_index); diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index e7fb789217..e75755949d 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -76,6 +76,12 @@ pub const File = union(enum) { } } + pub fn globals(file: File) []const Symbol.Index { + return switch (file) { + inline else => |x| x.globals(), + }; + } + pub const Index = u32; pub const Entry = union(enum) {