authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-02 22:52:19+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:04+02:00
log540ef3e010ea00d9bfb3ba8c2e43ebf8fa226084
treea9906f4e4c1b26c20eaeaec606034f649367d39a
parent679accd8873ab08ebb0e8d7b2b537c18bd77d821

elf: sort sections by their rank to combine them by segment flags

Currently this ignores ZigModule, however, I believe we can make it so that this is done excluding sections/segments emitted by ZigModule and everything should work out just fine.

1 files changed, 113 insertions(+), 8 deletions(-)

src/link/Elf.zig+113-8
......@@ -1243,7 +1243,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
12431243
12441244 // Generate and emit non-incremental sections.
12451245 try self.initSections();
1246 try self.initSyntheticSections();
1246 try self.sortSections();
12471247
12481248 // Dump the state for easy debugging.
12491249 // State can be dumped via `--debug-log link_state`.
......@@ -3430,6 +3430,11 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
34303430}
34313431
34323432fn initSections(self: *Elf) !void {
3433 const small_ptr = switch (self.ptr_width) {
3434 .p32 => true,
3435 .p64 => false,
3436 };
3437
34333438 for (self.objects.items) |index| {
34343439 const object = self.file(index).?.object;
34353440 for (object.atoms.items) |atom_index| {
......@@ -3439,13 +3444,6 @@ fn initSections(self: *Elf) !void {
34393444 atom_ptr.output_section_index = try object.getOutputSectionIndex(self, shdr);
34403445 }
34413446 }
3442}
3443
3444fn initSyntheticSections(self: *Elf) !void {
3445 const small_ptr = switch (self.ptr_width) {
3446 .p32 => true,
3447 .p64 => false,
3448 };
34493447
34503448 if (self.got.entries.items.len > 0 and self.got_section_index == null) {
34513449 self.got_section_index = try self.addSection(.{
......@@ -3482,6 +3480,113 @@ fn initSyntheticSections(self: *Elf) !void {
34823480 }
34833481}
34843482
3483fn sectionRank(self: *Elf, shdr: elf.Elf64_Shdr) u8 {
3484 const name = self.shstrtab.getAssumeExists(shdr.sh_name);
3485 const flags = shdr.sh_flags;
3486 switch (shdr.sh_type) {
3487 elf.SHT_NULL => return 0,
3488 elf.SHT_DYNSYM => return 2,
3489 elf.SHT_HASH => return 3,
3490 elf.SHT_GNU_HASH => return 3,
3491 elf.SHT_GNU_VERSYM => return 4,
3492 elf.SHT_GNU_VERDEF => return 4,
3493 elf.SHT_GNU_VERNEED => return 4,
3494
3495 elf.SHT_PREINIT_ARRAY,
3496 elf.SHT_INIT_ARRAY,
3497 elf.SHT_FINI_ARRAY,
3498 => return 0xf2,
3499
3500 elf.SHT_DYNAMIC => return 0xf3,
3501
3502 elf.SHT_RELA => return 0xf,
3503
3504 elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {
3505 if (flags & elf.SHF_EXECINSTR != 0) {
3506 return 0xf1;
3507 } else if (flags & elf.SHF_WRITE != 0) {
3508 return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6;
3509 } else if (mem.eql(u8, name, ".interp")) {
3510 return 1;
3511 } else {
3512 return 0xf0;
3513 }
3514 } else {
3515 if (mem.startsWith(u8, name, ".debug")) {
3516 return 0xf8;
3517 } else {
3518 return 0xf9;
3519 }
3520 },
3521
3522 elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7,
3523 elf.SHT_SYMTAB => return 0xfa,
3524 elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 4 else 0xfb,
3525 else => return 0xff,
3526 }
3527}
3528
3529fn sortSections(self: *Elf) !void {
3530 const Entry = struct {
3531 shndx: u16,
3532
3533 pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool {
3534 const lhs_shdr = elf_file.shdrs.items[lhs.shndx];
3535 const rhs_shdr = elf_file.shdrs.items[rhs.shndx];
3536 return elf_file.sectionRank(lhs_shdr) < elf_file.sectionRank(rhs_shdr);
3537 }
3538 };
3539
3540 const gpa = self.base.allocator;
3541 var entries = try std.ArrayList(Entry).initCapacity(gpa, self.shdrs.items.len);
3542 defer entries.deinit();
3543 for (0..self.shdrs.items.len) |shndx| {
3544 entries.appendAssumeCapacity(.{ .shndx = @as(u16, @intCast(shndx)) });
3545 }
3546
3547 mem.sort(Entry, entries.items, self, Entry.lessThan);
3548
3549 const backlinks = try gpa.alloc(u16, entries.items.len);
3550 defer gpa.free(backlinks);
3551 for (entries.items, 0..) |entry, i| {
3552 backlinks[entry.shndx] = @as(u16, @intCast(i));
3553 }
3554
3555 var slice = try self.shdrs.toOwnedSlice(gpa);
3556 defer gpa.free(slice);
3557
3558 try self.shdrs.ensureTotalCapacityPrecise(gpa, slice.len);
3559 for (entries.items) |sorted| {
3560 self.shdrs.appendAssumeCapacity(slice[sorted.shndx]);
3561 }
3562
3563 for (self.objects.items) |index| {
3564 for (self.file(index).?.object.atoms.items) |atom_index| {
3565 const atom_ptr = self.atom(atom_index) orelse continue;
3566 if (!atom_ptr.flags.alive) continue;
3567 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
3568 }
3569 }
3570
3571 for (&[_]*?u16{
3572 &self.eh_frame_section_index,
3573 &self.eh_frame_hdr_section_index,
3574 &self.got_section_index,
3575 &self.symtab_section_index,
3576 &self.strtab_section_index,
3577 &self.shstrtab_section_index,
3578 }) |maybe_index| {
3579 if (maybe_index.*) |*index| {
3580 index.* = backlinks[index.*];
3581 }
3582 }
3583
3584 if (self.symtab_section_index) |index| {
3585 const shdr = &self.shdrs.items[index];
3586 shdr.sh_link = self.strtab_section_index.?;
3587 }
3588}
3589
34853590fn updateSyntheticSectionSizes(self: *Elf) !void {
34863591 if (self.got_section_index) |index| {
34873592 if (self.got.dirty) {