elf: make init/fini sorting deterministic

This commit is contained in:
Jakub Konka
2023-10-09 14:23:46 +02:00
parent 44f3085851
commit 1efc0519ce
2 changed files with 34 additions and 21 deletions

View File

@@ -4123,6 +4123,21 @@ fn initSections(self: *Elf) !void {
}
}
/// We need to sort constructors/destuctors in the following sections:
/// * .init_array
/// * .fini_array
/// * .preinit_array
/// * .ctors
/// * .dtors
/// The prority of inclusion is defined as part of the input section's name. For example, .init_array.10000.
/// If no priority value has been specified,
/// * for .init_array, .fini_array and .preinit_array, we automatically assign that section max value of maxInt(i32)
/// and push it to the back of the queue,
/// * for .ctors and .dtors, we automatically assign that section min value of -1
/// and push it to the front of the queue,
/// crtbegin and ctrend are assigned minInt(i32) and maxInt(i32) respectively.
/// Ties are broken by the file prority which corresponds to the inclusion of input sections in this output section
/// we are about to sort.
fn sortInitFini(self: *Elf) !void {
const gpa = self.base.allocator;
@@ -4130,8 +4145,10 @@ fn sortInitFini(self: *Elf) !void {
priority: i32,
atom_index: Atom.Index,
pub fn lessThan(ctx: void, lhs: @This(), rhs: @This()) bool {
_ = ctx;
pub fn lessThan(ctx: *Elf, lhs: @This(), rhs: @This()) bool {
if (lhs.priority == rhs.priority) {
return ctx.atom(lhs.atom_index).?.priority(ctx) < ctx.atom(rhs.atom_index).?.priority(ctx);
}
return lhs.priority < rhs.priority;
}
};
@@ -4177,7 +4194,7 @@ fn sortInitFini(self: *Elf) !void {
entries.appendAssumeCapacity(.{ .priority = priority, .atom_index = atom_index });
}
mem.sort(Entry, entries.items, {}, Entry.lessThan);
mem.sort(Entry, entries.items, self, Entry.lessThan);
atom_list.clearRetainingCapacity();
for (entries.items) |entry| {
@@ -4387,8 +4404,18 @@ fn sortSections(self: *Elf) !void {
}
fn updateSectionSizes(self: *Elf) !void {
for (self.objects.items) |index| {
self.file(index).?.object.updateSectionSizes(self);
for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
if (atom_list.items.len == 0) continue;
const shdr = &self.shdrs.items[shndx];
for (atom_list.items) |atom_index| {
const atom_ptr = self.atom(atom_index) orelse continue;
if (!atom_ptr.flags.alive) continue;
const offset = atom_ptr.alignment.forward(shdr.sh_size);
const padding = offset - shdr.sh_size;
atom_ptr.value = offset;
shdr.sh_size += padding + atom_ptr.size;
shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1));
}
}
if (self.eh_frame_section_index) |index| {
@@ -4668,12 +4695,12 @@ fn allocateSectionsInMemory(self: *Elf, base_offset: u64) !void {
tls_start_align: u64 = 1,
first_tls_index: ?usize = null,
inline fn isFirstTlsShdr(this: @This(), other: usize) bool {
fn isFirstTlsShdr(this: @This(), other: usize) bool {
if (this.first_tls_index) |index| return index == other;
return false;
}
inline fn @"align"(this: @This(), index: usize, sh_addralign: u64, addr: u64) u64 {
fn @"align"(this: @This(), index: usize, sh_addralign: u64, addr: u64) u64 {
const alignment = if (this.isFirstTlsShdr(index)) this.tls_start_align else sh_addralign;
return mem.alignForward(u64, addr, alignment);
}

View File

@@ -630,7 +630,6 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
const shdr = atom.inputShdr(elf_file);
atom.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
if (shdr.sh_type == elf.SHT_NOBITS) continue;
const gpa = elf_file.base.allocator;
const gop = try elf_file.output_sections.getOrPut(gpa, atom.output_section_index);
if (!gop.found_existing) gop.value_ptr.* = .{};
@@ -638,19 +637,6 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
}
}
pub fn updateSectionSizes(self: Object, elf_file: *Elf) void {
for (self.atoms.items) |atom_index| {
const atom = elf_file.atom(atom_index) orelse continue;
if (!atom.flags.alive) continue;
const shdr = &elf_file.shdrs.items[atom.output_section_index];
const offset = atom.alignment.forward(shdr.sh_size);
const padding = offset - shdr.sh_size;
atom.value = offset;
shdr.sh_size += padding + atom.size;
shdr.sh_addralign = @max(shdr.sh_addralign, atom.alignment.toByteUnits(1));
}
}
pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
for (self.atoms.items) |atom_index| {
const atom = elf_file.atom(atom_index) orelse continue;