authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-15 17:53:36+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:06+02:00
log17b8e8ab29789e01c206244d6cf6c9bd8c99f27c
treef72f0cb5474a70ffd3a5a4fbdf206995fccd34b0
parent46cf4c5d9343af5da484b808a5c3153736ec62e9

elf: sort the entire shdr table the usual way


1 files changed, 75 insertions(+), 74 deletions(-)

src/link/Elf.zig+75-74
......@@ -1560,7 +1560,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
15601560 // Generate and emit non-incremental sections.
15611561 try self.initSections();
15621562 try self.initSpecialPhdrs();
1563 try self.sortSections();
1563 try self.sortShdrs();
15641564 for (self.objects.items) |index| {
15651565 try self.file(index).?.object.addAtomsToOutputSections(self);
15661566 }
......@@ -4146,38 +4146,28 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
41464146 index.* = backlinks[index.*];
41474147 }
41484148 }
4149
4150 {
4151 var it = self.phdr_to_shdr_table.iterator();
4152 while (it.next()) |entry| {
4153 entry.value_ptr.* = backlinks[entry.value_ptr.*];
4154 }
4155 }
41494156}
41504157
4151fn sectionRank(self: *Elf, shndx: u16) u8 {
4158fn shdrRank(self: *Elf, shndx: u16) u8 {
41524159 const shdr = self.shdrs.items[shndx];
41534160 const name = self.shstrtab.getAssumeExists(shdr.sh_name);
41544161 const flags = shdr.sh_flags;
41554162
4156 if (self.isZigSection(shndx)) {
4157 switch (shdr.sh_type) {
4158 elf.SHT_PROGBITS => {
4159 assert(flags & elf.SHF_ALLOC != 0);
4160 if (flags & elf.SHF_EXECINSTR != 0) {
4161 return 0x2;
4162 } else if (flags & elf.SHF_WRITE != 0) {
4163 return 0x3;
4164 } else {
4165 return 0x1;
4166 }
4167 },
4168 elf.SHT_NOBITS => return 0xf,
4169 else => unreachable,
4170 }
4171 }
4172
41734163 switch (shdr.sh_type) {
4174 elf.SHT_NULL => return 0x0,
4175 elf.SHT_DYNSYM => return 0x12,
4176 elf.SHT_HASH => return 0x13,
4177 elf.SHT_GNU_HASH => return 0x13,
4178 elf.SHT_GNU_VERSYM => return 0x14,
4179 elf.SHT_GNU_VERDEF => return 0x14,
4180 elf.SHT_GNU_VERNEED => return 0x14,
4164 elf.SHT_NULL => return 0,
4165 elf.SHT_DYNSYM => return 2,
4166 elf.SHT_HASH => return 3,
4167 elf.SHT_GNU_HASH => return 3,
4168 elf.SHT_GNU_VERSYM => return 4,
4169 elf.SHT_GNU_VERDEF => return 4,
4170 elf.SHT_GNU_VERNEED => return 4,
41814171
41824172 elf.SHT_PREINIT_ARRAY,
41834173 elf.SHT_INIT_ARRAY,
......@@ -4186,7 +4176,7 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {
41864176
41874177 elf.SHT_DYNAMIC => return 0xf3,
41884178
4189 elf.SHT_RELA => return 0x1f,
4179 elf.SHT_RELA => return 0xf,
41904180
41914181 elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {
41924182 if (flags & elf.SHF_EXECINSTR != 0) {
......@@ -4194,7 +4184,7 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {
41944184 } else if (flags & elf.SHF_WRITE != 0) {
41954185 return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6;
41964186 } else if (mem.eql(u8, name, ".interp")) {
4197 return 0x11;
4187 return 1;
41984188 } else {
41994189 return 0xf0;
42004190 }
......@@ -4208,17 +4198,17 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {
42084198
42094199 elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7,
42104200 elf.SHT_SYMTAB => return 0xfa,
4211 elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x14 else 0xfb,
4201 elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfb,
42124202 else => return 0xff,
42134203 }
42144204}
42154205
4216fn sortSections(self: *Elf) !void {
4206fn sortShdrs(self: *Elf) !void {
42174207 const Entry = struct {
42184208 shndx: u16,
42194209
42204210 pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool {
4221 return elf_file.sectionRank(lhs.shndx) < elf_file.sectionRank(rhs.shndx);
4211 return elf_file.shdrRank(lhs.shndx) < elf_file.shdrRank(rhs.shndx);
42224212 }
42234213 };
42244214
......@@ -4328,6 +4318,20 @@ fn sortSections(self: *Elf) !void {
43284318 shdr.sh_info = self.plt_section_index.?;
43294319 }
43304320
4321 {
4322 var phdr_to_shdr_table = try self.phdr_to_shdr_table.clone(gpa);
4323 defer phdr_to_shdr_table.deinit(gpa);
4324
4325 self.phdr_to_shdr_table.clearRetainingCapacity();
4326
4327 var it = phdr_to_shdr_table.iterator();
4328 while (it.next()) |entry| {
4329 const shndx = entry.key_ptr.*;
4330 const phndx = entry.value_ptr.*;
4331 self.phdr_to_shdr_table.putAssumeCapacityNoClobber(backlinks[shndx], phndx);
4332 }
4333 }
4334
43314335 if (self.zig_module_index) |index| {
43324336 const zig_module = self.file(index).?.zig_module;
43334337 for (zig_module.atoms.items) |atom_index| {
......@@ -4484,15 +4488,19 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 {
44844488
44854489/// Calculates how many segments (PT_LOAD progam headers) are required
44864490/// to cover the set of sections.
4491/// We permit a maximum of 3**2 number of segments.
44874492fn calcNumberOfSegments(self: *Elf) usize {
4488 var count: usize = 0;
4489 var flags: u64 = 0;
4493 var covers: [9]bool = [_]bool{false} ** 9;
44904494 for (self.shdrs.items, 0..) |shdr, shndx| {
44914495 if (shdr.sh_type == elf.SHT_NULL) continue;
44924496 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
44934497 if (self.isZigSection(@intCast(shndx))) continue;
4494 if (flags != shdrToPhdrFlags(shdr.sh_flags)) count += 1;
4495 flags = shdrToPhdrFlags(shdr.sh_flags);
4498 const flags = shdrToPhdrFlags(shdr.sh_flags);
4499 covers[flags - 1] = true;
4500 }
4501 var count: usize = 0;
4502 for (covers) |cover| {
4503 if (cover) count += 1;
44964504 }
44974505 return count;
44984506}
......@@ -4564,34 +4572,22 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
45644572 // virtual and file offsets. However, the simple one will do for one
45654573 // as we are more interested in quick turnaround and compatibility
45664574 // with `findFreeSpace` mechanics than anything else.
4575 const Cover = std.ArrayList(u16);
45674576 const gpa = self.base.allocator;
4568 const nphdrs = self.calcNumberOfSegments();
4569 var covers = try gpa.alloc(struct { start: u16, len: u16 }, nphdrs);
4570 defer gpa.free(covers);
4577 var covers: [9]Cover = undefined;
4578 for (&covers) |*cover| {
4579 cover.* = Cover.init(gpa);
4580 }
4581 defer for (&covers) |*cover| {
4582 cover.deinit();
4583 };
45714584
4572 var shndx = for (self.shdrs.items, 0..) |shdr, in| {
4585 for (self.shdrs.items, 0..) |shdr, shndx| {
45734586 if (shdr.sh_type == elf.SHT_NULL) continue;
45744587 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
4575 if (self.isZigSection(@intCast(in))) continue;
4576 break @as(u16, @intCast(in));
4577 } else @as(u16, @intCast(self.shdrs.items.len));
4578
4579 for (covers) |*cover| {
4580 cover.* = .{ .start = shndx, .len = 0 };
4581 var flags = shdrToPhdrFlags(self.shdrs.items[shndx].sh_flags);
4582
4583 while (shndx < self.shdrs.items.len) : (shndx += 1) {
4584 const shdr = self.shdrs.items[shndx];
4585 if (shdr.sh_flags & elf.SHF_ALLOC == 0) break;
4586 if (shdrToPhdrFlags(shdr.sh_flags) != flags) {
4587 cover.len = shndx - cover.start;
4588 break;
4589 }
4590 }
4591 }
4592
4593 if (nphdrs > 0) {
4594 covers[nphdrs - 1].len = shndx - covers[nphdrs - 1].start;
4588 if (self.isZigSection(@intCast(shndx))) continue;
4589 const flags = shdrToPhdrFlags(shdr.sh_flags);
4590 try covers[flags - 1].append(@intCast(shndx));
45954591 }
45964592
45974593 // Now we can proceed with allocating the sections in virtual memory.
......@@ -4603,10 +4599,11 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
46034599 var addr = phdr_table.p_vaddr + phdr_table.p_memsz;
46044600
46054601 for (covers) |cover| {
4606 const slice = self.shdrs.items[cover.start..][0..cover.len];
4602 if (cover.items.len == 0) continue;
46074603
46084604 var @"align": u64 = self.page_size;
4609 for (slice) |shdr| {
4605 for (cover.items) |shndx| {
4606 const shdr = self.shdrs.items[shndx];
46104607 if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) continue;
46114608 @"align" = @max(@"align", shdr.sh_addralign);
46124609 }
......@@ -4616,8 +4613,9 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
46164613 var memsz: u64 = 0;
46174614 var filesz: u64 = 0;
46184615 var i: usize = 0;
4619 while (i < cover.len) : (i += 1) {
4620 const shdr = &slice[i];
4616 while (i < cover.items.len) : (i += 1) {
4617 const shndx = cover.items[i];
4618 const shdr = &self.shdrs.items[shndx];
46214619 if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) {
46224620 // .tbss is a little special as it's used only by the loader meaning it doesn't
46234621 // need to be actually mmap'ed at runtime. We still need to correctly increment
......@@ -4632,19 +4630,20 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
46324630 // .data 0x10
46334631 // ...
46344632 var tbss_addr = addr;
4635 while (i < cover.len and
4636 slice[i].sh_type == elf.SHT_NOBITS and
4637 slice[i].sh_flags & elf.SHF_TLS != 0) : (i += 1)
4633 while (i < cover.items.len and
4634 self.shdrs.items[cover.items[i]].sh_type == elf.SHT_NOBITS and
4635 self.shdrs.items[cover.items[i]].sh_flags & elf.SHF_TLS != 0) : (i += 1)
46384636 {
4639 const tbss_shdr = &slice[i];
4640 tbss_addr = alignment.@"align"(cover.start + i, tbss_shdr.sh_addralign, tbss_addr);
4637 const tbss_shndx = cover.items[i];
4638 const tbss_shdr = &self.shdrs.items[tbss_shndx];
4639 tbss_addr = alignment.@"align"(tbss_shndx, tbss_shdr.sh_addralign, tbss_addr);
46414640 tbss_shdr.sh_addr = tbss_addr;
46424641 tbss_addr += tbss_shdr.sh_size;
46434642 }
46444643 i -= 1;
46454644 continue;
46464645 }
4647 const next = alignment.@"align"(cover.start + i, shdr.sh_addralign, addr);
4646 const next = alignment.@"align"(shndx, shdr.sh_addralign, addr);
46484647 const padding = next - addr;
46494648 addr = next;
46504649 shdr.sh_addr = addr;
......@@ -4655,23 +4654,25 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
46554654 addr += shdr.sh_size;
46564655 }
46574656
4657 const first = self.shdrs.items[cover.items[0]];
46584658 var off = self.findFreeSpace(filesz, @"align");
46594659 const phndx = try self.addPhdr(.{
46604660 .type = elf.PT_LOAD,
46614661 .offset = off,
4662 .addr = slice[0].sh_addr,
4662 .addr = first.sh_addr,
46634663 .memsz = memsz,
46644664 .filesz = filesz,
46654665 .@"align" = @"align",
4666 .flags = shdrToPhdrFlags(slice[0].sh_flags),
4666 .flags = shdrToPhdrFlags(first.sh_flags),
46674667 });
46684668
4669 for (slice, 0..) |*shdr, ii| {
4669 for (cover.items) |shndx| {
4670 const shdr = &self.shdrs.items[shndx];
46704671 if (shdr.sh_type == elf.SHT_NOBITS) continue;
4671 off = alignment.@"align"(cover.start + ii, shdr.sh_addralign, off);
4672 off = alignment.@"align"(shndx, shdr.sh_addralign, off);
46724673 shdr.sh_offset = off;
46734674 off += shdr.sh_size;
4674 try self.phdr_to_shdr_table.putNoClobber(gpa, @intCast(ii + cover.start), phndx);
4675 try self.phdr_to_shdr_table.putNoClobber(gpa, shndx, phndx);
46754676 }
46764677
46774678 addr += self.page_size;