authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-15 23:08:41+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:06+02:00
logb0e2c6323bfa8f5991546cb96122a29a599e0365
tree4eec1a2217bb6ef914f30c21aac913bda1ee5471
parent6993b3e23e3b8f45f66902ebe23980aa155b343c

elf: sort PT_LOAD by address in PHDR table

Turns out order matters as otherwise we face unexplainable segfaults to do with improper page mapping in static environments (dynamic environments seem unaffected).

1 files changed, 16 insertions(+), 30 deletions(-)

src/link/Elf.zig+16-30
......@@ -3927,20 +3927,9 @@ fn initSpecialPhdrs(self: *Elf) !void {
39273927 .@"align" = 1,
39283928 });
39293929
3930 const has_tls = has_tls: {
3931 if (self.base.options.link_libc and self.isStatic()) {
3932 // Even if we don't emit any TLS data, linking against musl-libc without
3933 // empty TLS phdr leads to a bizarre segfault in `__copy_tls` function.
3934 // So far I haven't been able to work out why that is, but adding an empty
3935 // TLS phdr seems to fix it, so let's go with it for now.
3936 // TODO try to investigate more
3937 break :has_tls true;
3938 }
3939 for (self.shdrs.items) |shdr| {
3940 if (shdr.sh_flags & elf.SHF_TLS != 0) break :has_tls true;
3941 }
3942 break :has_tls false;
3943 };
3930 const has_tls = for (self.shdrs.items) |shdr| {
3931 if (shdr.sh_flags & elf.SHF_TLS != 0) break true;
3932 } else false;
39443933 if (has_tls) {
39453934 self.phdr_tls_index = try self.addPhdr(.{
39463935 .type = elf.PT_TLS,
......@@ -4076,24 +4065,16 @@ fn setHashSections(self: *Elf) !void {
40764065 }
40774066}
40784067
4079fn phdrRank(self: *Elf, phndx: u16) u8 {
4080 const phdr = self.phdrs.items[phndx];
4081 const flags = phdr.p_flags;
4068fn phdrRank(phdr: elf.Elf64_Phdr) u8 {
40824069 switch (phdr.p_type) {
40834070 elf.PT_NULL => return 0,
40844071 elf.PT_PHDR => return 1,
40854072 elf.PT_INTERP => return 2,
4086 elf.PT_LOAD => if (flags & elf.PF_X != 0) {
4087 return 4;
4088 } else if (flags & elf.PF_W != 0) {
4089 return 5;
4090 } else {
4091 return 3;
4092 },
4093 elf.PT_DYNAMIC, elf.PT_TLS => return 6,
4094 elf.PT_GNU_EH_FRAME => return 7,
4095 elf.PT_GNU_STACK => return 8,
4096 else => return 0xf,
4073 elf.PT_LOAD => return 3,
4074 elf.PT_DYNAMIC, elf.PT_TLS => return 4,
4075 elf.PT_GNU_EH_FRAME => return 5,
4076 elf.PT_GNU_STACK => return 6,
4077 else => return 7,
40974078 }
40984079}
40994080
......@@ -4102,7 +4083,12 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
41024083 phndx: u16,
41034084
41044085 pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool {
4105 return elf_file.phdrRank(lhs.phndx) < elf_file.phdrRank(rhs.phndx);
4086 const lhs_phdr = elf_file.phdrs.items[lhs.phndx];
4087 const rhs_phdr = elf_file.phdrs.items[rhs.phndx];
4088 const lhs_rank = phdrRank(lhs_phdr);
4089 const rhs_rank = phdrRank(rhs_phdr);
4090 if (lhs_rank == rhs_rank) return lhs_phdr.p_vaddr < rhs_phdr.p_vaddr;
4091 return lhs_rank < rhs_rank;
41064092 }
41074093 };
41084094
......@@ -4674,7 +4660,7 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
46744660 try self.phdr_to_shdr_table.putNoClobber(gpa, shndx, phndx);
46754661 }
46764662
4677 addr += self.page_size;
4663 addr = mem.alignForward(u64, addr, self.page_size);
46784664 }
46794665}
46804666