diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 24140cd1d0c8b2d3678b198ebdaaf910fe892273..efd3dc9d54a9cbc80ecec81d63cdf8bb253ddd1d 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; + 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; - 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; - } - } - } + 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 7d855099017719d1e10db6a97de51adcbce49336..e99f7c63f8791894b6124c4cfacea144a9be4b06 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 f9df0d33ea1dd8532e77c57565e494845f03fe76..75fd3842e2c12d2bf4cbd20e92fc488e96033ca4 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 e7fb78921738a4a774a4812589f1f627db3b86ba..e75755949d59ac07bd8b3fb12216944917fa3f7a 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) {