Commit 46cf4c5d93

Jakub Konka <kubkon@jakubkonka.com>
2023-10-15 16:05:43
elf: sort phdr table
1 parent 5423778
Changed files (1)
src
link
src/link/Elf.zig
@@ -1573,6 +1573,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
 
     self.allocatePhdrTable();
     try self.allocateAllocSections();
+    try self.sortPhdrs();
     try self.allocateNonAllocSections();
     self.allocateSpecialPhdrs();
     self.allocateAtoms();
@@ -4076,6 +4077,77 @@ fn setHashSections(self: *Elf) !void {
     }
 }
 
+fn phdrRank(self: *Elf, phndx: u16) u8 {
+    const phdr = self.phdrs.items[phndx];
+    const flags = phdr.p_flags;
+    switch (phdr.p_type) {
+        elf.PT_NULL => return 0,
+        elf.PT_PHDR => return 1,
+        elf.PT_INTERP => return 2,
+        elf.PT_LOAD => if (flags & elf.PF_X != 0) {
+            return 4;
+        } else if (flags & elf.PF_W != 0) {
+            return 5;
+        } else {
+            return 3;
+        },
+        elf.PT_DYNAMIC, elf.PT_TLS => return 6,
+        elf.PT_GNU_EH_FRAME => return 7,
+        elf.PT_GNU_STACK => return 8,
+        else => return 0xf,
+    }
+}
+
+fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
+    const Entry = struct {
+        phndx: u16,
+
+        pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool {
+            return elf_file.phdrRank(lhs.phndx) < elf_file.phdrRank(rhs.phndx);
+        }
+    };
+
+    const gpa = self.base.allocator;
+    var entries = try std.ArrayList(Entry).initCapacity(gpa, self.phdrs.items.len);
+    defer entries.deinit();
+    for (0..self.phdrs.items.len) |phndx| {
+        entries.appendAssumeCapacity(.{ .phndx = @as(u16, @intCast(phndx)) });
+    }
+
+    mem.sort(Entry, entries.items, self, Entry.lessThan);
+
+    const backlinks = try gpa.alloc(u16, entries.items.len);
+    defer gpa.free(backlinks);
+    for (entries.items, 0..) |entry, i| {
+        backlinks[entry.phndx] = @as(u16, @intCast(i));
+    }
+
+    var slice = try self.phdrs.toOwnedSlice(gpa);
+    defer gpa.free(slice);
+
+    try self.phdrs.ensureTotalCapacityPrecise(gpa, slice.len);
+    for (entries.items) |sorted| {
+        self.phdrs.appendAssumeCapacity(slice[sorted.phndx]);
+    }
+
+    for (&[_]*?u16{
+        &self.phdr_zig_load_re_index,
+        &self.phdr_zig_got_index,
+        &self.phdr_zig_load_ro_index,
+        &self.phdr_zig_load_zerofill_index,
+        &self.phdr_table_index,
+        &self.phdr_table_load_index,
+        &self.phdr_interp_index,
+        &self.phdr_dynamic_index,
+        &self.phdr_gnu_eh_frame_index,
+        &self.phdr_tls_index,
+    }) |maybe_index| {
+        if (maybe_index.*) |*index| {
+            index.* = backlinks[index.*];
+        }
+    }
+}
+
 fn sectionRank(self: *Elf, shndx: u16) u8 {
     const shdr = self.shdrs.items[shndx];
     const name = self.shstrtab.getAssumeExists(shdr.sh_name);