From 05157e820a9fcc3a2a63c785c13c1bbde155c868 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 10 Oct 2024 20:34:17 -0700 Subject: [PATCH] link.Elf.sortShdrs: tease out data dependencies In order to reduce the logic that happens in flush() we need to see which data is being accessed by all this logic, so we can see which operations depend on each other. --- src/link/Elf.zig | 151 ++++++++++++++++++++++------------- src/link/Elf/relocatable.zig | 22 ++++- 2 files changed, 114 insertions(+), 59 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 24a99e5677..535008e873 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -992,7 +992,16 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod // Generate and emit synthetic sections. try self.initSyntheticSections(); try self.initSpecialPhdrs(); - try self.sortShdrs(); + try sortShdrs( + gpa, + &self.section_indexes, + &self.sections, + self.shstrtab.items, + self.merge_sections.items, + self.comdat_group_sections.items, + self.zigObjectPtr(), + self.files, + ); try self.setDynamicSection(self.rpath_table.keys()); self.sortDynamicSymtab(); @@ -3354,9 +3363,8 @@ fn sortPhdrs( } } -fn shdrRank(self: *Elf, shndx: u32) u8 { - const shdr = self.sections.items(.shdr)[shndx]; - const name = self.getShString(shdr.sh_name); +fn shdrRank(shdr: elf.Elf64_Shdr, shstrtab: []const u8) u8 { + const name = shString(shstrtab, shdr.sh_name); const flags = shdr.sh_flags; switch (shdr.sh_type) { @@ -3405,120 +3413,138 @@ fn shdrRank(self: *Elf, shndx: u32) u8 { } } -pub fn sortShdrs(self: *Elf) !void { +pub fn sortShdrs( + gpa: Allocator, + section_indexes: *SectionIndexes, + sections: *std.MultiArrayList(Section), + shstrtab: []const u8, + merge_sections: []Merge.Section, + comdat_group_sections: []ComdatGroupSection, + zig_object_ptr: ?*ZigObject, + files: std.MultiArrayList(File.Entry), +) !void { const Entry = struct { shndx: u32, - pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool { - return elf_file.shdrRank(lhs.shndx) < elf_file.shdrRank(rhs.shndx); + const Context = struct { + shdrs: []const elf.Elf64_Shdr, + shstrtab: []const u8, + }; + + pub fn lessThan(ctx: Context, lhs: @This(), rhs: @This()) bool { + return shdrRank(ctx.shdrs[lhs.shndx], ctx.shstrtab) < + shdrRank(ctx.shdrs[rhs.shndx], ctx.shstrtab); } }; - const gpa = self.base.comp.gpa; - var entries = try std.ArrayList(Entry).initCapacity(gpa, self.sections.items(.shdr).len); - defer entries.deinit(); - for (0..self.sections.items(.shdr).len) |shndx| { - entries.appendAssumeCapacity(.{ .shndx = @intCast(shndx) }); + const shdrs = sections.items(.shdr); + + const entries = try gpa.alloc(Entry, shdrs.len); + defer gpa.free(entries); + for (entries, 0..shdrs.len) |*entry, shndx| { + entry.* = .{ .shndx = @intCast(shndx) }; } - mem.sort(Entry, entries.items, self, Entry.lessThan); + const sort_context: Entry.Context = .{ + .shdrs = shdrs, + .shstrtab = shstrtab, + }; + mem.sort(Entry, entries, sort_context, Entry.lessThan); - const backlinks = try gpa.alloc(u32, entries.items.len); + const backlinks = try gpa.alloc(u32, entries.len); defer gpa.free(backlinks); { - var slice = self.sections.toOwnedSlice(); + var slice = sections.toOwnedSlice(); defer slice.deinit(gpa); - try self.sections.resize(gpa, slice.len); + try sections.resize(gpa, slice.len); - for (entries.items, 0..) |entry, i| { + for (entries, 0..) |entry, i| { backlinks[entry.shndx] = @intCast(i); - self.sections.set(i, slice.get(entry.shndx)); + sections.set(i, slice.get(entry.shndx)); } } - const special_indexes = &self.section_indexes; - inline for (@typeInfo(SectionIndexes).@"struct".fields) |field| { - if (@field(special_indexes, field.name)) |special_index| { - @field(special_indexes, field.name) = backlinks[special_index]; + if (@field(section_indexes, field.name)) |special_index| { + @field(section_indexes, field.name) = backlinks[special_index]; } } - for (self.merge_sections.items) |*msec| { + for (merge_sections) |*msec| { msec.output_section_index = backlinks[msec.output_section_index]; } - const slice = self.sections.slice(); + const slice = sections.slice(); for (slice.items(.shdr), slice.items(.atom_list_2)) |*shdr, *atom_list| { atom_list.output_section_index = backlinks[atom_list.output_section_index]; for (atom_list.atoms.keys()) |ref| { - self.atom(ref).?.output_section_index = atom_list.output_section_index; + fileLookup(files, ref.file).?.atom(ref.index).?.output_section_index = atom_list.output_section_index; } if (shdr.sh_type == elf.SHT_RELA) { // FIXME:JK we should spin up .symtab potentially earlier, or set all non-dynamic RELA sections // to point at symtab // shdr.sh_link = backlinks[shdr.sh_link]; - shdr.sh_link = self.section_indexes.symtab.?; + shdr.sh_link = section_indexes.symtab.?; shdr.sh_info = backlinks[shdr.sh_info]; } } - if (self.zigObjectPtr()) |zo| zo.resetShdrIndexes(backlinks); + if (zig_object_ptr) |zo| zo.resetShdrIndexes(backlinks); - for (self.comdat_group_sections.items) |*cg| { + for (comdat_group_sections) |*cg| { cg.shndx = backlinks[cg.shndx]; } - if (self.section_indexes.symtab) |index| { + if (section_indexes.symtab) |index| { const shdr = &slice.items(.shdr)[index]; - shdr.sh_link = self.section_indexes.strtab.?; + shdr.sh_link = section_indexes.strtab.?; } - if (self.section_indexes.dynamic) |index| { + if (section_indexes.dynamic) |index| { const shdr = &slice.items(.shdr)[index]; - shdr.sh_link = self.section_indexes.dynstrtab.?; + shdr.sh_link = section_indexes.dynstrtab.?; } - if (self.section_indexes.dynsymtab) |index| { + if (section_indexes.dynsymtab) |index| { const shdr = &slice.items(.shdr)[index]; - shdr.sh_link = self.section_indexes.dynstrtab.?; + shdr.sh_link = section_indexes.dynstrtab.?; } - if (self.section_indexes.hash) |index| { + if (section_indexes.hash) |index| { const shdr = &slice.items(.shdr)[index]; - shdr.sh_link = self.section_indexes.dynsymtab.?; + shdr.sh_link = section_indexes.dynsymtab.?; } - if (self.section_indexes.gnu_hash) |index| { + if (section_indexes.gnu_hash) |index| { const shdr = &slice.items(.shdr)[index]; - shdr.sh_link = self.section_indexes.dynsymtab.?; + shdr.sh_link = section_indexes.dynsymtab.?; } - if (self.section_indexes.versym) |index| { + if (section_indexes.versym) |index| { const shdr = &slice.items(.shdr)[index]; - shdr.sh_link = self.section_indexes.dynsymtab.?; + shdr.sh_link = section_indexes.dynsymtab.?; } - if (self.section_indexes.verneed) |index| { + if (section_indexes.verneed) |index| { const shdr = &slice.items(.shdr)[index]; - shdr.sh_link = self.section_indexes.dynstrtab.?; + shdr.sh_link = section_indexes.dynstrtab.?; } - if (self.section_indexes.rela_dyn) |index| { + if (section_indexes.rela_dyn) |index| { const shdr = &slice.items(.shdr)[index]; - shdr.sh_link = self.section_indexes.dynsymtab orelse 0; + shdr.sh_link = section_indexes.dynsymtab orelse 0; } - if (self.section_indexes.rela_plt) |index| { + if (section_indexes.rela_plt) |index| { const shdr = &slice.items(.shdr)[index]; - shdr.sh_link = self.section_indexes.dynsymtab.?; - shdr.sh_info = self.section_indexes.plt.?; + shdr.sh_link = section_indexes.dynsymtab.?; + shdr.sh_info = section_indexes.plt.?; } - if (self.section_indexes.eh_frame_rela) |index| { + if (section_indexes.eh_frame_rela) |index| { const shdr = &slice.items(.shdr)[index]; - shdr.sh_link = self.section_indexes.symtab.?; - shdr.sh_info = self.section_indexes.eh_frame.?; + shdr.sh_link = section_indexes.symtab.?; + shdr.sh_info = section_indexes.eh_frame.?; } } @@ -4677,13 +4703,17 @@ pub fn thunk(self: *Elf, index: Thunk.Index) *Thunk { } pub fn file(self: *Elf, index: File.Index) ?File { - const tag = self.files.items(.tags)[index]; + return fileLookup(self.files, index); +} + +fn fileLookup(files: std.MultiArrayList(File.Entry), index: File.Index) ?File { + const tag = files.items(.tags)[index]; return switch (tag) { .null => null, - .linker_defined => .{ .linker_defined = &self.files.items(.data)[index].linker_defined }, - .zig_object => .{ .zig_object = &self.files.items(.data)[index].zig_object }, - .object => .{ .object = &self.files.items(.data)[index].object }, - .shared_object => .{ .shared_object = &self.files.items(.data)[index].shared_object }, + .linker_defined => .{ .linker_defined = &files.items(.data)[index].linker_defined }, + .zig_object => .{ .zig_object = &files.items(.data)[index].zig_object }, + .object => .{ .object = &files.items(.data)[index].object }, + .shared_object => .{ .shared_object = &files.items(.data)[index].shared_object }, }; } @@ -4790,8 +4820,15 @@ pub fn tlsAddress(self: *Elf) i64 { } pub fn getShString(self: Elf, off: u32) [:0]const u8 { - assert(off < self.shstrtab.items.len); - return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.shstrtab.items.ptr + off)), 0); + return shString(self.shstrtab.items, off); +} + +fn shString( + shstrtab: []const u8, + off: u32, +) [:0]const u8 { + const slice = shstrtab[off..]; + return slice[0..std.mem.indexOfScalar(u8, slice, 0).? :0]; } pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 { diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index 73fcf6a44a..944a6e0e46 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -32,7 +32,16 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path zig_object.claimUnresolvedRelocatable(elf_file); try initSections(elf_file); - try elf_file.sortShdrs(); + try Elf.sortShdrs( + gpa, + &elf_file.section_indexes, + &elf_file.sections, + elf_file.shstrtab.items, + elf_file.merge_sections.items, + elf_file.comdat_group_sections.items, + elf_file.zigObjectPtr(), + elf_file.files, + ); try zig_object.addAtomsToRelaSections(elf_file); try elf_file.updateMergeSectionSizes(); try updateSectionSizes(elf_file); @@ -171,7 +180,16 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l claimUnresolved(elf_file); try initSections(elf_file); - try elf_file.sortShdrs(); + try Elf.sortShdrs( + comp.gpa, + &elf_file.section_indexes, + &elf_file.sections, + elf_file.shstrtab.items, + elf_file.merge_sections.items, + elf_file.comdat_group_sections.items, + elf_file.zigObjectPtr(), + elf_file.files, + ); if (elf_file.zigObjectPtr()) |zig_object| { try zig_object.addAtomsToRelaSections(elf_file); }