diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-07 13:12:26 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-07 13:31:31 +0100 |
| commit | c7ed7c4690dfa297c15b94fe7acba77c52d89e68 (patch) | |
| tree | c2e8791aefee2e92333ccea7491033179f559c6c /src | |
| parent | 3df53d1722da9e4fcc8606315c68ffb884a0dd5a (diff) | |
| download | zig-c7ed7c4690dfa297c15b94fe7acba77c52d89e68.tar.gz zig-c7ed7c4690dfa297c15b94fe7acba77c52d89e68.zip | |
elf: generate section symbols when writing symtab
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Elf.zig | 110 | ||||
| -rw-r--r-- | src/link/Elf/Atom.zig | 10 | ||||
| -rw-r--r-- | src/link/Elf/Object.zig | 15 | ||||
| -rw-r--r-- | src/link/Elf/Symbol.zig | 2 | ||||
| -rw-r--r-- | src/link/Elf/ZigObject.zig | 16 | ||||
| -rw-r--r-- | src/link/Elf/file.zig | 3 |
6 files changed, 106 insertions, 50 deletions
diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 300f4b9501..f38152fa27 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -597,7 +597,6 @@ pub fn initMetadata(self: *Elf) !void { const shdr = &self.shdrs.items[self.zig_text_section_index.?]; fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index); if (self.isRelocatable()) { - try zig_object.addSectionSymbol(self.zig_text_section_index.?, self); self.zig_text_rela_section_index = try self.addRelaShdr( ".rela.text.zig", self.zig_text_section_index.?, @@ -609,6 +608,7 @@ pub fn initMetadata(self: *Elf) !void { self.phdr_zig_load_re_index.?, ); } + try self.output_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{}); try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{}); } @@ -644,7 +644,6 @@ pub fn initMetadata(self: *Elf) !void { const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?]; fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index); if (self.isRelocatable()) { - try zig_object.addSectionSymbol(self.zig_data_rel_ro_section_index.?, self); self.zig_data_rel_ro_rela_section_index = try self.addRelaShdr( ".rela.data.rel.ro.zig", self.zig_data_rel_ro_section_index.?, @@ -656,6 +655,7 @@ pub fn initMetadata(self: *Elf) !void { self.phdr_zig_load_ro_index.?, ); } + try self.output_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{}); try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{}); } @@ -670,7 +670,6 @@ pub fn initMetadata(self: *Elf) !void { const shdr = &self.shdrs.items[self.zig_data_section_index.?]; fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index); if (self.isRelocatable()) { - try zig_object.addSectionSymbol(self.zig_data_section_index.?, self); self.zig_data_rela_section_index = try self.addRelaShdr( ".rela.data.zig", self.zig_data_section_index.?, @@ -682,6 +681,7 @@ pub fn initMetadata(self: *Elf) !void { self.phdr_zig_load_rw_index.?, ); } + try self.output_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{}); try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{}); } @@ -700,9 +700,9 @@ pub fn initMetadata(self: *Elf) !void { shdr.sh_size = phdr.p_memsz; try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_bss_section_index.?, phndx); } else { - try zig_object.addSectionSymbol(self.zig_bss_section_index.?, self); shdr.sh_size = 1024; } + try self.output_sections.putNoClobber(gpa, self.zig_bss_section_index.?, .{}); try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{}); } @@ -724,6 +724,7 @@ pub fn initMetadata(self: *Elf) !void { shdr.sh_offset = off; shdr.sh_size = size; zig_object.debug_strtab_dirty = true; + try self.output_sections.putNoClobber(gpa, self.debug_str_section_index.?, .{}); } if (self.debug_info_section_index == null) { @@ -739,6 +740,7 @@ pub fn initMetadata(self: *Elf) !void { shdr.sh_offset = off; shdr.sh_size = size; zig_object.debug_info_header_dirty = true; + try self.output_sections.putNoClobber(gpa, self.debug_info_section_index.?, .{}); } if (self.debug_abbrev_section_index == null) { @@ -754,6 +756,7 @@ pub fn initMetadata(self: *Elf) !void { shdr.sh_offset = off; shdr.sh_size = size; zig_object.debug_abbrev_section_dirty = true; + try self.output_sections.putNoClobber(gpa, self.debug_abbrev_section_index.?, .{}); } if (self.debug_aranges_section_index == null) { @@ -769,6 +772,7 @@ pub fn initMetadata(self: *Elf) !void { shdr.sh_offset = off; shdr.sh_size = size; zig_object.debug_aranges_section_dirty = true; + try self.output_sections.putNoClobber(gpa, self.debug_aranges_section_index.?, .{}); } if (self.debug_line_section_index == null) { @@ -784,6 +788,7 @@ pub fn initMetadata(self: *Elf) !void { shdr.sh_offset = off; shdr.sh_size = size; zig_object.debug_line_header_dirty = true; + try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{}); } } } @@ -1510,14 +1515,14 @@ pub fn flushStaticLib(self: *Elf) link.File.FlushError!void { try self.initShStrtab(); try self.sortShdrs(); zig_object.updateRelaSectionsSizes(self); - self.updateSymtabSizeObject(zig_object); + self.updateSymtabSizeZigObject(zig_object); self.updateShStrtabSize(); try self.allocateNonAllocSections(); try self.writeShdrTable(); try zig_object.writeRelaSections(self); - try self.writeSymtabObject(zig_object); + try self.writeSymtabZigObject(zig_object); try self.writeShStrtab(); try self.writeElfHeader(); } @@ -3579,7 +3584,8 @@ fn sortInitFini(self: *Elf) !void { if (!is_init_fini and !is_ctor_dtor) continue; - const atom_list = self.output_sections.getPtr(@intCast(shndx)) orelse continue; + const atom_list = self.output_sections.getPtr(@intCast(shndx)).?; + if (atom_list.items.len == 0) continue; var entries = std.ArrayList(Entry).init(gpa); try entries.ensureTotalCapacityPrecise(atom_list.items.len); @@ -3910,6 +3916,20 @@ fn sortShdrs(self: *Elf) !void { } { + var output_sections = try self.output_sections.clone(gpa); + defer output_sections.deinit(gpa); + + self.output_sections.clearRetainingCapacity(); + + var it = output_sections.iterator(); + while (it.next()) |entry| { + const shndx = entry.key_ptr.*; + const meta = entry.value_ptr.*; + self.output_sections.putAssumeCapacityNoClobber(backlinks[shndx], meta); + } + } + + { var last_atom_and_free_list_table = try self.last_atom_and_free_list_table.clone(gpa); defer last_atom_and_free_list_table.deinit(gpa); @@ -3962,7 +3982,6 @@ fn sortShdrs(self: *Elf) !void { fn updateSectionSizes(self: *Elf) !void { for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| { - if (atom_list.items.len == 0) continue; const shdr = &self.shdrs.items[shndx]; for (atom_list.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; @@ -4056,7 +4075,6 @@ fn updateSectionSizes(self: *Elf) !void { fn updateSectionSizesObject(self: *Elf) !void { for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| { - if (atom_list.items.len == 0) continue; const shdr = &self.shdrs.items[shndx]; for (atom_list.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; @@ -4317,7 +4335,6 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { /// Allocates alloc sections when merging relocatable objects files together. fn allocateAllocSectionsObject(self: *Elf) !void { _ = self; - @panic("TODO"); } /// Allocates non-alloc sections (debug info, symtabs, etc.). @@ -4444,6 +4461,7 @@ fn writeAtoms(self: *Elf) !void { if (shdr.sh_type == elf.SHT_NOBITS) continue; const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue; + if (atom_list.items.len == 0) continue; log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)}); @@ -4519,6 +4537,7 @@ fn writeAtomsObject(self: *Elf) !void { if (shdr.sh_type == elf.SHT_NOBITS) continue; const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue; + if (atom_list.items.len == 0) continue; log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)}); @@ -4617,6 +4636,11 @@ fn updateSymtabSize(self: *Elf) void { sizes.add(file_ptr.linker_defined.output_symtab_size); } + // Section symbols + for (self.output_sections.keys()) |_| { + sizes.nlocals += 1; + } + const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?]; symtab_shdr.sh_info = sizes.nlocals + 1; symtab_shdr.sh_link = self.strtab_section_index.?; @@ -4632,9 +4656,16 @@ fn updateSymtabSize(self: *Elf) void { strtab.sh_size = sizes.strsize + 1; } -fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void { +fn updateSymtabSizeZigObject(self: *Elf, zig_object: *ZigObject) void { + var sizes = SymtabSize{}; + zig_object.asFile().updateSymtabSize(self); - const sizes = zig_object.output_symtab_size; + sizes.add(zig_object.output_symtab_size); + + // Section symbols + for (self.output_sections.keys()) |_| { + sizes.nlocals += 1; + } const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?]; symtab_shdr.sh_info = sizes.nlocals + 1; @@ -4798,7 +4829,7 @@ fn writeSyntheticSectionsObject(self: *Elf) !void { var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); defer buffer.deinit(); try eh_frame.writeEhFrame(self, buffer.writer()); - try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); + // try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); } try self.writeSymtab(); @@ -4812,6 +4843,16 @@ fn writeShStrtab(self: *Elf) !void { } } +const WriteSymtabCtx = struct { + ilocal: usize, + iglobal: usize, + + fn incr(this: *@This(), ss: SymtabSize) void { + this.ilocal += ss.nlocals; + this.iglobal += ss.nglobals; + } +}; + fn writeSymtab(self: *Elf) !void { const gpa = self.base.allocator; const symtab_shdr = self.shdrs.items[self.symtab_section_index.?]; @@ -4828,20 +4869,13 @@ fn writeSymtab(self: *Elf) !void { const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow; try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size); - const Ctx = struct { - ilocal: usize, - iglobal: usize, - - fn incr(this: *@This(), ss: SymtabSize) void { - this.ilocal += ss.nlocals; - this.iglobal += ss.nglobals; - } - }; - var ctx: Ctx = .{ + var ctx: WriteSymtabCtx = .{ .ilocal = 1, .iglobal = symtab_shdr.sh_info, }; + ctx.incr(self.writeSectionSymbols(ctx)); + if (self.zigObjectPtr()) |zig_object| { zig_object.asFile().writeSymtab(self, ctx); ctx.incr(zig_object.output_symtab_size); @@ -4915,7 +4949,7 @@ fn writeSymtab(self: *Elf) !void { try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset); } -fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void { +fn writeSymtabZigObject(self: *Elf, zig_object: *ZigObject) !void { const gpa = self.base.allocator; const symtab_shdr = self.shdrs.items[self.symtab_section_index.?]; const strtab_shdr = self.shdrs.items[self.strtab_section_index.?]; @@ -4931,7 +4965,15 @@ fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void { const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow; try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size); - zig_object.asFile().writeSymtab(self, .{ .ilocal = 1, .iglobal = symtab_shdr.sh_info }); + var ctx: WriteSymtabCtx = .{ + .ilocal = 1, + .iglobal = symtab_shdr.sh_info, + }; + + ctx.incr(self.writeSectionSymbols(ctx)); + + zig_object.asFile().writeSymtab(self, ctx); + ctx.incr(zig_object.output_symtab_size); const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian(); switch (self.ptr_width) { @@ -4963,6 +5005,24 @@ fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void { try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset); } +fn writeSectionSymbols(self: *Elf, ctx: WriteSymtabCtx) SymtabSize { + var ilocal = ctx.ilocal; + for (self.output_sections.keys()) |shndx| { + const shdr = self.shdrs.items[shndx]; + const out_sym = &self.symtab.items[ilocal]; + out_sym.* = .{ + .st_name = 0, + .st_value = shdr.sh_addr, + .st_info = elf.STT_SECTION, + .st_shndx = @intCast(shndx), + .st_size = 0, + .st_other = 0, + }; + ilocal += 1; + } + return .{ .nlocals = @intCast(ilocal - ctx.ilocal) }; +} + /// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF. fn ptrWidthBytes(self: Elf) u8 { return switch (self.ptr_width) { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 1f6f77cc4b..98a9f13771 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -60,6 +60,11 @@ pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr { }; } +pub fn relocsShndx(self: Atom) ?u32 { + if (self.relocs_section_index == 0) return null; + return self.relocs_section_index; +} + pub fn outputShndx(self: Atom) ?u16 { if (self.output_section_index == 0) return null; return self.output_section_index; @@ -280,9 +285,10 @@ pub fn free(self: *Atom, elf_file: *Elf) void { } pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela { + const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{}; return switch (self.file(elf_file).?) { - .zig_object => |x| x.relocs.items[self.relocs_section_index].items, - .object => |x| x.getRelocs(self.relocs_section_index), + .zig_object => |x| x.relocs.items[shndx].items, + .object => |x| x.getRelocs(shndx), else => unreachable, }; } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index cb258a4c22..73bd3a7fb3 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -211,6 +211,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 { const name = blk: { const name = self.getString(shdr.sh_name); + if (elf_file.isRelocatable()) break :blk name; if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name; const sh_name_prefixes: []const [:0]const u8 = &.{ ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", @@ -237,7 +238,10 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem else => shdr.sh_type, }; const flags = blk: { - const flags = shdr.sh_flags & ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN); + var flags = shdr.sh_flags; + if (!elf_file.isRelocatable()) { + flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN); + } break :blk switch (@"type") { elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE, else => flags, @@ -655,8 +659,13 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void { } pub fn initRelaSections(self: Object, elf_file: *Elf) !void { - _ = self; - _ = elf_file; + for (self.atoms.items) |atom_index| { + const atom = elf_file.atom(atom_index) orelse continue; + if (!atom.flags.alive) continue; + const shndx = atom.relocsShndx() orelse continue; + const shdr = self.shdrs.items[shndx]; + _ = try self.initOutputSection(elf_file, shdr); + } } pub fn updateRelaSectionsSizes(self: Object, elf_file: *Elf) void { diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 13d9041813..9a9daff358 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -219,8 +219,6 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { const st_shndx = blk: { if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?; if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF; - // TODO I think this is wrong and obsolete - if (elf_file.isRelocatable() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?; if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS; break :blk symbol.outputShndx() orelse elf.SHN_UNDEF; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 4b7e97ed13..3c5174b86e 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -287,22 +287,6 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index { return symbol_index; } -pub fn addSectionSymbol(self: *ZigObject, shndx: u16, elf_file: *Elf) !void { - assert(elf_file.isRelocatable()); - const gpa = elf_file.base.allocator; - 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.output_section_index = shndx; - - const esym_index = try self.addLocalEsym(gpa); - const esym = &self.local_esyms.items(.elf_sym)[esym_index]; - esym.st_info = elf.STT_SECTION; - esym.st_shndx = shndx; - symbol_ptr.esym_index = esym_index; -} - /// TODO actually create fake input shdrs and return that instead. pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr { _ = self; diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index cc0b486692..0fae6bc9f4 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -136,8 +136,7 @@ pub const File = union(enum) { if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue; const esym = local.elfSym(elf_file); switch (esym.st_type()) { - elf.STT_SECTION => if (!elf_file.isRelocatable()) continue, - elf.STT_NOTYPE => continue, + elf.STT_SECTION, elf.STT_NOTYPE => continue, else => {}, } local.flags.output_symtab = true; |
