Commit 5148e38751

Jakub Konka <kubkon@jakubkonka.com>
2023-10-10 14:55:08
elf: create and allocate special PHDRs out of the loop
1 parent 59fcf16
Changed files (1)
src
link
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);