From 518c7908f01cafac9acfbbb708fc49d2c3b5d460 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 30 Jul 2024 14:59:59 +0200 Subject: [PATCH 01/20] elf: always create symbol extra --- src/link/Elf.zig | 22 ++++------------------ src/link/Elf/Atom.zig | 6 +++--- src/link/Elf/Object.zig | 2 ++ src/link/Elf/Symbol.zig | 27 ++++++++++++--------------- src/link/Elf/ZigObject.zig | 6 +++--- src/link/Elf/file.zig | 2 ++ src/link/Elf/synthetic_sections.zig | 10 +++++----- 7 files changed, 31 insertions(+), 44 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index a8590c18d3..69685dc0e9 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -176,7 +176,6 @@ symtab_section_index: ?u32 = null, /// An array of symbols parsed across all input files. symbols: std.ArrayListUnmanaged(Symbol) = .{}, symbols_extra: std.ArrayListUnmanaged(u32) = .{}, -symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{}, resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{}, @@ -343,8 +342,6 @@ pub fn createEmpty( // Index 0 is always a null symbol. try self.symbols.append(gpa, .{}); - // Index 0 is always a null symbol. - try self.symbols_extra.append(gpa, 0); // Append null file at index 0 try self.files.append(gpa, .null); // Append null byte to string tables @@ -462,7 +459,6 @@ pub fn deinit(self: *Elf) void { self.strtab.deinit(gpa); self.symbols.deinit(gpa); self.symbols_extra.deinit(gpa); - self.symbols_free_list.deinit(gpa); self.resolver.deinit(gpa); for (self.thunks.items) |*th| { @@ -5389,17 +5385,8 @@ pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol { pub fn addSymbol(self: *Elf) !Symbol.Index { const gpa = self.base.comp.gpa; try self.symbols.ensureUnusedCapacity(gpa, 1); - const index = blk: { - if (self.symbols_free_list.popOrNull()) |index| { - log.debug(" (reusing symbol index {d})", .{index}); - break :blk index; - } else { - log.debug(" (allocating symbol index {d})", .{self.symbols.items.len}); - const index: Symbol.Index = @intCast(self.symbols.items.len); - _ = self.symbols.addOneAssumeCapacity(); - break :blk index; - } - }; + const index: Symbol.Index = @intCast(self.symbols.items.len); + _ = self.symbols.addOneAssumeCapacity(); self.symbols.items[index] = .{}; return index; } @@ -5423,8 +5410,7 @@ pub fn addSymbolExtraAssumeCapacity(self: *Elf, extra: Symbol.Extra) u32 { return index; } -pub fn symbolExtra(self: *Elf, index: u32) ?Symbol.Extra { - if (index == 0) return null; +pub fn symbolExtra(self: *Elf, index: u32) Symbol.Extra { const fields = @typeInfo(Symbol.Extra).Struct.fields; var i: usize = index; var result: Symbol.Extra = undefined; @@ -5439,7 +5425,6 @@ pub fn symbolExtra(self: *Elf, index: u32) ?Symbol.Extra { } pub fn setSymbolExtra(self: *Elf, index: u32, extra: Symbol.Extra) void { - assert(index > 0); const fields = @typeInfo(Symbol.Extra).Struct.fields; inline for (fields, 0..) |field, i| { self.symbols_extra.items[index + i] = switch (field.type) { @@ -5464,6 +5449,7 @@ pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult { const global = self.symbol(index); global.name_offset = name_off; global.flags.global = true; + global.extra_index = try self.addSymbolExtra(.{}); gop.value_ptr.* = index; } return .{ diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index b91b546103..0f1ea4b6e3 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -845,7 +845,7 @@ fn resolveDynAbsReloc( if (is_writeable or elf_file.z_nocopyreloc) { elf_file.addRelaDynAssumeCapacity(.{ .offset = P, - .sym = target.extra(elf_file).?.dynamic, + .sym = target.extra(elf_file).dynamic, .type = relocation.encode(.abs, cpu_arch), .addend = A, }); @@ -859,7 +859,7 @@ fn resolveDynAbsReloc( if (is_writeable) { elf_file.addRelaDynAssumeCapacity(.{ .offset = P, - .sym = target.extra(elf_file).?.dynamic, + .sym = target.extra(elf_file).dynamic, .type = relocation.encode(.abs, cpu_arch), .addend = A, }); @@ -872,7 +872,7 @@ fn resolveDynAbsReloc( .dynrel => { elf_file.addRelaDynAssumeCapacity(.{ .offset = P, - .sym = target.extra(elf_file).?.dynamic, + .sym = target.extra(elf_file).dynamic, .type = relocation.encode(.abs, cpu_arch), .addend = A, }); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 9185ca0ef7..1b3e768c7d 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -387,6 +387,7 @@ fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void { sym_ptr.name_offset = sym.st_name; sym_ptr.esym_index = @as(u32, @intCast(i)); sym_ptr.file_index = self.index; + sym_ptr.extra_index = try elf_file.addSymbolExtra(.{}); if (sym.st_shndx != elf.SHN_ABS) { sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index }; } @@ -865,6 +866,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void { .name_offset = try self.addString(gpa, name), .esym_index = rel.r_sym(), .file_index = self.index, + .extra_index = try elf_file.addSymbolExtra(.{}), }; sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index }; sym.flags.merge_subsection = true; diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 68d23cb74d..2c1ce0a104 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -159,20 +159,20 @@ pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 { const symtab_ctx = switch (file_ptr) { inline else => |x| x.output_symtab_ctx, }; - const idx = symbol.extra(elf_file).?.symtab; + const idx = symbol.extra(elf_file).symtab; return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal; } pub fn gotAddress(symbol: Symbol, elf_file: *Elf) i64 { if (!symbol.flags.has_got) return 0; - const extras = symbol.extra(elf_file).?; + const extras = symbol.extra(elf_file); const entry = elf_file.got.entries.items[extras.got]; return entry.address(elf_file); } pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 { if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0; - const extras = symbol.extra(elf_file).?; + const extras = symbol.extra(elf_file); const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?]; const cpu_arch = elf_file.getTarget().cpu.arch; return @intCast(shdr.sh_addr + extras.plt_got * PltGotSection.entrySize(cpu_arch)); @@ -180,7 +180,7 @@ pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 { pub fn pltAddress(symbol: Symbol, elf_file: *Elf) i64 { if (!symbol.flags.has_plt) return 0; - const extras = symbol.extra(elf_file).?; + const extras = symbol.extra(elf_file); const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?]; const cpu_arch = elf_file.getTarget().cpu.arch; return @intCast(shdr.sh_addr + extras.plt * PltSection.entrySize(cpu_arch) + PltSection.preambleSize(cpu_arch)); @@ -188,7 +188,7 @@ pub fn pltAddress(symbol: Symbol, elf_file: *Elf) i64 { pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) i64 { if (!symbol.flags.has_plt) return 0; - const extras = symbol.extra(elf_file).?; + const extras = symbol.extra(elf_file); const shdr = elf_file.shdrs.items[elf_file.got_plt_section_index.?]; return @intCast(shdr.sh_addr + extras.plt * 8 + GotPltSection.preamble_size); } @@ -201,21 +201,21 @@ pub fn copyRelAddress(symbol: Symbol, elf_file: *Elf) i64 { pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) i64 { if (!symbol.flags.has_tlsgd) return 0; - const extras = symbol.extra(elf_file).?; + const extras = symbol.extra(elf_file); const entry = elf_file.got.entries.items[extras.tlsgd]; return entry.address(elf_file); } pub fn gotTpAddress(symbol: Symbol, elf_file: *Elf) i64 { if (!symbol.flags.has_gottp) return 0; - const extras = symbol.extra(elf_file).?; + const extras = symbol.extra(elf_file); const entry = elf_file.got.entries.items[extras.gottp]; return entry.address(elf_file); } pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 { if (!symbol.flags.has_tlsdesc) return 0; - const extras = symbol.extra(elf_file).?; + const extras = symbol.extra(elf_file); const entry = elf_file.got.entries.items[extras.tlsdesc]; return entry.address(elf_file); } @@ -228,14 +228,14 @@ const GetOrCreateZigGotEntryResult = struct { pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult { assert(!elf_file.base.isRelocatable()); assert(symbol.flags.needs_zig_got); - if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.zig_got }; + if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).zig_got }; const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file); return .{ .found_existing = false, .index = index }; } pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 { if (!symbol.flags.has_zig_got) return 0; - const extras = symbol.extra(elf_file).?; + const extras = symbol.extra(elf_file); return elf_file.zig_got.entryAddress(extras.zig_got, elf_file); } @@ -266,10 +266,7 @@ const AddExtraOpts = struct { }; pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void { - if (symbol.extra(elf_file) == null) { - symbol.extra_index = try elf_file.addSymbolExtra(.{}); - } - var extras = symbol.extra(elf_file).?; + var extras = symbol.extra(elf_file); inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { if (@field(opts, field.name)) |x| { @field(extras, field.name) = x; @@ -278,7 +275,7 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void { symbol.setExtra(extras, elf_file); } -pub fn extra(symbol: Symbol, elf_file: *Elf) ?Extra { +pub fn extra(symbol: Symbol, elf_file: *Elf) Extra { return elf_file.symbolExtra(symbol.extra_index); } diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 454646bfeb..554e038d95 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -92,6 +92,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { const symbol_ptr = elf_file.symbol(symbol_index); symbol_ptr.file_index = self.index; symbol_ptr.name_offset = name_off; + symbol_ptr.extra_index = try elf_file.addSymbolExtra(.{}); const esym_index = try self.addLocalEsym(gpa); const esym = &self.local_esyms.items(.elf_sym)[esym_index]; @@ -292,6 +293,7 @@ pub fn newAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index { const symbol_ptr = elf_file.symbol(symbol_index); symbol_ptr.file_index = self.index; symbol_ptr.ref = .{ .index = atom_index, .file = self.index }; + symbol_ptr.extra_index = try elf_file.addSymbolExtra(.{}); self.local_esyms.items(.shndx)[esym_index] = atom_index; self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM; @@ -779,11 +781,9 @@ fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.De fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void { _ = self; - const gpa = elf_file.base.comp.gpa; const sym = elf_file.symbol(sym_index); sym.atom(elf_file).?.free(elf_file); log.debug("adding %{d} to local symbols free list", .{sym_index}); - elf_file.symbols_free_list.append(gpa, sym_index) catch {}; elf_file.symbols.items[sym_index] = .{}; // TODO free GOT entry here } @@ -940,7 +940,7 @@ fn updateDeclCode( if (!elf_file.base.isRelocatable()) { log.debug(" (writing new offset table entry)", .{}); assert(sym.flags.has_zig_got); - const extra = sym.extra(elf_file).?; + const extra = sym.extra(elf_file); try elf_file.zig_got.writeOne(elf_file, extra.zig_got); } } diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index 9d2560e11b..346f83d10b 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -71,9 +71,11 @@ pub const File = union(enum) { for (file.globals()) |global_index| { const global = elf_file.symbol(global_index); const name_offset = global.name_offset; + const extra_index = global.extra_index; global.* = .{}; global.name_offset = name_offset; global.flags.global = true; + global.extra_index = extra_index; } } diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index c5c2359890..df98b753b3 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -641,7 +641,7 @@ pub const GotSection = struct { .tlsld => null, inline else => elf_file.symbol(entry.symbol_index), }; - const extra = if (symbol) |s| s.extra(elf_file).? else null; + const extra = if (symbol) |s| s.extra(elf_file) else null; switch (entry.tag) { .got => { @@ -898,7 +898,7 @@ pub const PltSection = struct { for (plt.symbols.items) |sym_index| { const sym = elf_file.symbol(sym_index); assert(sym.flags.import); - const extra = sym.extra(elf_file).?; + const extra = sym.extra(elf_file); const r_offset: u64 = @intCast(sym.gotPltAddress(elf_file)); const r_sym: u64 = extra.dynamic; const r_type = relocation.encode(.jump_slot, cpu_arch); @@ -1267,7 +1267,7 @@ pub const CopyRelSection = struct { for (copy_rel.symbols.items) |sym_index| { const sym = elf_file.symbol(sym_index); assert(sym.flags.import and sym.flags.has_copy_rel); - const extra = sym.extra(elf_file).?; + const extra = sym.extra(elf_file); elf_file.addRelaDynAssumeCapacity(.{ .offset = @intCast(sym.address(.{}, elf_file)), .sym = extra.dynamic, @@ -1322,7 +1322,7 @@ pub const DynsymSection = struct { const rhs_hash = GnuHashSection.hasher(rhs_sym.name(ctx)) % nbuckets; if (lhs_hash == rhs_hash) - return lhs_sym.extra(ctx).?.dynamic < rhs_sym.extra(ctx).?.dynamic; + return lhs_sym.extra(ctx).dynamic < rhs_sym.extra(ctx).dynamic; return lhs_hash < rhs_hash; } }; @@ -1339,7 +1339,7 @@ pub const DynsymSection = struct { for (dynsym.entries.items, 1..) |entry, index| { const sym = elf_file.symbol(entry.symbol_index); - var extra = sym.extra(elf_file).?; + var extra = sym.extra(elf_file); extra.dynamic = @as(u32, @intCast(index)); sym.setExtra(extra, elf_file); } From 9ec415d4de1dcdac4c5fc772883c952b337d65e7 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 30 Jul 2024 18:30:00 +0200 Subject: [PATCH 02/20] elf: null symbol is obsolete --- src/link/Elf.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 69685dc0e9..c366be409c 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -340,8 +340,6 @@ pub fn createEmpty( const gpa = comp.gpa; - // Index 0 is always a null symbol. - try self.symbols.append(gpa, .{}); // Append null file at index 0 try self.files.append(gpa, .null); // Append null byte to string tables From d0367b02199417c10b2cde6d0deae4242689d127 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 31 Jul 2024 12:16:31 +0200 Subject: [PATCH 03/20] elf: move symbol ownership to Object --- src/link/Elf.zig | 174 +++++++++++++++++++----------------- src/link/Elf/Object.zig | 190 ++++++++++++++++++++++++++-------------- 2 files changed, 221 insertions(+), 143 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index c366be409c..1e68374502 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -5375,85 +5375,9 @@ pub fn comdatGroup(self: *Elf, ref: Ref) *ComdatGroup { return self.file(ref.file).?.comdatGroup(ref.index); } -/// Returns pointer-to-symbol described at sym_index. -pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol { - return &self.symbols.items[sym_index]; -} - -pub fn addSymbol(self: *Elf) !Symbol.Index { - const gpa = self.base.comp.gpa; - try self.symbols.ensureUnusedCapacity(gpa, 1); - const index: Symbol.Index = @intCast(self.symbols.items.len); - _ = self.symbols.addOneAssumeCapacity(); - self.symbols.items[index] = .{}; - return index; -} - -pub fn addSymbolExtra(self: *Elf, extra: Symbol.Extra) !u32 { - const gpa = self.base.comp.gpa; - const fields = @typeInfo(Symbol.Extra).Struct.fields; - try self.symbols_extra.ensureUnusedCapacity(gpa, fields.len); - return self.addSymbolExtraAssumeCapacity(extra); -} - -pub fn addSymbolExtraAssumeCapacity(self: *Elf, extra: Symbol.Extra) u32 { - const index = @as(u32, @intCast(self.symbols_extra.items.len)); - const fields = @typeInfo(Symbol.Extra).Struct.fields; - inline for (fields) |field| { - self.symbols_extra.appendAssumeCapacity(switch (field.type) { - u32 => @field(extra, field.name), - else => @compileError("bad field type"), - }); - } - return index; -} - -pub fn symbolExtra(self: *Elf, index: u32) Symbol.Extra { - const fields = @typeInfo(Symbol.Extra).Struct.fields; - var i: usize = index; - var result: Symbol.Extra = undefined; - inline for (fields) |field| { - @field(result, field.name) = switch (field.type) { - u32 => self.symbols_extra.items[i], - else => @compileError("bad field type"), - }; - i += 1; - } - return result; -} - -pub fn setSymbolExtra(self: *Elf, index: u32, extra: Symbol.Extra) void { - const fields = @typeInfo(Symbol.Extra).Struct.fields; - inline for (fields, 0..) |field, i| { - self.symbols_extra.items[index + i] = switch (field.type) { - u32 => @field(extra, field.name), - else => @compileError("bad field type"), - }; - } -} - -const GetOrPutGlobalResult = struct { - found_existing: bool, - index: Symbol.Index, -}; - -pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult { - const gpa = self.base.comp.gpa; - const name_off = try self.strings.insert(gpa, name); - const gop = try self.resolver.getOrPut(gpa, name_off); - if (!gop.found_existing) { - const index = try self.addSymbol(); - log.debug("added symbol '{s}' at index {d}", .{ name, index }); - const global = self.symbol(index); - global.name_offset = name_off; - global.flags.global = true; - global.extra_index = try self.addSymbolExtra(.{}); - gop.value_ptr.* = index; - } - return .{ - .found_existing = gop.found_existing, - .index = gop.value_ptr.*, - }; +pub fn symbol(self: *Elf, ref: Ref) ?*Symbol { + const file_ptr = self.file(ref.file) orelse return null; + return file_ptr.symbol(ref.index); } pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 { @@ -6014,6 +5938,97 @@ pub const Ref = struct { } }; +pub const SymbolResolver = struct { + keys: std.ArrayListUnmanaged(Key) = .{}, + values: std.ArrayListUnmanaged(Ref) = .{}, + table: std.AutoArrayHashMapUnmanaged(void, void) = .{}, + + const Result = struct { + found_existing: bool, + index: Index, + ref: *Ref, + }; + + pub fn deinit(resolver: *SymbolResolver, allocator: Allocator) void { + resolver.keys.deinit(allocator); + resolver.values.deinit(allocator); + resolver.table.deinit(allocator); + } + + pub fn getOrPut( + resolver: *SymbolResolver, + allocator: Allocator, + ref: Ref, + elf_file: *Elf, + ) !Result { + const adapter = Adapter{ .keys = resolver.keys.items, .elf_file = elf_file }; + const key = Key{ .index = ref.index, .file = ref.file }; + const gop = try resolver.table.getOrPutAdapted(allocator, key, adapter); + if (!gop.found_existing) { + try resolver.keys.append(allocator, key); + _ = try resolver.values.addOne(allocator); + } + return .{ + .found_existing = gop.found_existing, + .index = @intCast(gop.index + 1), + .ref = &resolver.values.items[gop.index], + }; + } + + pub fn get(resolver: SymbolResolver, index: Index) ?Ref { + if (index == 0) return null; + return resolver.values.items[index - 1]; + } + + pub fn reset(resolver: *SymbolResolver) void { + resolver.keys.clearRetainingCapacity(); + resolver.values.clearRetainingCapacity(); + resolver.table.clearRetainingCapacity(); + } + + const Key = struct { + index: Symbol.Index, + file: File.Index, + + fn name(key: Key, elf_file: *Elf) [:0]const u8 { + const ref = Ref{ .index = key.index, .file = key.file }; + return ref.symbol(elf_file).?.name(elf_file); + } + + pub fn file(key: Key, elf_file: *Elf) ?File { + const ref = Ref{ .index = key.index, .file = key.file }; + return ref.file(elf_file); + } + + fn eql(key: Key, other: Key, elf_file: *Elf) bool { + const key_name = key.name(elf_file); + const other_name = other.name(elf_file); + return mem.eql(u8, key_name, other_name); + } + + fn hash(key: Key, elf_file: *Elf) u32 { + return @truncate(Hash.hash(0, key.name(elf_file))); + } + }; + + const Adapter = struct { + keys: []const Key, + elf_file: *Elf, + + pub fn eql(ctx: @This(), key: Key, b_void: void, b_map_index: usize) bool { + _ = b_void; + const other = ctx.keys[b_map_index]; + return key.eql(other, ctx.elf_file); + } + + pub fn hash(ctx: @This(), key: Key) u32 { + return key.hash(ctx.elf_file); + } + }; + + pub const Index = u32; +}; + const LastAtomAndFreeList = struct { /// Index of the last allocated atom in this section. last_atom_index: Atom.Index = 0, @@ -6127,6 +6142,7 @@ const File = @import("Elf/file.zig").File; const GnuHashSection = synthetic_sections.GnuHashSection; const GotSection = synthetic_sections.GotSection; const GotPltSection = synthetic_sections.GotPltSection; +const Hash = std.hash.Wyhash; const HashSection = synthetic_sections.HashSection; const InputMergeSection = merge_section.InputMergeSection; const LdScript = @import("Elf/LdScript.zig"); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 1b3e768c7d..71c566b5dd 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -9,7 +9,9 @@ shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, strtab: std.ArrayListUnmanaged(u8) = .{}, first_global: ?Symbol.Index = null, -symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, +symbols: std.ArrayListUnmanaged(Symbol) = .{}, +symbols_extra: std.ArrayListUnmanaged(u32) = .{}, +symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{}, relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, atoms: std.ArrayListUnmanaged(Atom) = .{}, @@ -51,6 +53,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void { self.symtab.deinit(allocator); self.strtab.deinit(allocator); self.symbols.deinit(allocator); + self.symbols_extra.deinit(allocator); + self.symbols_resolver.deinit(allocator); self.atoms.deinit(allocator); self.atoms_indexes.deinit(allocator); self.atoms_extra.deinit(allocator); @@ -80,7 +84,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); try self.initAtoms(gpa, handle, elf_file); - try self.initSymtab(gpa, elf_file); + try self.initSymbols(gpa, elf_file); for (self.shdrs.items, 0..) |shdr, i| { const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue; @@ -374,30 +378,30 @@ fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool { return ignore; } -fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void { +fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void { const first_global = self.first_global orelse self.symtab.items.len; + const nglobals = self.symtab.items.len - first_global; try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len); + try self.symbols_extra.ensureTotalCapacityPrecise(allocator, self.symtab.items.len * @sizeOf(Symbol.Extra)); + try self.symbols_resolver.ensureTotalCapacityPrecise(allocator, nglobals); + self.symbols_resolver.resize(allocator, nglobals) catch unreachable; + @memset(self.symbols_resolver.items, 0); - for (self.symtab.items[0..first_global], 0..) |sym, i| { - const index = try elf_file.addSymbol(); - self.symbols.appendAssumeCapacity(index); - const sym_ptr = elf_file.symbol(index); + for (self.symtab.items, 0..) |sym, i| { + const index = self.addSymbolAssumeCapacity(); + const sym_ptr = &self.symbols.items[index]; sym_ptr.value = @intCast(sym.st_value); sym_ptr.name_offset = sym.st_name; - sym_ptr.esym_index = @as(u32, @intCast(i)); - sym_ptr.file_index = self.index; - sym_ptr.extra_index = try elf_file.addSymbolExtra(.{}); - if (sym.st_shndx != elf.SHN_ABS) { + sym_ptr.esym_index = @intCast(i); + sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{ + .weak = sym.st_bind() == elf.STB_WEAK, + }); + sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else elf.VER_NDX_LOCAL; + if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) { sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index }; } } - - for (self.symtab.items[first_global..]) |sym| { - const name = self.getString(sym.st_name); - const gop = try elf_file.getOrPutGlobal(name); - self.symbols.addOneAssumeCapacity().* = gop.index; - } } fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void { @@ -544,7 +548,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { for (self.cies.items) |cie| { for (cie.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(self.symbols.items[rel.r_sym()]); + const sym = elf_file.symbol(self.resolveSymbol(rel.r_sym())); if (sym.flags.import) { if (sym.type(elf_file) != elf.STT_FUNC) // TODO convert into an error @@ -559,48 +563,46 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { } pub fn resolveSymbols(self: *Object, elf_file: *Elf) void { + const gpa = elf_file.base.comp.gpa; + const first_global = self.first_global orelse return; - for (self.globals(), 0..) |index, i| { - const esym_index = @as(Symbol.Index, @intCast(first_global + i)); - const esym = self.symtab.items[esym_index]; - - if (esym.st_shndx == elf.SHN_UNDEF) continue; - + for (self.globals(), first_global..) |_, i| { + const esym = self.symtab.items[i]; if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { const atom_index = self.atoms_indexes.items[esym.st_shndx]; const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; } - const global = elf_file.symbol(index); - if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) { - switch (esym.st_shndx) { - elf.SHN_ABS, elf.SHN_COMMON => {}, - else => global.ref = .{ - .index = self.atoms_indexes.items[esym.st_shndx], - .file = self.index, - }, - } - global.value = @intCast(esym.st_value); - 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; + const resolv = &self.symbols_resolver.items[i - first_global]; + const gop = try elf_file.resolver.getOrPut(gpa, .{ + .index = @intCast(i), + .file = self.index, + }, elf_file); + if (!gop.found_existing) { + gop.ref.* = .{ .index = 0, .file = 0 }; + } + resolv.* = gop.index; + + if (esym.st_shndx == elf.SHN_UNDEF) continue; + if (elf_file.symbol(gop.ref) == null) { + gop.ref.* = .{ .index = @intCast(i), .file = self.index }; + continue; + } + + if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref).?.symbolRank(elf_file)) { + gop.ref.* = .{ .index = @intCast(i), .file = self.index }; } } } pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { const first_global = self.first_global orelse return; - for (self.globals(), 0..) |index, i| { + for (self.globals(), 0..) |*sym, i| { const esym_index = @as(u32, @intCast(first_global + i)); const esym = self.symtab.items[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; - } + if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue; const is_import = blk: { if (!elf_file.isEffectivelyDynLib()) break :blk false; @@ -609,12 +611,15 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { break :blk true; }; - global.value = 0; - global.ref = .{ .index = 0, .file = 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; + sym.value = 0; + sym.ref = .{ .index = 0, .file = 0 }; + sym.esym_index = esym_index; + sym.file_index = self.index; + sym.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version; + sym.flags.import = is_import; + + const idx = self.symbols_resolver.items[i]; + elf_file.resolver.values.items[idx - 1] = .{ .index = esym_index, .file = self.index }; } } @@ -1141,20 +1146,6 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void { } } -pub fn locals(self: Object) []const Symbol.Index { - if (self.symbols.items.len == 0) return &[0]Symbol.Index{}; - assert(self.symbols.items.len >= self.symtab.items.len); - const end = self.first_global orelse self.symtab.items.len; - return self.symbols.items[0..end]; -} - -pub fn globals(self: Object) []const Symbol.Index { - if (self.symbols.items.len == 0) return &[0]Symbol.Index{}; - assert(self.symbols.items.len >= self.symtab.items.len); - const start = self.first_global orelse self.symtab.items.len; - return self.symbols.items[start..self.symtab.items.len]; -} - /// Returns atom's code and optionally uncompresses data if required (for compressed sections). /// Caller owns the memory. pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { @@ -1187,6 +1178,77 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index return data; } +pub fn locals(self: *Object) []Symbol { + if (self.symbols.items.len == 0) return &[0]Symbol{}; + assert(self.symbols.items.len >= self.symtab.items.len); + const end = self.first_global orelse self.symtab.items.len; + return self.symbols.items[0..end]; +} + +pub fn globals(self: *Object) []Symbol { + if (self.symbols.items.len == 0) return &[0]Symbol{}; + assert(self.symbols.items.len >= self.symtab.items.len); + const start = self.first_global orelse self.symtab.items.len; + return self.symbols.items[start..self.symtab.items.len]; +} + +pub fn resolveSymbol(self: Object, index: Symbol.Index, elf_file: *Elf) Elf.Ref { + const start = self.first_global orelse self.symtab.items.len; + const end = self.symtab.items.len; + if (index < start or index >= end) return .{ .index = index, .file = self.index }; + const resolv = self.symbols_resolver.items[index - start]; + return elf_file.resolver.get(resolv).?; +} + +pub fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index { + try self.symbols.ensureUnusedCapacity(allocator, 1); + const index: Symbol.Index = @intCast(self.symbols.items.len); + self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); + return index; +} + +pub fn addSymbolExtra(self: *Object, allocator: Allocator, extra: Symbol.Extra) !u32 { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len); + return self.addSymbolExtraAssumeCapacity(extra); +} + +pub fn addSymbolExtraAssumeCapacity(self: *Object, extra: Symbol.Extra) u32 { + const index = @as(u32, @intCast(self.symbols_extra.items.len)); + const fields = @typeInfo(Symbol.Extra).Struct.fields; + inline for (fields) |field| { + self.symbols_extra.appendAssumeCapacity(switch (field.type) { + u32 => @field(extra, field.name), + else => @compileError("bad field type"), + }); + } + return index; +} + +pub fn symbolExtra(self: *Object, index: u32) Symbol.Extra { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + var i: usize = index; + var result: Symbol.Extra = undefined; + inline for (fields) |field| { + @field(result, field.name) = switch (field.type) { + u32 => self.symbols_extra.items[i], + else => @compileError("bad field type"), + }; + i += 1; + } + return result; +} + +pub fn setSymbolExtra(self: *Object, index: u32, extra: Symbol.Extra) void { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + inline for (fields, 0..) |field, i| { + self.symbols_extra.items[index + i] = switch (field.type) { + u32 => @field(extra, field.name), + else => @compileError("bad field type"), + }; + } +} + pub fn asFile(self: *Object) File { return .{ .object = self }; } From 9fe69cc0b588ff96075854d687f3fce3d4457258 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 31 Jul 2024 15:45:36 +0200 Subject: [PATCH 04/20] elf: move symbol ownership to SharedObject --- src/link/Elf/Object.zig | 153 ++++++++++++++---------------- src/link/Elf/SharedObject.zig | 172 ++++++++++++++++++++++++---------- 2 files changed, 197 insertions(+), 128 deletions(-) diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 71c566b5dd..fa912c0119 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -562,7 +562,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { } } -pub fn resolveSymbols(self: *Object, elf_file: *Elf) void { +pub fn resolveSymbols(self: *Object, elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; const first_global = self.first_global orelse return; @@ -585,12 +585,12 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void { resolv.* = gop.index; if (esym.st_shndx == elf.SHN_UNDEF) continue; - if (elf_file.symbol(gop.ref) == null) { + if (elf_file.symbol(gop.ref.*) == null) { gop.ref.* = .{ .index = @intCast(i), .file = self.index }; continue; } - if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref).?.symbolRank(elf_file)) { + if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) { gop.ref.* = .{ .index = @intCast(i), .file = self.index }; } } @@ -625,34 +625,40 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void { const first_global = self.first_global orelse return; - for (self.globals(), 0..) |index, i| { + for (self.globals(), 0..) |*sym, i| { const esym_index = @as(u32, @intCast(first_global + i)); const esym = self.symtab.items[esym_index]; if (esym.st_shndx != elf.SHN_UNDEF) continue; + if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue; - const global = elf_file.symbol(index); - if (global.file(elf_file)) |file| { - if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue; - } + // TODO: audit this + // const global = elf_file.symbol(index); + // if (global.file(elf_file)) |file| { + // if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue; + // } - global.value = 0; - global.ref = .{ .index = 0, .file = 0 }; - global.esym_index = esym_index; - global.file_index = self.index; + sym.value = 0; + sym.ref = .{ .index = 0, .file = 0 }; + sym.esym_index = esym_index; + sym.file_index = self.index; + + const idx = self.symbols_resolver.items[i]; + elf_file.resolver.items[idx - 1] = .{ .index = esym_index, .file = self.index }; } } pub fn markLive(self: *Object, elf_file: *Elf) void { const first_global = self.first_global orelse return; - for (self.globals(), 0..) |index, i| { - const sym_idx = first_global + i; - const sym = self.symtab.items[sym_idx]; - if (sym.st_bind() == elf.STB_WEAK) continue; + for (0..self.globals().len) |i| { + const esym_idx = first_global + i; + const esym = self.symtab.items[esym_idx]; + if (esym.st_bind() == elf.STB_WEAK) continue; - const global = elf_file.symbol(index); - const file = global.file(elf_file) orelse continue; - const should_keep = sym.st_shndx == elf.SHN_UNDEF or - (sym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON); + const ref = self.resolveSymbol(@intCast(esym_idx), elf_file); + const sym = elf_file.symbol(ref) orelse continue; + const file = sym.file(elf_file).?; + const should_keep = esym.st_shndx == elf.SHN_UNDEF or + (esym.st_shndx == elf.SHN_COMMON and sym.elfSym(elf_file).st_shndx != elf.SHN_COMMON); if (should_keep and !file.isAlive()) { file.setAlive(); file.markLive(elf_file); @@ -672,24 +678,25 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void { pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void { const first_global = self.first_global orelse return; - for (self.globals(), 0..) |index, i| { - const sym_idx = first_global + i; - const sym = self.symtab.items[sym_idx]; - const global = elf_file.symbol(index); - const global_file = global.file(elf_file) orelse continue; + for (0..self.globals().len) |i| { + const esym_idx = first_global + i; + const esym = self.symtab.items[esym_idx]; + const ref = self.resolveSymbol(@intCast(esym_idx), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + const ref_file = ref_sym.file(elf_file).?; - if (self.index == global_file.index() or - sym.st_shndx == elf.SHN_UNDEF or - sym.st_bind() == elf.STB_WEAK or - sym.st_shndx == elf.SHN_COMMON) continue; + if (self.index == ref_file.index() or + esym.st_shndx == elf.SHN_UNDEF or + esym.st_bind() == elf.STB_WEAK or + esym.st_shndx == elf.SHN_COMMON) continue; - if (sym.st_shndx != elf.SHN_ABS) { - const atom_index = self.atoms_indexes.items[sym.st_shndx]; + if (esym.st_shndx != elf.SHN_ABS) { + const atom_index = self.atoms_indexes.items[esym.st_shndx]; const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; } - const gop = try dupes.getOrPut(index); + const gop = try dupes.getOrPut(self.symbols_resolver.items[i]); if (!gop.found_existing) { gop.value_ptr.* = .{}; } @@ -819,8 +826,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void { } for (self.symtab.items, 0..) |*esym, idx| { - const sym_index = self.symbols.items[idx]; - const sym = elf_file.symbol(sym_index); + const sym = &self.symbols.items[idx]; + // TODO: do we need ref here? if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue; @@ -860,23 +867,20 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void { return error.MalformedObject; }; - const out_sym_idx: u64 = @intCast(self.symbols.items.len); - try self.symbols.ensureUnusedCapacity(gpa, 1); + const sym_index = try self.addSymbol(gpa); + const sym = &self.symbols.items[sym_index]; const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), res.msub_index }); defer gpa.free(name); - const sym_index = try elf_file.addSymbol(); - const sym = elf_file.symbol(sym_index); sym.* = .{ .value = @bitCast(@as(i64, @intCast(res.offset)) - rel.r_addend), .name_offset = try self.addString(gpa, name), .esym_index = rel.r_sym(), .file_index = self.index, - .extra_index = try elf_file.addSymbolExtra(.{}), + .extra_index = try self.addSymbolExtra(gpa, .{}), }; sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index }; sym.flags.merge_subsection = true; - self.symbols.addOneAssumeCapacity().* = sym_index; - rel.r_info = (out_sym_idx << 32) | rel.r_type(); + rel.r_info = (@as(u64, @intCast(sym_index)) << 32) | rel.r_type(); } } } @@ -885,27 +889,16 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void { /// play nicely with the rest of the system. pub fn convertCommonSymbols(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.items[sym_idx]; - if (this_sym.st_shndx != elf.SHN_COMMON) continue; - - const global = elf_file.symbol(index); - const global_file = global.file(elf_file).?; - if (global_file.index() != self.index) { - // if (elf_file.options.warn_common) { - // elf_file.base.warn("{}: multiple common symbols: {s}", .{ - // self.fmtPath(), - // global.getName(elf_file), - // }); - // } - continue; - } + for (self.globals(), self.symbols_resolver.items, 0..) |*sym, resolv, i| { + const esym_idx = @as(u32, @intCast(first_global + i)); + const esym = self.symtab.items[esym_idx]; + if (esym.st_shndx != elf.SHN_COMMON) continue; + if (elf_file.resolver.get(resolv).?.file != self.index) continue; const comp = elf_file.base.comp; const gpa = comp.gpa; - const is_tls = global.type(elf_file) == elf.STT_TLS; + const is_tls = sym.type(elf_file) == elf.STT_TLS; const name = if (is_tls) ".tls_common" else ".common"; const name_offset = @as(u32, @intCast(self.strtab.items.len)); try self.strtab.writer(gpa).print("{s}\x00", .{name}); @@ -914,7 +907,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { if (is_tls) sh_flags |= elf.SHF_TLS; const shndx = @as(u32, @intCast(self.shdrs.items.len)); const shdr = try self.shdrs.addOne(gpa); - const sh_size = math.cast(usize, this_sym.st_size) orelse return error.Overflow; + const sh_size = math.cast(usize, esym.st_size) orelse return error.Overflow; shdr.* = .{ .sh_name = name_offset, .sh_type = elf.SHT_NOBITS, @@ -924,21 +917,21 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { .sh_size = sh_size, .sh_link = 0, .sh_info = 0, - .sh_addralign = this_sym.st_value, + .sh_addralign = esym.st_value, .sh_entsize = 0, }; const atom_index = try self.addAtom(gpa, .{ .name = name_offset, .shndx = shndx, - .size = this_sym.st_size, - .alignment = Alignment.fromNonzeroByteUnits(this_sym.st_value), + .size = esym.st_size, + .alignment = Alignment.fromNonzeroByteUnits(esym.st_value), }); try self.atoms_indexes.append(gpa, atom_index); - global.value = 0; - global.ref = .{ .index = atom_index, .file = self.index }; - global.flags.weak = false; + sym.value = 0; + sym.ref = .{ .index = atom_index, .file = self.index }; + sym.flags.weak = false; } } @@ -1080,7 +1073,7 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void { try writer.writeAll(data); } -pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { +pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void { const isAlive = struct { fn isAlive(sym: *const Symbol, ctx: *Elf) bool { if (sym.mergeSubsection(ctx)) |msub| return msub.alive; @@ -1089,8 +1082,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { } }.isAlive; - for (self.locals()) |local_index| { - const local = elf_file.symbol(local_index); + for (self.locals()) |*local| { if (!isAlive(local, elf_file)) continue; const esym = local.elfSym(elf_file); switch (esym.st_type()) { @@ -1099,22 +1091,22 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { else => {}, } local.flags.output_symtab = true; - try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); + local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); self.output_symtab_ctx.nlocals += 1; self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1; } - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - const file_ptr = global.file(elf_file) orelse continue; - if (file_ptr.index() != self.index) continue; + for (self.globals(), self.symbols_resolver.items) |*global, resolv| { + const ref = elf_file.resolver.items[resolv]; + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; if (!isAlive(global, elf_file)) continue; global.flags.output_symtab = true; if (global.isLocal(elf_file)) { - try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); + global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); self.output_symtab_ctx.nlocals += 1; } else { - try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); + global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); self.output_symtab_ctx.nglobals += 1; } self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; @@ -1122,8 +1114,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { } pub fn writeSymtab(self: Object, elf_file: *Elf) void { - for (self.locals()) |local_index| { - const local = elf_file.symbol(local_index); + for (self.locals()) |local| { const idx = local.outputSymtabIndex(elf_file) orelse continue; const out_sym = &elf_file.symtab.items[idx]; out_sym.st_name = @intCast(elf_file.strtab.items.len); @@ -1132,10 +1123,10 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void { local.setOutputSym(elf_file, out_sym); } - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - const file_ptr = global.file(elf_file) orelse continue; - if (file_ptr.index() != self.index) continue; + for (self.globals(), self.symbols_resolver.items) |global, resolv| { + const ref = elf_file.resolver.items[resolv]; + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; const idx = global.outputSymtabIndex(elf_file) orelse continue; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file)); diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index 461a56ae39..00a64c3950 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -10,7 +10,10 @@ strtab: std.ArrayListUnmanaged(u8) = .{}, versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{}, verstrings: std.ArrayListUnmanaged(u32) = .{}, -symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, +symbols: std.ArrayListUnmanaged(Symbol) = .{}, +symbols_extra: std.ArrayListUnmanaged(u32) = .{}, +symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{}, + aliases: ?std.ArrayListUnmanaged(u32) = null, dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .{}, @@ -38,6 +41,8 @@ pub fn deinit(self: *SharedObject, allocator: Allocator) void { self.versyms.deinit(allocator); self.verstrings.deinit(allocator); self.symbols.deinit(allocator); + self.symbols_extra.deinit(allocator); + self.symbols_resolver.deinit(allocator); if (self.aliases) |*aliases| aliases.deinit(allocator); self.dynamic_table.deinit(allocator); } @@ -129,7 +134,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void { .versym_sect_index = versym_sect_index, }); - try self.initSymtab(elf_file, .{ + try self.initSymbols(elf_file, .{ .symtab = symtab, .strtab = strtab, }); @@ -188,16 +193,20 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts: } } -fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct { +fn initSymbols(self: *SharedObject, elf_file: *Elf, opts: struct { symtab: []align(1) const elf.Elf64_Sym, strtab: []const u8, }) !void { - const comp = elf_file.base.comp; - const gpa = comp.gpa; + const gpa = elf_file.base.comp.gpa; + const nsyms = opts.symtab.len; try self.strtab.appendSlice(gpa, opts.strtab); - try self.symtab.ensureTotalCapacityPrecise(gpa, opts.symtab.len); - try self.symbols.ensureTotalCapacityPrecise(gpa, opts.symtab.len); + try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms); + try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms); + try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra)); + try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms); + self.symbols_resolver.resize(gpa, nsyms) catch unreachable; + @memset(self.symbols_resolver.items, 0); for (opts.symtab, 0..) |sym, i| { const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0; @@ -214,41 +223,56 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct { try self.strtab.writer(gpa).print("{s}\x00", .{mangled}); break :blk name_off; } else sym.st_name; - const out_sym = self.symtab.addOneAssumeCapacity(); - out_sym.* = sym; - out_sym.st_name = name_off; - const gop = try elf_file.getOrPutGlobal(self.getString(name_off)); - self.symbols.addOneAssumeCapacity().* = gop.index; + const out_esym_index: u32 = @intCast(self.symtab.items.len); + const out_esym = self.symtab.addOneAssumeCapacity(); + out_esym.* = sym; + out_esym.st_name = name_off; + const out_sym_index = self.addSymbolAssumeCapacity(); + const out_sym = &self.symbols.items[out_sym_index]; + out_sym.* = .{ + .value = @intCast(out_esym.st_value), + .ref = .{ .index = 0, .file = 0 }, + .esym_index = out_esym_index, + .version_index = self.versyms.items[out_esym_index], + .extra_index = self.addSymbolExtraAssumeCapacity(.{}), + }; } } -pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void { - for (self.globals(), 0..) |index, i| { - const esym_index = @as(u32, @intCast(i)); - const this_sym = self.symtab.items[esym_index]; +pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; - if (this_sym.st_shndx == elf.SHN_UNDEF) continue; + for (self.symtab.items, self.symbols_resolver.items, 0..) |esym, *resolv, i| { + const gop = try elf_file.resolver.getOrPut(gpa, .{ + .index = @intCast(i), + .file = self.index, + }, elf_file); + if (!gop.found_existing) { + gop.ref.* = .{ .index = 0, .file = 0 }; + } + resolv.* = gop.index; - const global = elf_file.symbol(index); - if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) { - global.value = @intCast(this_sym.st_value); - global.ref = .{ .index = 0, .file = 0 }; - global.esym_index = esym_index; - global.version_index = self.versyms.items[esym_index]; - global.file_index = self.index; + if (esym.st_shndx == elf.SHN_UNDEF) continue; + if (elf_file.symbol(gop.ref.*) == null) { + gop.ref.* = .{ .index = @intCast(i), .file = self.index }; + continue; + } + + if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) { + gop.ref.* = .{ .index = @intCast(i), .file = self.index }; } } } pub fn markLive(self: *SharedObject, elf_file: *Elf) void { - for (self.globals(), 0..) |index, i| { - const sym = self.symtab.items[i]; - if (sym.st_shndx != elf.SHN_UNDEF) continue; + for (self.symtab.items, 0..) |esym, i| { + if (esym.st_shndx != elf.SHN_UNDEF) continue; - const global = elf_file.symbol(index); - const file = global.file(elf_file) orelse continue; + const ref = self.resolveSymbol(@intCast(i), elf_file); + const sym = elf_file.symbol(ref) orelse continue; + const file = sym.file(elf_file).?; const should_drop = switch (file) { - .shared_object => |sh| !sh.needed and sym.st_bind() == elf.STB_WEAK, + .shared_object => |sh| !sh.needed and esym.st_bind() == elf.STB_WEAK, else => false, }; if (!should_drop and !file.isAlive()) { @@ -262,24 +286,24 @@ pub fn globals(self: SharedObject) []const Symbol.Index { return self.symbols.items; } -pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) !void { - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - const file_ptr = global.file(elf_file) orelse continue; - if (file_ptr.index() != self.index) continue; +pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void { + for (self.globals(), self.symbols_resolver.items) |*global, resolv| { + const ref = elf_file.resolver.get(resolv).?; + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; if (global.isLocal(elf_file)) continue; global.flags.output_symtab = true; - try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); + global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); self.output_symtab_ctx.nglobals += 1; self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; } } pub fn writeSymtab(self: SharedObject, elf_file: *Elf) void { - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - const file_ptr = global.file(elf_file) orelse continue; - if (file_ptr.index() != self.index) continue; + for (self.globals(), self.symbols_resolver.items) |global, resolv| { + const ref = elf_file.resolver.get(resolv).?; + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; const idx = global.outputSymtabIndex(elf_file) orelse continue; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file)); @@ -332,10 +356,10 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { defer aliases.deinit(); try aliases.ensureTotalCapacityPrecise(self.globals().len); - for (self.globals()) |index| { - const global = elf_file.symbol(index); - const global_file = global.file(elf_file) orelse continue; - if (global_file.index() != self.index) continue; + for (self.symbols_resolvers.items, 0..) |resolv, index| { + const ref = elf_file.resolver.get(resolv).?; + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; aliases.appendAssumeCapacity(index); } @@ -347,16 +371,16 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u32 { assert(self.aliases != null); - const symbol = elf_file.symbol(index).elfSym(elf_file); + const symbol = self.symbol(index).elfSym(elf_file); const aliases = self.aliases.?; const start = for (aliases.items, 0..) |alias, i| { - const alias_sym = elf_file.symbol(alias).elfSym(elf_file); + const alias_sym = self.symbol(alias).elfSym(elf_file); if (symbol.st_value == alias_sym.st_value) break i; } else aliases.items.len; const end = for (aliases.items[start..], 0..) |alias, i| { - const alias_sym = elf_file.symbol(alias).elfSym(elf_file); + const alias_sym = self.symbol(alias).elfSym(elf_file); if (symbol.st_value < alias_sym.st_value) break i + start; } else aliases.items.len; @@ -368,6 +392,60 @@ pub fn getString(self: SharedObject, off: u32) [:0]const u8 { return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); } +pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref { + const resolv = self.symbols_resolver.items[index]; + return elf_file.resolver.get(resolv).?; +} + +pub fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index { + try self.symbols.ensureUnusedCapacity(allocator, 1); + const index: Symbol.Index = @intCast(self.symbols.items.len); + self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); + return index; +} + +pub fn addSymbolExtra(self: *SharedObject, allocator: Allocator, extra: Symbol.Extra) !u32 { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len); + return self.addSymbolExtraAssumeCapacity(extra); +} + +pub fn addSymbolExtraAssumeCapacity(self: *SharedObject, extra: Symbol.Extra) u32 { + const index = @as(u32, @intCast(self.symbols_extra.items.len)); + const fields = @typeInfo(Symbol.Extra).Struct.fields; + inline for (fields) |field| { + self.symbols_extra.appendAssumeCapacity(switch (field.type) { + u32 => @field(extra, field.name), + else => @compileError("bad field type"), + }); + } + return index; +} + +pub fn symbolExtra(self: *SharedObject, index: u32) Symbol.Extra { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + var i: usize = index; + var result: Symbol.Extra = undefined; + inline for (fields) |field| { + @field(result, field.name) = switch (field.type) { + u32 => self.symbols_extra.items[i], + else => @compileError("bad field type"), + }; + i += 1; + } + return result; +} + +pub fn setSymbolExtra(self: *SharedObject, index: u32, extra: Symbol.Extra) void { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + inline for (fields, 0..) |field, i| { + self.symbols_extra.items[index + i] = switch (field.type) { + u32 => @field(extra, field.name), + else => @compileError("bad field type"), + }; + } +} + pub fn format( self: SharedObject, comptime unused_fmt_string: []const u8, From de80e4fec2a29c5aac70c8d72b11a90cb96feeaf Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 31 Jul 2024 16:30:45 +0200 Subject: [PATCH 05/20] elf: move symbol ownership to LinkerDefined --- src/link/Elf/LinkerDefined.zig | 379 +++++++++++++++++++++------------ src/link/Elf/SharedObject.zig | 4 +- 2 files changed, 239 insertions(+), 144 deletions(-) diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index 676c49cc7d..1247a08ef1 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -2,7 +2,10 @@ index: File.Index, symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, strtab: std.ArrayListUnmanaged(u8) = .{}, -symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, + +symbols: std.ArrayListUnmanaged(Symbol) = .{}, +symbols_extra: std.ArrayListUnmanaged(u32) = .{}, +symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{}, entry_index: ?Symbol.Index = null, dynamic_index: ?Symbol.Index = null, @@ -29,6 +32,8 @@ pub fn deinit(self: *LinkerDefined, allocator: Allocator) void { self.symtab.deinit(allocator); self.strtab.deinit(allocator); self.symbols.deinit(allocator); + self.symbols_extra.deinit(allocator); + self.symbols_resolver.deinit(allocator); self.start_stop_indexes.deinit(allocator); } @@ -38,85 +43,137 @@ pub fn init(self: *LinkerDefined, allocator: Allocator) !void { } pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { + const newSymbolAssumeCapacity = struct { + fn newSymbolAssumeCapacity(ld: *LinkerDefined, name_off: u32) Symbol.Index { + const esym_index: u32 = @intCast(ld.symtab.items.len); + const esym = ld.symtab.addOneAssumeCapacity(); + esym.* = .{ + .st_name = name_off, + .st_info = elf.STB_GLOBAL << 4, + .st_other = @intFromEnum(elf.STV.HIDDEN), + .st_shndx = elf.SHN_ABS, + .st_value = 0, + .st_size = 0, + }; + const index = ld.addSymbolAssumeCapacity(); + const symbol = &ld.symbols.items[index]; + symbol.name_offset = name_off; + symbol.extra_index = ld.addSymbolExtraAssumeCapacity(.{}); + symbol.ref = .{ .index = 0, .file = 0 }; + symbol.esym_index = esym_index; + symbol.version_index = elf_file.default_sym_version; + } + }.newSymbolAssumeCapacity; + const gpa = elf_file.base.comp.gpa; - if (elf_file.entry_name) |name| { - self.entry_index = try self.addGlobal(name, elf_file); + var nsyms: usize = 0; + if (elf_file.entry_name) |_| { + nsyms += 1; // entry } - - self.dynamic_index = try self.addGlobal("_DYNAMIC", elf_file); - self.ehdr_start_index = try self.addGlobal("__ehdr_start", elf_file); - self.init_array_start_index = try self.addGlobal("__init_array_start", elf_file); - self.init_array_end_index = try self.addGlobal("__init_array_end", elf_file); - self.fini_array_start_index = try self.addGlobal("__fini_array_start", elf_file); - self.fini_array_end_index = try self.addGlobal("__fini_array_end", elf_file); - self.preinit_array_start_index = try self.addGlobal("__preinit_array_start", elf_file); - self.preinit_array_end_index = try self.addGlobal("__preinit_array_end", elf_file); - self.got_index = try self.addGlobal("_GLOBAL_OFFSET_TABLE_", elf_file); - self.plt_index = try self.addGlobal("_PROCEDURE_LINKAGE_TABLE_", elf_file); - self.end_index = try self.addGlobal("_end", elf_file); - + nsyms += 1; // _DYNAMIC + nsyms += 1; // __ehdr_start + nsyms += 1; // __init_array_start + nsyms += 1; // __init_array_end + nsyms += 1; // __fini_array_start + nsyms += 1; // __fini_array_end + nsyms += 1; // __preinit_array_start + nsyms += 1; // __preinit_array_end + nsyms += 1; // _GLOBAL_OFFSET_TABLE_ + nsyms += 1; // _PROCEDURE_LINKAGE_TABLE_ + nsyms += 1; // _end if (elf_file.base.comp.link_eh_frame_hdr) { - self.gnu_eh_frame_hdr_index = try self.addGlobal("__GNU_EH_FRAME_HDR", elf_file); + nsyms += 1; // __GNU_EH_FRAME_HDR + } + nsyms += 1; // __dso_handle + nsyms += 1; // __rela_iplt_start + nsyms += 1; // __rela_iplt_end + if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) { + nsyms += 1; // __global_pointer$ } - self.dso_handle_index = try self.addGlobal("__dso_handle", elf_file); - self.rela_iplt_start_index = try self.addGlobal("__rela_iplt_start", elf_file); - self.rela_iplt_end_index = try self.addGlobal("__rela_iplt_end", elf_file); - - for (elf_file.shdrs.items) |shdr| { - if (elf_file.getStartStopBasename(shdr)) |name| { - try self.start_stop_indexes.ensureUnusedCapacity(gpa, 2); - - const start = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name}); - defer gpa.free(start); - const stop = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name}); - defer gpa.free(stop); - - self.start_stop_indexes.appendAssumeCapacity(try self.addGlobal(start, elf_file)); - self.start_stop_indexes.appendAssumeCapacity(try self.addGlobal(stop, elf_file)); + var start_stop_count: usize = 0; + for (elf_file.objects.items) |index| { + for (elf_file.file(index).?.object.shdrs.items) |shdr| { + if (elf_file.getStartStopBasename(shdr)) |_| { + start_stop_count += 2; // __start_, __stop_ + } } } + nsyms += start_stop_count; + + try self.start_stop_indexes.ensureTotalCapacityPrecise(gpa, start_stop_count); + try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms); + try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms); + try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra)); + try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms); + self.symbols_resolver.resize(gpa, nsyms) catch unreachable; + @memset(self.symbols_resolver.items, 0); + + if (elf_file.entry_name) |name| { + self.entry_index = newSymbolAssumeCapacity(self, try self.addString(gpa, name)); + } + + self.dynamic_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_DYNAMIC")); + self.ehdr_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__ehdr_start")); + self.init_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_start")); + self.init_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_end")); + self.fini_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_start")); + self.fini_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_end")); + self.preinit_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_start")); + self.preinit_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_end")); + self.got_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_")); + self.plt_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_")); + self.end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_end")); + + if (elf_file.base.comp.link_eh_frame_hdr) { + self.gnu_eh_frame_hdr_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__GNU_EH_FRAME_HDR")); + } + + self.dso_handle_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__dso_handle")); + self.rela_iplt_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_start")); + self.rela_iplt_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_end")); if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) { - self.global_pointer_index = try self.addGlobal("__global_pointer$", elf_file); + self.global_pointer_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__global_pointer$")); + } + + for (elf_file.objects.items) |index| { + for (elf_file.file(index).?.object.shdrs.items) |shdr| { + if (elf_file.getStartStopBasename(shdr)) |name| { + const start_name = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name}); + defer gpa.free(start_name); + const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name}); + defer gpa.free(stop_name); + const start = newSymbolAssumeCapacity(self, try self.addString(gpa, start_name)); + const stop = newSymbolAssumeCapacity(self, try self.addString(gpa, stop_name)); + self.start_stop_indexes.appendSliceAssumeCapacity(&.{ start, stop }); + } + } } } -fn addGlobal(self: *LinkerDefined, name: []const u8, elf_file: *Elf) !u32 { - const comp = elf_file.base.comp; - const gpa = comp.gpa; - try self.symtab.ensureUnusedCapacity(gpa, 1); - try self.symbols.ensureUnusedCapacity(gpa, 1); - const name_off = @as(u32, @intCast(self.strtab.items.len)); - try self.strtab.writer(gpa).print("{s}\x00", .{name}); - self.symtab.appendAssumeCapacity(.{ - .st_name = name_off, - .st_info = elf.STB_GLOBAL << 4, - .st_other = @intFromEnum(elf.STV.HIDDEN), - .st_shndx = elf.SHN_ABS, - .st_value = 0, - .st_size = 0, - }); - const gop = try elf_file.getOrPutGlobal(name); - self.symbols.addOneAssumeCapacity().* = gop.index; - return gop.index; -} +pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; -pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void { - for (self.symbols.items, 0..) |index, i| { - const sym_idx = @as(Symbol.Index, @intCast(i)); - const this_sym = self.symtab.items[sym_idx]; + for (self.symtab.items, self.symbols_resolver.items, 0..) |esym, *resolv, i| { + const gop = try elf_file.resolver.getOrPut(gpa, .{ + .index = @intCast(i), + .file = self.index, + }, elf_file); + if (!gop.found_existing) { + gop.ref.* = .{ .index = 0, .file = 0 }; + } + resolv.* = gop.index; - if (this_sym.st_shndx == elf.SHN_UNDEF) continue; + if (esym.st_shndx == elf.SHN_UNDEF) continue; + if (elf_file.symbol(gop.ref.*) == null) { + gop.ref.* = .{ .index = @intCast(i), .file = self.index }; + continue; + } - const global = elf_file.symbol(index); - if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) { - global.value = 0; - global.ref = .{ .index = 0, .file = 0 }; - global.file_index = self.index; - global.esym_index = sym_idx; - global.version_index = elf_file.default_sym_version; + if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) { + gop.ref.* = .{ .index = @intCast(i), .file = self.index }; } } } @@ -125,93 +182,73 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void { const comp = elf_file.base.comp; const link_mode = comp.config.link_mode; + const allocSymbol = struct { + fn allocSymbol(ld: *LinkerDefined, index: Symbol.Index, value: u64, osec: u32, ef: *Elf) void { + const sym = ef.symbol(ld.resolveSymbol(index, ef)).?; + sym.value = @intCast(value); + sym.output_section_index = osec; + } + }.allocSymbol; + // _DYNAMIC if (elf_file.dynamic_section_index) |shndx| { const shdr = &elf_file.shdrs.items[shndx]; - const symbol_ptr = elf_file.symbol(self.dynamic_index.?); - symbol_ptr.value = @intCast(shdr.sh_addr); - symbol_ptr.output_section_index = shndx; + allocSymbol(self, self.dynamic_index.?, shdr.sh_addr, shndx, elf_file); } // __ehdr_start - { - const symbol_ptr = elf_file.symbol(self.ehdr_start_index.?); - symbol_ptr.value = @intCast(elf_file.image_base); - symbol_ptr.output_section_index = 1; - } + allocSymbol(self, self.ehdr_start_index.?, elf_file.image_base, 1, elf_file); // __init_array_start, __init_array_end if (elf_file.sectionByName(".init_array")) |shndx| { - const start_sym = elf_file.symbol(self.init_array_start_index.?); - const end_sym = elf_file.symbol(self.init_array_end_index.?); const shdr = &elf_file.shdrs.items[shndx]; - start_sym.output_section_index = shndx; - start_sym.value = @intCast(shdr.sh_addr); - end_sym.output_section_index = shndx; - end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size); + allocSymbol(self, self.init_array_start_index.?, shdr.sh_addr, shndx, elf_file); + allocSymbol(self, self.init_array_end_index.?, shdr.sh_addr + shdr.sh_size, shndx, elf_file); } // __fini_array_start, __fini_array_end if (elf_file.sectionByName(".fini_array")) |shndx| { - const start_sym = elf_file.symbol(self.fini_array_start_index.?); - const end_sym = elf_file.symbol(self.fini_array_end_index.?); const shdr = &elf_file.shdrs.items[shndx]; - start_sym.output_section_index = shndx; - start_sym.value = @intCast(shdr.sh_addr); - end_sym.output_section_index = shndx; - end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size); + allocSymbol(self, self.fini_array_start_index.?, shdr.sh_addr, shndx, elf_file); + allocSymbol(self, self.fini_array_end_index.?, shdr.sh_addr + shdr.sh_size, shndx, elf_file); } // __preinit_array_start, __preinit_array_end if (elf_file.sectionByName(".preinit_array")) |shndx| { - const start_sym = elf_file.symbol(self.preinit_array_start_index.?); - const end_sym = elf_file.symbol(self.preinit_array_end_index.?); const shdr = &elf_file.shdrs.items[shndx]; - start_sym.output_section_index = shndx; - start_sym.value = @intCast(shdr.sh_addr); - end_sym.output_section_index = shndx; - end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size); + allocSymbol(self, self.preinit_array_start_index.?, shdr.sh_addr, shndx, elf_file); + allocSymbol(self, self.preinit_array_end_index.?, shdr.sh_addr + shdr.sh_size, shndx, elf_file); } // _GLOBAL_OFFSET_TABLE_ if (elf_file.getTarget().cpu.arch == .x86_64) { if (elf_file.got_plt_section_index) |shndx| { const shdr = elf_file.shdrs.items[shndx]; - const sym = elf_file.symbol(self.got_index.?); - sym.value = @intCast(shdr.sh_addr); - sym.output_section_index = shndx; + allocSymbol(self, self.got_index.?, shdr.sh_addr, shndx, elf_file); } } else { if (elf_file.got_section_index) |shndx| { const shdr = elf_file.shdrs.items[shndx]; - const sym = elf_file.symbol(self.got_index.?); - sym.value = @intCast(shdr.sh_addr); - sym.output_section_index = shndx; + allocSymbol(self, self.got_index.?, shdr.sh_addr, shndx, elf_file); } } // _PROCEDURE_LINKAGE_TABLE_ if (elf_file.plt_section_index) |shndx| { const shdr = &elf_file.shdrs.items[shndx]; - const symbol_ptr = elf_file.symbol(self.plt_index.?); - symbol_ptr.value = @intCast(shdr.sh_addr); - symbol_ptr.output_section_index = shndx; + allocSymbol(self, self.plt_index.?, shdr.sh_addr, shndx, elf_file); } // __dso_handle if (self.dso_handle_index) |index| { const shdr = &elf_file.shdrs.items[1]; - const symbol_ptr = elf_file.symbol(index); - symbol_ptr.value = @intCast(shdr.sh_addr); - symbol_ptr.output_section_index = 0; + allocSymbol(self, index, shdr.sh_addr, 0, elf_file); } // __GNU_EH_FRAME_HDR if (elf_file.eh_frame_hdr_section_index) |shndx| { const shdr = &elf_file.shdrs.items[shndx]; - const symbol_ptr = elf_file.symbol(self.gnu_eh_frame_hdr_index.?); - symbol_ptr.value = @intCast(shdr.sh_addr); - symbol_ptr.output_section_index = shndx; + allocSymbol(self, self.gnu_eh_frame_hdr_index.?, shdr.sh_addr, shndx, elf_file); } // __rela_iplt_start, __rela_iplt_end @@ -220,32 +257,41 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void { const shdr = &elf_file.shdrs.items[shndx]; const end_addr = shdr.sh_addr + shdr.sh_size; const start_addr = end_addr - elf_file.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela); - const start_sym = elf_file.symbol(self.rela_iplt_start_index.?); - const end_sym = elf_file.symbol(self.rela_iplt_end_index.?); - start_sym.value = @intCast(start_addr); - start_sym.output_section_index = shndx; - end_sym.value = @intCast(end_addr); - end_sym.output_section_index = shndx; + allocSymbol(self, self.rela_iplt_start_index.?, start_addr, shndx, elf_file); + allocSymbol(self, self.rela_iplt_end_index.?, end_addr, shndx, elf_file); } // _end { - const end_symbol = elf_file.symbol(self.end_index.?); + var value: u64 = 0; + var osec: u32 = 0; for (elf_file.shdrs.items, 0..) |shdr, shndx| { if (shdr.sh_flags & elf.SHF_ALLOC != 0) { - end_symbol.value = @intCast(shdr.sh_addr + shdr.sh_size); - end_symbol.output_section_index = @intCast(shndx); + value = shdr.sh_addr + shdr.sh_size; + osec = shndx; } } + allocSymbol(self, self.end_index.?, value, osec, elf_file); + } + + // __global_pointer$ + if (self.global_pointer_index) |index| { + const value, const osec = if (elf_file.sectionByName(".sdata")) |shndx| .{ + elf_file.shdrs.items[shndx].sh_addr + 0x800, + shndx, + } else .{ 0, 0 }; + allocSymbol(self, index, value, osec, elf_file); } // __start_*, __stop_* { var index: usize = 0; while (index < self.start_stop_indexes.items.len) : (index += 2) { - const start = elf_file.symbol(self.start_stop_indexes.items[index]); + const start_ref = self.resolveSymbol(self.start_stop_indexes.items[index]); + const start = elf_file.symbol(start_ref).?; const name = start.name(elf_file); - const stop = elf_file.symbol(self.start_stop_indexes.items[index + 1]); + const stop_ref = self.resolveSymbol(self.start_stop_indexes.items[index + 1]); + const stop = elf_file.symbol(stop_ref).?; const shndx = elf_file.sectionByName(name["__start_".len..]).?; const shdr = &elf_file.shdrs.items[shndx]; start.value = @intCast(shdr.sh_addr); @@ -254,47 +300,34 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void { stop.output_section_index = shndx; } } - - // __global_pointer$ - if (self.global_pointer_index) |index| { - const sym = elf_file.symbol(index); - if (elf_file.sectionByName(".sdata")) |shndx| { - const shdr = elf_file.shdrs.items[shndx]; - sym.value = @intCast(shdr.sh_addr + 0x800); - sym.output_section_index = shndx; - } else { - sym.value = 0; - sym.output_section_index = 0; - } - } } -pub fn globals(self: LinkerDefined) []const Symbol.Index { +pub fn globals(self: *LinkerDefined) []Symbol { return self.symbols.items; } -pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) !void { - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - const file_ptr = global.file(elf_file) orelse continue; - if (file_ptr.index() != self.index) continue; +pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void { + for (self.globals(), self.symbols_resolver.items) |*global, resolv| { + const ref = elf_file.resolver.get(resolv).?; + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; global.flags.output_symtab = true; if (global.isLocal(elf_file)) { - try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); + global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); self.output_symtab_ctx.nlocals += 1; } else { - try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); + global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); self.output_symtab_ctx.nglobals += 1; } self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; } } -pub fn writeSymtab(self: LinkerDefined, elf_file: *Elf) void { - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - const file_ptr = global.file(elf_file) orelse continue; - if (file_ptr.index() != self.index) continue; +pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf) void { + for (self.globals(), self.symbols_resolver.items) |global, resolv| { + const ref = elf_file.resolver.get(resolv).?; + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; const idx = global.outputSymtabIndex(elf_file) orelse continue; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file)); @@ -309,11 +342,73 @@ pub fn asFile(self: *LinkerDefined) File { return .{ .linker_defined = self }; } +fn addString(self: *LinkerDefined, allocator: Allocator, str: []const u8) !u32 { + const off: u32 = @intCast(self.strtab.items.len); + try self.strtab.ensureUnusedCapacity(allocator, str.len + 1); + self.strtab.appendSliceAssumeCapacity(str); + self.strtab.appendAssumeCapacity(0); + return off; +} + pub fn getString(self: LinkerDefined, off: u32) [:0]const u8 { assert(off < self.strtab.items.len); return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); } +pub fn resolveSymbol(self: LinkerDefined, index: Symbol.Index, elf_file: *Elf) Elf.Ref { + const resolv = self.symbols_resolver.items[index]; + return elf_file.resolver.get(resolv).?; +} + +pub fn addSymbol(self: *LinkerDefined, allocator: Allocator) !Symbol.Index { + try self.symbols.ensureUnusedCapacity(allocator, 1); + const index: Symbol.Index = @intCast(self.symbols.items.len); + self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); + return index; +} + +pub fn addSymbolExtra(self: *LinkerDefined, allocator: Allocator, extra: Symbol.Extra) !u32 { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len); + return self.addSymbolExtraAssumeCapacity(extra); +} + +pub fn addSymbolExtraAssumeCapacity(self: *LinkerDefined, extra: Symbol.Extra) u32 { + const index = @as(u32, @intCast(self.symbols_extra.items.len)); + const fields = @typeInfo(Symbol.Extra).Struct.fields; + inline for (fields) |field| { + self.symbols_extra.appendAssumeCapacity(switch (field.type) { + u32 => @field(extra, field.name), + else => @compileError("bad field type"), + }); + } + return index; +} + +pub fn symbolExtra(self: *LinkerDefined, index: u32) Symbol.Extra { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + var i: usize = index; + var result: Symbol.Extra = undefined; + inline for (fields) |field| { + @field(result, field.name) = switch (field.type) { + u32 => self.symbols_extra.items[i], + else => @compileError("bad field type"), + }; + i += 1; + } + return result; +} + +pub fn setSymbolExtra(self: *LinkerDefined, index: u32, extra: Symbol.Extra) void { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + inline for (fields, 0..) |field, i| { + self.symbols_extra.items[index + i] = switch (field.type) { + u32 => @field(extra, field.name), + else => @compileError("bad field type"), + }; + } +} + pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) { return .{ .data = .{ .self = self, diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index 00a64c3950..245805e59e 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -282,7 +282,7 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void { } } -pub fn globals(self: SharedObject) []const Symbol.Index { +pub fn globals(self: *SharedObject) []Symbol { return self.symbols.items; } @@ -299,7 +299,7 @@ pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void { } } -pub fn writeSymtab(self: SharedObject, elf_file: *Elf) void { +pub fn writeSymtab(self: *SharedObject, elf_file: *Elf) void { for (self.globals(), self.symbols_resolver.items) |global, resolv| { const ref = elf_file.resolver.get(resolv).?; const ref_sym = elf_file.symbol(ref) orelse continue; From deeaa1bb0cb8a8c7ccebb23cc68be64e4b013ab2 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 1 Aug 2024 08:50:01 +0200 Subject: [PATCH 06/20] elf: redo symbol mgmt and ownership in ZigObject --- src/link/Elf.zig | 78 ++---- src/link/Elf/LinkerDefined.zig | 8 +- src/link/Elf/Object.zig | 27 +- src/link/Elf/SharedObject.zig | 16 +- src/link/Elf/Symbol.zig | 14 +- src/link/Elf/ZigObject.zig | 457 ++++++++++++++++++++------------- src/link/Elf/file.zig | 13 - 7 files changed, 335 insertions(+), 278 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 1e68374502..f2dc7b563f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -173,11 +173,7 @@ shstrtab_section_index: ?u32 = null, strtab_section_index: ?u32 = null, symtab_section_index: ?u32 = null, -/// An array of symbols parsed across all input files. -symbols: std.ArrayListUnmanaged(Symbol) = .{}, -symbols_extra: std.ArrayListUnmanaged(u32) = .{}, - -resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{}, +resolver: SymbolResolver = .{}, has_text_reloc: bool = false, num_ifunc_dynrelocs: usize = 0, @@ -191,10 +187,6 @@ merge_sections: std.ArrayListUnmanaged(MergeSection) = .{}, /// Table of last atom index in a section and matching atom free list if any. last_atom_and_free_list_table: LastAtomAndFreeListTable = .{}, -/// Global string table used to provide quick access to global symbol resolvers -/// such as `resolver`. -strings: StringTable = .{}, - first_eflags: ?elf.Elf64_Word = null, /// When allocating, the ideal_capacity is calculated by @@ -455,8 +447,6 @@ pub fn deinit(self: *Elf) void { self.shstrtab.deinit(gpa); self.symtab.deinit(gpa); self.strtab.deinit(gpa); - self.symbols.deinit(gpa); - self.symbols_extra.deinit(gpa); self.resolver.deinit(gpa); for (self.thunks.items) |*th| { @@ -472,8 +462,6 @@ pub fn deinit(self: *Elf) void { } self.last_atom_and_free_list_table.deinit(gpa); - self.strings.deinit(gpa); - self.got.deinit(gpa); self.plt.deinit(gpa); self.plt_got.deinit(gpa); @@ -1916,20 +1904,17 @@ fn accessLibPath( /// 6. Re-run symbol resolution on pruned objects and shared objects sets. pub fn resolveSymbols(self: *Elf) !void { // Resolve symbols in the ZigObject. For now, we assume that it's always live. - if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self); + if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self); // Resolve symbols on the set of all objects and shared objects (even if some are unneeded). - for (self.objects.items) |index| self.file(index).?.resolveSymbols(self); - for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self); - if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self); + for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self); + for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self); + if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self); // Mark live objects. self.markLive(); // Reset state of all globals after marking live objects. - if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self); - for (self.objects.items) |index| self.file(index).?.resetGlobals(self); - for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self); - if (self.linkerDefinedPtr()) |obj| obj.asFile().resetGlobals(self); + self.resolver.reset(); // Prune dead objects and shared objects. var i: usize = 0; @@ -1962,10 +1947,10 @@ pub fn resolveSymbols(self: *Elf) !void { } // Re-resolve the symbols. - if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self); - for (self.objects.items) |index| self.file(index).?.resolveSymbols(self); - for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self); - if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self); + if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self); + for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self); + for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self); + if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self); } /// Traverses all objects and shared objects marking any object referenced by @@ -1999,46 +1984,17 @@ fn convertCommonSymbols(self: *Elf) !void { } fn markImportsExports(self: *Elf) void { - 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_ptr == .shared_object and !global.isAbs(elf_file)) { - global.flags.import = true; - continue; - } - if (file_ptr.index() == file_index) { - global.flags.@"export" = true; - if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) { - global.flags.import = true; - } - } - } - } - }.mark; - + if (self.zigObjectPtr()) |zo| { + zo.markImportsExports(self); + } + for (self.objects.items) |index| { + self.file(index).?.object.markImportsExports(self); + } if (!self.isEffectivelyDynLib()) { for (self.shared_objects.items) |index| { - for (self.file(index).?.globals()) |global_index| { - const global = self.symbol(global_index); - const file_ptr = global.file(self) orelse continue; - const vis = @as(elf.STV, @enumFromInt(global.elfSym(self).st_other)); - if (file_ptr != .shared_object and vis != .HIDDEN) global.flags.@"export" = true; - } + self.file(index).?.shared_object.markImportExports(self); } } - - if (self.zig_object_index) |index| { - mark(self, index); - } - - for (self.objects.items) |index| { - mark(self, index); - } } fn claimUnresolved(self: *Elf) void { diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index 1247a08ef1..89e56a7e16 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -302,12 +302,8 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void { } } -pub fn globals(self: *LinkerDefined) []Symbol { - return self.symbols.items; -} - pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void { - for (self.globals(), self.symbols_resolver.items) |*global, resolv| { + for (self.symbols.items, self.symbols_resolver.items) |*global, resolv| { const ref = elf_file.resolver.get(resolv).?; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; @@ -324,7 +320,7 @@ pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void { } pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf) void { - for (self.globals(), self.symbols_resolver.items) |global, resolv| { + for (self.symbols.items, self.symbols_resolver.items) |global, resolv| { const ref = elf_file.resolver.get(resolv).?; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index fa912c0119..feb70776d5 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -676,6 +676,29 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void { } } +pub fn markImportsExports(self: *Object, elf_file: *Elf) void { + const first_global = self.first_global orelse return; + for (0..self.globals().len) |i| { + const idx = first_global + i; + const ref = self.resolveSymbol(@intCast(idx), elf_file); + const sym = elf_file.symbol(ref) orelse continue; + const file = sym.file(elf_file).?; + if (sym.version_index == elf.VER_NDX_LOCAL) continue; + const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other)); + if (vis == .HIDDEN) continue; + if (file == .shared_object and !sym.isAbs(elf_file)) { + sym.flags.import = true; + continue; + } + if (file.index() == self.index) { + sym.flags.@"export" = true; + if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) { + sym.flags.import = true; + } + } + } +} + pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void { const first_global = self.first_global orelse return; for (0..self.globals().len) |i| { @@ -1169,14 +1192,14 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index return data; } -pub fn locals(self: *Object) []Symbol { +fn locals(self: *Object) []Symbol { if (self.symbols.items.len == 0) return &[0]Symbol{}; assert(self.symbols.items.len >= self.symtab.items.len); const end = self.first_global orelse self.symtab.items.len; return self.symbols.items[0..end]; } -pub fn globals(self: *Object) []Symbol { +fn globals(self: *Object) []Symbol { if (self.symbols.items.len == 0) return &[0]Symbol{}; assert(self.symbols.items.len >= self.symtab.items.len); const start = self.first_global orelse self.symtab.items.len; diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index 245805e59e..aff07e4469 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -282,12 +282,18 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void { } } -pub fn globals(self: *SharedObject) []Symbol { - return self.symbols.items; +pub fn markImportExports(self: *SharedObject, elf_file: *Elf) void { + for (0..self.symbols.items.len) |i| { + const ref = self.resolveSymbol(@intCast(i), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + const ref_file = ref_sym.file(self).?; + const vis = @as(elf.STV, @enumFromInt(ref_sym.elfSym(self).st_other)); + if (ref_file != .shared_object and vis != .HIDDEN) ref_sym.flags.@"export" = true; + } } pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void { - for (self.globals(), self.symbols_resolver.items) |*global, resolv| { + for (self.symbols.items, self.symbols_resolver.items) |*global, resolv| { const ref = elf_file.resolver.get(resolv).?; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; @@ -300,7 +306,7 @@ pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void { } pub fn writeSymtab(self: *SharedObject, elf_file: *Elf) void { - for (self.globals(), self.symbols_resolver.items) |global, resolv| { + for (self.symbols.items, self.symbols_resolver.items) |global, resolv| { const ref = elf_file.resolver.get(resolv).?; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; @@ -354,7 +360,7 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { const gpa = comp.gpa; var aliases = std.ArrayList(Symbol.Index).init(gpa); defer aliases.deinit(); - try aliases.ensureTotalCapacityPrecise(self.globals().len); + try aliases.ensureTotalCapacityPrecise(self.symbols.items.len); for (self.symbols_resolvers.items, 0..) |resolv, index| { const ref = elf_file.resolver.get(resolv).?; diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 2c1ce0a104..ba5c8f4986 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -63,9 +63,7 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 { } pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 { - if (symbol.flags.global) return elf_file.strings.getAssumeExists(symbol.name_offset); - const file_ptr = symbol.file(elf_file).?; - return switch (file_ptr) { + return switch (symbol.file(elf_file).?) { inline else => |x| x.getString(symbol.name_offset), }; } @@ -87,9 +85,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File { } pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym { - const file_ptr = symbol.file(elf_file).?; - return switch (file_ptr) { - .zig_object => |x| x.elfSym(symbol.esym_index).*, + return switch (symbol.file(elf_file).?) { inline else => |x| x.symtab.items[symbol.esym_index], }; } @@ -423,12 +419,6 @@ pub const Flags = packed struct { /// Whether this symbol is weak. weak: bool = false, - /// Whether the symbol has its name interned in global symbol - /// resolver table. - /// This happens for any symbol that is considered a global - /// symbol, but is not necessarily an import or export. - global: bool = false, - /// Whether the symbol makes into the output symtab. output_symtab: bool = false, diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 554e038d95..fb41cd2c97 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -8,9 +8,11 @@ data: std.ArrayListUnmanaged(u8) = .{}, path: []const u8, index: File.Index, -local_esyms: std.MultiArrayList(ElfSym) = .{}, -global_esyms: std.MultiArrayList(ElfSym) = .{}, +symtab: std.MultiArrayList(ElfSym) = .{}, strtab: StringTable = .{}, +symbols: std.ArrayListUnmanaged(Symbol) = .{}, +symbols_extra: std.ArrayListUnmanaged(u32) = .{}, +symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{}, local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{}, @@ -113,9 +115,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { pub fn deinit(self: *ZigObject, allocator: Allocator) void { self.data.deinit(allocator); - self.local_esyms.deinit(allocator); - self.global_esyms.deinit(allocator); + self.symtab.deinit(allocator); self.strtab.deinit(allocator); + self.symbols.deinit(allocator); + self.symbols_extra.deinit(allocator); + self.symbols_resolver.deinit(allocator); self.local_symbols.deinit(allocator); self.global_symbols.deinit(allocator); self.globals_lookup.deinit(allocator); @@ -263,51 +267,73 @@ fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void { } } -pub fn addLocalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index { - try self.local_esyms.ensureUnusedCapacity(allocator, 1); - const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity())); - var esym = ElfSym{ .elf_sym = Elf.null_sym }; - esym.elf_sym.st_info = elf.STB_LOCAL << 4; - self.local_esyms.set(index, esym); +fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) !Symbol.Index { + try self.symtab.ensureUnusedCapacity(allocator, 1); + try self.symbols.ensureUnusedCapacity(allocator, 1); + try self.symbols_extra.ensureUnusedCapacity(allocator, @sizeOf(Symbol.Extra)); + + const index = self.addSymbolAssumeCapacity(); + const sym = &self.symbols.items[index]; + sym.name_offset = name_off; + sym.extra = self.addSymbolExtraAssumeCapacity(.{}); + + const esym_idx: u32 = @intCast(self.symtab.addOneAssumeCapacity()); + const esym = ElfSym{ .elf_sym = .{ + .st_value = 0, + .st_name = name_off, + .st_info = @as(u8, @intCast(st_bind)) << 4, + .st_other = 0, + .st_size = 0, + .st_shndx = 0, + } }; + self.symtab.set(index, esym); + sym.esym_index = esym_idx; + return index; } -pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index { - try self.global_esyms.ensureUnusedCapacity(allocator, 1); - const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity())); - var esym = ElfSym{ .elf_sym = Elf.null_sym }; - esym.elf_sym.st_info = elf.STB_GLOBAL << 4; - self.global_esyms.set(index, esym); - return index | global_symbol_bit; +fn newLocalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index { + try self.local_symbols.ensureUnusedCapacity(allocator, 1); + const fake_index: Symbol.Index = @intCast(self.local_symbols.items.len); + const index = try self.newSymbol(allocator, name_off, elf.STB_LOCAL); + self.local_symbols.appendAssumeCapacity(index); + return fake_index; } -pub fn newAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index { - const gpa = elf_file.base.comp.gpa; - const atom_index = try self.addAtom(gpa); - const symbol_index = try elf_file.addSymbol(); - const esym_index = try self.addLocalEsym(gpa); +fn newGlobalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index { + try self.global_symbols.ensureUnusedCapacity(allocator, 1); + const fake_index: Symbol.Index = @intCast(self.global_symbols.items.len); + const index = try self.newSymbol(allocator, name_off, elf.STB_GLOBAL); + self.global_symbols.appendAssumeCapacity(index); + return fake_index | global_symbol_bit; +} - try self.atoms_indexes.append(gpa, atom_index); - try self.local_symbols.append(gpa, symbol_index); +fn newAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Atom.Index { + try self.atoms.ensureUnusedCapacity(allocator, 1); + try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra)); + try self.atoms_indexes.ensureUnusedCapacity(allocator, 1); + try self.relocs.ensureUnusedCapacity(allocator, 1); - const symbol_ptr = elf_file.symbol(symbol_index); - symbol_ptr.file_index = self.index; - symbol_ptr.ref = .{ .index = atom_index, .file = self.index }; - symbol_ptr.extra_index = try elf_file.addSymbolExtra(.{}); + const index = self.addAtomAssumeCapacity(); + self.atoms_indexes.appendAssumeCapacity(index); + const atom_ptr = self.atom(index).?; + atom_ptr.name_offset = name_off; - self.local_esyms.items(.shndx)[esym_index] = atom_index; - self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM; - symbol_ptr.esym_index = esym_index; - - // TODO I'm thinking that maybe we shouldn' set this value unless it's actually needed? - const relocs_index = @as(u32, @intCast(self.relocs.items.len)); - const relocs = try self.relocs.addOne(gpa); - relocs.* = .{}; - - const atom_ptr = self.atom(atom_index).?; + const relocs_index: u32 = @intCast(self.relocs.items.len); + self.relocs.addOneAssumeCapacity().* = .{}; atom_ptr.relocs_section_index = relocs_index; - return symbol_index; + return index; +} + +fn newSymbolWithAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index { + const atom_index = try self.newAtom(allocator, name_off); + const sym_index = try self.newLocalSymbol(allocator, name_off); + const sym = self.symbol(sym_index); + sym.ref = .{ .index = atom_index, .file = self.index }; + self.symtab.items(.shndx)[sym.esym_index] = atom_index; + self.symtab.items(.elf_sym)[sym.esym_index].st_shndx = SHN_ATOM; + return sym_index; } /// TODO actually create fake input shdrs and return that instead. @@ -322,48 +348,47 @@ pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.E return shdr; } -pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void { - for (self.globals(), 0..) |index, i| { - const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit; - const esym = self.global_esyms.items(.elf_sym)[i]; - const shndx = self.global_esyms.items(.shndx)[i]; - - if (esym.st_shndx == elf.SHN_UNDEF) continue; +pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; + for (self.global_symbols.items, 0..) |index, i| { + const global = &self.symbols.items[index]; + const esym = global.elfSym(elf_file); + const shndx = self.symtab.items(.shndx)[global.esym_index]; if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { assert(esym.st_shndx == SHN_ATOM); const atom_ptr = self.atom(shndx) orelse continue; if (!atom_ptr.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, - SHN_ATOM => shndx, - else => unreachable, - }; - global.value = @intCast(esym.st_value); - global.ref = .{ .index = atom_index, .file = self.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; + const resolv = &self.symbols_resolver.items[i]; + const gop = try elf_file.resolver.getOrPut(gpa, .{ + .index = @intCast(i | global_symbol_bit), + .file = self.index, + }, elf_file); + if (!gop.found_existing) { + gop.ref.* = .{ .index = 0, .file = 0 }; + } + resolv.* = gop.index; + + if (esym.st_shndx == elf.SHN_UNDEF) continue; + if (elf_file.symbol(gop.ref.*) == null) { + gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index }; + continue; + } + + if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) { + gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index }; } } } -pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void { - for (self.globals(), 0..) |index, i| { - const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit; - const esym = self.global_esyms.items(.elf_sym)[i]; - +pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void { + for (self.global_symbols.items, 0..) |index, i| { + const global = &self.symbols.items[index]; + const esym = self.symtab.items(.elf_sym)[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; - } + if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue; const is_import = blk: { if (!elf_file.isEffectivelyDynLib()) break :blk false; @@ -374,29 +399,36 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void { global.value = 0; global.ref = .{ .index = 0, .file = 0 }; - global.esym_index = esym_index; + global.esym_index = @intCast(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; + + const idx = self.symbols_resolver.items[i]; + elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index }; } } pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void { - for (self.globals(), 0..) |index, i| { - const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit; - const esym = self.global_esyms.items(.elf_sym)[i]; - + for (self.global_symbols.items, 0..) |index, i| { + const global = &self.symbols.items[index]; + const esym = self.symtab.items(.elf_sym)[index]; if (esym.st_shndx != elf.SHN_UNDEF) continue; + if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue; - const global = elf_file.symbol(index); - if (global.file(elf_file)) |file| { - if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue; - } + // TODO: audit this + // const global = elf_file.symbol(index); + // if (global.file(elf_file)) |file| { + // if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue; + // } global.value = 0; global.ref = .{ .index = 0, .file = 0 }; - global.esym_index = esym_index; + global.esym_index = @intCast(index); global.file_index = self.index; + + const idx = self.symbols_resolver.items[i]; + elf_file.resolver.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index }; } } @@ -419,12 +451,14 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void { } pub fn markLive(self: *ZigObject, elf_file: *Elf) void { - for (self.globals(), 0..) |index, i| { - const esym = self.global_esyms.items(.elf_sym)[i]; + for (self.global_symbols.items, 0..) |index, i| { + const global = self.symbols.items[index]; + const esym = self.symtab.items(.elf_sym)[index]; if (esym.st_bind() == elf.STB_WEAK) continue; - const global = elf_file.symbol(index); - const file = global.file(elf_file) orelse continue; + const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file); + const sym = elf_file.symbol(ref) orelse continue; + const file = sym.file(elf_file).?; const should_keep = esym.st_shndx == elf.SHN_UNDEF or (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON); if (should_keep and !file.isAlive()) { @@ -434,14 +468,36 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void { } } -pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void { - for (self.globals(), 0..) |index, i| { - const esym = self.global_esyms.items(.elf_sym)[i]; - const shndx = self.global_esyms.items(.shndx)[i]; - const global = elf_file.symbol(index); - const global_file = global.file(elf_file) orelse continue; +pub fn markImportsExports(self: *Object, elf_file: *Elf) void { + for (0..self.global_symbols.items.len) |i| { + const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file); + const sym = elf_file.symbol(ref) orelse continue; + const file = sym.file(elf_file).?; + if (sym.version_index == elf.VER_NDX_LOCAL) continue; + const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other)); + if (vis == .HIDDEN) continue; + if (file == .shared_object and !sym.isAbs(elf_file)) { + sym.flags.import = true; + continue; + } + if (file.index() == self.index) { + sym.flags.@"export" = true; + if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) { + sym.flags.import = true; + } + } + } +} - if (self.index == global_file.index() or +pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void { + for (self.global_symbols.items, 0..) |index, i| { + const esym = self.symtab.items(.elf_sym)[index]; + const shndx = self.symtab.items(.shndx)[index]; + const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + const ref_file = ref_sym.file(elf_file).?; + + if (self.index == ref_file.index() or esym.st_shndx == elf.SHN_UNDEF or esym.st_bind() == elf.STB_WEAK or esym.st_shndx == elf.SHN_COMMON) continue; @@ -451,7 +507,7 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O if (!atom_ptr.alive) continue; } - const gop = try dupes.getOrPut(index); + const gop = try dupes.getOrPut(self.symbols_resolver.items[i]); if (!gop.found_existing) { gop.value_ptr.* = .{}; } @@ -483,12 +539,13 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void { pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void { const gpa = elf_file.base.comp.gpa; - try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len); + try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.global_symbols.items.len); - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - const file_ptr = global.file(elf_file).?; - assert(file_ptr.index() == self.index); + for (self.global_symbols.items, 0..) |index, i| { + const global = self.symbols.items[index]; + const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file); + const sym = elf_file.symbol(ref).?; + assert(sym.file(elf_file).?.index() == self.index); if (global.outputShndx(elf_file) == null) continue; const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file)); @@ -530,33 +587,9 @@ pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void { } } -inline fn isGlobal(index: Symbol.Index) bool { - return index & global_symbol_bit != 0; -} - -pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index { - const actual_index = index & symbol_mask; - if (isGlobal(index)) return self.globals()[actual_index]; - return self.locals()[actual_index]; -} - -pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym { - const actual_index = index & symbol_mask; - if (isGlobal(index)) return &self.global_esyms.items(.elf_sym)[actual_index]; - return &self.local_esyms.items(.elf_sym)[actual_index]; -} - -pub fn locals(self: ZigObject) []const Symbol.Index { - return self.local_symbols.items; -} - -pub fn globals(self: ZigObject) []const Symbol.Index { - return self.global_symbols.items; -} - pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { - for (self.locals()) |local_index| { - const local = elf_file.symbol(local_index); + for (self.local_symbols.items) |index| { + const local = &self.symbols.items[index]; if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue; const esym = local.elfSym(elf_file); switch (esym.st_type()) { @@ -564,22 +597,23 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { else => {}, } local.flags.output_symtab = true; - try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); + local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); self.output_symtab_ctx.nlocals += 1; self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1; } - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - const file_ptr = global.file(elf_file) orelse continue; - if (file_ptr.index() != self.index) continue; + for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| { + const global = &self.symbols.items[index]; + const ref = elf_file.resolver.items[resolv]; + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue; global.flags.output_symtab = true; if (global.isLocal(elf_file)) { - try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); + global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file); self.output_symtab_ctx.nlocals += 1; } else { - try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); + global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file); self.output_symtab_ctx.nglobals += 1; } self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1; @@ -587,8 +621,8 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { } pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void { - for (self.locals()) |local_index| { - const local = elf_file.symbol(local_index); + for (self.local_symbols.items) |index| { + const local = &self.symbols.items[index]; const idx = local.outputSymtabIndex(elf_file) orelse continue; const out_sym = &elf_file.symtab.items[idx]; out_sym.st_name = @intCast(elf_file.strtab.items.len); @@ -597,10 +631,11 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void { local.setOutputSym(elf_file, out_sym); } - for (self.globals()) |global_index| { - const global = elf_file.symbol(global_index); - const file_ptr = global.file(elf_file) orelse continue; - if (file_ptr.index() != self.index) continue; + for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| { + const global = self.symbols.items[index]; + const ref = elf_file.resolver.items[resolv]; + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; const idx = global.outputSymtabIndex(elf_file) orelse continue; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file)); @@ -611,10 +646,6 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void { } } -pub fn asFile(self: *ZigObject) File { - return .{ .zig_object = self }; -} - /// Returns atom's code. /// Caller owns the memory. pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { @@ -755,8 +786,8 @@ pub fn getOrCreateMetadataForLazySymbol( }; switch (metadata.state.*) { .unused => { - const symbol_index = try self.newAtom(elf_file); - const sym = elf_file.symbol(symbol_index); + const symbol_index = try self.newSymbolWithAtom(gpa, 0); + const sym = self.symbol(symbol_index); sym.flags.needs_zig_got = true; metadata.symbol_index.* = symbol_index; }, @@ -817,10 +848,10 @@ pub fn getOrCreateMetadataForDecl( const gop = try self.decls.getOrPut(gpa, decl_index); if (!gop.found_existing) { const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; - const symbol_index = try self.newAtom(elf_file); + const symbol_index = try self.newSymbolWithAtom(gpa, 0); const mod = elf_file.base.comp.module.?; const decl = mod.declPtr(decl_index); - const sym = elf_file.symbol(symbol_index); + const sym = self.symbol(symbol_index); if (decl.getOwnedVariable(mod)) |variable| { if (variable.is_threadlocal and any_non_single_threaded) { sym.flags.is_tls = true; @@ -1064,7 +1095,7 @@ pub fn updateFunc( const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index); self.freeUnnamedConsts(elf_file, decl_index); - elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); + self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); @@ -1096,7 +1127,7 @@ pub fn updateFunc( try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_FUNC); if (decl_state) |*ds| { - const sym = elf_file.symbol(sym_index); + const sym = self.symbol(sym_index); try self.dwarf.?.commitDeclState( pt, decl_index, @@ -1130,13 +1161,13 @@ pub fn updateDecl( const variable = decl.getOwnedVariable(mod).?; const name = decl.name.toSlice(&mod.intern_pool); const lib_name = variable.lib_name.toSlice(&mod.intern_pool); - const esym_index = try self.getGlobalSymbol(elf_file, name, lib_name); - elf_file.symbol(self.symbol(esym_index)).flags.needs_got = true; + const sym_index = try self.getGlobalSymbol(elf_file, name, lib_name); + self.symbol(sym_index).flags.needs_got = true; return; } const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index); - elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); + self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); const gpa = elf_file.base.comp.gpa; var code_buffer = std.ArrayList(u8).init(gpa); @@ -1174,7 +1205,7 @@ pub fn updateDecl( try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_OBJECT); if (decl_state) |*ds| { - const sym = elf_file.symbol(sym_index); + const sym = self.symbol(sym_index); try self.dwarf.?.commitDeclState( pt, decl_index, @@ -1323,7 +1354,8 @@ fn lowerConst( var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); - const sym_index = try self.newAtom(elf_file); + const name_off = try self.addString(gpa, name); + const sym_index = try self.newSymbolWithAtom(gpa, name_off); const res = try codegen.generateSymbol( &elf_file.base, @@ -1339,27 +1371,19 @@ fn lowerConst( .fail => |em| return .{ .fail = em }, }; - const local_sym = elf_file.symbol(sym_index); - const name_str_index = try self.strtab.insert(gpa, name); - local_sym.name_offset = name_str_index; - const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index]; - local_esym.st_name = name_str_index; + const local_sym = self.symbol(sym_index); + const local_esym = local_sym.elfSym(elf_file); local_esym.st_info |= elf.STT_OBJECT; local_esym.st_size = code.len; const atom_ptr = local_sym.atom(elf_file).?; atom_ptr.alive = true; - atom_ptr.name_offset = name_str_index; atom_ptr.alignment = required_alignment; atom_ptr.size = code.len; atom_ptr.output_section_index = output_section_index; try atom_ptr.allocate(elf_file); - // TODO rename and re-audit this method errdefer self.freeDeclMetadata(elf_file, sym_index); - local_sym.value = 0; - local_esym.st_value = 0; - const shdr = elf_file.shdrs.items[output_section_index]; const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); try elf_file.base.file.?.pwriteAll(code, file_offset); @@ -1401,9 +1425,9 @@ pub fn updateExports( }, }; const sym_index = metadata.symbol_index; - const esym_index = elf_file.symbol(sym_index).esym_index; - const esym = self.local_esyms.items(.elf_sym)[esym_index]; - const esym_shndx = self.local_esyms.items(.shndx)[esym_index]; + const esym_index = self.symbol(sym_index).esym_index; + const esym = self.symtab.items(.elf_sym)[esym_index]; + const esym_shndx = self.symtab.items(.shndx)[esym_index]; for (export_indices) |export_idx| { const exp = mod.all_exports.items[export_idx]; @@ -1437,22 +1461,27 @@ pub fn updateExports( const stt_bits: u8 = @as(u4, @truncate(esym.st_info)); const exp_name = exp.opts.name.toSlice(&mod.intern_pool); const name_off = try self.strtab.insert(gpa, exp_name); - const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index| + const global_sym_index = if (metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: { - const global_esym_index = try self.getGlobalSymbol(elf_file, exp_name, null); - try metadata.exports.append(gpa, global_esym_index); - break :blk global_esym_index; + const global_sym_index = try self.getGlobalSymbol(elf_file, exp_name, null); + try metadata.exports.append(gpa, global_sym_index); + break :blk global_sym_index; }; - const actual_esym_index = global_esym_index & symbol_mask; - const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index]; - global_esym.st_value = @intCast(elf_file.symbol(sym_index).value); + const value = self.symbol(sym_index).value; + const global_sym = self.symbol(global_sym_index); + global_sym.value = value; + global_sym.flags.weak = exp.opts.linkage == .weak; + global_sym.version_index = elf_file.default_version_index; + global_sym.ref = .{ .index = esym_shndx, .file = self.index }; + const global_esym = global_sym.elfSym(elf_file); + global_esym.st_value = @intCast(value); global_esym.st_shndx = esym.st_shndx; global_esym.st_info = (stb_bits << 4) | stt_bits; global_esym.st_name = name_off; global_esym.st_size = esym.st_size; - self.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx; + self.symtab.items(.shndx)[global_sym.esym_index] = esym_shndx; } } @@ -1506,16 +1535,19 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n const off = try self.strtab.insert(gpa, name); const lookup_gop = try self.globals_lookup.getOrPut(gpa, off); if (!lookup_gop.found_existing) { - const esym_index = try self.addGlobalEsym(gpa); - const esym = self.elfSym(esym_index); - esym.st_name = off; - lookup_gop.value_ptr.* = esym_index; - const gop = try elf_file.getOrPutGlobal(name); - try self.global_symbols.append(gpa, gop.index); + lookup_gop.value_ptr.* = try self.newSymbol(gpa, off); } return lookup_gop.value_ptr.*; } +pub fn asFile(self: *ZigObject) File { + return .{ .zig_object = self }; +} + +fn addString(self: *ZigObject, allocator: Allocator, string: []const u8) !u32 { + return self.strtab.insert(allocator, string); +} + pub fn getString(self: ZigObject, off: u32) [:0]const u8 { return self.strtab.getAssumeExists(off); } @@ -1586,6 +1618,73 @@ pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void { } } +inline fn isGlobal(index: Symbol.Index) bool { + return index & global_symbol_bit != 0; +} + +pub fn symbol(self: *ZigObject, index: Symbol.Index) *Symbol { + const actual_index = index & symbol_mask; + if (isGlobal(index)) return &self.symbols.items[self.global_symbols.items[actual_index]]; + return &self.symbols.items[self.local_symbols.items[actual_index]]; +} + +pub fn resolveSymbol(self: ZigObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref { + if (isGlobal(index)) { + const resolv = self.symbols_resolver.items[index & symbol_mask]; + return elf_file.resolver.get(resolv).?; + } + return .{ .index = index, .file = self.index }; +} + +pub fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index { + try self.symbols.ensureUnusedCapacity(allocator, 1); + const index: Symbol.Index = @intCast(self.symbols.items.len); + self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); + return index; +} + +pub fn addSymbolExtra(self: *ZigObject, allocator: Allocator, extra: Symbol.Extra) !u32 { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len); + return self.addSymbolExtraAssumeCapacity(extra); +} + +pub fn addSymbolExtraAssumeCapacity(self: *ZigObject, extra: Symbol.Extra) u32 { + const index = @as(u32, @intCast(self.symbols_extra.items.len)); + const fields = @typeInfo(Symbol.Extra).Struct.fields; + inline for (fields) |field| { + self.symbols_extra.appendAssumeCapacity(switch (field.type) { + u32 => @field(extra, field.name), + else => @compileError("bad field type"), + }); + } + return index; +} + +pub fn symbolExtra(self: *ZigObject, index: u32) Symbol.Extra { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + var i: usize = index; + var result: Symbol.Extra = undefined; + inline for (fields) |field| { + @field(result, field.name) = switch (field.type) { + u32 => self.symbols_extra.items[i], + else => @compileError("bad field type"), + }; + i += 1; + } + return result; +} + +pub fn setSymbolExtra(self: *ZigObject, index: u32, extra: Symbol.Extra) void { + const fields = @typeInfo(Symbol.Extra).Struct.fields; + inline for (fields, 0..) |field, i| { + self.symbols_extra.items[index + i] = switch (field.type) { + u32 => @field(extra, field.name), + else => @compileError("bad field type"), + }; + } +} + pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) { return .{ .data = .{ .self = self, @@ -1658,9 +1757,9 @@ const DeclMetadata = struct { /// A list of all exports aliases of this Decl. exports: std.ArrayListUnmanaged(Symbol.Index) = .{}, - fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 { + fn @"export"(m: DeclMetadata, zo: *ZigObject, name: []const u8) ?*u32 { for (m.exports.items) |*exp| { - const exp_name = zig_object.getString(zig_object.elfSym(exp.*).st_name); + const exp_name = zo.getString(zo.symbol(exp.*).name_off); if (mem.eql(u8, name, exp_name)) return exp; } return null; diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index 346f83d10b..9c7cd27626 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -153,19 +153,6 @@ pub const File = union(enum) { }; } - pub fn locals(file: File) []const Symbol.Index { - return switch (file) { - .linker_defined, .shared_object => &[0]Symbol.Index{}, - inline else => |x| x.locals(), - }; - } - - pub fn globals(file: File) []const Symbol.Index { - return switch (file) { - inline else => |x| x.globals(), - }; - } - pub fn getString(file: File, off: u32) [:0]const u8 { return switch (file) { inline else => |x| x.getString(off), From 41e9b8b6c84a1787ffa647fc42980dcce4942b7d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 1 Aug 2024 22:28:28 +0200 Subject: [PATCH 07/20] elf: fix compile errors --- src/arch/aarch64/CodeGen.zig | 5 +- src/arch/arm/CodeGen.zig | 5 +- src/arch/riscv64/CodeGen.zig | 18 +- src/arch/riscv64/Emit.zig | 14 +- src/arch/sparc64/CodeGen.zig | 5 +- src/arch/x86_64/CodeGen.zig | 10 +- src/arch/x86_64/Emit.zig | 17 +- src/arch/x86_64/Lower.zig | 4 +- src/codegen.zig | 14 +- src/link/Elf.zig | 131 ++++++-------- src/link/Elf/Atom.zig | 109 ++++++------ src/link/Elf/LinkerDefined.zig | 74 +++++--- src/link/Elf/Object.zig | 79 +++++++-- src/link/Elf/SharedObject.zig | 37 ++-- src/link/Elf/Symbol.zig | 11 +- src/link/Elf/ZigObject.zig | 161 ++++++++++++------ src/link/Elf/eh_frame.zig | 15 +- src/link/Elf/file.zig | 23 ++- src/link/Elf/gc.zig | 149 +++++++++------- src/link/Elf/relocatable.zig | 4 +- src/link/Elf/synthetic_sections.zig | 255 ++++++++++++++-------------- src/link/Elf/thunks.zig | 40 ++--- 22 files changed, 654 insertions(+), 526 deletions(-) diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 8a020fc521..695bd4211b 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4354,8 +4354,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier if (try self.air.value(callee, pt)) |func_value| { if (func_value.getFunction(mod)) |func| { if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); - const sym = elf_file.symbol(sym_index); + const zo = elf_file.zigObjectPtr().?; + const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl); + const sym = zo.symbol(sym_index); _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file))); try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr }); diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index f923c001e1..19bef2f991 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -4336,8 +4336,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier if (try self.air.value(callee, pt)) |func_value| { if (func_value.getFunction(mod)) |func| { if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); - const sym = elf_file.symbol(sym_index); + const zo = elf_file.zigObjectPtr().?; + const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl); + const sym = zo.symbol(sym_index); _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); const got_addr: u32 = @intCast(sym.zigGotAddress(elf_file)); try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr }); diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 040afd3160..979f76f50d 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1409,12 +1409,13 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void { defer func.register_manager.unlockReg(data_lock); const elf_file = func.bin_file.cast(link.File.Elf).?; - const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, .{ + const zo = elf_file.zigObjectPtr().?; + const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, .{ .kind = .const_data, .ty = enum_ty, }) catch |err| return func.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym = elf_file.symbol(sym_index); + const sym = zo.symbol(sym_index); try func.genSetReg(Type.u64, data_reg, .{ .lea_symbol = .{ .sym = sym.esym_index } }); @@ -4946,8 +4947,9 @@ fn genCall( }) { .func => |func_val| { if (func.bin_file.cast(link.File.Elf)) |elf_file| { - const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func_val.owner_decl); - const sym = elf_file.symbol(sym_index); + const zo = elf_file.zigObjectPtr().?; + const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func_val.owner_decl); + const sym = zo.symbol(sym_index); if (func.mod.pic) { return func.fail("TODO: genCall pic", .{}); @@ -7822,9 +7824,10 @@ fn airTagName(func: *Func, inst: Air.Inst.Index) !void { const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(zcu), zcu); const elf_file = func.bin_file.cast(link.File.Elf).?; - const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err| + const zo = elf_file.zigObjectPtr().?; + const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err| return func.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym = elf_file.symbol(sym_index); + const sym = zo.symbol(sym_index); if (func.mod.pic) { return func.fail("TODO: airTagName pic", .{}); @@ -8049,7 +8052,8 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { switch (lf.tag) { .elf => { const elf_file = lf.cast(link.File.Elf).?; - const local = elf_file.symbol(local_sym_index); + const zo = elf_file.zigObjectPtr().?; + const local = zo.symbol(local_sym_index); return MCValue{ .undef = local.esym_index }; }, else => unreachable, diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index beb232b776..9345f5dacc 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -50,16 +50,16 @@ pub fn emitMir(emit: *Emit) Error!void { }; const elf_file = emit.bin_file.cast(link.File.Elf).?; + const zo = elf_file.zigObjectPtr().?; - const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; - const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index); - const sym = elf_file.symbol(sym_index); + const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?; + const sym = zo.symbol(symbol.sym_index); var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { - _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); + _ = try sym.getOrCreateZigGotEntry(symbol.sym_index, elf_file); hi_r_type = Elf.R_ZIG_GOT_HI20; lo_r_type = Elf.R_ZIG_GOT_LO12; @@ -82,8 +82,9 @@ pub fn emitMir(emit: *Emit) Error!void { }, .load_tlv_reloc => |symbol| { const elf_file = emit.bin_file.cast(link.File.Elf).?; + const zo = elf_file.zigObjectPtr().?; - const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; + const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?; const R_RISCV = std.elf.R_RISCV; @@ -107,7 +108,8 @@ pub fn emitMir(emit: *Emit) Error!void { }, .call_extern_fn_reloc => |symbol| { const elf_file = emit.bin_file.cast(link.File.Elf).?; - const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; + const zo = elf_file.zigObjectPtr().?; + const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?; const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT); diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 1c3b2327b6..f9bcfe7003 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -1354,8 +1354,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier switch (mod.intern_pool.indexToKey(func_value.ip_index)) { .func => |func| { const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { - const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); - const sym = elf_file.symbol(sym_index); + const zo = elf_file.zigObjectPtr().?; + const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl); + const sym = zo.symbol(sym_index); _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file))); } else unreachable; diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 4e227e2253..4543cce33c 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -12327,8 +12327,9 @@ fn genCall(self: *Self, info: union(enum) { }) { .func => |func| { if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl); - const sym = elf_file.symbol(sym_index); + const zo = elf_file.zigObjectPtr().?; + const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl); + const sym = zo.symbol(sym_index); if (self.mod.pic) { const callee_reg: Register = switch (resolved_cc) { .SysV => callee: { @@ -15320,9 +15321,10 @@ fn genLazySymbolRef( ) InnerError!void { const pt = self.pt; if (self.bin_file.cast(link.File.Elf)) |elf_file| { - const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err| + const zo = elf_file.zigObjectPtr().?; + const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err| return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym = elf_file.symbol(sym_index); + const sym = zo.symbol(sym_index); if (self.mod.pic) { switch (tag) { .lea, .call => try self.genSetReg(reg, Type.usize, .{ diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index fd7a87f50d..bc439bd7ab 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -42,7 +42,8 @@ pub fn emitMir(emit: *Emit) Error!void { }), .linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| { // Add relocation to the decl. - const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; + const zo = elf_file.zigObjectPtr().?; + const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.PLT32); try atom_ptr.addReloc(elf_file, .{ .r_offset = end_offset - 4, @@ -88,7 +89,8 @@ pub fn emitMir(emit: *Emit) Error!void { }), .linker_tlsld => |data| { const elf_file = emit.lower.bin_file.cast(link.File.Elf).?; - const atom = elf_file.symbol(data.atom_index).atom(elf_file).?; + const zo = elf_file.zigObjectPtr().?; + const atom = zo.symbol(data.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD); try atom.addReloc(elf_file, .{ .r_offset = end_offset - 4, @@ -98,7 +100,8 @@ pub fn emitMir(emit: *Emit) Error!void { }, .linker_dtpoff => |data| { const elf_file = emit.lower.bin_file.cast(link.File.Elf).?; - const atom = elf_file.symbol(data.atom_index).atom(elf_file).?; + const zo = elf_file.zigObjectPtr().?; + const atom = zo.symbol(data.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32); try atom.addReloc(elf_file, .{ .r_offset = end_offset - 4, @@ -112,11 +115,11 @@ pub fn emitMir(emit: *Emit) Error!void { .Obj => true, .Lib => emit.lower.link_mode == .static, }; - const atom = elf_file.symbol(data.atom_index).atom(elf_file).?; - const sym_index = elf_file.zigObjectPtr().?.symbol(data.sym_index); - const sym = elf_file.symbol(sym_index); + const zo = elf_file.zigObjectPtr().?; + const atom = zo.symbol(data.atom_index).atom(elf_file).?; + const sym = zo.symbol(data.sym_index); if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { - _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); + _ = try sym.getOrCreateZigGotEntry(data.sym_index, elf_file); } if (emit.lower.pic) { const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib) diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index 2a19186176..1efcacdc2a 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -349,8 +349,8 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) assert(mem_op.sib.scale_index.scale == 0); if (lower.bin_file.cast(link.File.Elf)) |elf_file| { - const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index); - const elf_sym = elf_file.symbol(sym_index); + const zo = elf_file.zigObjectPtr().?; + const elf_sym = zo.symbol(sym.sym_index); if (elf_sym.flags.is_tls) { // TODO handle extern TLS vars, i.e., emit GD model diff --git a/src/codegen.zig b/src/codegen.zig index 9c3fd1914b..50688151ed 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -906,20 +906,20 @@ fn genDeclRef( const is_extern = decl.isExtern(zcu); if (lf.cast(link.File.Elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; if (is_extern) { const name = decl.name.toSlice(ip); // TODO audit this const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null; const sym_index = try elf_file.getGlobalSymbol(name, lib_name); - elf_file.symbol(elf_file.zigObjectPtr().?.symbol(sym_index)).flags.needs_got = true; + zo.symbol(sym_index).flags.needs_got = true; return GenResult.mcv(.{ .load_symbol = sym_index }); } - const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index); - const sym = elf_file.symbol(sym_index); + const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, decl_index); if (is_threadlocal) { - return GenResult.mcv(.{ .load_tlv = sym.esym_index }); + return GenResult.mcv(.{ .load_tlv = sym_index }); } - return GenResult.mcv(.{ .load_symbol = sym.esym_index }); + return GenResult.mcv(.{ .load_symbol = sym_index }); } else if (lf.cast(link.File.MachO)) |macho_file| { const zo = macho_file.getZigObject().?; if (is_extern) { @@ -971,9 +971,7 @@ fn genUnnamedConst( }; switch (lf.tag) { .elf => { - const elf_file = lf.cast(link.File.Elf).?; - const local = elf_file.symbol(local_sym_index); - return GenResult.mcv(.{ .load_symbol = local.esym_index }); + return GenResult.mcv(.{ .load_symbol = local_sym_index }); }, .macho => { const macho_file = lf.cast(link.File.MachO).?; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index f2dc7b563f..987d108567 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2013,11 +2013,10 @@ fn claimUnresolved(self: *Elf) void { fn scanRelocs(self: *Elf) !void { const gpa = self.base.comp.gpa; - var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa); + var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa); defer { - var it = undefs.iterator(); - while (it.next()) |entry| { - entry.value_ptr.deinit(); + for (undefs.values()) |*refs| { + refs.deinit(); } undefs.deinit(); } @@ -2028,7 +2027,18 @@ fn scanRelocs(self: *Elf) !void { objects.appendSliceAssumeCapacity(self.objects.items); var has_reloc_errors = false; - for (objects.items) |index| { + if (self.zigObjectPtr()) |zo| { + zo.asFile().scanRelocs(self, &undefs) catch |err| switch (err) { + error.RelaxFailure => unreachable, + error.UnsupportedCpuArch => { + try self.reportUnsupportedCpuArch(); + return error.FlushFailure; + }, + error.RelocFailure => has_reloc_errors = true, + else => |e| return e, + }; + } + for (self.objects.items) |index| { self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) { error.RelaxFailure => unreachable, error.UnsupportedCpuArch => { @@ -2044,47 +2054,12 @@ fn scanRelocs(self: *Elf) !void { if (has_reloc_errors) return error.FlushFailure; - for (self.symbols.items, 0..) |*sym, i| { - const index = @as(u32, @intCast(i)); - if (!sym.isLocal(self) and !sym.flags.has_dynamic) { - log.debug("'{s}' is non-local", .{sym.name(self)}); - try self.dynsym.addSymbol(index, self); - } - if (sym.flags.needs_got) { - log.debug("'{s}' needs GOT", .{sym.name(self)}); - _ = try self.got.addGotSymbol(index, self); - } - if (sym.flags.needs_plt) { - if (sym.flags.is_canonical) { - log.debug("'{s}' needs CPLT", .{sym.name(self)}); - sym.flags.@"export" = true; - try self.plt.addSymbol(index, self); - } else if (sym.flags.needs_got) { - log.debug("'{s}' needs PLTGOT", .{sym.name(self)}); - try self.plt_got.addSymbol(index, self); - } else { - log.debug("'{s}' needs PLT", .{sym.name(self)}); - try self.plt.addSymbol(index, self); - } - } - if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) { - log.debug("'{s}' needs COPYREL", .{sym.name(self)}); - try self.copy_rel.addSymbol(index, self); - } - if (sym.flags.needs_tlsgd) { - log.debug("'{s}' needs TLSGD", .{sym.name(self)}); - try self.got.addTlsGdSymbol(index, self); - } - if (sym.flags.needs_gottp) { - log.debug("'{s}' needs GOTTP", .{sym.name(self)}); - try self.got.addGotTpSymbol(index, self); - } - if (sym.flags.needs_tlsdesc) { - log.debug("'{s}' needs TLSDESC", .{sym.name(self)}); - try self.got.addTlsDescSymbol(index, self); - } + if (self.zigObjectPtr()) |zo| { + try zo.asFile().createSymbolIndirection(self); + } + for (self.objects.items) |index| { + try self.file(index).?.createSymbolIndirection(self); } - if (self.got.flags.needs_tlsld) { log.debug("program needs TLSLD", .{}); try self.got.addTlsLdSymbol(self); @@ -2861,8 +2836,8 @@ pub fn writeElfHeader(self: *Elf) !void { index += 4; const e_entry: u64 = if (self.linkerDefinedPtr()) |obj| blk: { - const entry_index = obj.entry_index orelse break :blk 0; - break :blk @intCast(self.symbol(entry_index).address(.{}, self)); + const entry_sym = obj.entrySymbol(self) orelse break :blk 0; + break :blk @intCast(entry_sym.address(.{}, self)); } else 0; const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0; switch (self.ptr_width) { @@ -2993,7 +2968,7 @@ pub fn deleteExport( fn checkDuplicates(self: *Elf) !void { const gpa = self.base.comp.gpa; - var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa); + var dupes = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)).init(gpa); defer { for (dupes.values()) |*list| { list.deinit(gpa); @@ -3301,7 +3276,7 @@ fn initSyntheticSections(self: *Elf) !void { }); const needs_versions = for (self.dynsym.entries.items) |entry| { - const sym = self.symbol(entry.symbol_index); + const sym = self.symbol(entry.ref).?; if (sym.flags.import and sym.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) break true; } else false; if (needs_versions) { @@ -3515,7 +3490,7 @@ fn setVersionSymtab(self: *Elf) !void { try self.versym.resize(gpa, self.dynsym.count()); self.versym.items[0] = elf.VER_NDX_LOCAL; for (self.dynsym.entries.items, 1..) |entry, i| { - const sym = self.symbol(entry.symbol_index); + const sym = self.symbol(entry.ref).?; self.versym.items[i] = sym.version_index; } @@ -4307,11 +4282,10 @@ fn allocateSpecialPhdrs(self: *Elf) void { fn writeAtoms(self: *Elf) !void { const gpa = self.base.comp.gpa; - var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa); + var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa); defer { - var it = undefs.iterator(); - while (it.next()) |entry| { - entry.value_ptr.deinit(); + for (undefs.values()) |*refs| { + refs.deinit(); } undefs.deinit(); } @@ -5261,7 +5235,7 @@ pub fn calcNumIRelativeRelocs(self: *Elf) usize { for (self.got.entries.items) |entry| { if (entry.tag != .got) continue; - const sym = self.symbol(entry.symbol_index); + const sym = self.symbol(entry.ref).?; if (sym.isIFunc(self)) count += 1; } @@ -5443,36 +5417,34 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { try self.base.comp.link_errors.ensureUnusedCapacity(gpa, undefs.count()); - var it = undefs.iterator(); - while (it.next()) |entry| { - const undef_index = entry.key_ptr.*; - const atoms = entry.value_ptr.*.items; - const natoms = @min(atoms.len, max_notes); - const nnotes = natoms + @intFromBool(atoms.len > max_notes); + for (undefs.keys(), undefs.values()) |key, refs| { + const undef_sym = self.resolver.keys.items[key - 1]; + const nrefs = @min(refs.items.len, max_notes); + const nnotes = nrefs + @intFromBool(refs.items.len > max_notes); var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes); - try err.addMsg("undefined symbol: {s}", .{self.symbol(undef_index).name(self)}); + try err.addMsg("undefined symbol: {s}", .{undef_sym.name(self)}); - for (atoms[0..natoms]) |ref| { + for (refs.items[0..nrefs]) |ref| { const atom_ptr = self.atom(ref).?; - const file_ptr = self.file(ref.file).?; + const file_ptr = atom_ptr.file(self).?; try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) }); } - if (atoms.len > max_notes) { - const remaining = atoms.len - max_notes; + if (refs.items.len > max_notes) { + const remaining = refs.items.len - max_notes; try err.addNote("referenced {d} more times", .{remaining}); } } } fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void { + if (dupes.keys().len == 0) return; // Nothing to do + const max_notes = 3; - var has_dupes = false; - var it = dupes.iterator(); - while (it.next()) |entry| { - const sym = self.symbol(entry.key_ptr.*); - const notes = entry.value_ptr.*; + + for (dupes.keys(), dupes.values()) |key, notes| { + const sym = self.resolver.keys.items[key - 1]; const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); var err = try self.base.addErrorWithNotes(nnotes + 1); @@ -5489,11 +5461,9 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor const remaining = notes.items.len - max_notes; try err.addNote("defined {d} more times", .{remaining}); } - - has_dupes = true; } - if (has_dupes) return error.HasDuplicates; + return error.HasDuplicates; } fn reportMissingLibraryError( @@ -5918,7 +5888,7 @@ pub const SymbolResolver = struct { elf_file: *Elf, ) !Result { const adapter = Adapter{ .keys = resolver.keys.items, .elf_file = elf_file }; - const key = Key{ .index = ref.index, .file = ref.file }; + const key = Key{ .index = ref.index, .file_index = ref.file }; const gop = try resolver.table.getOrPutAdapted(allocator, key, adapter); if (!gop.found_existing) { try resolver.keys.append(allocator, key); @@ -5944,16 +5914,15 @@ pub const SymbolResolver = struct { const Key = struct { index: Symbol.Index, - file: File.Index, + file_index: File.Index, fn name(key: Key, elf_file: *Elf) [:0]const u8 { - const ref = Ref{ .index = key.index, .file = key.file }; - return ref.symbol(elf_file).?.name(elf_file); + const ref = Ref{ .index = key.index, .file = key.file_index }; + return elf_file.symbol(ref).?.name(elf_file); } - pub fn file(key: Key, elf_file: *Elf) ?File { - const ref = Ref{ .index = key.index, .file = key.file }; - return ref.file(elf_file); + fn file(key: Key, elf_file: *Elf) ?File { + return elf_file.file(key.file_index); } fn eql(key: Key, other: Key, elf_file: *Elf) bool { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 0f1ea4b6e3..f2757f570b 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -326,12 +326,8 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El const cpu_arch = elf_file.getTarget().cpu.arch; const file_ptr = self.file(elf_file).?; for (self.relocs(elf_file)) |rel| { - const target_index = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, - }; - const target = elf_file.symbol(target_index); + const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target = elf_file.symbol(target_ref).?; const r_type = rel.r_type(); const r_offset: u64 = @intCast(self.value + @as(i64, @intCast(rel.r_offset))); var r_addend = rel.r_addend; @@ -422,12 +418,21 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype const r_kind = relocation.decode(rel.r_type(), cpu_arch); if (r_kind == .none) continue; - const symbol_index = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, + const symbol_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const symbol = elf_file.symbol(symbol_ref) orelse { + const sym_name = switch (file_ptr) { + .zig_object => |x| x.symbol(rel.r_sym()).name(elf_file), + inline else => |x| x.symbols.items[rel.r_sym()].name(elf_file), + }; + // Violation of One Definition Rule for COMDATs. + // TODO convert into an error + log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ + file_ptr.fmtPath(), + self.name(elf_file), + sym_name, + }); + continue; }; - const symbol = elf_file.symbol(symbol_index); const is_synthetic_symbol = switch (file_ptr) { .zig_object => false, // TODO: implement this once we support merge sections in ZigObject @@ -435,19 +440,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype else => unreachable, }; - // Check for violation of One Definition Rule for COMDATs. - if (symbol.file(elf_file) == null) { - // TODO convert into an error - log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ - file_ptr.fmtPath(), - self.name(elf_file), - symbol.name(elf_file), - }); - continue; - } - // Report an undefined symbol. - if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs))) + if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, symbol, rel, undefs))) continue; if (symbol.isIFunc(elf_file)) { @@ -694,16 +688,15 @@ fn reportUndefined( self: Atom, elf_file: *Elf, sym: *const Symbol, - sym_index: Symbol.Index, rel: elf.Elf64_Rela, undefs: anytype, ) !bool { const comp = elf_file.base.comp; const gpa = comp.gpa; - const rel_esym = switch (self.file(elf_file).?) { - .zig_object => |x| x.elfSym(rel.r_sym()).*, - .object => |x| x.symtab.items[rel.r_sym()], - else => unreachable, + const file_ptr = self.file(elf_file).?; + const rel_esym = switch (file_ptr) { + .zig_object => |x| x.symbol(rel.r_sym()).elfSym(elf_file), + inline else => |x| x.symtab.items[rel.r_sym()], }; const esym = sym.elfSym(elf_file); if (rel_esym.st_shndx == elf.SHN_UNDEF and @@ -712,7 +705,12 @@ fn reportUndefined( !sym.flags.import and esym.st_shndx == elf.SHN_UNDEF) { - const gop = try undefs.getOrPut(sym_index); + const idx = switch (file_ptr) { + .zig_object => |x| x.symbols_resolver.items[rel.r_sym() & ZigObject.symbol_mask], + .object => |x| x.symbols_resolver.items[rel.r_sym() - x.first_global.?], + inline else => |x| x.symbols_resolver.items[rel.r_sym()], + }; + const gop = try undefs.getOrPut(idx); if (!gop.found_existing) { gop.value_ptr.* = std.ArrayList(Elf.Ref).init(gpa); } @@ -737,11 +735,8 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi const r_kind = relocation.decode(rel.r_type(), cpu_arch); if (r_kind == .none) continue; - const target = switch (file_ptr) { - .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())), - .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]), - else => unreachable, - }; + const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target = elf_file.symbol(target_ref).?; const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; // We will use equation format to resolve relocations: @@ -923,31 +918,29 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; - const target_index = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, + const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target = elf_file.symbol(target_ref) orelse { + const sym_name = switch (file_ptr) { + .zig_object => |x| x.symbol(rel.r_sym()).name(elf_file), + inline else => |x| x.symbols.items[rel.r_sym()].name(elf_file), + }; + // Violation of One Definition Rule for COMDATs. + // TODO convert into an error + log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ + file_ptr.fmtPath(), + self.name(elf_file), + sym_name, + }); + continue; }; - const target = elf_file.symbol(target_index); const is_synthetic_symbol = switch (file_ptr) { .zig_object => false, // TODO: implement this once we support merge sections in ZigObject .object => |x| rel.r_sym() >= x.symtab.items.len, else => unreachable, }; - // Check for violation of One Definition Rule for COMDATs. - if (target.file(elf_file) == null) { - // TODO convert into an error - log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ - file_ptr.fmtPath(), - self.name(elf_file), - target.name(elf_file), - }); - continue; - } - // Report an undefined symbol. - if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, target, target_index, rel, undefs))) + if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, target, rel, undefs))) continue; // We will use equation format to resolve relocations: @@ -1766,11 +1759,7 @@ const aarch64 = struct { => { const disp: i28 = math.cast(i28, S + A - P) orelse blk: { const th = atom.thunk(elf_file); - const target_index = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, - }; + const target_index = file_ptr.resolveSymbol(rel.r_sym(), elf_file); const S_ = th.targetAddress(target_index, elf_file); break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; }; @@ -2106,11 +2095,8 @@ const riscv = struct { return error.RelocFailure; }; it.pos = pos; - const target_ = switch (file_ptr) { - .zig_object => |x| elf_file.symbol(x.symbol(pair.r_sym())), - .object => |x| elf_file.symbol(x.symbols.items[pair.r_sym()]), - else => unreachable, - }; + const target_ref_ = file_ptr.resolveSymbol(pair.r_sym(), elf_file); + const target_ = elf_file.symbol(target_ref_).?; const S_ = target_.address(.{}, elf_file); const A_ = pair.r_addend; const P_ = atom_addr + @as(i64, @intCast(pair.r_offset)); @@ -2313,4 +2299,5 @@ const File = @import("file.zig").File; const Object = @import("Object.zig"); const Symbol = @import("Symbol.zig"); const Thunk = @import("thunks.zig").Thunk; +const ZigObject = @import("ZigObject.zig"); const dev = @import("../../dev.zig"); diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index 89e56a7e16..ee9a1e2956 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -44,7 +44,7 @@ pub fn init(self: *LinkerDefined, allocator: Allocator) !void { pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { const newSymbolAssumeCapacity = struct { - fn newSymbolAssumeCapacity(ld: *LinkerDefined, name_off: u32) Symbol.Index { + fn newSymbolAssumeCapacity(ld: *LinkerDefined, name_off: u32, ef: *Elf) Symbol.Index { const esym_index: u32 = @intCast(ld.symtab.items.len); const esym = ld.symtab.addOneAssumeCapacity(); esym.* = .{ @@ -61,7 +61,8 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { symbol.extra_index = ld.addSymbolExtraAssumeCapacity(.{}); symbol.ref = .{ .index = 0, .file = 0 }; symbol.esym_index = esym_index; - symbol.version_index = elf_file.default_sym_version; + symbol.version_index = ef.default_sym_version; + return index; } }.newSymbolAssumeCapacity; @@ -111,31 +112,31 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { @memset(self.symbols_resolver.items, 0); if (elf_file.entry_name) |name| { - self.entry_index = newSymbolAssumeCapacity(self, try self.addString(gpa, name)); + self.entry_index = newSymbolAssumeCapacity(self, try self.addString(gpa, name), elf_file); } - self.dynamic_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_DYNAMIC")); - self.ehdr_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__ehdr_start")); - self.init_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_start")); - self.init_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_end")); - self.fini_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_start")); - self.fini_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_end")); - self.preinit_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_start")); - self.preinit_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_end")); - self.got_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_")); - self.plt_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_")); - self.end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_end")); + self.dynamic_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_DYNAMIC"), elf_file); + self.ehdr_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__ehdr_start"), elf_file); + self.init_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_start"), elf_file); + self.init_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_end"), elf_file); + self.fini_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_start"), elf_file); + self.fini_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_end"), elf_file); + self.preinit_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_start"), elf_file); + self.preinit_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_end"), elf_file); + self.got_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_"), elf_file); + self.plt_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_"), elf_file); + self.end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_end"), elf_file); if (elf_file.base.comp.link_eh_frame_hdr) { - self.gnu_eh_frame_hdr_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__GNU_EH_FRAME_HDR")); + self.gnu_eh_frame_hdr_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__GNU_EH_FRAME_HDR"), elf_file); } - self.dso_handle_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__dso_handle")); - self.rela_iplt_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_start")); - self.rela_iplt_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_end")); + self.dso_handle_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__dso_handle"), elf_file); + self.rela_iplt_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_start"), elf_file); + self.rela_iplt_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_end"), elf_file); if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) { - self.global_pointer_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__global_pointer$")); + self.global_pointer_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__global_pointer$"), elf_file); } for (elf_file.objects.items) |index| { @@ -145,8 +146,8 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { defer gpa.free(start_name); const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name}); defer gpa.free(stop_name); - const start = newSymbolAssumeCapacity(self, try self.addString(gpa, start_name)); - const stop = newSymbolAssumeCapacity(self, try self.addString(gpa, stop_name)); + const start = newSymbolAssumeCapacity(self, try self.addString(gpa, start_name), elf_file); + const stop = newSymbolAssumeCapacity(self, try self.addString(gpa, stop_name), elf_file); self.start_stop_indexes.appendSliceAssumeCapacity(&.{ start, stop }); } } @@ -268,7 +269,7 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void { for (elf_file.shdrs.items, 0..) |shdr, shndx| { if (shdr.sh_flags & elf.SHF_ALLOC != 0) { value = shdr.sh_addr + shdr.sh_size; - osec = shndx; + osec = @intCast(shndx); } } allocSymbol(self, self.end_index.?, value, osec, elf_file); @@ -287,10 +288,10 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void { { var index: usize = 0; while (index < self.start_stop_indexes.items.len) : (index += 2) { - const start_ref = self.resolveSymbol(self.start_stop_indexes.items[index]); + const start_ref = self.resolveSymbol(self.start_stop_indexes.items[index], elf_file); const start = elf_file.symbol(start_ref).?; const name = start.name(elf_file); - const stop_ref = self.resolveSymbol(self.start_stop_indexes.items[index + 1]); + const stop_ref = self.resolveSymbol(self.start_stop_indexes.items[index + 1], elf_file); const stop = elf_file.symbol(stop_ref).?; const shndx = elf_file.sectionByName(name["__start_".len..]).?; const shdr = &elf_file.shdrs.items[shndx]; @@ -334,6 +335,18 @@ pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf) void { } } +pub fn dynamicSymbol(self: LinkerDefined, elf_file: *Elf) ?*Symbol { + const index = self.dynamic_index orelse return null; + const resolv = self.resolveSymbol(index, elf_file); + return elf_file.symbol(resolv); +} + +pub fn entrySymbol(self: LinkerDefined, elf_file: *Elf) ?*Symbol { + const index = self.entry_index orelse return null; + const resolv = self.resolveSymbol(index, elf_file); + return elf_file.symbol(resolv); +} + pub fn asFile(self: *LinkerDefined) File { return .{ .linker_defined = self }; } @@ -356,8 +369,12 @@ pub fn resolveSymbol(self: LinkerDefined, index: Symbol.Index, elf_file: *Elf) E return elf_file.resolver.get(resolv).?; } -pub fn addSymbol(self: *LinkerDefined, allocator: Allocator) !Symbol.Index { +fn addSymbol(self: *LinkerDefined, allocator: Allocator) !Symbol.Index { try self.symbols.ensureUnusedCapacity(allocator, 1); + return self.addSymbolAssumeCapacity(); +} + +fn addSymbolAssumeCapacity(self: *LinkerDefined) Symbol.Index { const index: Symbol.Index = @intCast(self.symbols.items.len); self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); return index; @@ -425,10 +442,11 @@ fn formatSymtab( ) !void { _ = unused_fmt_string; _ = options; + const self = ctx.self; + const elf_file = ctx.elf_file; try writer.writeAll(" globals\n"); - for (ctx.self.globals()) |index| { - const global = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); + for (self.symbols.items) |sym| { + try writer.print(" {}\n", .{sym.fmt(elf_file)}); } } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index feb70776d5..47c74967eb 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -394,10 +394,9 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void { sym_ptr.value = @intCast(sym.st_value); sym_ptr.name_offset = sym.st_name; sym_ptr.esym_index = @intCast(i); - sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{ - .weak = sym.st_bind() == elf.STB_WEAK, - }); + sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{}); sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else elf.VER_NDX_LOCAL; + sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK; if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) { sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index }; } @@ -548,7 +547,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { for (self.cies.items) |cie| { for (cie.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(self.resolveSymbol(rel.r_sym())); + const sym = elf_file.symbol(self.resolveSymbol(rel.r_sym(), elf_file)).?; if (sym.flags.import) { if (sym.type(elf_file) != elf.STT_FUNC) // TODO convert into an error @@ -562,6 +561,51 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { } } +pub fn createSymbolIndirection(self: *Object, elf_file: *Elf) !void { + for (self.symbols.items, 0..) |*sym, i| { + const ref = self.resolveSymbol(@intCast(i), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; + if (!sym.isLocal(elf_file) and !sym.flags.has_dynamic) { + log.debug("'{s}' is non-local", .{sym.name(elf_file)}); + try elf_file.dynsym.addSymbol(ref, elf_file); + } + if (sym.flags.needs_got) { + log.debug("'{s}' needs GOT", .{sym.name(elf_file)}); + _ = try elf_file.got.addGotSymbol(ref, elf_file); + } + if (sym.flags.needs_plt) { + if (sym.flags.is_canonical) { + log.debug("'{s}' needs CPLT", .{sym.name(elf_file)}); + sym.flags.@"export" = true; + try elf_file.plt.addSymbol(ref, elf_file); + } else if (sym.flags.needs_got) { + log.debug("'{s}' needs PLTGOT", .{sym.name(elf_file)}); + try elf_file.plt_got.addSymbol(ref, elf_file); + } else { + log.debug("'{s}' needs PLT", .{sym.name(elf_file)}); + try elf_file.plt.addSymbol(ref, elf_file); + } + } + if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) { + log.debug("'{s}' needs COPYREL", .{sym.name(elf_file)}); + try elf_file.copy_rel.addSymbol(ref, elf_file); + } + if (sym.flags.needs_tlsgd) { + log.debug("'{s}' needs TLSGD", .{sym.name(elf_file)}); + try elf_file.got.addTlsGdSymbol(ref, elf_file); + } + if (sym.flags.needs_gottp) { + log.debug("'{s}' needs GOTTP", .{sym.name(elf_file)}); + try elf_file.got.addGotTpSymbol(ref, elf_file); + } + if (sym.flags.needs_tlsdesc) { + log.debug("'{s}' needs TLSDESC", .{sym.name(elf_file)}); + try elf_file.got.addTlsDescSymbol(ref, elf_file); + } + } +} + pub fn resolveSymbols(self: *Object, elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; @@ -643,7 +687,7 @@ pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void { sym.file_index = self.index; const idx = self.symbols_resolver.items[i]; - elf_file.resolver.items[idx - 1] = .{ .index = esym_index, .file = self.index }; + elf_file.resolver.values.items[idx - 1] = .{ .index = esym_index, .file = self.index }; } } @@ -1120,7 +1164,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void { } for (self.globals(), self.symbols_resolver.items) |*global, resolv| { - const ref = elf_file.resolver.items[resolv]; + const ref = elf_file.resolver.values.items[resolv]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; if (!isAlive(global, elf_file)) continue; @@ -1136,7 +1180,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void { } } -pub fn writeSymtab(self: Object, elf_file: *Elf) void { +pub fn writeSymtab(self: *Object, elf_file: *Elf) void { for (self.locals()) |local| { const idx = local.outputSymtabIndex(elf_file) orelse continue; const out_sym = &elf_file.symtab.items[idx]; @@ -1147,7 +1191,7 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void { } for (self.globals(), self.symbols_resolver.items) |global, resolv| { - const ref = elf_file.resolver.items[resolv]; + const ref = elf_file.resolver.values.items[resolv]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; const idx = global.outputSymtabIndex(elf_file) orelse continue; @@ -1199,7 +1243,7 @@ fn locals(self: *Object) []Symbol { return self.symbols.items[0..end]; } -fn globals(self: *Object) []Symbol { +pub fn globals(self: *Object) []Symbol { if (self.symbols.items.len == 0) return &[0]Symbol{}; assert(self.symbols.items.len >= self.symtab.items.len); const start = self.first_global orelse self.symtab.items.len; @@ -1214,8 +1258,12 @@ pub fn resolveSymbol(self: Object, index: Symbol.Index, elf_file: *Elf) Elf.Ref return elf_file.resolver.get(resolv).?; } -pub fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index { +fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index { try self.symbols.ensureUnusedCapacity(allocator, 1); + return self.addSymbolAssumeCapacity(); +} + +fn addSymbolAssumeCapacity(self: *Object) Symbol.Index { const index: Symbol.Index = @intCast(self.symbols.items.len); self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); return index; @@ -1430,15 +1478,14 @@ fn formatSymtab( _ = unused_fmt_string; _ = options; const object = ctx.object; + const elf_file = ctx.elf_file; try writer.writeAll(" locals\n"); - for (object.locals()) |index| { - const local = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{local.fmt(ctx.elf_file)}); + for (object.locals()) |sym| { + try writer.print(" {}\n", .{sym.fmt(elf_file)}); } try writer.writeAll(" globals\n"); - for (object.globals()) |index| { - const global = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); + for (object.globals()) |sym| { + try writer.print(" {}\n", .{sym.fmt(elf_file)}); } } diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index aff07e4469..3c360c3c46 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -286,8 +286,8 @@ pub fn markImportExports(self: *SharedObject, elf_file: *Elf) void { for (0..self.symbols.items.len) |i| { const ref = self.resolveSymbol(@intCast(i), elf_file); const ref_sym = elf_file.symbol(ref) orelse continue; - const ref_file = ref_sym.file(self).?; - const vis = @as(elf.STV, @enumFromInt(ref_sym.elfSym(self).st_other)); + const ref_file = ref_sym.file(elf_file).?; + const vis = @as(elf.STV, @enumFromInt(ref_sym.elfSym(elf_file).st_other)); if (ref_file != .shared_object and vis != .HIDDEN) ref_sym.flags.@"export" = true; } } @@ -349,9 +349,12 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { assert(self.aliases == null); const SortAlias = struct { - pub fn lessThan(ctx: *Elf, lhs: Symbol.Index, rhs: Symbol.Index) bool { - const lhs_sym = ctx.symbol(lhs).elfSym(ctx); - const rhs_sym = ctx.symbol(rhs).elfSym(ctx); + so: *SharedObject, + ef: *Elf, + + pub fn lessThan(ctx: @This(), lhs: Symbol.Index, rhs: Symbol.Index) bool { + const lhs_sym = ctx.so.symbols.items[lhs].elfSym(ctx.ef); + const rhs_sym = ctx.so.symbols.items[rhs].elfSym(ctx.ef); return lhs_sym.st_value < rhs_sym.st_value; } }; @@ -362,14 +365,14 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { defer aliases.deinit(); try aliases.ensureTotalCapacityPrecise(self.symbols.items.len); - for (self.symbols_resolvers.items, 0..) |resolv, index| { + for (self.symbols_resolver.items, 0..) |resolv, index| { const ref = elf_file.resolver.get(resolv).?; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; - aliases.appendAssumeCapacity(index); + aliases.appendAssumeCapacity(@intCast(index)); } - std.mem.sort(u32, aliases.items, elf_file, SortAlias.lessThan); + std.mem.sort(u32, aliases.items, SortAlias{ .so = self, .ef = elf_file }, SortAlias.lessThan); self.aliases = aliases.moveToUnmanaged(); } @@ -377,16 +380,16 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u32 { assert(self.aliases != null); - const symbol = self.symbol(index).elfSym(elf_file); + const symbol = self.symbols.items[index].elfSym(elf_file); const aliases = self.aliases.?; const start = for (aliases.items, 0..) |alias, i| { - const alias_sym = self.symbol(alias).elfSym(elf_file); + const alias_sym = self.symbols.items[alias].elfSym(elf_file); if (symbol.st_value == alias_sym.st_value) break i; } else aliases.items.len; const end = for (aliases.items[start..], 0..) |alias, i| { - const alias_sym = self.symbol(alias).elfSym(elf_file); + const alias_sym = self.symbols.items[alias].elfSym(elf_file); if (symbol.st_value < alias_sym.st_value) break i + start; } else aliases.items.len; @@ -403,8 +406,12 @@ pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) El return elf_file.resolver.get(resolv).?; } -pub fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index { +fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index { try self.symbols.ensureUnusedCapacity(allocator, 1); + return self.addSymbolAssumeCapacity(); +} + +fn addSymbolAssumeCapacity(self: *SharedObject) Symbol.Index { const index: Symbol.Index = @intCast(self.symbols.items.len); self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); return index; @@ -486,10 +493,10 @@ fn formatSymtab( _ = unused_fmt_string; _ = options; const shared = ctx.shared; + const elf_file = ctx.elf_file; try writer.writeAll(" globals\n"); - for (shared.symbols.items) |index| { - const global = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); + for (shared.symbols.items) |sym| { + try writer.print(" {}\n", .{sym.fmt(elf_file)}); } } diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index ba5c8f4986..ce6b94a185 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -86,6 +86,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File { pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym { return switch (symbol.file(elf_file).?) { + .zig_object => |x| x.symtab.items(.elf_sym)[symbol.esym_index], inline else => |x| x.symtab.items[symbol.esym_index], }; } @@ -261,7 +262,7 @@ const AddExtraOpts = struct { zig_got: ?u32 = null, }; -pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void { +pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void { var extras = symbol.extra(elf_file); inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| { if (@field(opts, field.name)) |x| { @@ -272,11 +273,15 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void { } pub fn extra(symbol: Symbol, elf_file: *Elf) Extra { - return elf_file.symbolExtra(symbol.extra_index); + return switch (symbol.file(elf_file).?) { + inline else => |x| x.symbolExtra(symbol.extra_index), + }; } pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void { - elf_file.setSymbolExtra(symbol.extra_index, extras); + return switch (symbol.file(elf_file).?) { + inline else => |x| x.setSymbolExtra(symbol.extra_index, extras), + }; } pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index fb41cd2c97..1970ab5701 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -89,19 +89,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { try self.strtab.buffer.append(gpa, 0); const name_off = try self.strtab.insert(gpa, self.path); - const symbol_index = try elf_file.addSymbol(); - try self.local_symbols.append(gpa, symbol_index); - const symbol_ptr = elf_file.symbol(symbol_index); - symbol_ptr.file_index = self.index; - symbol_ptr.name_offset = name_off; - symbol_ptr.extra_index = try elf_file.addSymbolExtra(.{}); - - const esym_index = try self.addLocalEsym(gpa); - const esym = &self.local_esyms.items(.elf_sym)[esym_index]; - esym.st_name = name_off; + const symbol_index = try self.newLocalSymbol(gpa, name_off); + const sym = self.symbol(symbol_index); + const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; esym.st_info = elf.STT_FILE; esym.st_shndx = elf.SHN_ABS; - symbol_ptr.esym_index = esym_index; switch (comp.config.debug_format) { .strip => {}, @@ -275,7 +267,7 @@ fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) const index = self.addSymbolAssumeCapacity(); const sym = &self.symbols.items[index]; sym.name_offset = name_off; - sym.extra = self.addSymbolExtraAssumeCapacity(.{}); + sym.extra_index = self.addSymbolExtraAssumeCapacity(.{}); const esym_idx: u32 = @intCast(self.symtab.addOneAssumeCapacity()); const esym = ElfSym{ .elf_sym = .{ @@ -377,7 +369,7 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) !void { continue; } - if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) { + if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) { gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index }; } } @@ -428,7 +420,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void { global.file_index = self.index; const idx = self.symbols_resolver.items[i]; - elf_file.resolver.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index }; + elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index }; } } @@ -450,6 +442,64 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void { } } +pub fn createSymbolIndirection(self: *ZigObject, elf_file: *Elf) !void { + const impl = struct { + fn impl(sym: *Symbol, ref: Elf.Ref, ef: *Elf) !void { + if (!sym.isLocal(ef) and !sym.flags.has_dynamic) { + log.debug("'{s}' is non-local", .{sym.name(ef)}); + try ef.dynsym.addSymbol(ref, ef); + } + if (sym.flags.needs_got) { + log.debug("'{s}' needs GOT", .{sym.name(ef)}); + _ = try ef.got.addGotSymbol(ref, ef); + } + if (sym.flags.needs_plt) { + if (sym.flags.is_canonical) { + log.debug("'{s}' needs CPLT", .{sym.name(ef)}); + sym.flags.@"export" = true; + try ef.plt.addSymbol(ref, ef); + } else if (sym.flags.needs_got) { + log.debug("'{s}' needs PLTGOT", .{sym.name(ef)}); + try ef.plt_got.addSymbol(ref, ef); + } else { + log.debug("'{s}' needs PLT", .{sym.name(ef)}); + try ef.plt.addSymbol(ref, ef); + } + } + if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) { + log.debug("'{s}' needs COPYREL", .{sym.name(ef)}); + try ef.copy_rel.addSymbol(ref, ef); + } + if (sym.flags.needs_tlsgd) { + log.debug("'{s}' needs TLSGD", .{sym.name(ef)}); + try ef.got.addTlsGdSymbol(ref, ef); + } + if (sym.flags.needs_gottp) { + log.debug("'{s}' needs GOTTP", .{sym.name(ef)}); + try ef.got.addGotTpSymbol(ref, ef); + } + if (sym.flags.needs_tlsdesc) { + log.debug("'{s}' needs TLSDESC", .{sym.name(ef)}); + try ef.got.addTlsDescSymbol(ref, ef); + } + } + }.impl; + for (self.local_symbols.items, 0..) |index, i| { + const sym = &self.symbols.items[index]; + const ref = self.resolveSymbol(@intCast(i), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; + try impl(sym, ref, elf_file); + } + for (self.global_symbols.items, 0..) |index, i| { + const sym = &self.symbols.items[index]; + const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != self.index) continue; + try impl(sym, ref, elf_file); + } +} + pub fn markLive(self: *ZigObject, elf_file: *Elf) void { for (self.global_symbols.items, 0..) |index, i| { const global = self.symbols.items[index]; @@ -468,7 +518,7 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void { } } -pub fn markImportsExports(self: *Object, elf_file: *Elf) void { +pub fn markImportsExports(self: *ZigObject, elf_file: *Elf) void { for (0..self.global_symbols.items.len) |i| { const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file); const sym = elf_file.symbol(ref) orelse continue; @@ -604,7 +654,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| { const global = &self.symbols.items[index]; - const ref = elf_file.resolver.items[resolv]; + const ref = elf_file.resolver.values.items[resolv]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue; @@ -633,7 +683,7 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void { for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| { const global = self.symbols.items[index]; - const ref = elf_file.resolver.items[resolv]; + const ref = elf_file.resolver.values.items[resolv]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; const idx = global.outputSymtabIndex(elf_file) orelse continue; @@ -678,13 +728,13 @@ pub fn getDeclVAddr( reloc_info: link.File.RelocInfo, ) !u64 { const this_sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index); - const this_sym = elf_file.symbol(this_sym_index); + const this_sym = self.symbol(this_sym_index); const vaddr = this_sym.address(.{}, elf_file); - const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?; + const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?; const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch); try parent_atom.addReloc(elf_file, .{ .r_offset = reloc_info.offset, - .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | r_type, + .r_info = (@as(u64, @intCast(this_sym_index)) << 32) | r_type, .r_addend = reloc_info.addend, }); return @intCast(vaddr); @@ -697,13 +747,13 @@ pub fn getAnonDeclVAddr( reloc_info: link.File.RelocInfo, ) !u64 { const sym_index = self.anon_decls.get(decl_val).?.symbol_index; - const sym = elf_file.symbol(sym_index); + const sym = self.symbol(sym_index); const vaddr = sym.address(.{}, elf_file); - const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?; + const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?; const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch); try parent_atom.addReloc(elf_file, .{ .r_offset = reloc_info.offset, - .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | r_type, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, .r_addend = reloc_info.addend, }); return @intCast(vaddr); @@ -725,7 +775,7 @@ pub fn lowerAnonDecl( else => explicit_alignment, }; if (self.anon_decls.get(decl_val)) |metadata| { - const existing_alignment = elf_file.symbol(metadata.symbol_index).atom(elf_file).?.alignment; + const existing_alignment = self.symbol(metadata.symbol_index).atom(elf_file).?.alignment; if (decl_alignment.order(existing_alignment).compare(.lte)) return .ok; } @@ -811,11 +861,10 @@ fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.De } fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void { - _ = self; - const sym = elf_file.symbol(sym_index); + const sym = self.symbol(sym_index); sym.atom(elf_file).?.free(elf_file); log.debug("adding %{d} to local symbols free list", .{sym_index}); - elf_file.symbols.items[sym_index] = .{}; + self.symbols.items[sym_index] = .{}; // TODO free GOT entry here } @@ -940,8 +989,8 @@ fn updateDeclCode( target_util.minFunctionAlignment(mod.getTarget()), ); - const sym = elf_file.symbol(sym_index); - const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index]; + const sym = self.symbol(sym_index); + const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; const atom_ptr = sym.atom(elf_file).?; const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip)); @@ -1038,8 +1087,8 @@ fn updateTlv( const required_alignment = decl.getAlignment(pt); - const sym = elf_file.symbol(sym_index); - const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index]; + const sym = self.symbol(sym_index); + const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; const atom_ptr = sym.atom(elf_file).?; const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip)); @@ -1264,9 +1313,9 @@ fn updateLazySymbol( .code => elf_file.zig_text_section_index.?, .const_data => elf_file.zig_data_rel_ro_section_index.?, }; - const local_sym = elf_file.symbol(symbol_index); + const local_sym = self.symbol(symbol_index); local_sym.name_offset = name_str_index; - const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index]; + const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index]; local_esym.st_name = name_str_index; local_esym.st_info |= elf.STT_OBJECT; local_esym.st_size = code.len; @@ -1372,7 +1421,7 @@ fn lowerConst( }; const local_sym = self.symbol(sym_index); - const local_esym = local_sym.elfSym(elf_file); + const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index]; local_esym.st_info |= elf.STT_OBJECT; local_esym.st_size = code.len; const atom_ptr = local_sym.atom(elf_file).?; @@ -1473,9 +1522,9 @@ pub fn updateExports( const global_sym = self.symbol(global_sym_index); global_sym.value = value; global_sym.flags.weak = exp.opts.linkage == .weak; - global_sym.version_index = elf_file.default_version_index; + global_sym.version_index = elf_file.default_sym_version; global_sym.ref = .{ .index = esym_shndx, .file = self.index }; - const global_esym = global_sym.elfSym(elf_file); + const global_esym = &self.symtab.items(.elf_sym)[global_sym.esym_index]; global_esym.st_value = @intCast(value); global_esym.st_shndx = esym.st_shndx; global_esym.st_info = (stb_bits << 4) | stt_bits; @@ -1517,16 +1566,16 @@ pub fn deleteExport( const exp_name = name.toSlice(&mod.intern_pool); const esym_index = metadata.@"export"(self, exp_name) orelse return; log.debug("deleting export '{s}'", .{exp_name}); - const esym = &self.global_esyms.items(.elf_sym)[esym_index.*]; + const esym = &self.symtab.items(.elf_sym)[esym_index.*]; _ = self.globals_lookup.remove(esym.st_name); - const sym_index = elf_file.resolver.get(esym.st_name).?; - const sym = elf_file.symbol(sym_index); - if (sym.file_index == self.index) { - _ = elf_file.resolver.swapRemove(esym.st_name); - sym.* = .{}; - } + // const sym_index = elf_file.resolver.get(esym.st_name).?; + // const sym = elf_file.symbol(sym_index); + // if (sym.file_index == self.index) { + // _ = elf_file.resolver.swapRemove(esym.st_name); + // sym.* = .{}; + // } esym.* = Elf.null_sym; - self.global_esyms.items(.shndx)[esym_index.*] = elf.SHN_UNDEF; + self.symtab.items(.shndx)[esym_index.*] = elf.SHN_UNDEF; } pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 { @@ -1535,7 +1584,7 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n const off = try self.strtab.insert(gpa, name); const lookup_gop = try self.globals_lookup.getOrPut(gpa, off); if (!lookup_gop.found_existing) { - lookup_gop.value_ptr.* = try self.newSymbol(gpa, off); + lookup_gop.value_ptr.* = try self.newGlobalSymbol(gpa, off); } return lookup_gop.value_ptr.*; } @@ -1636,8 +1685,12 @@ pub fn resolveSymbol(self: ZigObject, index: Symbol.Index, elf_file: *Elf) Elf.R return .{ .index = index, .file = self.index }; } -pub fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index { +fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index { try self.symbols.ensureUnusedCapacity(allocator, 1); + return self.addSymbolAssumeCapacity(); +} + +fn addSymbolAssumeCapacity(self: *ZigObject) Symbol.Index { const index: Symbol.Index = @intCast(self.symbols.items.len); self.symbols.appendAssumeCapacity(.{ .file_index = self.index }); return index; @@ -1705,15 +1758,17 @@ fn formatSymtab( ) !void { _ = unused_fmt_string; _ = options; + const self = ctx.self; + const elf_file = ctx.elf_file; try writer.writeAll(" locals\n"); - for (ctx.self.locals()) |index| { - const local = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{local.fmt(ctx.elf_file)}); + for (self.local_symbols.items) |index| { + const local = self.symbols.items[index]; + try writer.print(" {}\n", .{local.fmt(elf_file)}); } try writer.writeAll(" globals\n"); - for (ctx.self.globals()) |index| { - const global = ctx.elf_file.symbol(index); - try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); + for (ctx.self.global_symbols.items) |index| { + const global = self.symbols.items[index]; + try writer.print(" {}\n", .{global.fmt(elf_file)}); } } @@ -1759,7 +1814,7 @@ const DeclMetadata = struct { fn @"export"(m: DeclMetadata, zo: *ZigObject, name: []const u8) ?*u32 { for (m.exports.items) |*exp| { - const exp_name = zo.getString(zo.symbol(exp.*).name_off); + const exp_name = zo.getString(zo.symbol(exp.*).name_offset); if (mem.eql(u8, name, exp_name)) return exp; } return null; diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index 1ca1b90906..30f35b16d8 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -339,7 +339,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { const contents = cie.data(elf_file); for (cie.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const sym = elf_file.symbol(ref).?; resolveReloc(cie, sym, rel, elf_file, contents) catch |err| switch (err) { error.RelocFailure => has_reloc_errors = true, else => |e| return e, @@ -366,7 +367,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { ); for (fde.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const sym = elf_file.symbol(ref).?; resolveReloc(fde, sym, rel, elf_file, contents) catch |err| switch (err) { error.RelocFailure => has_reloc_errors = true, else => |e| return e, @@ -452,7 +454,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { for (object.cies.items) |cie| { if (!cie.alive) continue; for (cie.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const sym = elf_file.symbol(ref).?; const out_rel = emitReloc(elf_file, cie, sym, rel); try writer.writeStruct(out_rel); } @@ -461,7 +464,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { for (object.fdes.items) |fde| { if (!fde.alive) continue; for (fde.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const sym = elf_file.symbol(ref).?; const out_rel = emitReloc(elf_file, fde, sym, rel); try writer.writeStruct(out_rel); } @@ -513,7 +517,8 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { const relocs = fde.relocs(elf_file); assert(relocs.len > 0); // Should this be an error? Things are completely broken anyhow if this trips... const rel = relocs[0]; - const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const sym = elf_file.symbol(ref).?; const P = @as(i64, @intCast(fde.address(elf_file))); const S = @as(i64, @intCast(sym.address(.{}, elf_file))); const A = rel.r_addend; diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index 9c7cd27626..32a540ce39 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -61,10 +61,10 @@ pub const File = union(enum) { return (@as(u32, base) << 24) + file.index(); } - pub fn resolveSymbols(file: File, elf_file: *Elf) void { - switch (file) { + pub fn resolveSymbols(file: File, elf_file: *Elf) !void { + return switch (file) { inline else => |x| x.resolveSymbols(elf_file), - } + }; } pub fn resetGlobals(file: File, elf_file: *Elf) void { @@ -100,6 +100,13 @@ pub const File = union(enum) { } } + pub fn createSymbolIndirection(file: File, elf_file: *Elf) !void { + return switch (file) { + .linker_defined, .shared_object => unreachable, + inline else => |x| x.createSymbolIndirection(elf_file), + }; + } + pub fn atom(file: File, atom_index: Atom.Index) ?*Atom { return switch (file) { .shared_object => unreachable, @@ -146,10 +153,16 @@ pub const File = union(enum) { }; } - pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index { + pub fn resolveSymbol(file: File, ind: Symbol.Index, elf_file: *Elf) Elf.Ref { + return switch (file) { + inline else => |x| x.resolveSymbol(ind, elf_file), + }; + } + + pub fn symbol(file: File, ind: Symbol.Index) *Symbol { return switch (file) { .zig_object => |x| x.symbol(ind), - inline else => |x| x.symbols.items[ind], + inline else => |x| &x.symbols.items[ind], }; } diff --git a/src/link/Elf/gc.zig b/src/link/Elf/gc.zig index de2d43f738..e0680d5db6 100644 --- a/src/link/Elf/gc.zig +++ b/src/link/Elf/gc.zig @@ -1,72 +1,85 @@ pub fn gcAtoms(elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; - const num_files = elf_file.objects.items.len + @intFromBool(elf_file.zig_object_index != null); - var files = try std.ArrayList(File.Index).initCapacity(gpa, num_files); - defer files.deinit(); - if (elf_file.zig_object_index) |index| files.appendAssumeCapacity(index); - for (elf_file.objects.items) |index| files.appendAssumeCapacity(index); - var roots = std.ArrayList(*Atom).init(gpa); defer roots.deinit(); - try collectRoots(&roots, files.items, elf_file); - + try collectRoots(&roots, elf_file); mark(roots, elf_file); - prune(files.items, elf_file); + prune(elf_file); } -fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_file: *Elf) !void { +fn collectRoots(roots: *std.ArrayList(*Atom), elf_file: *Elf) !void { if (elf_file.linkerDefinedPtr()) |obj| { - if (obj.entry_index) |index| { - const global = elf_file.symbol(index); - try markSymbol(global, roots, elf_file); + if (obj.entrySymbol(elf_file)) |sym| { + try markSymbol(sym, roots, elf_file); } } - for (files) |index| { - for (elf_file.file(index).?.globals()) |global_index| { - const global = elf_file.symbol(global_index); - if (global.file(elf_file)) |file| { - if (file.index() == index and global.flags.@"export") - try markSymbol(global, roots, elf_file); - } - } - } - - for (files) |index| { - const file = elf_file.file(index).?; - - for (file.atoms()) |atom_index| { - const atom = file.atom(atom_index) orelse continue; - if (!atom.alive) continue; - - const shdr = atom.inputShdr(elf_file); - const name = atom.name(elf_file); - const is_gc_root = blk: { - if (shdr.sh_flags & elf.SHF_GNU_RETAIN != 0) break :blk true; - if (shdr.sh_type == elf.SHT_NOTE) break :blk true; - if (shdr.sh_type == elf.SHT_PREINIT_ARRAY) break :blk true; - if (shdr.sh_type == elf.SHT_INIT_ARRAY) break :blk true; - if (shdr.sh_type == elf.SHT_FINI_ARRAY) break :blk true; - if (mem.startsWith(u8, name, ".ctors")) break :blk true; - if (mem.startsWith(u8, name, ".dtors")) break :blk true; - if (mem.startsWith(u8, name, ".init")) break :blk true; - if (mem.startsWith(u8, name, ".fini")) break :blk true; - if (Elf.isCIdentifier(name)) break :blk true; - break :blk false; - }; - if (is_gc_root and markAtom(atom)) try roots.append(atom); - if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.visited = true; - } - - // Mark every atom referenced by CIE as alive. - for (file.cies()) |cie| { - for (cie.relocs(elf_file)) |rel| { - const sym = elf_file.symbol(file.symbol(rel.r_sym())); + if (elf_file.zigObjectPtr()) |zo| { + for (0..zo.global_symbols.items.len) |i| { + const ref = zo.resolveSymbol(@intCast(i | ZigObject.global_symbol_bit), elf_file); + const sym = elf_file.symbol(ref) orelse continue; + if (sym.file(elf_file).?.index() != zo.index) continue; + if (sym.flags.@"export") { try markSymbol(sym, roots, elf_file); } } } + + for (elf_file.objects.items) |index| { + const object = elf_file.file(index).?.object; + for (0..object.globals().len) |i| { + const ref = object.resolveSymbol(@intCast(i), elf_file); + const sym = elf_file.symbol(ref) orelse continue; + if (sym.file(elf_file).?.index() != object.index) continue; + if (sym.flags.@"export") { + try markSymbol(sym, roots, elf_file); + } + } + } + + const atomRoots = struct { + fn atomRoots(file: File, rs: anytype, ef: *Elf) !void { + for (file.atoms()) |atom_index| { + const atom = file.atom(atom_index) orelse continue; + if (!atom.alive) continue; + + const shdr = atom.inputShdr(ef); + const name = atom.name(ef); + const is_gc_root = blk: { + if (shdr.sh_flags & elf.SHF_GNU_RETAIN != 0) break :blk true; + if (shdr.sh_type == elf.SHT_NOTE) break :blk true; + if (shdr.sh_type == elf.SHT_PREINIT_ARRAY) break :blk true; + if (shdr.sh_type == elf.SHT_INIT_ARRAY) break :blk true; + if (shdr.sh_type == elf.SHT_FINI_ARRAY) break :blk true; + if (mem.startsWith(u8, name, ".ctors")) break :blk true; + if (mem.startsWith(u8, name, ".dtors")) break :blk true; + if (mem.startsWith(u8, name, ".init")) break :blk true; + if (mem.startsWith(u8, name, ".fini")) break :blk true; + if (Elf.isCIdentifier(name)) break :blk true; + break :blk false; + }; + if (is_gc_root and markAtom(atom)) try rs.append(atom); + if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.visited = true; + } + + // Mark every atom referenced by CIE as alive. + for (file.cies()) |cie| { + for (cie.relocs(ef)) |rel| { + const ref = file.resolveSymbol(rel.r_sym(), ef); + const sym = ef.symbol(ref) orelse continue; + try markSymbol(sym, rs, ef); + } + } + } + }.atomRoots; + + if (elf_file.zigObjectPtr()) |zo| { + try atomRoots(zo.asFile(), roots, elf_file); + } + for (elf_file.objects.items) |index| { + try atomRoots(elf_file.file(index).?, roots, elf_file); + } } fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), elf_file: *Elf) !void { @@ -92,7 +105,8 @@ fn markLive(atom: *Atom, elf_file: *Elf) void { for (atom.fdes(elf_file)) |fde| { for (fde.relocs(elf_file)[1..]) |rel| { - const target_sym = elf_file.symbol(file.symbol(rel.r_sym())); + const ref = file.resolveSymbol(rel.r_sym(), elf_file); + const target_sym = elf_file.symbol(ref) orelse continue; const target_atom = target_sym.atom(elf_file) orelse continue; target_atom.alive = true; gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index }); @@ -101,7 +115,8 @@ fn markLive(atom: *Atom, elf_file: *Elf) void { } for (atom.relocs(elf_file)) |rel| { - const target_sym = elf_file.symbol(file.symbol(rel.r_sym())); + const ref = file.resolveSymbol(rel.r_sym(), elf_file); + const target_sym = elf_file.symbol(ref) orelse continue; if (target_sym.mergeSubsection(elf_file)) |msub| { msub.alive = true; continue; @@ -120,16 +135,23 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void { } } -fn prune(files: []const File.Index, elf_file: *Elf) void { - for (files) |index| { - const file = elf_file.file(index).?; - for (file.atoms()) |atom_index| { - const atom = file.atom(atom_index) orelse continue; - if (atom.alive and !atom.visited) { - atom.alive = false; - atom.markFdesDead(elf_file); +fn prune(elf_file: *Elf) void { + const pruneInFile = struct { + fn pruneInFile(file: File, ef: *Elf) void { + for (file.atoms()) |atom_index| { + const atom = file.atom(atom_index) orelse continue; + if (atom.alive and !atom.visited) { + atom.alive = false; + atom.markFdesDead(ef); + } } } + }.pruneInFile; + if (elf_file.zigObjectPtr()) |zo| { + pruneInFile(zo.asFile(), elf_file); + } + for (elf_file.objects.items) |index| { + pruneInFile(elf_file.file(index).?, elf_file); } } @@ -181,3 +203,4 @@ const Atom = @import("Atom.zig"); const Elf = @import("../Elf.zig"); const File = @import("file.zig").File; const Symbol = @import("Symbol.zig"); +const ZigObject = @import("ZigObject.zig"); diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index ce65b8eb72..92eace8501 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -37,7 +37,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co // First, we flush relocatable object file generated with our backends. if (elf_file.zigObjectPtr()) |zig_object| { - zig_object.resolveSymbols(elf_file); + try zig_object.resolveSymbols(elf_file); try elf_file.addCommentString(); try elf_file.finalizeMergeSections(); zig_object.claimUnresolvedObject(elf_file); @@ -383,7 +383,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void { shdr.sh_size = cg.size(elf_file); shdr.sh_link = elf_file.symtab_section_index.?; - const sym = elf_file.symbol(cg.symbol(elf_file)); + const sym = cg.symbol(elf_file); shdr.sh_info = sym.outputSymtabIndex(elf_file) orelse elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx(elf_file).?); } diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index df98b753b3..c767fb093c 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -251,15 +251,16 @@ pub const ZigGotSection = struct { pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index { const comp = elf_file.base.comp; const gpa = comp.gpa; + const zo = elf_file.zigObjectPtr().?; const index = try zig_got.allocateEntry(gpa); const entry = &zig_got.entries.items[index]; entry.* = sym_index; - const symbol = elf_file.symbol(sym_index); + const symbol = zo.symbol(sym_index); symbol.flags.has_zig_got = true; if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) { zig_got.flags.needs_rela = true; } - try symbol.addExtra(.{ .zig_got = index }, elf_file); + symbol.addExtra(.{ .zig_got = index }, elf_file); return index; } @@ -282,6 +283,7 @@ pub const ZigGotSection = struct { } pub fn writeOne(zig_got: *ZigGotSection, elf_file: *Elf, index: Index) !void { + const zo = elf_file.zigObjectPtr().?; if (zig_got.flags.dirty) { const needed_size = zig_got.size(elf_file); try elf_file.growAllocSection(elf_file.zig_got_section_index.?, needed_size); @@ -293,7 +295,7 @@ pub const ZigGotSection = struct { const off = zig_got.entryOffset(index, elf_file); const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file)); const entry = zig_got.entries.items[index]; - const value = elf_file.symbol(entry).address(.{}, elf_file); + const value = zo.symbol(entry).address(.{}, elf_file); switch (entry_size) { 2 => { var buf: [2]u8 = undefined; @@ -336,8 +338,9 @@ pub const ZigGotSection = struct { } pub fn writeAll(zig_got: ZigGotSection, elf_file: *Elf, writer: anytype) !void { + const zo = elf_file.zigObjectPtr().?; for (zig_got.entries.items) |entry| { - const symbol = elf_file.symbol(entry); + const symbol = zo.symbol(entry); const value = symbol.address(.{ .plt = false }, elf_file); try writeInt(value, elf_file, writer); } @@ -351,9 +354,10 @@ pub const ZigGotSection = struct { const comp = elf_file.base.comp; const gpa = comp.gpa; const cpu_arch = elf_file.getTarget().cpu.arch; + const zo = elf_file.zigObjectPtr().?; try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela()); for (zig_got.entries.items) |entry| { - const symbol = elf_file.symbol(entry); + const symbol = zo.symbol(entry); const offset = symbol.zigGotAddress(elf_file); elf_file.addRelaDynAssumeCapacity(.{ .offset = @intCast(offset), @@ -364,16 +368,18 @@ pub const ZigGotSection = struct { } pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void { + const zo = elf_file.zigObjectPtr().?; zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len)); for (zig_got.entries.items) |entry| { - const name = elf_file.symbol(entry).name(elf_file); + const name = zo.symbol(entry).name(elf_file); zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1; } } pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void { + const zo = elf_file.zigObjectPtr().?; for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| { - const symbol = elf_file.symbol(entry); + const symbol = zo.symbol(entry); const symbol_name = symbol.name(elf_file); const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(symbol_name); @@ -409,15 +415,18 @@ pub const ZigGotSection = struct { ) !void { _ = options; _ = unused_fmt_string; + const zig_got = ctx.zig_got; + const elf_file = ctx.elf_file; + const zo = elf_file.zigObjectPtr().?; try writer.writeAll(".zig.got\n"); - for (ctx.zig_got.entries.items, 0..) |entry, index| { - const symbol = ctx.elf_file.symbol(entry); + for (zig_got.entries.items, 0..) |entry, index| { + const symbol = zo.symbol(entry); try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ index, - ctx.zig_got.entryAddress(@intCast(index), ctx.elf_file), + zig_got.entryAddress(@intCast(index), elf_file), entry, - symbol.address(.{}, ctx.elf_file), - symbol.name(ctx.elf_file), + symbol.address(.{}, elf_file), + symbol.name(elf_file), }); } } @@ -446,7 +455,7 @@ pub const GotSection = struct { const Entry = struct { tag: Tag, - symbol_index: Symbol.Index, + ref: Elf.Ref, cell_index: Index, /// Returns how many indexes in the GOT this entry uses. @@ -477,25 +486,25 @@ pub const GotSection = struct { const last = got.entries.items[index - 1]; break :blk last.cell_index + @as(Index, @intCast(last.len())); } else 0; - entry.* = .{ .tag = undefined, .symbol_index = undefined, .cell_index = cell_index }; + entry.* = .{ .tag = undefined, .ref = undefined, .cell_index = cell_index }; return index; } - pub fn addGotSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index { + pub fn addGotSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !Index { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = try got.allocateEntry(gpa); const entry = &got.entries.items[index]; entry.tag = .got; - entry.symbol_index = sym_index; - const symbol = elf_file.symbol(sym_index); + entry.ref = ref; + const symbol = elf_file.symbol(ref).?; symbol.flags.has_got = true; if (symbol.flags.import or symbol.isIFunc(elf_file) or ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and !symbol.isAbs(elf_file))) { got.flags.needs_rela = true; } - try symbol.addExtra(.{ .got = index }, elf_file); + symbol.addExtra(.{ .got = index }, elf_file); return index; } @@ -506,48 +515,48 @@ pub const GotSection = struct { const index = try got.allocateEntry(gpa); const entry = &got.entries.items[index]; entry.tag = .tlsld; - entry.symbol_index = undefined; // unused + entry.ref = .{ .index = 0, .file = 0 }; // unused got.flags.needs_rela = true; got.tlsld_index = index; } - pub fn addTlsGdSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addTlsGdSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = try got.allocateEntry(gpa); const entry = &got.entries.items[index]; entry.tag = .tlsgd; - entry.symbol_index = sym_index; - const symbol = elf_file.symbol(sym_index); + entry.ref = ref; + const symbol = elf_file.symbol(ref).?; symbol.flags.has_tlsgd = true; if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true; - try symbol.addExtra(.{ .tlsgd = index }, elf_file); + symbol.addExtra(.{ .tlsgd = index }, elf_file); } - pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addGotTpSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = try got.allocateEntry(gpa); const entry = &got.entries.items[index]; entry.tag = .gottp; - entry.symbol_index = sym_index; - const symbol = elf_file.symbol(sym_index); + entry.ref = ref; + const symbol = elf_file.symbol(ref).?; symbol.flags.has_gottp = true; if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true; - try symbol.addExtra(.{ .gottp = index }, elf_file); + symbol.addExtra(.{ .gottp = index }, elf_file); } - pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addTlsDescSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = try got.allocateEntry(gpa); const entry = &got.entries.items[index]; entry.tag = .tlsdesc; - entry.symbol_index = sym_index; - const symbol = elf_file.symbol(sym_index); + entry.ref = ref; + const symbol = elf_file.symbol(ref).?; symbol.flags.has_tlsdesc = true; got.flags.needs_rela = true; - try symbol.addExtra(.{ .tlsdesc = index }, elf_file); + symbol.addExtra(.{ .tlsdesc = index }, elf_file); } pub fn size(got: GotSection, elf_file: *Elf) usize { @@ -564,10 +573,7 @@ pub const GotSection = struct { const apply_relocs = true; // TODO add user option for this for (got.entries.items) |entry| { - const symbol = switch (entry.tag) { - .tlsld => null, - inline else => elf_file.symbol(entry.symbol_index), - }; + const symbol = elf_file.symbol(entry.ref); switch (entry.tag) { .got => { const value = blk: { @@ -637,10 +643,7 @@ pub const GotSection = struct { try elf_file.rela_dyn.ensureUnusedCapacity(gpa, got.numRela(elf_file)); for (got.entries.items) |entry| { - const symbol = switch (entry.tag) { - .tlsld => null, - inline else => elf_file.symbol(entry.symbol_index), - }; + const symbol = elf_file.symbol(entry.ref); const extra = if (symbol) |s| s.extra(elf_file) else null; switch (entry.tag) { @@ -740,10 +743,7 @@ pub const GotSection = struct { const is_dyn_lib = elf_file.isEffectivelyDynLib(); var num: usize = 0; for (got.entries.items) |entry| { - const symbol = switch (entry.tag) { - .tlsld => null, - inline else => elf_file.symbol(entry.symbol_index), - }; + const symbol = elf_file.symbol(entry.ref); switch (entry.tag) { .got => if (symbol.?.flags.import or symbol.?.isIFunc(elf_file) or ((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and @@ -775,24 +775,15 @@ pub const GotSection = struct { pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void { got.output_symtab_ctx.nlocals = @as(u32, @intCast(got.entries.items.len)); for (got.entries.items) |entry| { - const symbol_name = switch (entry.tag) { - .tlsld => "", - inline else => elf_file.symbol(entry.symbol_index).name(elf_file), - }; + const symbol_name = if (elf_file.symbol(entry.ref)) |sym| sym.name(elf_file) else ""; got.output_symtab_ctx.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1; } } pub fn writeSymtab(got: GotSection, elf_file: *Elf) void { for (got.entries.items, got.output_symtab_ctx.ilocal..) |entry, ilocal| { - const symbol = switch (entry.tag) { - .tlsld => null, - inline else => elf_file.symbol(entry.symbol_index), - }; - const symbol_name = switch (entry.tag) { - .tlsld => "", - inline else => symbol.?.name(elf_file), - }; + const symbol = elf_file.symbol(entry.ref); + const symbol_name = if (symbol) |s| s.name(elf_file) else ""; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(symbol_name); elf_file.strtab.appendAssumeCapacity('$'); @@ -828,36 +819,38 @@ pub const GotSection = struct { ) !void { _ = options; _ = unused_fmt_string; + const got = ctx.got; + const elf_file = ctx.elf_file; try writer.writeAll("GOT\n"); - for (ctx.got.entries.items) |entry| { - const symbol = ctx.elf_file.symbol(entry.symbol_index); - try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ + for (got.entries.items) |entry| { + const symbol = elf_file.symbol(entry.ref).?; + try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{ entry.cell_index, - entry.address(ctx.elf_file), - entry.symbol_index, - symbol.address(.{}, ctx.elf_file), - symbol.name(ctx.elf_file), + entry.address(elf_file), + entry.ref, + symbol.address(.{}, elf_file), + symbol.name(elf_file), }); } } }; pub const PltSection = struct { - symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, + symbols: std.ArrayListUnmanaged(Elf.Ref) = .{}, output_symtab_ctx: Elf.SymtabCtx = .{}, pub fn deinit(plt: *PltSection, allocator: Allocator) void { plt.symbols.deinit(allocator); } - pub fn addSymbol(plt: *PltSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addSymbol(plt: *PltSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = @as(u32, @intCast(plt.symbols.items.len)); - const symbol = elf_file.symbol(sym_index); + const symbol = elf_file.symbol(ref).?; symbol.flags.has_plt = true; - try symbol.addExtra(.{ .plt = index }, elf_file); - try plt.symbols.append(gpa, sym_index); + symbol.addExtra(.{ .plt = index }, elf_file); + try plt.symbols.append(gpa, ref); } pub fn size(plt: PltSection, elf_file: *Elf) usize { @@ -895,8 +888,8 @@ pub const PltSection = struct { const gpa = comp.gpa; const cpu_arch = elf_file.getTarget().cpu.arch; try elf_file.rela_plt.ensureUnusedCapacity(gpa, plt.numRela()); - for (plt.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (plt.symbols.items) |ref| { + const sym = elf_file.symbol(ref).?; assert(sym.flags.import); const extra = sym.extra(elf_file); const r_offset: u64 = @intCast(sym.gotPltAddress(elf_file)); @@ -916,16 +909,16 @@ pub const PltSection = struct { pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void { plt.output_symtab_ctx.nlocals = @as(u32, @intCast(plt.symbols.items.len)); - for (plt.symbols.items) |sym_index| { - const name = elf_file.symbol(sym_index).name(elf_file); + for (plt.symbols.items) |ref| { + const name = elf_file.symbol(ref).?.name(elf_file); plt.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1; } } pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void { const cpu_arch = elf_file.getTarget().cpu.arch; - for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |sym_index, ilocal| { - const sym = elf_file.symbol(sym_index); + for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |ref, ilocal| { + const sym = elf_file.symbol(ref).?; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file)); elf_file.strtab.appendSliceAssumeCapacity("$plt"); @@ -958,15 +951,17 @@ pub const PltSection = struct { ) !void { _ = options; _ = unused_fmt_string; + const plt = ctx.plt; + const elf_file = ctx.elf_file; try writer.writeAll("PLT\n"); - for (ctx.plt.symbols.items, 0..) |symbol_index, i| { - const symbol = ctx.elf_file.symbol(symbol_index); - try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ + for (plt.symbols.items, 0..) |ref, i| { + const symbol = elf_file.symbol(ref).?; + try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{ i, - symbol.pltAddress(ctx.elf_file), - symbol_index, - symbol.address(.{}, ctx.elf_file), - symbol.name(ctx.elf_file), + symbol.pltAddress(elf_file), + ref, + symbol.address(.{}, elf_file), + symbol.name(elf_file), }); } } @@ -988,8 +983,8 @@ pub const PltSection = struct { try writer.writeAll(&preamble); try writer.writeByteNTimes(0xcc, preambleSize(.x86_64) - preamble.len); - for (plt.symbols.items, 0..) |sym_index, i| { - const sym = elf_file.symbol(sym_index); + for (plt.symbols.items, 0..) |ref, i| { + const sym = elf_file.symbol(ref).?; const target_addr = sym.gotPltAddress(elf_file); const source_addr = sym.pltAddress(elf_file); disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4; @@ -1037,8 +1032,8 @@ pub const PltSection = struct { } } - for (plt.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (plt.symbols.items) |ref| { + const sym = elf_file.symbol(ref).?; const target_addr = sym.gotPltAddress(elf_file); const source_addr = sym.pltAddress(elf_file); const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); @@ -1075,7 +1070,7 @@ pub const GotPltSection = struct { _ = got_plt; { // [0]: _DYNAMIC - const symbol = elf_file.symbol(elf_file.linkerDefinedPtr().?.dynamic_index.?); + const symbol = elf_file.linkerDefinedPtr().?.dynamicSymbol(elf_file).?; try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little); } // [1]: 0x0 @@ -1093,22 +1088,22 @@ pub const GotPltSection = struct { }; pub const PltGotSection = struct { - symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, + symbols: std.ArrayListUnmanaged(Elf.Ref) = .{}, output_symtab_ctx: Elf.SymtabCtx = .{}, pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void { plt_got.symbols.deinit(allocator); } - pub fn addSymbol(plt_got: *PltGotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addSymbol(plt_got: *PltGotSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = @as(u32, @intCast(plt_got.symbols.items.len)); - const symbol = elf_file.symbol(sym_index); + const symbol = elf_file.symbol(ref).?; symbol.flags.has_plt = true; symbol.flags.has_got = true; - try symbol.addExtra(.{ .plt_got = index }, elf_file); - try plt_got.symbols.append(gpa, sym_index); + symbol.addExtra(.{ .plt_got = index }, elf_file); + try plt_got.symbols.append(gpa, ref); } pub fn size(plt_got: PltGotSection, elf_file: *Elf) usize { @@ -1134,15 +1129,15 @@ pub const PltGotSection = struct { pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void { plt_got.output_symtab_ctx.nlocals = @as(u32, @intCast(plt_got.symbols.items.len)); - for (plt_got.symbols.items) |sym_index| { - const name = elf_file.symbol(sym_index).name(elf_file); + for (plt_got.symbols.items) |ref| { + const name = elf_file.symbol(ref).?.name(elf_file); plt_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1; } } pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf) void { - for (plt_got.symbols.items, plt_got.output_symtab_ctx.ilocal..) |sym_index, ilocal| { - const sym = elf_file.symbol(sym_index); + for (plt_got.symbols.items, plt_got.output_symtab_ctx.ilocal..) |ref, ilocal| { + const sym = elf_file.symbol(ref).?; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file)); elf_file.strtab.appendSliceAssumeCapacity("$pltgot"); @@ -1160,8 +1155,8 @@ pub const PltGotSection = struct { const x86_64 = struct { pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { - for (plt_got.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (plt_got.symbols.items) |ref| { + const sym = elf_file.symbol(ref).?; const target_addr = sym.gotAddress(elf_file); const source_addr = sym.pltGotAddress(elf_file); const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 6)) - 4; @@ -1178,8 +1173,8 @@ pub const PltGotSection = struct { const aarch64 = struct { fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { - for (plt_got.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (plt_got.symbols.items) |ref| { + const sym = elf_file.symbol(ref).?; const target_addr = sym.gotAddress(elf_file); const source_addr = sym.pltGotAddress(elf_file); const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); @@ -1204,56 +1199,56 @@ pub const PltGotSection = struct { }; pub const CopyRelSection = struct { - symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, + symbols: std.ArrayListUnmanaged(Elf.Ref) = .{}, pub fn deinit(copy_rel: *CopyRelSection, allocator: Allocator) void { copy_rel.symbols.deinit(allocator); } - pub fn addSymbol(copy_rel: *CopyRelSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addSymbol(copy_rel: *CopyRelSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = @as(u32, @intCast(copy_rel.symbols.items.len)); - const symbol = elf_file.symbol(sym_index); + const symbol = elf_file.symbol(ref).?; symbol.flags.import = true; symbol.flags.@"export" = true; symbol.flags.has_copy_rel = true; symbol.flags.weak = false; - try symbol.addExtra(.{ .copy_rel = index }, elf_file); - try copy_rel.symbols.append(gpa, sym_index); + symbol.addExtra(.{ .copy_rel = index }, elf_file); + try copy_rel.symbols.append(gpa, ref); const shared_object = symbol.file(elf_file).?.shared_object; if (shared_object.aliases == null) { try shared_object.initSymbolAliases(elf_file); } - const aliases = shared_object.symbolAliases(sym_index, elf_file); + const aliases = shared_object.symbolAliases(ref.index, elf_file); for (aliases) |alias| { - if (alias == sym_index) continue; - const alias_sym = elf_file.symbol(alias); + if (alias == ref.index) continue; + const alias_sym = &shared_object.symbols.items[alias]; alias_sym.flags.import = true; alias_sym.flags.@"export" = true; alias_sym.flags.has_copy_rel = true; alias_sym.flags.needs_copy_rel = true; alias_sym.flags.weak = false; - try elf_file.dynsym.addSymbol(alias, elf_file); + try elf_file.dynsym.addSymbol(.{ .index = alias, .file = shared_object.index }, elf_file); } } pub fn updateSectionSize(copy_rel: CopyRelSection, shndx: u32, elf_file: *Elf) !void { const shdr = &elf_file.shdrs.items[shndx]; - for (copy_rel.symbols.items) |sym_index| { - const symbol = elf_file.symbol(sym_index); + for (copy_rel.symbols.items) |ref| { + const symbol = elf_file.symbol(ref).?; const shared_object = symbol.file(elf_file).?.shared_object; const alignment = try symbol.dsoAlignment(elf_file); symbol.value = @intCast(mem.alignForward(u64, shdr.sh_size, alignment)); shdr.sh_addralign = @max(shdr.sh_addralign, alignment); shdr.sh_size = @as(u64, @intCast(symbol.value)) + symbol.elfSym(elf_file).st_size; - const aliases = shared_object.symbolAliases(sym_index, elf_file); + const aliases = shared_object.symbolAliases(ref.index, elf_file); for (aliases) |alias| { - if (alias == sym_index) continue; - const alias_sym = elf_file.symbol(alias); + if (alias == ref.index) continue; + const alias_sym = &shared_object.symbols.items[alias]; alias_sym.value = symbol.value; } } @@ -1264,8 +1259,8 @@ pub const CopyRelSection = struct { const gpa = comp.gpa; const cpu_arch = elf_file.getTarget().cpu.arch; try elf_file.rela_dyn.ensureUnusedCapacity(gpa, copy_rel.numRela()); - for (copy_rel.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (copy_rel.symbols.items) |ref| { + const sym = elf_file.symbol(ref).?; assert(sym.flags.import and sym.flags.has_copy_rel); const extra = sym.extra(elf_file); elf_file.addRelaDynAssumeCapacity(.{ @@ -1285,8 +1280,8 @@ pub const DynsymSection = struct { entries: std.ArrayListUnmanaged(Entry) = .{}, pub const Entry = struct { - /// Index of the symbol which gets privilege of getting a dynamic treatment - symbol_index: Symbol.Index, + /// Ref of the symbol which gets privilege of getting a dynamic treatment + ref: Elf.Ref, /// Offset into .dynstrtab off: u32, }; @@ -1295,22 +1290,22 @@ pub const DynsymSection = struct { dynsym.entries.deinit(allocator); } - pub fn addSymbol(dynsym: *DynsymSection, sym_index: Symbol.Index, elf_file: *Elf) !void { + pub fn addSymbol(dynsym: *DynsymSection, ref: Elf.Ref, elf_file: *Elf) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const index = @as(u32, @intCast(dynsym.entries.items.len + 1)); - const sym = elf_file.symbol(sym_index); + const sym = elf_file.symbol(ref).?; sym.flags.has_dynamic = true; - try sym.addExtra(.{ .dynamic = index }, elf_file); + sym.addExtra(.{ .dynamic = index }, elf_file); const off = try elf_file.insertDynString(sym.name(elf_file)); - try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off }); + try dynsym.entries.append(gpa, .{ .ref = ref, .off = off }); } pub fn sort(dynsym: *DynsymSection, elf_file: *Elf) void { const Sort = struct { pub fn lessThan(ctx: *Elf, lhs: Entry, rhs: Entry) bool { - const lhs_sym = ctx.symbol(lhs.symbol_index); - const rhs_sym = ctx.symbol(rhs.symbol_index); + const lhs_sym = ctx.symbol(lhs.ref).?; + const rhs_sym = ctx.symbol(rhs.ref).?; if (lhs_sym.flags.@"export" != rhs_sym.flags.@"export") { return rhs_sym.flags.@"export"; @@ -1329,7 +1324,7 @@ pub const DynsymSection = struct { var num_exports: u32 = 0; for (dynsym.entries.items) |entry| { - const sym = elf_file.symbol(entry.symbol_index); + const sym = elf_file.symbol(entry.ref).?; if (sym.flags.@"export") num_exports += 1; } @@ -1338,7 +1333,7 @@ pub const DynsymSection = struct { std.mem.sort(Entry, dynsym.entries.items, elf_file, Sort.lessThan); for (dynsym.entries.items, 1..) |entry, index| { - const sym = elf_file.symbol(entry.symbol_index); + const sym = elf_file.symbol(entry.ref).?; var extra = sym.extra(elf_file); extra.dynamic = @as(u32, @intCast(index)); sym.setExtra(extra, elf_file); @@ -1356,7 +1351,7 @@ pub const DynsymSection = struct { pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: anytype) !void { try writer.writeStruct(Elf.null_sym); for (dynsym.entries.items) |entry| { - const sym = elf_file.symbol(entry.symbol_index); + const sym = elf_file.symbol(entry.ref).?; var out_sym: elf.Elf64_Sym = Elf.null_sym; sym.setOutputSym(elf_file, &out_sym); out_sym.st_name = entry.off; @@ -1429,7 +1424,7 @@ pub const GnuHashSection = struct { fn getExports(elf_file: *Elf) []const DynsymSection.Entry { const start = for (elf_file.dynsym.entries.items, 0..) |entry, i| { - const sym = elf_file.symbol(entry.symbol_index); + const sym = elf_file.symbol(entry.ref).?; if (sym.flags.@"export") break i; } else elf_file.dynsym.entries.items.len; return elf_file.dynsym.entries.items[start..]; @@ -1477,7 +1472,7 @@ pub const GnuHashSection = struct { @memset(bloom, 0); for (exports, 0..) |entry, i| { - const sym = elf_file.symbol(entry.symbol_index); + const sym = elf_file.symbol(entry.ref).?; const h = hasher(sym.name(elf_file)); hashes[i] = h; indices[i] = h % hash.num_buckets; @@ -1574,7 +1569,7 @@ pub const VerneedSection = struct { try verneed.ensureTotalCapacity(dynsyms.len); for (dynsyms, 1..) |entry, i| { - const symbol = elf_file.symbol(entry.symbol_index); + const symbol = elf_file.symbol(entry.ref).?; if (symbol.flags.import and symbol.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) { const shared_object = symbol.file(elf_file).?.shared_object; verneed.appendAssumeCapacity(.{ @@ -1677,11 +1672,11 @@ pub const ComdatGroupSection = struct { return cg_file.object.comdatGroup(cgs.cg_ref.index); } - pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index { + pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) *Symbol { const cg = cgs.comdatGroup(elf_file); const object = cg.file(elf_file).object; const shdr = object.shdrs.items[cg.shndx]; - return object.symbols.items[shdr.sh_info]; + return &object.symbols.items[shdr.sh_info]; } pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize { diff --git a/src/link/Elf/thunks.zig b/src/link/Elf/thunks.zig index 8353eea98a..c62c81bd38 100644 --- a/src/link/Elf/thunks.zig +++ b/src/link/Elf/thunks.zig @@ -43,11 +43,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { else => @panic("unsupported arch"), }; if (is_reachable) continue; - const target = switch (file) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, - }; + const target = file.resolveSymbol(rel.r_sym(), elf_file); try thunk.symbols.put(gpa, target, {}); } atom.addExtra(.{ .thunk = thunk_index }, elf_file); @@ -80,7 +76,7 @@ fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 { pub const Thunk = struct { value: i64 = 0, output_section_index: u32 = 0, - symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, + symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .{}, output_symtab_ctx: Elf.SymtabCtx = .{}, pub fn deinit(thunk: *Thunk, allocator: Allocator) void { @@ -97,9 +93,9 @@ pub const Thunk = struct { return @as(i64, @intCast(shdr.sh_addr)) + thunk.value; } - pub fn targetAddress(thunk: Thunk, sym_index: Symbol.Index, elf_file: *Elf) i64 { + pub fn targetAddress(thunk: Thunk, ref: Elf.Ref, elf_file: *Elf) i64 { const cpu_arch = elf_file.getTarget().cpu.arch; - return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(sym_index).? * trampolineSize(cpu_arch))); + return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(ref).? * trampolineSize(cpu_arch))); } pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { @@ -112,16 +108,16 @@ pub const Thunk = struct { pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void { thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len)); - for (thunk.symbols.keys()) |sym_index| { - const sym = elf_file.symbol(sym_index); + for (thunk.symbols.keys()) |ref| { + const sym = elf_file.symbol(ref).?; thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1)); } } pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void { const cpu_arch = elf_file.getTarget().cpu.arch; - for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |sym_index, ilocal| { - const sym = elf_file.symbol(sym_index); + for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| { + const sym = elf_file.symbol(ref).?; const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file)); elf_file.strtab.appendSliceAssumeCapacity("$thunk"); @@ -131,7 +127,7 @@ pub const Thunk = struct { .st_info = elf.STT_FUNC, .st_other = 0, .st_shndx = @intCast(thunk.output_section_index), - .st_value = @intCast(thunk.targetAddress(sym_index, elf_file)), + .st_value = @intCast(thunk.targetAddress(ref, elf_file)), .st_size = trampolineSize(cpu_arch), }; } @@ -181,9 +177,9 @@ pub const Thunk = struct { const thunk = ctx.thunk; const elf_file = ctx.elf_file; try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) }); - for (thunk.symbols.keys()) |index| { - const sym = elf_file.symbol(index); - try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.name(elf_file), sym.value }); + for (thunk.symbols.keys()) |ref| { + const sym = elf_file.symbol(ref).?; + try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value }); } } @@ -195,12 +191,8 @@ const aarch64 = struct { const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); if (r_type != .CALL26 and r_type != .JUMP26) return true; const file = atom.file(elf_file).?; - const target_index = switch (file) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, - }; - const target = elf_file.symbol(target_index); + const target_ref = file.resolveSymbol(rel.r_sym(), elf_file); + const target = elf_file.symbol(target_ref).?; if (target.flags.has_plt) return false; if (atom.output_section_index != target.output_section_index) return false; const target_atom = target.atom(elf_file).?; @@ -212,8 +204,8 @@ const aarch64 = struct { } fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { - for (thunk.symbols.keys(), 0..) |sym_index, i| { - const sym = elf_file.symbol(sym_index); + for (thunk.symbols.keys(), 0..) |ref, i| { + const sym = elf_file.symbol(ref).?; const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size)); const taddr = sym.address(.{}, elf_file); const pages = try util.calcNumberOfPages(saddr, taddr); From 8ca809d928219950ce606b4f8a18ccb52e644407 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 2 Aug 2024 18:32:07 +0200 Subject: [PATCH 08/20] elf: move getStartStopBasename into Object --- src/link/Elf.zig | 8 -------- src/link/Elf/LinkerDefined.zig | 10 ++++++---- src/link/Elf/Object.zig | 8 ++++++++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 987d108567..ac2bff0882 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -5252,14 +5252,6 @@ pub fn isCIdentifier(name: []const u8) bool { return true; } -pub fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 { - const name = self.getShString(shdr.sh_name); - if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) { - if (isCIdentifier(name)) return name; - } - return null; -} - pub fn addThunk(self: *Elf) !Thunk.Index { const index = @as(Thunk.Index, @intCast(self.thunks.items.len)); const th = try self.thunks.addOne(self.base.comp.gpa); diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index ee9a1e2956..f28b94e369 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -95,8 +95,9 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { var start_stop_count: usize = 0; for (elf_file.objects.items) |index| { - for (elf_file.file(index).?.object.shdrs.items) |shdr| { - if (elf_file.getStartStopBasename(shdr)) |_| { + const object = elf_file.file(index).?.object; + for (object.shdrs.items) |shdr| { + if (object.getStartStopBasename(shdr)) |_| { start_stop_count += 2; // __start_, __stop_ } } @@ -140,8 +141,9 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { } for (elf_file.objects.items) |index| { - for (elf_file.file(index).?.object.shdrs.items) |shdr| { - if (elf_file.getStartStopBasename(shdr)) |name| { + const object = elf_file.file(index).?.object; + for (object.shdrs.items) |shdr| { + if (object.getStartStopBasename(shdr)) |name| { const start_name = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name}); defer gpa.free(start_name); const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name}); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 47c74967eb..03bc60d937 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -1444,6 +1444,14 @@ pub fn comdatGroup(self: *Object, index: Elf.ComdatGroup.Index) *Elf.ComdatGroup return &self.comdat_groups.items[index]; } +pub fn getStartStopBasename(self: Object, shdr: elf.Elf64_Shdr) ?[]const u8 { + const name = self.getString(shdr.sh_name); + if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) { + if (Elf.isCIdentifier(name)) return name; + } + return null; +} + pub fn format( self: *Object, comptime unused_fmt_string: []const u8, From 04f8f8ad3e5c00927a5eb64e03b5381a988ed472 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 2 Aug 2024 18:32:25 +0200 Subject: [PATCH 09/20] elf: do not re-init Symbol when initializing --- src/link/Elf/SharedObject.zig | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index 3c360c3c46..4fa3bf6ee7 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -229,13 +229,11 @@ fn initSymbols(self: *SharedObject, elf_file: *Elf, opts: struct { out_esym.st_name = name_off; const out_sym_index = self.addSymbolAssumeCapacity(); const out_sym = &self.symbols.items[out_sym_index]; - out_sym.* = .{ - .value = @intCast(out_esym.st_value), - .ref = .{ .index = 0, .file = 0 }, - .esym_index = out_esym_index, - .version_index = self.versyms.items[out_esym_index], - .extra_index = self.addSymbolExtraAssumeCapacity(.{}), - }; + out_sym.value = @intCast(out_esym.st_value); + out_sym.ref = .{ .index = 0, .file = 0 }; + out_sym.esym_index = out_esym_index; + out_sym.version_index = self.versyms.items[out_esym_index]; + out_sym.extra_index = self.addSymbolExtraAssumeCapacity(.{}); } } From 26da7c8207ff73927bcc8d5608703175074e266f Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 3 Aug 2024 13:12:52 +0200 Subject: [PATCH 10/20] elf: fix symbol resolution for Objects --- src/link/Elf/LinkerDefined.zig | 9 +++++++-- src/link/Elf/Object.zig | 12 +++++++++--- src/link/Elf/SharedObject.zig | 9 +++++++-- src/link/Elf/synthetic_sections.zig | 2 +- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index f28b94e369..0ead1dba62 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -447,8 +447,13 @@ fn formatSymtab( const self = ctx.self; const elf_file = ctx.elf_file; try writer.writeAll(" globals\n"); - for (self.symbols.items) |sym| { - try writer.print(" {}\n", .{sym.fmt(elf_file)}); + for (self.symbols.items, 0..) |sym, i| { + const ref = self.resolveSymbol(@intCast(i), elf_file); + if (elf_file.symbol(ref)) |ref_sym| { + try writer.print(" {}\n", .{ref_sym.fmt(elf_file)}); + } else { + try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)}); + } } } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 03bc60d937..ef327dc9fb 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -612,7 +612,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) !void { const first_global = self.first_global orelse return; for (self.globals(), first_global..) |_, i| { const esym = self.symtab.items[i]; - if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { + if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON and esym.st_shndx != elf.SHN_UNDEF) { const atom_index = self.atoms_indexes.items[esym.st_shndx]; const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; @@ -1492,8 +1492,14 @@ fn formatSymtab( try writer.print(" {}\n", .{sym.fmt(elf_file)}); } try writer.writeAll(" globals\n"); - for (object.globals()) |sym| { - try writer.print(" {}\n", .{sym.fmt(elf_file)}); + for (object.globals(), 0..) |sym, i| { + const first_global = object.first_global.?; + const ref = object.resolveSymbol(@intCast(i + first_global), elf_file); + if (elf_file.symbol(ref)) |ref_sym| { + try writer.print(" {}\n", .{ref_sym.fmt(elf_file)}); + } else { + try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)}); + } } } diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index 4fa3bf6ee7..c4d84e29c9 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -493,8 +493,13 @@ fn formatSymtab( const shared = ctx.shared; const elf_file = ctx.elf_file; try writer.writeAll(" globals\n"); - for (shared.symbols.items) |sym| { - try writer.print(" {}\n", .{sym.fmt(elf_file)}); + for (shared.symbols.items, 0..) |sym, i| { + const ref = shared.resolveSymbol(@intCast(i), elf_file); + if (elf_file.symbol(ref)) |ref_sym| { + try writer.print(" {}\n", .{ref_sym.fmt(elf_file)}); + } else { + try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)}); + } } } diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index c767fb093c..e1ec90139e 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -417,9 +417,9 @@ pub const ZigGotSection = struct { _ = unused_fmt_string; const zig_got = ctx.zig_got; const elf_file = ctx.elf_file; - const zo = elf_file.zigObjectPtr().?; try writer.writeAll(".zig.got\n"); for (zig_got.entries.items, 0..) |entry, index| { + const zo = elf_file.zigObjectPtr().?; const symbol = zo.symbol(entry); try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ index, From 137d43c0ea77d5cc21040eadbd38fdfd945a3216 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 5 Aug 2024 07:44:35 +0200 Subject: [PATCH 11/20] elf: get hello-world glibc working again --- src/link/Elf.zig | 19 ++++++--- src/link/Elf/Object.zig | 45 --------------------- src/link/Elf/SharedObject.zig | 13 +++++-- src/link/Elf/ZigObject.zig | 58 ---------------------------- src/link/Elf/file.zig | 73 +++++++++++++++++++++++++++++++++-- 5 files changed, 92 insertions(+), 116 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ac2bff0882..0c0cec630f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2060,6 +2060,9 @@ fn scanRelocs(self: *Elf) !void { for (self.objects.items) |index| { try self.file(index).?.createSymbolIndirection(self); } + for (self.shared_objects.items) |index| { + try self.file(index).?.createSymbolIndirection(self); + } if (self.got.flags.needs_tlsld) { log.debug("program needs TLSLD", .{}); try self.got.addTlsLdSymbol(self); @@ -4431,11 +4434,13 @@ pub fn updateSymtabSize(self: *Elf) !void { strsize += ctx.strsize; } - if (self.zig_got_section_index) |_| { - self.zig_got.output_symtab_ctx.ilocal = nlocals + 1; - self.zig_got.updateSymtabSize(self); - nlocals += self.zig_got.output_symtab_ctx.nlocals; - strsize += self.zig_got.output_symtab_ctx.strsize; + if (self.zigObjectPtr()) |_| { + if (self.zig_got_section_index) |_| { + self.zig_got.output_symtab_ctx.ilocal = nlocals + 1; + self.zig_got.updateSymtabSize(self); + nlocals += self.zig_got.output_symtab_ctx.nlocals; + strsize += self.zig_got.output_symtab_ctx.strsize; + } } if (self.got_section_index) |_| { @@ -4574,7 +4579,9 @@ fn writeSyntheticSections(self: *Elf) !void { const shdr = self.shdrs.items[shndx]; try self.got.addRela(self); try self.copy_rel.addRela(self); - try self.zig_got.addRela(self); + if (self.zigObjectPtr()) |_| { + try self.zig_got.addRela(self); + } self.sortRelaDyn(); try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset); } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index ef327dc9fb..30324e1e21 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -561,51 +561,6 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { } } -pub fn createSymbolIndirection(self: *Object, elf_file: *Elf) !void { - for (self.symbols.items, 0..) |*sym, i| { - const ref = self.resolveSymbol(@intCast(i), elf_file); - const ref_sym = elf_file.symbol(ref) orelse continue; - if (ref_sym.file(elf_file).?.index() != self.index) continue; - if (!sym.isLocal(elf_file) and !sym.flags.has_dynamic) { - log.debug("'{s}' is non-local", .{sym.name(elf_file)}); - try elf_file.dynsym.addSymbol(ref, elf_file); - } - if (sym.flags.needs_got) { - log.debug("'{s}' needs GOT", .{sym.name(elf_file)}); - _ = try elf_file.got.addGotSymbol(ref, elf_file); - } - if (sym.flags.needs_plt) { - if (sym.flags.is_canonical) { - log.debug("'{s}' needs CPLT", .{sym.name(elf_file)}); - sym.flags.@"export" = true; - try elf_file.plt.addSymbol(ref, elf_file); - } else if (sym.flags.needs_got) { - log.debug("'{s}' needs PLTGOT", .{sym.name(elf_file)}); - try elf_file.plt_got.addSymbol(ref, elf_file); - } else { - log.debug("'{s}' needs PLT", .{sym.name(elf_file)}); - try elf_file.plt.addSymbol(ref, elf_file); - } - } - if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) { - log.debug("'{s}' needs COPYREL", .{sym.name(elf_file)}); - try elf_file.copy_rel.addSymbol(ref, elf_file); - } - if (sym.flags.needs_tlsgd) { - log.debug("'{s}' needs TLSGD", .{sym.name(elf_file)}); - try elf_file.got.addTlsGdSymbol(ref, elf_file); - } - if (sym.flags.needs_gottp) { - log.debug("'{s}' needs GOTTP", .{sym.name(elf_file)}); - try elf_file.got.addGotTpSymbol(ref, elf_file); - } - if (sym.flags.needs_tlsdesc) { - log.debug("'{s}' needs TLSDESC", .{sym.name(elf_file)}); - try elf_file.got.addTlsDescSymbol(ref, elf_file); - } - } -} - pub fn resolveSymbols(self: *Object, elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index c4d84e29c9..b33853d23c 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -219,9 +219,7 @@ fn initSymbols(self: *SharedObject, elf_file: *Elf, opts: struct { self.versionString(self.versyms.items[i]), }); defer gpa.free(mangled); - const name_off = @as(u32, @intCast(self.strtab.items.len)); - try self.strtab.writer(gpa).print("{s}\x00", .{mangled}); - break :blk name_off; + break :blk try self.addString(gpa, mangled); } else sym.st_name; const out_esym_index: u32 = @intCast(self.symtab.items.len); const out_esym = self.symtab.addOneAssumeCapacity(); @@ -230,6 +228,7 @@ fn initSymbols(self: *SharedObject, elf_file: *Elf, opts: struct { const out_sym_index = self.addSymbolAssumeCapacity(); const out_sym = &self.symbols.items[out_sym_index]; out_sym.value = @intCast(out_esym.st_value); + out_sym.name_offset = name_off; out_sym.ref = .{ .index = 0, .file = 0 }; out_sym.esym_index = out_esym_index; out_sym.version_index = self.versyms.items[out_esym_index]; @@ -394,6 +393,14 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3 return aliases.items[start..end]; } +fn addString(self: *SharedObject, allocator: Allocator, str: []const u8) !u32 { + const off: u32 = @intCast(self.strtab.items.len); + try self.strtab.ensureUnusedCapacity(allocator, str.len + 1); + self.strtab.appendSliceAssumeCapacity(str); + self.strtab.appendAssumeCapacity(0); + return off; +} + pub fn getString(self: SharedObject, off: u32) [:0]const u8 { assert(off < self.strtab.items.len); return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 1970ab5701..4544320c71 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -442,64 +442,6 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void { } } -pub fn createSymbolIndirection(self: *ZigObject, elf_file: *Elf) !void { - const impl = struct { - fn impl(sym: *Symbol, ref: Elf.Ref, ef: *Elf) !void { - if (!sym.isLocal(ef) and !sym.flags.has_dynamic) { - log.debug("'{s}' is non-local", .{sym.name(ef)}); - try ef.dynsym.addSymbol(ref, ef); - } - if (sym.flags.needs_got) { - log.debug("'{s}' needs GOT", .{sym.name(ef)}); - _ = try ef.got.addGotSymbol(ref, ef); - } - if (sym.flags.needs_plt) { - if (sym.flags.is_canonical) { - log.debug("'{s}' needs CPLT", .{sym.name(ef)}); - sym.flags.@"export" = true; - try ef.plt.addSymbol(ref, ef); - } else if (sym.flags.needs_got) { - log.debug("'{s}' needs PLTGOT", .{sym.name(ef)}); - try ef.plt_got.addSymbol(ref, ef); - } else { - log.debug("'{s}' needs PLT", .{sym.name(ef)}); - try ef.plt.addSymbol(ref, ef); - } - } - if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) { - log.debug("'{s}' needs COPYREL", .{sym.name(ef)}); - try ef.copy_rel.addSymbol(ref, ef); - } - if (sym.flags.needs_tlsgd) { - log.debug("'{s}' needs TLSGD", .{sym.name(ef)}); - try ef.got.addTlsGdSymbol(ref, ef); - } - if (sym.flags.needs_gottp) { - log.debug("'{s}' needs GOTTP", .{sym.name(ef)}); - try ef.got.addGotTpSymbol(ref, ef); - } - if (sym.flags.needs_tlsdesc) { - log.debug("'{s}' needs TLSDESC", .{sym.name(ef)}); - try ef.got.addTlsDescSymbol(ref, ef); - } - } - }.impl; - for (self.local_symbols.items, 0..) |index, i| { - const sym = &self.symbols.items[index]; - const ref = self.resolveSymbol(@intCast(i), elf_file); - const ref_sym = elf_file.symbol(ref) orelse continue; - if (ref_sym.file(elf_file).?.index() != self.index) continue; - try impl(sym, ref, elf_file); - } - for (self.global_symbols.items, 0..) |index, i| { - const sym = &self.symbols.items[index]; - const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file); - const ref_sym = elf_file.symbol(ref) orelse continue; - if (ref_sym.file(elf_file).?.index() != self.index) continue; - try impl(sym, ref, elf_file); - } -} - pub fn markLive(self: *ZigObject, elf_file: *Elf) void { for (self.global_symbols.items, 0..) |index, i| { const global = self.symbols.items[index]; diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index 32a540ce39..2c3b953523 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -101,10 +101,74 @@ pub const File = union(enum) { } pub fn createSymbolIndirection(file: File, elf_file: *Elf) !void { - return switch (file) { - .linker_defined, .shared_object => unreachable, - inline else => |x| x.createSymbolIndirection(elf_file), - }; + const impl = struct { + fn impl(sym: *Symbol, ref: Elf.Ref, ef: *Elf) !void { + if (!sym.isLocal(ef) and !sym.flags.has_dynamic) { + log.debug("'{s}' is non-local", .{sym.name(ef)}); + try ef.dynsym.addSymbol(ref, ef); + } + if (sym.flags.needs_got) { + log.debug("'{s}' needs GOT", .{sym.name(ef)}); + _ = try ef.got.addGotSymbol(ref, ef); + } + if (sym.flags.needs_plt) { + if (sym.flags.is_canonical) { + log.debug("'{s}' needs CPLT", .{sym.name(ef)}); + sym.flags.@"export" = true; + try ef.plt.addSymbol(ref, ef); + } else if (sym.flags.needs_got) { + log.debug("'{s}' needs PLTGOT", .{sym.name(ef)}); + try ef.plt_got.addSymbol(ref, ef); + } else { + log.debug("'{s}' needs PLT", .{sym.name(ef)}); + try ef.plt.addSymbol(ref, ef); + } + } + if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) { + log.debug("'{s}' needs COPYREL", .{sym.name(ef)}); + try ef.copy_rel.addSymbol(ref, ef); + } + if (sym.flags.needs_tlsgd) { + log.debug("'{s}' needs TLSGD", .{sym.name(ef)}); + try ef.got.addTlsGdSymbol(ref, ef); + } + if (sym.flags.needs_gottp) { + log.debug("'{s}' needs GOTTP", .{sym.name(ef)}); + try ef.got.addGotTpSymbol(ref, ef); + } + if (sym.flags.needs_tlsdesc) { + log.debug("'{s}' needs TLSDESC", .{sym.name(ef)}); + try ef.got.addTlsDescSymbol(ref, ef); + } + } + }.impl; + + switch (file) { + .zig_object => |x| { + for (x.local_symbols.items, 0..) |idx, i| { + const sym = &x.symbols.items[idx]; + const ref = x.resolveSymbol(@intCast(i), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != x.index) continue; + try impl(sym, ref, elf_file); + } + for (x.global_symbols.items, 0..) |idx, i| { + const sym = &x.symbols.items[idx]; + const ref = x.resolveSymbol(@intCast(i | ZigObject.global_symbol_bit), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != x.index) continue; + try impl(sym, ref, elf_file); + } + }, + inline else => |x| { + for (x.symbols.items, 0..) |*sym, i| { + const ref = x.resolveSymbol(@intCast(i), elf_file); + const ref_sym = elf_file.symbol(ref) orelse continue; + if (ref_sym.file(elf_file).?.index() != x.index) continue; + try impl(sym, ref, elf_file); + } + }, + } } pub fn atom(file: File, atom_index: Atom.Index) ?*Atom { @@ -239,6 +303,7 @@ pub const File = union(enum) { const std = @import("std"); const elf = std.elf; +const log = std.log.scoped(.link); const Allocator = std.mem.Allocator; const Archive = @import("Archive.zig"); From 0a198789f14f56dc55e6006e243b36402e3c20fc Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 5 Aug 2024 08:08:29 +0200 Subject: [PATCH 12/20] elf: scan LinkerDefined obj for symbol indirection too --- src/link/Elf.zig | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 0c0cec630f..4478bb0760 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2021,11 +2021,6 @@ fn scanRelocs(self: *Elf) !void { undefs.deinit(); } - var objects = try std.ArrayList(File.Index).initCapacity(gpa, self.objects.items.len + 1); - defer objects.deinit(); - if (self.zigObjectPtr()) |zo| objects.appendAssumeCapacity(zo.index); - objects.appendSliceAssumeCapacity(self.objects.items); - var has_reloc_errors = false; if (self.zigObjectPtr()) |zo| { zo.asFile().scanRelocs(self, &undefs) catch |err| switch (err) { @@ -2063,6 +2058,9 @@ fn scanRelocs(self: *Elf) !void { for (self.shared_objects.items) |index| { try self.file(index).?.createSymbolIndirection(self); } + if (self.linkerDefinedPtr()) |obj| { + try obj.asFile().createSymbolIndirection(self); + } if (self.got.flags.needs_tlsld) { log.debug("program needs TLSLD", .{}); try self.got.addTlsLdSymbol(self); From 835f1fc03f795663bfd98a768f132bf99168d40f Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 6 Aug 2024 08:51:06 +0200 Subject: [PATCH 13/20] elf: fix off-by-one when referring to resolved table directly --- src/link/Elf/Object.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 30324e1e21..b9903e7bbc 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -1119,7 +1119,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void { } for (self.globals(), self.symbols_resolver.items) |*global, resolv| { - const ref = elf_file.resolver.values.items[resolv]; + const ref = elf_file.resolver.values.items[resolv - 1]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; if (!isAlive(global, elf_file)) continue; @@ -1146,7 +1146,7 @@ pub fn writeSymtab(self: *Object, elf_file: *Elf) void { } for (self.globals(), self.symbols_resolver.items) |global, resolv| { - const ref = elf_file.resolver.values.items[resolv]; + const ref = elf_file.resolver.values.items[resolv - 1]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; const idx = global.outputSymtabIndex(elf_file) orelse continue; From e99818c602f7e2f75c62be7c4329688c8fa5afe1 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 6 Aug 2024 12:36:51 +0200 Subject: [PATCH 14/20] elf: start-stop resolution has to come after init output sections --- src/link/Elf.zig | 11 +++ src/link/Elf/LinkerDefined.zig | 135 ++++++++++++++++++--------------- src/link/Elf/Object.zig | 8 -- 3 files changed, 83 insertions(+), 71 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 4478bb0760..1a3087e8f9 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1282,6 +1282,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod try self.finalizeMergeSections(); try self.initOutputSections(); try self.initMergeSections(); + if (self.linkerDefinedPtr()) |obj| { + try obj.initStartStopSymbols(self); + } self.claimUnresolved(); // Scan and create missing synthetic entries such as GOT indirection. @@ -5247,6 +5250,14 @@ pub fn calcNumIRelativeRelocs(self: *Elf) usize { return count; } +pub fn getStartStopBasename(self: Elf, shdr: elf.Elf64_Shdr) ?[]const u8 { + const name = self.getShString(shdr.sh_name); + if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) { + if (Elf.isCIdentifier(name)) return name; + } + return null; +} + pub fn isCIdentifier(name: []const u8) bool { if (name.len == 0) return false; const first_c = name[0]; diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index 0ead1dba62..0a3a96d95e 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -42,30 +42,28 @@ pub fn init(self: *LinkerDefined, allocator: Allocator) !void { try self.strtab.append(allocator, 0); } -pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { - const newSymbolAssumeCapacity = struct { - fn newSymbolAssumeCapacity(ld: *LinkerDefined, name_off: u32, ef: *Elf) Symbol.Index { - const esym_index: u32 = @intCast(ld.symtab.items.len); - const esym = ld.symtab.addOneAssumeCapacity(); - esym.* = .{ - .st_name = name_off, - .st_info = elf.STB_GLOBAL << 4, - .st_other = @intFromEnum(elf.STV.HIDDEN), - .st_shndx = elf.SHN_ABS, - .st_value = 0, - .st_size = 0, - }; - const index = ld.addSymbolAssumeCapacity(); - const symbol = &ld.symbols.items[index]; - symbol.name_offset = name_off; - symbol.extra_index = ld.addSymbolExtraAssumeCapacity(.{}); - symbol.ref = .{ .index = 0, .file = 0 }; - symbol.esym_index = esym_index; - symbol.version_index = ef.default_sym_version; - return index; - } - }.newSymbolAssumeCapacity; +fn newSymbolAssumeCapacity(self: *LinkerDefined, name_off: u32, elf_file: *Elf) Symbol.Index { + const esym_index: u32 = @intCast(self.symtab.items.len); + const esym = self.symtab.addOneAssumeCapacity(); + esym.* = .{ + .st_name = name_off, + .st_info = elf.STB_GLOBAL << 4, + .st_other = @intFromEnum(elf.STV.HIDDEN), + .st_shndx = elf.SHN_ABS, + .st_value = 0, + .st_size = 0, + }; + const index = self.addSymbolAssumeCapacity(); + const symbol = &self.symbols.items[index]; + symbol.name_offset = name_off; + symbol.extra_index = self.addSymbolExtraAssumeCapacity(.{}); + symbol.ref = .{ .index = 0, .file = 0 }; + symbol.esym_index = esym_index; + symbol.version_index = elf_file.default_sym_version; + return index; +} +pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; var nsyms: usize = 0; @@ -93,18 +91,6 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { nsyms += 1; // __global_pointer$ } - var start_stop_count: usize = 0; - for (elf_file.objects.items) |index| { - const object = elf_file.file(index).?.object; - for (object.shdrs.items) |shdr| { - if (object.getStartStopBasename(shdr)) |_| { - start_stop_count += 2; // __start_, __stop_ - } - } - } - nsyms += start_stop_count; - - try self.start_stop_indexes.ensureTotalCapacityPrecise(gpa, start_stop_count); try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms); try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms); try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra)); @@ -113,44 +99,67 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void { @memset(self.symbols_resolver.items, 0); if (elf_file.entry_name) |name| { - self.entry_index = newSymbolAssumeCapacity(self, try self.addString(gpa, name), elf_file); + self.entry_index = self.newSymbolAssumeCapacity(try self.addString(gpa, name), elf_file); } - self.dynamic_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_DYNAMIC"), elf_file); - self.ehdr_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__ehdr_start"), elf_file); - self.init_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_start"), elf_file); - self.init_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_end"), elf_file); - self.fini_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_start"), elf_file); - self.fini_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_end"), elf_file); - self.preinit_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_start"), elf_file); - self.preinit_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_end"), elf_file); - self.got_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_"), elf_file); - self.plt_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_"), elf_file); - self.end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_end"), elf_file); + self.dynamic_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_DYNAMIC"), elf_file); + self.ehdr_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__ehdr_start"), elf_file); + self.init_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__init_array_start"), elf_file); + self.init_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__init_array_end"), elf_file); + self.fini_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__fini_array_start"), elf_file); + self.fini_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__fini_array_end"), elf_file); + self.preinit_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__preinit_array_start"), elf_file); + self.preinit_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__preinit_array_end"), elf_file); + self.got_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_"), elf_file); + self.plt_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_"), elf_file); + self.end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_end"), elf_file); if (elf_file.base.comp.link_eh_frame_hdr) { - self.gnu_eh_frame_hdr_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__GNU_EH_FRAME_HDR"), elf_file); + self.gnu_eh_frame_hdr_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__GNU_EH_FRAME_HDR"), elf_file); } - self.dso_handle_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__dso_handle"), elf_file); - self.rela_iplt_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_start"), elf_file); - self.rela_iplt_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_end"), elf_file); + self.dso_handle_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__dso_handle"), elf_file); + self.rela_iplt_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__rela_iplt_start"), elf_file); + self.rela_iplt_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__rela_iplt_end"), elf_file); if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) { - self.global_pointer_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__global_pointer$"), elf_file); + self.global_pointer_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__global_pointer$"), elf_file); + } +} + +pub fn initStartStopSymbols(self: *LinkerDefined, elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; + + var nsyms: usize = 0; + for (elf_file.shdrs.items) |shdr| { + if (elf_file.getStartStopBasename(shdr)) |_| { + nsyms += 2; // __start_, __stop_ + } } - for (elf_file.objects.items) |index| { - const object = elf_file.file(index).?.object; - for (object.shdrs.items) |shdr| { - if (object.getStartStopBasename(shdr)) |name| { - const start_name = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name}); - defer gpa.free(start_name); - const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name}); - defer gpa.free(stop_name); - const start = newSymbolAssumeCapacity(self, try self.addString(gpa, start_name), elf_file); - const stop = newSymbolAssumeCapacity(self, try self.addString(gpa, stop_name), elf_file); - self.start_stop_indexes.appendSliceAssumeCapacity(&.{ start, stop }); + try self.start_stop_indexes.ensureTotalCapacityPrecise(gpa, nsyms); + try self.symtab.ensureUnusedCapacity(gpa, nsyms); + try self.symbols.ensureUnusedCapacity(gpa, nsyms); + try self.symbols_extra.ensureUnusedCapacity(gpa, nsyms * @sizeOf(Symbol.Extra)); + try self.symbols_resolver.ensureUnusedCapacity(gpa, nsyms); + + for (elf_file.shdrs.items) |shdr| { + if (elf_file.getStartStopBasename(shdr)) |name| { + const start_name = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name}); + defer gpa.free(start_name); + const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name}); + defer gpa.free(stop_name); + + for (&[_][]const u8{ start_name, stop_name }) |nn| { + const index = self.newSymbolAssumeCapacity(try self.addString(gpa, nn), elf_file); + self.start_stop_indexes.appendAssumeCapacity(index); + const gop = try elf_file.resolver.getOrPut(gpa, .{ + .index = index, + .file = self.index, + }, elf_file); + assert(!gop.found_existing); + gop.ref.* = .{ .index = index, .file = self.index }; + self.symbols_resolver.appendAssumeCapacity(gop.index); } } } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index b9903e7bbc..a81a6f34f3 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -1399,14 +1399,6 @@ pub fn comdatGroup(self: *Object, index: Elf.ComdatGroup.Index) *Elf.ComdatGroup return &self.comdat_groups.items[index]; } -pub fn getStartStopBasename(self: Object, shdr: elf.Elf64_Shdr) ?[]const u8 { - const name = self.getString(shdr.sh_name); - if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) { - if (Elf.isCIdentifier(name)) return name; - } - return null; -} - pub fn format( self: *Object, comptime unused_fmt_string: []const u8, From 89db24ec6d6195cc10f17bf21dd9bf23e6ff1bf1 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 6 Aug 2024 22:28:38 +0200 Subject: [PATCH 15/20] elf: fix .eh_frame calc in relocatable mode --- src/link/Elf.zig | 4 ++++ src/link/Elf/eh_frame.zig | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 1a3087e8f9..e5885cefc4 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -5860,6 +5860,10 @@ pub const Ref = struct { index: u32, file: u32, + pub fn eql(ref: Ref, other: Ref) bool { + return ref.index == other.index and ref.file == other.file; + } + pub fn format( ref: Ref, comptime unused_fmt_string: []const u8, diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index 30f35b16d8..f090cf0820 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -145,10 +145,10 @@ pub const Cie = struct { if (cie_rel.r_addend != other_rel.r_addend) return false; const cie_object = elf_file.file(cie.file_index).?.object; + const cie_ref = cie_object.resolveSymbol(cie_rel.r_sym(), elf_file); const other_object = elf_file.file(other.file_index).?.object; - const cie_sym = cie_object.symbols.items[cie_rel.r_sym()]; - const other_sym = other_object.symbols.items[other_rel.r_sym()]; - if (!std.mem.eql(u8, std.mem.asBytes(&cie_sym), std.mem.asBytes(&other_sym))) return false; + const other_ref = other_object.resolveSymbol(other_rel.r_sym(), elf_file); + if (!cie_ref.eql(other_ref)) return false; } return true; } From 02f38d7749e5260dc2f48caef10390dd8d3cede5 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 7 Aug 2024 06:50:54 +0200 Subject: [PATCH 16/20] codegen: fix Elf symbol refs --- src/arch/riscv64/CodeGen.zig | 16 ++++------------ src/arch/x86_64/CodeGen.zig | 12 +++++------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 979f76f50d..c4adb82ee6 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1415,9 +1415,8 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void { .ty = enum_ty, }) catch |err| return func.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym = zo.symbol(sym_index); - try func.genSetReg(Type.u64, data_reg, .{ .lea_symbol = .{ .sym = sym.esym_index } }); + try func.genSetReg(Type.u64, data_reg, .{ .lea_symbol = .{ .sym = sym_index } }); const cmp_reg, const cmp_lock = try func.allocReg(.int); defer func.register_manager.unlockReg(cmp_lock); @@ -4949,12 +4948,11 @@ fn genCall( if (func.bin_file.cast(link.File.Elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func_val.owner_decl); - const sym = zo.symbol(sym_index); if (func.mod.pic) { return func.fail("TODO: genCall pic", .{}); } else { - try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } }); + try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym_index } }); _ = try func.addInst(.{ .tag = .jalr, .data = .{ .i_type = .{ @@ -7827,12 +7825,11 @@ fn airTagName(func: *Func, inst: Air.Inst.Index) !void { const zo = elf_file.zigObjectPtr().?; const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err| return func.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym = zo.symbol(sym_index); if (func.mod.pic) { return func.fail("TODO: airTagName pic", .{}); } else { - try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } }); + try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym_index } }); _ = try func.addInst(.{ .tag = .jalr, .data = .{ .i_type = .{ @@ -8050,12 +8047,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue { return error.CodegenFail; }; switch (lf.tag) { - .elf => { - const elf_file = lf.cast(link.File.Elf).?; - const zo = elf_file.zigObjectPtr().?; - const local = zo.symbol(local_sym_index); - return MCValue{ .undef = local.esym_index }; - }, + .elf => return MCValue{ .undef = local_sym_index }, else => unreachable, } } diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 4543cce33c..924de9d25a 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -12329,7 +12329,6 @@ fn genCall(self: *Self, info: union(enum) { if (self.bin_file.cast(link.File.Elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl); - const sym = zo.symbol(sym_index); if (self.mod.pic) { const callee_reg: Register = switch (resolved_cc) { .SysV => callee: { @@ -12346,14 +12345,14 @@ fn genCall(self: *Self, info: union(enum) { try self.genSetReg( callee_reg, Type.usize, - .{ .load_symbol = .{ .sym = sym.esym_index } }, + .{ .load_symbol = .{ .sym = sym_index } }, .{}, ); try self.asmRegister(.{ ._, .call }, callee_reg); } else try self.asmMemory(.{ ._, .call }, .{ .base = .{ .reloc = .{ .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym.esym_index, + .sym_index = sym_index, } }, .mod = .{ .rm = .{ .size = .qword } }, }); @@ -15324,14 +15323,13 @@ fn genLazySymbolRef( const zo = elf_file.zigObjectPtr().?; const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err| return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym = zo.symbol(sym_index); if (self.mod.pic) { switch (tag) { .lea, .call => try self.genSetReg(reg, Type.usize, .{ - .load_symbol = .{ .sym = sym.esym_index }, + .load_symbol = .{ .sym = sym_index }, }, .{}), .mov => try self.genSetReg(reg, Type.usize, .{ - .load_symbol = .{ .sym = sym.esym_index }, + .load_symbol = .{ .sym = sym_index }, }, .{}), else => unreachable, } @@ -15343,7 +15341,7 @@ fn genLazySymbolRef( } else { const reloc = bits.Symbol{ .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym.esym_index, + .sym_index = sym_index, }; switch (tag) { .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), .{ From 668fd7aca6364fdd1caf99dbe7473e93488b893e Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 7 Aug 2024 06:59:41 +0200 Subject: [PATCH 17/20] elf: handle SHN_UNDEF explicitly in ZigObject.resolveSymbols --- src/link/Elf/ZigObject.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 4544320c71..19e3674dd2 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -347,7 +347,7 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) !void { const global = &self.symbols.items[index]; const esym = global.elfSym(elf_file); const shndx = self.symtab.items(.shndx)[global.esym_index]; - if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { + if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON and esym.st_shndx != elf.SHN_UNDEF) { assert(esym.st_shndx == SHN_ATOM); const atom_ptr = self.atom(shndx) orelse continue; if (!atom_ptr.alive) continue; From 128289fda1bc6cd361182adc1d47863509399d63 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 7 Aug 2024 06:59:58 +0200 Subject: [PATCH 18/20] elf: actually init symbol resolvers array in ZigObject --- src/link/Elf/ZigObject.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 19e3674dd2..806c157e89 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -294,9 +294,11 @@ fn newLocalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol fn newGlobalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index { try self.global_symbols.ensureUnusedCapacity(allocator, 1); + try self.symbols_resolver.ensureUnusedCapacity(allocator, 1); const fake_index: Symbol.Index = @intCast(self.global_symbols.items.len); const index = try self.newSymbol(allocator, name_off, elf.STB_GLOBAL); self.global_symbols.appendAssumeCapacity(index); + self.symbols_resolver.addOneAssumeCapacity().* = 0; return fake_index | global_symbol_bit; } From 90c4037819b44f285e78dafac5a0196abb36b86a Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 7 Aug 2024 09:41:28 +0200 Subject: [PATCH 19/20] elf: fix off-by-one direct access to symbol resolver in ZigObject --- src/link/Elf/ZigObject.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 806c157e89..46c249d29f 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -598,7 +598,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void { for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| { const global = &self.symbols.items[index]; - const ref = elf_file.resolver.values.items[resolv]; + const ref = elf_file.resolver.values.items[resolv - 1]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue; @@ -627,7 +627,7 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void { for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| { const global = self.symbols.items[index]; - const ref = elf_file.resolver.values.items[resolv]; + const ref = elf_file.resolver.values.items[resolv - 1]; const ref_sym = elf_file.symbol(ref) orelse continue; if (ref_sym.file(elf_file).?.index() != self.index) continue; const idx = global.outputSymtabIndex(elf_file) orelse continue; From b058545970efb6f533f9930d23af2a6d0c6ce9c3 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 7 Aug 2024 10:16:49 +0200 Subject: [PATCH 20/20] elf: remove stale code --- src/link/Elf/Object.zig | 8 -------- src/link/Elf/ZigObject.zig | 12 ------------ src/link/Elf/file.zig | 12 ------------ 3 files changed, 32 deletions(-) diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index a81a6f34f3..a6f9c4ac18 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -630,12 +630,6 @@ pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void { if (esym.st_shndx != elf.SHN_UNDEF) continue; if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue; - // TODO: audit this - // const global = elf_file.symbol(index); - // if (global.file(elf_file)) |file| { - // if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue; - // } - sym.value = 0; sym.ref = .{ .index = 0, .file = 0 }; sym.esym_index = esym_index; @@ -849,8 +843,6 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void { for (self.symtab.items, 0..) |*esym, idx| { const sym = &self.symbols.items[idx]; - // TODO: do we need ref here? - if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue; const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx]; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 46c249d29f..e01c820f89 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -410,12 +410,6 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void { if (esym.st_shndx != elf.SHN_UNDEF) continue; if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue; - // TODO: audit this - // const global = elf_file.symbol(index); - // if (global.file(elf_file)) |file| { - // if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue; - // } - global.value = 0; global.ref = .{ .index = 0, .file = 0 }; global.esym_index = @intCast(index); @@ -1512,12 +1506,6 @@ pub fn deleteExport( log.debug("deleting export '{s}'", .{exp_name}); const esym = &self.symtab.items(.elf_sym)[esym_index.*]; _ = self.globals_lookup.remove(esym.st_name); - // const sym_index = elf_file.resolver.get(esym.st_name).?; - // const sym = elf_file.symbol(sym_index); - // if (sym.file_index == self.index) { - // _ = elf_file.resolver.swapRemove(esym.st_name); - // sym.* = .{}; - // } esym.* = Elf.null_sym; self.symtab.items(.shndx)[esym_index.*] = elf.SHN_UNDEF; } diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index 2c3b953523..88dc807274 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -67,18 +67,6 @@ pub const File = union(enum) { }; } - pub fn resetGlobals(file: File, elf_file: *Elf) void { - for (file.globals()) |global_index| { - const global = elf_file.symbol(global_index); - const name_offset = global.name_offset; - const extra_index = global.extra_index; - global.* = .{}; - global.name_offset = name_offset; - global.flags.global = true; - global.extra_index = extra_index; - } - } - pub fn setAlive(file: File) void { switch (file) { .zig_object, .linker_defined => {},