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...@@ -1560,7 +1560,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1560 // Generate and emit non-incremental sections.1560 // Generate and emit non-incremental sections.
1561 try self.initSections();1561 try self.initSections();
1562 try self.initSpecialPhdrs();1562 try self.initSpecialPhdrs();
1563 try self.sortSections();1563 try self.sortShdrs();
1564 for (self.objects.items) |index| {1564 for (self.objects.items) |index| {
1565 try self.file(index).?.object.addAtomsToOutputSections(self);1565 try self.file(index).?.object.addAtomsToOutputSections(self);
1566 }1566 }
...@@ -4146,38 +4146,28 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {...@@ -4146,38 +4146,28 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
4146 index.* = backlinks[index.*];4146 index.* = backlinks[index.*];
4147 }4147 }
4148 }4148 }
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 }
4149}4156}
41504157
4151fn sectionRank(self: *Elf, shndx: u16) u8 {4158fn shdrRank(self: *Elf, shndx: u16) u8 {
4152 const shdr = self.shdrs.items[shndx];4159 const shdr = self.shdrs.items[shndx];
4153 const name = self.shstrtab.getAssumeExists(shdr.sh_name);4160 const name = self.shstrtab.getAssumeExists(shdr.sh_name);
4154 const flags = shdr.sh_flags;4161 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
4173 switch (shdr.sh_type) {4163 switch (shdr.sh_type) {
4174 elf.SHT_NULL => return 0x0,4164 elf.SHT_NULL => return 0,
4175 elf.SHT_DYNSYM => return 0x12,4165 elf.SHT_DYNSYM => return 2,
4176 elf.SHT_HASH => return 0x13,4166 elf.SHT_HASH => return 3,
4177 elf.SHT_GNU_HASH => return 0x13,4167 elf.SHT_GNU_HASH => return 3,
4178 elf.SHT_GNU_VERSYM => return 0x14,4168 elf.SHT_GNU_VERSYM => return 4,
4179 elf.SHT_GNU_VERDEF => return 0x14,4169 elf.SHT_GNU_VERDEF => return 4,
4180 elf.SHT_GNU_VERNEED => return 0x14,4170 elf.SHT_GNU_VERNEED => return 4,
41814171
4182 elf.SHT_PREINIT_ARRAY,4172 elf.SHT_PREINIT_ARRAY,
4183 elf.SHT_INIT_ARRAY,4173 elf.SHT_INIT_ARRAY,
...@@ -4186,7 +4176,7 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {...@@ -4186,7 +4176,7 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {
41864176
4187 elf.SHT_DYNAMIC => return 0xf3,4177 elf.SHT_DYNAMIC => return 0xf3,
41884178
4189 elf.SHT_RELA => return 0x1f,4179 elf.SHT_RELA => return 0xf,
41904180
4191 elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {4181 elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {
4192 if (flags & elf.SHF_EXECINSTR != 0) {4182 if (flags & elf.SHF_EXECINSTR != 0) {
...@@ -4194,7 +4184,7 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {...@@ -4194,7 +4184,7 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {
4194 } else if (flags & elf.SHF_WRITE != 0) {4184 } else if (flags & elf.SHF_WRITE != 0) {
4195 return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6;4185 return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6;
4196 } else if (mem.eql(u8, name, ".interp")) {4186 } else if (mem.eql(u8, name, ".interp")) {
4197 return 0x11;4187 return 1;
4198 } else {4188 } else {
4199 return 0xf0;4189 return 0xf0;
4200 }4190 }
...@@ -4208,17 +4198,17 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {...@@ -4208,17 +4198,17 @@ fn sectionRank(self: *Elf, shndx: u16) u8 {
42084198
4209 elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7,4199 elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7,
4210 elf.SHT_SYMTAB => return 0xfa,4200 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,
4212 else => return 0xff,4202 else => return 0xff,
4213 }4203 }
4214}4204}
42154205
4216fn sortSections(self: *Elf) !void {4206fn sortShdrs(self: *Elf) !void {
4217 const Entry = struct {4207 const Entry = struct {
4218 shndx: u16,4208 shndx: u16,
42194209
4220 pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool {4210 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);
4222 }4212 }
4223 };4213 };
42244214
...@@ -4328,6 +4318,20 @@ fn sortSections(self: *Elf) !void {...@@ -4328,6 +4318,20 @@ fn sortSections(self: *Elf) !void {
4328 shdr.sh_info = self.plt_section_index.?;4318 shdr.sh_info = self.plt_section_index.?;
4329 }4319 }
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
4331 if (self.zig_module_index) |index| {4335 if (self.zig_module_index) |index| {
4332 const zig_module = self.file(index).?.zig_module;4336 const zig_module = self.file(index).?.zig_module;
4333 for (zig_module.atoms.items) |atom_index| {4337 for (zig_module.atoms.items) |atom_index| {
...@@ -4484,15 +4488,19 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 {...@@ -4484,15 +4488,19 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 {
44844488
4485/// Calculates how many segments (PT_LOAD progam headers) are required4489/// Calculates how many segments (PT_LOAD progam headers) are required
4486/// to cover the set of sections.4490/// to cover the set of sections.
4491/// We permit a maximum of 3**2 number of segments.
4487fn calcNumberOfSegments(self: *Elf) usize {4492fn calcNumberOfSegments(self: *Elf) usize {
4488 var count: usize = 0;4493 var covers: [9]bool = [_]bool{false} ** 9;
4489 var flags: u64 = 0;
4490 for (self.shdrs.items, 0..) |shdr, shndx| {4494 for (self.shdrs.items, 0..) |shdr, shndx| {
4491 if (shdr.sh_type == elf.SHT_NULL) continue;4495 if (shdr.sh_type == elf.SHT_NULL) continue;
4492 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;4496 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
4493 if (self.isZigSection(@intCast(shndx))) continue;4497 if (self.isZigSection(@intCast(shndx))) continue;
4494 if (flags != shdrToPhdrFlags(shdr.sh_flags)) count += 1;4498 const flags = shdrToPhdrFlags(shdr.sh_flags);
4495 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;
4496 }4504 }
4497 return count;4505 return count;
4498}4506}
...@@ -4564,34 +4572,22 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {...@@ -4564,34 +4572,22 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
4564 // virtual and file offsets. However, the simple one will do for one4572 // virtual and file offsets. However, the simple one will do for one
4565 // as we are more interested in quick turnaround and compatibility4573 // as we are more interested in quick turnaround and compatibility
4566 // with `findFreeSpace` mechanics than anything else.4574 // with `findFreeSpace` mechanics than anything else.
4575 const Cover = std.ArrayList(u16);
4567 const gpa = self.base.allocator;4576 const gpa = self.base.allocator;
4568 const nphdrs = self.calcNumberOfSegments();4577 var covers: [9]Cover = undefined;
4569 var covers = try gpa.alloc(struct { start: u16, len: u16 }, nphdrs);4578 for (&covers) |*cover| {
4570 defer gpa.free(covers);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| {
4573 if (shdr.sh_type == elf.SHT_NULL) continue;4586 if (shdr.sh_type == elf.SHT_NULL) continue;
4574 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;4587 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
4575 if (self.isZigSection(@intCast(in))) continue;4588 if (self.isZigSection(@intCast(shndx))) continue;
4576 break @as(u16, @intCast(in));4589 const flags = shdrToPhdrFlags(shdr.sh_flags);
4577 } else @as(u16, @intCast(self.shdrs.items.len));4590 try covers[flags - 1].append(@intCast(shndx));
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;
4595 }4591 }
45964592
4597 // Now we can proceed with allocating the sections in virtual memory.4593 // Now we can proceed with allocating the sections in virtual memory.
...@@ -4603,10 +4599,11 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {...@@ -4603,10 +4599,11 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
4603 var addr = phdr_table.p_vaddr + phdr_table.p_memsz;4599 var addr = phdr_table.p_vaddr + phdr_table.p_memsz;
46044600
4605 for (covers) |cover| {4601 for (covers) |cover| {
4606 const slice = self.shdrs.items[cover.start..][0..cover.len];4602 if (cover.items.len == 0) continue;
46074603
4608 var @"align": u64 = self.page_size;4604 var @"align": u64 = self.page_size;
4609 for (slice) |shdr| {4605 for (cover.items) |shndx| {
4606 const shdr = self.shdrs.items[shndx];
4610 if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) continue;4607 if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) continue;
4611 @"align" = @max(@"align", shdr.sh_addralign);4608 @"align" = @max(@"align", shdr.sh_addralign);
4612 }4609 }
...@@ -4616,8 +4613,9 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {...@@ -4616,8 +4613,9 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
4616 var memsz: u64 = 0;4613 var memsz: u64 = 0;
4617 var filesz: u64 = 0;4614 var filesz: u64 = 0;
4618 var i: usize = 0;4615 var i: usize = 0;
4619 while (i < cover.len) : (i += 1) {4616 while (i < cover.items.len) : (i += 1) {
4620 const shdr = &slice[i];4617 const shndx = cover.items[i];
4618 const shdr = &self.shdrs.items[shndx];
4621 if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) {4619 if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) {
4622 // .tbss is a little special as it's used only by the loader meaning it doesn't4620 // .tbss is a little special as it's used only by the loader meaning it doesn't
4623 // need to be actually mmap'ed at runtime. We still need to correctly increment4621 // 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 {...@@ -4632,19 +4630,20 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
4632 // .data 0x104630 // .data 0x10
4633 // ...4631 // ...
4634 var tbss_addr = addr;4632 var tbss_addr = addr;
4635 while (i < cover.len and4633 while (i < cover.items.len and
4636 slice[i].sh_type == elf.SHT_NOBITS and4634 self.shdrs.items[cover.items[i]].sh_type == elf.SHT_NOBITS and
4637 slice[i].sh_flags & elf.SHF_TLS != 0) : (i += 1)4635 self.shdrs.items[cover.items[i]].sh_flags & elf.SHF_TLS != 0) : (i += 1)
4638 {4636 {
4639 const tbss_shdr = &slice[i];4637 const tbss_shndx = cover.items[i];
4640 tbss_addr = alignment.@"align"(cover.start + i, tbss_shdr.sh_addralign, tbss_addr);4638 const tbss_shdr = &self.shdrs.items[tbss_shndx];
4639 tbss_addr = alignment.@"align"(tbss_shndx, tbss_shdr.sh_addralign, tbss_addr);
4641 tbss_shdr.sh_addr = tbss_addr;4640 tbss_shdr.sh_addr = tbss_addr;
4642 tbss_addr += tbss_shdr.sh_size;4641 tbss_addr += tbss_shdr.sh_size;
4643 }4642 }
4644 i -= 1;4643 i -= 1;
4645 continue;4644 continue;
4646 }4645 }
4647 const next = alignment.@"align"(cover.start + i, shdr.sh_addralign, addr);4646 const next = alignment.@"align"(shndx, shdr.sh_addralign, addr);
4648 const padding = next - addr;4647 const padding = next - addr;
4649 addr = next;4648 addr = next;
4650 shdr.sh_addr = addr;4649 shdr.sh_addr = addr;
...@@ -4655,23 +4654,25 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {...@@ -4655,23 +4654,25 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
4655 addr += shdr.sh_size;4654 addr += shdr.sh_size;
4656 }4655 }
46574656
4657 const first = self.shdrs.items[cover.items[0]];
4658 var off = self.findFreeSpace(filesz, @"align");4658 var off = self.findFreeSpace(filesz, @"align");
4659 const phndx = try self.addPhdr(.{4659 const phndx = try self.addPhdr(.{
4660 .type = elf.PT_LOAD,4660 .type = elf.PT_LOAD,
4661 .offset = off,4661 .offset = off,
4662 .addr = slice[0].sh_addr,4662 .addr = first.sh_addr,
4663 .memsz = memsz,4663 .memsz = memsz,
4664 .filesz = filesz,4664 .filesz = filesz,
4665 .@"align" = @"align",4665 .@"align" = @"align",
4666 .flags = shdrToPhdrFlags(slice[0].sh_flags),4666 .flags = shdrToPhdrFlags(first.sh_flags),
4667 });4667 });
46684668
4669 for (slice, 0..) |*shdr, ii| {4669 for (cover.items) |shndx| {
4670 const shdr = &self.shdrs.items[shndx];
4670 if (shdr.sh_type == elf.SHT_NOBITS) continue;4671 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);
4672 shdr.sh_offset = off;4673 shdr.sh_offset = off;
4673 off += shdr.sh_size;4674 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);
4675 }4676 }
46764677
4677 addr += self.page_size;4678 addr += self.page_size;