authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-07 13:12:26+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-07 13:31:31+01:00
logc7ed7c4690dfa297c15b94fe7acba77c52d89e68
treec2e8791aefee2e92333ccea7491033179f559c6c
parent3df53d1722da9e4fcc8606315c68ffb884a0dd5a

elf: generate section symbols when writing symtab


6 files changed, 106 insertions(+), 50 deletions(-)

src/link/Elf.zig+85-25
......@@ -597,7 +597,6 @@ pub fn initMetadata(self: *Elf) !void {
597597 const shdr = &self.shdrs.items[self.zig_text_section_index.?];
598598 fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);
599599 if (self.isRelocatable()) {
600 try zig_object.addSectionSymbol(self.zig_text_section_index.?, self);
601600 self.zig_text_rela_section_index = try self.addRelaShdr(
602601 ".rela.text.zig",
603602 self.zig_text_section_index.?,
......@@ -609,6 +608,7 @@ pub fn initMetadata(self: *Elf) !void {
609608 self.phdr_zig_load_re_index.?,
610609 );
611610 }
611 try self.output_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{});
612612 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
613613 }
614614
......@@ -644,7 +644,6 @@ pub fn initMetadata(self: *Elf) !void {
644644 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
645645 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
646646 if (self.isRelocatable()) {
647 try zig_object.addSectionSymbol(self.zig_data_rel_ro_section_index.?, self);
648647 self.zig_data_rel_ro_rela_section_index = try self.addRelaShdr(
649648 ".rela.data.rel.ro.zig",
650649 self.zig_data_rel_ro_section_index.?,
......@@ -656,6 +655,7 @@ pub fn initMetadata(self: *Elf) !void {
656655 self.phdr_zig_load_ro_index.?,
657656 );
658657 }
658 try self.output_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});
659659 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});
660660 }
661661
......@@ -670,7 +670,6 @@ pub fn initMetadata(self: *Elf) !void {
670670 const shdr = &self.shdrs.items[self.zig_data_section_index.?];
671671 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
672672 if (self.isRelocatable()) {
673 try zig_object.addSectionSymbol(self.zig_data_section_index.?, self);
674673 self.zig_data_rela_section_index = try self.addRelaShdr(
675674 ".rela.data.zig",
676675 self.zig_data_section_index.?,
......@@ -682,6 +681,7 @@ pub fn initMetadata(self: *Elf) !void {
682681 self.phdr_zig_load_rw_index.?,
683682 );
684683 }
684 try self.output_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{});
685685 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{});
686686 }
687687
......@@ -700,9 +700,9 @@ pub fn initMetadata(self: *Elf) !void {
700700 shdr.sh_size = phdr.p_memsz;
701701 try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_bss_section_index.?, phndx);
702702 } else {
703 try zig_object.addSectionSymbol(self.zig_bss_section_index.?, self);
704703 shdr.sh_size = 1024;
705704 }
705 try self.output_sections.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
706706 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
707707 }
708708
......@@ -724,6 +724,7 @@ pub fn initMetadata(self: *Elf) !void {
724724 shdr.sh_offset = off;
725725 shdr.sh_size = size;
726726 zig_object.debug_strtab_dirty = true;
727 try self.output_sections.putNoClobber(gpa, self.debug_str_section_index.?, .{});
727728 }
728729
729730 if (self.debug_info_section_index == null) {
......@@ -739,6 +740,7 @@ pub fn initMetadata(self: *Elf) !void {
739740 shdr.sh_offset = off;
740741 shdr.sh_size = size;
741742 zig_object.debug_info_header_dirty = true;
743 try self.output_sections.putNoClobber(gpa, self.debug_info_section_index.?, .{});
742744 }
743745
744746 if (self.debug_abbrev_section_index == null) {
......@@ -754,6 +756,7 @@ pub fn initMetadata(self: *Elf) !void {
754756 shdr.sh_offset = off;
755757 shdr.sh_size = size;
756758 zig_object.debug_abbrev_section_dirty = true;
759 try self.output_sections.putNoClobber(gpa, self.debug_abbrev_section_index.?, .{});
757760 }
758761
759762 if (self.debug_aranges_section_index == null) {
......@@ -769,6 +772,7 @@ pub fn initMetadata(self: *Elf) !void {
769772 shdr.sh_offset = off;
770773 shdr.sh_size = size;
771774 zig_object.debug_aranges_section_dirty = true;
775 try self.output_sections.putNoClobber(gpa, self.debug_aranges_section_index.?, .{});
772776 }
773777
774778 if (self.debug_line_section_index == null) {
......@@ -784,6 +788,7 @@ pub fn initMetadata(self: *Elf) !void {
784788 shdr.sh_offset = off;
785789 shdr.sh_size = size;
786790 zig_object.debug_line_header_dirty = true;
791 try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{});
787792 }
788793 }
789794}
......@@ -1510,14 +1515,14 @@ pub fn flushStaticLib(self: *Elf) link.File.FlushError!void {
15101515 try self.initShStrtab();
15111516 try self.sortShdrs();
15121517 zig_object.updateRelaSectionsSizes(self);
1513 self.updateSymtabSizeObject(zig_object);
1518 self.updateSymtabSizeZigObject(zig_object);
15141519 self.updateShStrtabSize();
15151520
15161521 try self.allocateNonAllocSections();
15171522
15181523 try self.writeShdrTable();
15191524 try zig_object.writeRelaSections(self);
1520 try self.writeSymtabObject(zig_object);
1525 try self.writeSymtabZigObject(zig_object);
15211526 try self.writeShStrtab();
15221527 try self.writeElfHeader();
15231528 }
......@@ -3579,7 +3584,8 @@ fn sortInitFini(self: *Elf) !void {
35793584
35803585 if (!is_init_fini and !is_ctor_dtor) continue;
35813586
3582 const atom_list = self.output_sections.getPtr(@intCast(shndx)) orelse continue;
3587 const atom_list = self.output_sections.getPtr(@intCast(shndx)).?;
3588 if (atom_list.items.len == 0) continue;
35833589
35843590 var entries = std.ArrayList(Entry).init(gpa);
35853591 try entries.ensureTotalCapacityPrecise(atom_list.items.len);
......@@ -3909,6 +3915,20 @@ fn sortShdrs(self: *Elf) !void {
39093915 shdr.sh_info = backlinks[shdr.sh_info];
39103916 }
39113917
3918 {
3919 var output_sections = try self.output_sections.clone(gpa);
3920 defer output_sections.deinit(gpa);
3921
3922 self.output_sections.clearRetainingCapacity();
3923
3924 var it = output_sections.iterator();
3925 while (it.next()) |entry| {
3926 const shndx = entry.key_ptr.*;
3927 const meta = entry.value_ptr.*;
3928 self.output_sections.putAssumeCapacityNoClobber(backlinks[shndx], meta);
3929 }
3930 }
3931
39123932 {
39133933 var last_atom_and_free_list_table = try self.last_atom_and_free_list_table.clone(gpa);
39143934 defer last_atom_and_free_list_table.deinit(gpa);
......@@ -3962,7 +3982,6 @@ fn sortShdrs(self: *Elf) !void {
39623982
39633983fn updateSectionSizes(self: *Elf) !void {
39643984 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
3965 if (atom_list.items.len == 0) continue;
39663985 const shdr = &self.shdrs.items[shndx];
39673986 for (atom_list.items) |atom_index| {
39683987 const atom_ptr = self.atom(atom_index) orelse continue;
......@@ -4056,7 +4075,6 @@ fn updateSectionSizes(self: *Elf) !void {
40564075
40574076fn updateSectionSizesObject(self: *Elf) !void {
40584077 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
4059 if (atom_list.items.len == 0) continue;
40604078 const shdr = &self.shdrs.items[shndx];
40614079 for (atom_list.items) |atom_index| {
40624080 const atom_ptr = self.atom(atom_index) orelse continue;
......@@ -4317,7 +4335,6 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
43174335/// Allocates alloc sections when merging relocatable objects files together.
43184336fn allocateAllocSectionsObject(self: *Elf) !void {
43194337 _ = self;
4320 @panic("TODO");
43214338}
43224339
43234340/// Allocates non-alloc sections (debug info, symtabs, etc.).
......@@ -4444,6 +4461,7 @@ fn writeAtoms(self: *Elf) !void {
44444461 if (shdr.sh_type == elf.SHT_NOBITS) continue;
44454462
44464463 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
4464 if (atom_list.items.len == 0) continue;
44474465
44484466 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
44494467
......@@ -4519,6 +4537,7 @@ fn writeAtomsObject(self: *Elf) !void {
45194537 if (shdr.sh_type == elf.SHT_NOBITS) continue;
45204538
45214539 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
4540 if (atom_list.items.len == 0) continue;
45224541
45234542 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
45244543
......@@ -4617,6 +4636,11 @@ fn updateSymtabSize(self: *Elf) void {
46174636 sizes.add(file_ptr.linker_defined.output_symtab_size);
46184637 }
46194638
4639 // Section symbols
4640 for (self.output_sections.keys()) |_| {
4641 sizes.nlocals += 1;
4642 }
4643
46204644 const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
46214645 symtab_shdr.sh_info = sizes.nlocals + 1;
46224646 symtab_shdr.sh_link = self.strtab_section_index.?;
......@@ -4632,9 +4656,16 @@ fn updateSymtabSize(self: *Elf) void {
46324656 strtab.sh_size = sizes.strsize + 1;
46334657}
46344658
4635fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void {
4659fn updateSymtabSizeZigObject(self: *Elf, zig_object: *ZigObject) void {
4660 var sizes = SymtabSize{};
4661
46364662 zig_object.asFile().updateSymtabSize(self);
4637 const sizes = zig_object.output_symtab_size;
4663 sizes.add(zig_object.output_symtab_size);
4664
4665 // Section symbols
4666 for (self.output_sections.keys()) |_| {
4667 sizes.nlocals += 1;
4668 }
46384669
46394670 const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
46404671 symtab_shdr.sh_info = sizes.nlocals + 1;
......@@ -4798,7 +4829,7 @@ fn writeSyntheticSectionsObject(self: *Elf) !void {
47984829 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
47994830 defer buffer.deinit();
48004831 try eh_frame.writeEhFrame(self, buffer.writer());
4801 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
4832 // try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
48024833 }
48034834
48044835 try self.writeSymtab();
......@@ -4812,6 +4843,16 @@ fn writeShStrtab(self: *Elf) !void {
48124843 }
48134844}
48144845
4846const WriteSymtabCtx = struct {
4847 ilocal: usize,
4848 iglobal: usize,
4849
4850 fn incr(this: *@This(), ss: SymtabSize) void {
4851 this.ilocal += ss.nlocals;
4852 this.iglobal += ss.nglobals;
4853 }
4854};
4855
48154856fn writeSymtab(self: *Elf) !void {
48164857 const gpa = self.base.allocator;
48174858 const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
......@@ -4828,20 +4869,13 @@ fn writeSymtab(self: *Elf) !void {
48284869 const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
48294870 try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);
48304871
4831 const Ctx = struct {
4832 ilocal: usize,
4833 iglobal: usize,
4834
4835 fn incr(this: *@This(), ss: SymtabSize) void {
4836 this.ilocal += ss.nlocals;
4837 this.iglobal += ss.nglobals;
4838 }
4839 };
4840 var ctx: Ctx = .{
4872 var ctx: WriteSymtabCtx = .{
48414873 .ilocal = 1,
48424874 .iglobal = symtab_shdr.sh_info,
48434875 };
48444876
4877 ctx.incr(self.writeSectionSymbols(ctx));
4878
48454879 if (self.zigObjectPtr()) |zig_object| {
48464880 zig_object.asFile().writeSymtab(self, ctx);
48474881 ctx.incr(zig_object.output_symtab_size);
......@@ -4915,7 +4949,7 @@ fn writeSymtab(self: *Elf) !void {
49154949 try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
49164950}
49174951
4918fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void {
4952fn writeSymtabZigObject(self: *Elf, zig_object: *ZigObject) !void {
49194953 const gpa = self.base.allocator;
49204954 const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
49214955 const strtab_shdr = self.shdrs.items[self.strtab_section_index.?];
......@@ -4931,7 +4965,15 @@ fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void {
49314965 const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
49324966 try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);
49334967
4934 zig_object.asFile().writeSymtab(self, .{ .ilocal = 1, .iglobal = symtab_shdr.sh_info });
4968 var ctx: WriteSymtabCtx = .{
4969 .ilocal = 1,
4970 .iglobal = symtab_shdr.sh_info,
4971 };
4972
4973 ctx.incr(self.writeSectionSymbols(ctx));
4974
4975 zig_object.asFile().writeSymtab(self, ctx);
4976 ctx.incr(zig_object.output_symtab_size);
49354977
49364978 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
49374979 switch (self.ptr_width) {
......@@ -4963,6 +5005,24 @@ fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void {
49635005 try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
49645006}
49655007
5008fn writeSectionSymbols(self: *Elf, ctx: WriteSymtabCtx) SymtabSize {
5009 var ilocal = ctx.ilocal;
5010 for (self.output_sections.keys()) |shndx| {
5011 const shdr = self.shdrs.items[shndx];
5012 const out_sym = &self.symtab.items[ilocal];
5013 out_sym.* = .{
5014 .st_name = 0,
5015 .st_value = shdr.sh_addr,
5016 .st_info = elf.STT_SECTION,
5017 .st_shndx = @intCast(shndx),
5018 .st_size = 0,
5019 .st_other = 0,
5020 };
5021 ilocal += 1;
5022 }
5023 return .{ .nlocals = @intCast(ilocal - ctx.ilocal) };
5024}
5025
49665026/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
49675027fn ptrWidthBytes(self: Elf) u8 {
49685028 return switch (self.ptr_width) {
src/link/Elf/Atom.zig+8-2
......@@ -60,6 +60,11 @@ pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {
6060 };
6161}
6262
63pub fn relocsShndx(self: Atom) ?u32 {
64 if (self.relocs_section_index == 0) return null;
65 return self.relocs_section_index;
66}
67
6368pub fn outputShndx(self: Atom) ?u16 {
6469 if (self.output_section_index == 0) return null;
6570 return self.output_section_index;
......@@ -280,9 +285,10 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
280285}
281286
282287pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
288 const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{};
283289 return switch (self.file(elf_file).?) {
284 .zig_object => |x| x.relocs.items[self.relocs_section_index].items,
285 .object => |x| x.getRelocs(self.relocs_section_index),
290 .zig_object => |x| x.relocs.items[shndx].items,
291 .object => |x| x.getRelocs(shndx),
286292 else => unreachable,
287293 };
288294}
src/link/Elf/Object.zig+12-3
......@@ -211,6 +211,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf
211211fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
212212 const name = blk: {
213213 const name = self.getString(shdr.sh_name);
214 if (elf_file.isRelocatable()) break :blk name;
214215 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
215216 const sh_name_prefixes: []const [:0]const u8 = &.{
216217 ".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
237238 else => shdr.sh_type,
238239 };
239240 const flags = blk: {
240 const flags = shdr.sh_flags & ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN);
241 var flags = shdr.sh_flags;
242 if (!elf_file.isRelocatable()) {
243 flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN);
244 }
241245 break :blk switch (@"type") {
242246 elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE,
243247 else => flags,
......@@ -655,8 +659,13 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
655659}
656660
657661pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
658 _ = self;
659 _ = elf_file;
662 for (self.atoms.items) |atom_index| {
663 const atom = elf_file.atom(atom_index) orelse continue;
664 if (!atom.flags.alive) continue;
665 const shndx = atom.relocsShndx() orelse continue;
666 const shdr = self.shdrs.items[shndx];
667 _ = try self.initOutputSection(elf_file, shdr);
668 }
660669}
661670
662671pub fn updateRelaSectionsSizes(self: Object, elf_file: *Elf) void {
src/link/Elf/Symbol.zig-2
......@@ -219,8 +219,6 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
219219 const st_shndx = blk: {
220220 if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
221221 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
222 // TODO I think this is wrong and obsolete
223 if (elf_file.isRelocatable() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?;
224222 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
225223 break :blk elf.SHN_ABS;
226224 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
src/link/Elf/ZigObject.zig-16
......@@ -287,22 +287,6 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
287287 return symbol_index;
288288}
289289
290pub fn addSectionSymbol(self: *ZigObject, shndx: u16, elf_file: *Elf) !void {
291 assert(elf_file.isRelocatable());
292 const gpa = elf_file.base.allocator;
293 const symbol_index = try elf_file.addSymbol();
294 try self.local_symbols.append(gpa, symbol_index);
295 const symbol_ptr = elf_file.symbol(symbol_index);
296 symbol_ptr.file_index = self.index;
297 symbol_ptr.output_section_index = shndx;
298
299 const esym_index = try self.addLocalEsym(gpa);
300 const esym = &self.local_esyms.items(.elf_sym)[esym_index];
301 esym.st_info = elf.STT_SECTION;
302 esym.st_shndx = shndx;
303 symbol_ptr.esym_index = esym_index;
304}
305
306290/// TODO actually create fake input shdrs and return that instead.
307291pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
308292 _ = self;
src/link/Elf/file.zig+1-2
......@@ -136,8 +136,7 @@ pub const File = union(enum) {
136136 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
137137 const esym = local.elfSym(elf_file);
138138 switch (esym.st_type()) {
139 elf.STT_SECTION => if (!elf_file.isRelocatable()) continue,
140 elf.STT_NOTYPE => continue,
139 elf.STT_SECTION, elf.STT_NOTYPE => continue,
141140 else => {},
142141 }
143142 local.flags.output_symtab = true;