From 5148e38751e5f9415e226a6bc7f8f8c0d104f818 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 10 Oct 2023 14:55:08 +0200 Subject: elf: create and allocate special PHDRs out of the loop --- src/link/Elf.zig | 160 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 93 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 5f4cd627f7..6bee54e36a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -30,15 +30,13 @@ output_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom. /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. /// Same order as in the file. phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{}, -/// The index into the program headers of the PT_PHDR program header -phdr_table_index: ?u16 = null, + +/// Tracked loadable segments during incremental linking. /// The index into the program headers of the PT_LOAD program header containing the phdr /// Most linkers would merge this with phdr_load_ro_index, /// but incremental linking means we can't ensure they are consecutive. /// If this segment is not needed, it won't get emitted. phdr_table_load_index: ?u16 = null, -/// The index into the program headers of the PT_TLS program header. -phdr_tls_index: ?u16 = null, /// The index into the program headers of a PT_LOAD program header with Read and Execute flags phdr_load_re_zig_index: ?u16 = null, /// The index into the program headers of the global offset table. @@ -51,6 +49,20 @@ phdr_load_rw_zig_index: ?u16 = null, /// The index into the program headers of a PT_LOAD program header with zerofill data. phdr_load_zerofill_zig_index: ?u16 = null, +/// Special program headers +/// PT_PHDR +phdr_table_index: ?u16 = null, +/// PT_INTERP +phdr_interp_index: ?u16 = null, +/// PT_DYNAMIC +phdr_dynamic_index: ?u16 = null, +/// PT_GNU_EH_FRAME +phdr_gnu_eh_frame_index: ?u16 = null, +/// PT_GNU_STACK +phdr_gnu_stack_index: ?u16 = null, +/// PT_TLS +phdr_tls_index: ?u16 = null, + entry_index: ?Symbol.Index = null, page_size: u32, default_sym_version: elf.Elf64_Versym, @@ -1607,6 +1619,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // Generate and emit non-incremental sections. try self.initSections(); + try self.initSpecialPhdrs(); try self.sortSections(); for (self.objects.items) |index| { try self.file(index).?.object.addAtomsToOutputSections(self); @@ -1619,6 +1632,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node try self.updateSectionSizes(); try self.allocateSections(); + self.allocateSpecialPhdrs(); self.allocateAtoms(); self.allocateLinkerDefinedSymbols(); @@ -4025,6 +4039,35 @@ fn initSections(self: *Elf) !void { } } +fn initSpecialPhdrs(self: *Elf) !void { + if (self.interp_section_index != null) { + self.phdr_interp_index = try self.addPhdr(.{ + .type = elf.PT_INTERP, + .flags = elf.PF_R, + .@"align" = 1, + }); + } + if (self.dynamic_section_index != null) { + self.phdr_dynamic_index = try self.addPhdr(.{ + .type = elf.PT_DYNAMIC, + .flags = elf.PF_R | elf.PF_W, + }); + } + if (self.eh_frame_hdr_section_index != null) { + self.phdr_gnu_eh_frame_index = try self.addPhdr(.{ + .type = elf.PT_GNU_EH_FRAME, + .flags = elf.PF_R, + }); + } + self.phdr_gnu_stack_index = try self.addPhdr(.{ + .type = elf.PT_GNU_STACK, + .flags = elf.PF_W | elf.PF_R, + .memsz = self.base.options.stack_size_override orelse 0, + .@"align" = 1, + }); + // self.phdr_table_dirty = true; +} + /// We need to sort constructors/destuctors in the following sections: /// * .init_array /// * .fini_array @@ -4416,31 +4459,33 @@ fn updateSectionSizes(self: *Elf) !void { } } +/// The assumed layout of PHDRs in file is as follows: +/// PT_PHDR +/// PT_INTERP +/// PT_DYNAMIC +/// PT_GNU_EH_FRAME +/// PT_GNU_STACK +/// PT_LOAD... +/// PT_TLS fn resetPhdrs(self: *Elf) !void { const gpa = self.base.allocator; const phdrs = try self.phdrs.toOwnedSlice(gpa); try self.phdrs.ensureUnusedCapacity(gpa, phdrs.len); - if (self.phdr_table_index) |phndx| { - self.phdrs.appendAssumeCapacity(phdrs[phndx]); + for (&[_]?u16{ + self.phdr_table_index.?, + self.phdr_interp_index, + self.phdr_dynamic_index, + self.phdr_gnu_eh_frame_index, + self.phdr_gnu_stack_index, + }) |maybe_index| { + if (maybe_index) |index| { + self.phdrs.appendAssumeCapacity(phdrs[index]); + } } } -fn initPhdrs(self: *Elf) !void { - // Add INTERP phdr if required - if (self.interp_section_index) |index| { - const shdr = self.shdrs.items[index]; - _ = try self.addPhdr(.{ - .type = elf.PT_INTERP, - .flags = elf.PF_R, - .@"align" = 1, - .offset = shdr.sh_offset, - .addr = shdr.sh_addr, - .filesz = shdr.sh_size, - .memsz = shdr.sh_size, - }); - } - +fn initSegments(self: *Elf) !void { // Add LOAD phdrs const slice = self.shdrs.items; { @@ -4503,51 +4548,6 @@ fn initPhdrs(self: *Elf) !void { } } } - - // Add DYNAMIC phdr - if (self.dynamic_section_index) |index| { - const shdr = self.shdrs.items[index]; - _ = try self.addPhdr(.{ - .type = elf.PT_DYNAMIC, - .flags = elf.PF_R | elf.PF_W, - .@"align" = shdr.sh_addralign, - .offset = shdr.sh_offset, - .addr = shdr.sh_addr, - .memsz = shdr.sh_size, - .filesz = shdr.sh_size, - }); - } - - // Add PT_GNU_EH_FRAME phdr if required. - if (self.eh_frame_hdr_section_index) |index| { - const shdr = self.shdrs.items[index]; - _ = try self.addPhdr(.{ - .type = elf.PT_GNU_EH_FRAME, - .flags = elf.PF_R, - .@"align" = shdr.sh_addralign, - .offset = shdr.sh_offset, - .addr = shdr.sh_addr, - .memsz = shdr.sh_size, - .filesz = shdr.sh_size, - }); - } - - // Add PT_GNU_STACK phdr that controls some stack attributes that apparently may or may not - // be respected by the OS. - _ = try self.addPhdr(.{ - .type = elf.PT_GNU_STACK, - .flags = elf.PF_W | elf.PF_R, - .memsz = self.base.options.stack_size_override orelse 0, - .@"align" = 1, - }); - - // Backpatch size of the PHDR phdr - { - const phdr = &self.phdrs.items[self.phdr_table_index.?]; - const size = @sizeOf(elf.Elf64_Phdr) * self.phdrs.items.len; - phdr.p_filesz = size; - phdr.p_memsz = size; - } } fn addShdrToPhdr(self: *Elf, phdr_index: u16, shdr: *const elf.Elf64_Shdr) !void { @@ -4716,11 +4716,37 @@ fn allocateSections(self: *Elf) !void { self.allocateSectionsInMemory(base_offset); self.allocateSectionsInFile(base_offset); try self.resetPhdrs(); - try self.initPhdrs(); + try self.initSegments(); if (nphdrs == self.phdrs.items.len) break; } } +fn allocateSpecialPhdrs(self: *Elf) void { + for (&[_]struct { ?u16, ?u16 }{ + .{ self.phdr_interp_index, self.interp_section_index }, + .{ self.phdr_dynamic_index, self.dynamic_section_index }, + .{ self.phdr_gnu_eh_frame_index, self.eh_frame_hdr_section_index }, + }) |pair| { + if (pair[0]) |index| { + const shdr = self.shdrs.items[pair[1].?]; + const phdr = &self.phdrs.items[index]; + phdr.p_align = shdr.sh_addralign; + phdr.p_offset = shdr.sh_offset; + phdr.p_vaddr = shdr.sh_addr; + phdr.p_filesz = shdr.sh_size; + phdr.p_memsz = shdr.sh_size; + } + } + + { + // Backpatch size of the PHDR phdr + const phdr = &self.phdrs.items[self.phdr_table_index.?]; + const size = @sizeOf(elf.Elf64_Phdr) * self.phdrs.items.len; + phdr.p_filesz = size; + phdr.p_memsz = size; + } +} + fn allocateAtoms(self: *Elf) void { for (self.objects.items) |index| { self.file(index).?.object.allocateAtoms(self); -- cgit v1.2.3