Commit 4b082d89c9

Jakub Konka <kubkon@jakubkonka.com>
2023-09-10 21:58:42
elf: decouple notion of atom free list from shdrs
Not every section will have the need for such a free list.
1 parent a3ce011
src/link/Elf/Atom.zig
@@ -79,9 +79,10 @@ pub fn freeRelocations(elf_file: *Elf, atom_index: Index) void {
 }
 
 pub fn allocate(self: *Atom, elf_file: *Elf) !void {
-    const shdr = &elf_file.sections.items(.shdr)[self.output_section_index];
-    const free_list = &elf_file.sections.items(.free_list)[self.output_section_index];
-    const last_atom_index = &elf_file.sections.items(.last_atom_index)[self.output_section_index];
+    const shdr = &elf_file.shdrs.items[self.output_section_index];
+    const meta = elf_file.last_atom_and_free_list_table.getPtr(self.output_section_index).?;
+    const free_list = &meta.free_list;
+    const last_atom_index = &meta.last_atom_index;
     const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
     const alignment = try std.math.powi(u64, 2, self.alignment);
 
@@ -208,7 +209,9 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
 
     const gpa = elf_file.base.allocator;
     const shndx = self.output_section_index;
-    const free_list = &elf_file.sections.items(.free_list)[shndx];
+    const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;
+    const free_list = &meta.free_list;
+    const last_atom_index = &meta.last_atom_index;
     var already_have_free_list_node = false;
     {
         var i: usize = 0;
@@ -225,7 +228,6 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
         }
     }
 
-    const last_atom_index = &elf_file.sections.items(.last_atom_index)[shndx];
     if (elf_file.atom(last_atom_index.*)) |last_atom| {
         if (last_atom.atom_index == self.atom_index) {
             if (elf_file.atom(self.prev_index)) |_| {
src/link/Elf/synthetic_sections.zig
@@ -29,7 +29,7 @@ pub const GotSection = struct {
 
         pub fn address(entry: Entry, elf_file: *Elf) u64 {
             const ptr_bytes = @as(u64, elf_file.archPtrWidthBytes());
-            const shdr = &elf_file.sections.items(.shdr)[elf_file.got_section_index.?];
+            const shdr = &elf_file.shdrs.items[elf_file.got_section_index.?];
             return shdr.sh_addr + @as(u64, entry.cell_index) * ptr_bytes;
         }
     };
@@ -124,7 +124,7 @@ pub const GotSection = struct {
         }
         const endian = elf_file.base.options.target.cpu.arch.endian();
         const entry = got.entries.items[index];
-        const shdr = &elf_file.sections.items(.shdr)[elf_file.got_section_index.?];
+        const shdr = &elf_file.shdrs.items[elf_file.got_section_index.?];
         const off = shdr.sh_offset + @as(u64, entry_size) * entry.cell_index;
         const vaddr = shdr.sh_addr + @as(u64, entry_size) * entry.cell_index;
         const value = elf_file.symbol(entry.symbol_index).value;
src/link/Dwarf.zig
@@ -1108,7 +1108,7 @@ pub fn commitDeclState(
                         switch (self.bin_file.tag) {
                             .elf => {
                                 const elf_file = self.bin_file.cast(File.Elf).?;
-                                const debug_line_sect = &elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
+                                const debug_line_sect = &elf_file.shdrs.items[elf_file.debug_line_section_index.?];
                                 const file_pos = debug_line_sect.sh_offset + src_fn.off;
                                 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
                             },
@@ -1170,7 +1170,7 @@ pub fn commitDeclState(
                     const elf_file = self.bin_file.cast(File.Elf).?;
                     const shdr_index = elf_file.debug_line_section_index.?;
                     try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
-                    const debug_line_sect = elf_file.sections.items(.shdr)[shdr_index];
+                    const debug_line_sect = elf_file.shdrs.items[shdr_index];
                     const file_pos = debug_line_sect.sh_offset + src_fn.off;
                     try pwriteDbgLineNops(
                         elf_file.base.file.?,
@@ -1337,7 +1337,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom_index: Atom.Index, len: u32)
                 switch (self.bin_file.tag) {
                     .elf => {
                         const elf_file = self.bin_file.cast(File.Elf).?;
-                        const debug_info_sect = &elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?];
+                        const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?];
                         const file_pos = debug_info_sect.sh_offset + atom.off;
                         try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
                     },
@@ -1415,7 +1415,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons
             const elf_file = self.bin_file.cast(File.Elf).?;
             const shdr_index = elf_file.debug_info_section_index.?;
             try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
-            const debug_info_sect = elf_file.sections.items(.shdr)[shdr_index];
+            const debug_info_sect = &elf_file.shdrs.items[shdr_index];
             const file_pos = debug_info_sect.sh_offset + atom.off;
             try pwriteDbgInfoNops(
                 elf_file.base.file.?,
@@ -1496,7 +1496,7 @@ pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: Module.Decl.
     switch (self.bin_file.tag) {
         .elf => {
             const elf_file = self.bin_file.cast(File.Elf).?;
-            const shdr = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
+            const shdr = elf_file.shdrs.items[elf_file.debug_line_section_index.?];
             const file_pos = shdr.sh_offset + atom.off + self.getRelocDbgLineOff();
             try elf_file.base.file.?.pwriteAll(&data, file_pos);
         },
@@ -1713,7 +1713,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
             const elf_file = self.bin_file.cast(File.Elf).?;
             const shdr_index = elf_file.debug_abbrev_section_index.?;
             try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false);
-            const debug_abbrev_sect = elf_file.sections.items(.shdr)[shdr_index];
+            const debug_abbrev_sect = &elf_file.shdrs.items[shdr_index];
             const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;
             try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
         },
@@ -1828,7 +1828,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
     switch (self.bin_file.tag) {
         .elf => {
             const elf_file = self.bin_file.cast(File.Elf).?;
-            const debug_info_sect = elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?];
+            const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?];
             const file_pos = debug_info_sect.sh_offset;
             try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
         },
@@ -2147,7 +2147,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
             const elf_file = self.bin_file.cast(File.Elf).?;
             const shdr_index = elf_file.debug_aranges_section_index.?;
             try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false);
-            const debug_aranges_sect = elf_file.sections.items(.shdr)[shdr_index];
+            const debug_aranges_sect = &elf_file.shdrs.items[shdr_index];
             const file_pos = debug_aranges_sect.sh_offset;
             try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);
         },
@@ -2312,9 +2312,9 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
             .elf => {
                 const elf_file = self.bin_file.cast(File.Elf).?;
                 const shdr_index = elf_file.debug_line_section_index.?;
-                const needed_size = elf_file.sections.items(.shdr)[shdr_index].sh_size + delta;
+                const needed_size = elf_file.shdrs.items[shdr_index].sh_size + delta;
                 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
-                const file_pos = elf_file.sections.items(.shdr)[shdr_index].sh_offset + first_fn.off;
+                const file_pos = elf_file.shdrs.items[shdr_index].sh_offset + first_fn.off;
 
                 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);
                 if (amt != buffer.len) return error.InputOutput;
@@ -2377,7 +2377,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
     switch (self.bin_file.tag) {
         .elf => {
             const elf_file = self.bin_file.cast(File.Elf).?;
-            const debug_line_sect = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
+            const debug_line_sect = &elf_file.shdrs.items[elf_file.debug_line_section_index.?];
             const file_pos = debug_line_sect.sh_offset;
             try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
         },
@@ -2500,7 +2500,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
             switch (self.bin_file.tag) {
                 .elf => {
                     const elf_file = self.bin_file.cast(File.Elf).?;
-                    const debug_info_sect = &elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?];
+                    const debug_info_sect = &elf_file.shdrs.items[elf_file.debug_info_section_index.?];
                     break :blk debug_info_sect.sh_offset;
                 },
                 .macho => {
src/link/Elf.zig
@@ -12,7 +12,10 @@ linker_defined_index: ?File.Index = null,
 
 /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
 /// Same order as in the file.
-sections: std.MultiArrayList(Section) = .{},
+shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},
+/// Given index to a section, pulls index of containing phdr if any.
+phdr_to_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},
+/// File offset into the shdr table.
 shdr_table_offset: ?u64 = null,
 
 /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
@@ -85,7 +88,6 @@ symbols: std.ArrayListUnmanaged(Symbol) = .{},
 symbols_extra: std.ArrayListUnmanaged(u32) = .{},
 resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
 unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
-
 symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
 
 phdr_table_dirty: bool = false,
@@ -109,6 +111,8 @@ decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
 
 /// List of atoms that are owned directly by the linker.
 atoms: std.ArrayListUnmanaged(Atom) = .{},
+/// Table of last atom index in a section and matching atom free list if any.
+last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList) = .{},
 
 /// Table of unnamed constants associated with a parent `Decl`.
 /// We store them here so that we can free the constants whenever the `Decl`
@@ -176,21 +180,18 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
     try self.atoms.append(allocator, .{});
     // Append null file at index 0
     try self.files.append(allocator, .null);
-    // There must always be a null section in index 0
-    try self.sections.append(allocator, .{
-        .shdr = .{
-            .sh_name = 0,
-            .sh_type = elf.SHT_NULL,
-            .sh_flags = 0,
-            .sh_addr = 0,
-            .sh_offset = 0,
-            .sh_size = 0,
-            .sh_link = 0,
-            .sh_info = 0,
-            .sh_addralign = 0,
-            .sh_entsize = 0,
-        },
-        .phdr_index = undefined,
+    // There must always be a null shdr in index 0
+    try self.shdrs.append(allocator, .{
+        .sh_name = 0,
+        .sh_type = elf.SHT_NULL,
+        .sh_flags = 0,
+        .sh_addr = 0,
+        .sh_offset = 0,
+        .sh_size = 0,
+        .sh_link = 0,
+        .sh_info = 0,
+        .sh_addralign = 0,
+        .sh_entsize = 0,
     });
 
     try self.populateMissingMetadata();
@@ -256,11 +257,8 @@ pub fn deinit(self: *Elf) void {
     };
     self.files.deinit(gpa);
 
-    for (self.sections.items(.free_list)) |*free_list| {
-        free_list.deinit(gpa);
-    }
-    self.sections.deinit(gpa);
-
+    self.shdrs.deinit(gpa);
+    self.phdr_to_shdr_table.deinit(gpa);
     self.phdrs.deinit(gpa);
     self.shstrtab.deinit(gpa);
     self.strtab.deinit(gpa);
@@ -281,6 +279,10 @@ pub fn deinit(self: *Elf) void {
     }
 
     self.atoms.deinit(gpa);
+    for (self.last_atom_and_free_list_table.values()) |*value| {
+        value.free_list.deinit(gpa);
+    }
+    self.last_atom_and_free_list_table.deinit(gpa);
     self.lazy_syms.deinit(gpa);
 
     {
@@ -332,7 +334,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
 
     if (self.shdr_table_offset) |off| {
         const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);
-        const tight_size = self.sections.slice().len * shdr_size;
+        const tight_size = self.shdrs.items.len * shdr_size;
         const increased_size = padToIdeal(tight_size);
         const test_end = off + increased_size;
         if (end > off and start < test_end) {
@@ -340,7 +342,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
         }
     }
 
-    for (self.sections.items(.shdr)) |section| {
+    for (self.shdrs.items) |section| {
         const increased_size = padToIdeal(section.sh_size);
         const test_end = section.sh_offset + increased_size;
         if (end > section.sh_offset and start < test_end) {
@@ -364,7 +366,7 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
     if (self.shdr_table_offset) |off| {
         if (off > start and off < min_pos) min_pos = off;
     }
-    for (self.sections.items(.shdr)) |section| {
+    for (self.shdrs.items) |section| {
         if (section.sh_offset <= start) continue;
         if (section.sh_offset < min_pos) min_pos = section.sh_offset;
     }
@@ -522,197 +524,174 @@ pub fn populateMissingMetadata(self: *Elf) !void {
     }
 
     if (self.shstrtab_section_index == null) {
-        self.shstrtab_section_index = @as(u16, @intCast(self.sections.slice().len));
+        self.shstrtab_section_index = @as(u16, @intCast(self.shdrs.items.len));
         assert(self.shstrtab.buffer.items.len == 0);
         try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0
         const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1);
         log.debug("found .shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.buffer.items.len });
-        try self.sections.append(gpa, .{
-            .shdr = .{
-                .sh_name = try self.shstrtab.insert(gpa, ".shstrtab"),
-                .sh_type = elf.SHT_STRTAB,
-                .sh_flags = 0,
-                .sh_addr = 0,
-                .sh_offset = off,
-                .sh_size = self.shstrtab.buffer.items.len,
-                .sh_link = 0,
-                .sh_info = 0,
-                .sh_addralign = 1,
-                .sh_entsize = 0,
-            },
-            .phdr_index = undefined,
+        try self.shdrs.append(gpa, .{
+            .sh_name = try self.shstrtab.insert(gpa, ".shstrtab"),
+            .sh_type = elf.SHT_STRTAB,
+            .sh_flags = 0,
+            .sh_addr = 0,
+            .sh_offset = off,
+            .sh_size = self.shstrtab.buffer.items.len,
+            .sh_link = 0,
+            .sh_info = 0,
+            .sh_addralign = 1,
+            .sh_entsize = 0,
         });
         self.shstrtab_dirty = true;
         self.shdr_table_dirty = true;
     }
 
     if (self.strtab_section_index == null) {
-        self.strtab_section_index = @as(u16, @intCast(self.sections.slice().len));
+        self.strtab_section_index = @as(u16, @intCast(self.shdrs.items.len));
         assert(self.strtab.buffer.items.len == 0);
         try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0
         const off = self.findFreeSpace(self.strtab.buffer.items.len, 1);
         log.debug("found .strtab free space 0x{x} to 0x{x}", .{ off, off + self.strtab.buffer.items.len });
-        try self.sections.append(gpa, .{
-            .shdr = .{
-                .sh_name = try self.shstrtab.insert(gpa, ".strtab"),
-                .sh_type = elf.SHT_STRTAB,
-                .sh_flags = 0,
-                .sh_addr = 0,
-                .sh_offset = off,
-                .sh_size = self.strtab.buffer.items.len,
-                .sh_link = 0,
-                .sh_info = 0,
-                .sh_addralign = 1,
-                .sh_entsize = 0,
-            },
-            .phdr_index = undefined,
+        try self.shdrs.append(gpa, .{
+            .sh_name = try self.shstrtab.insert(gpa, ".strtab"),
+            .sh_type = elf.SHT_STRTAB,
+            .sh_flags = 0,
+            .sh_addr = 0,
+            .sh_offset = off,
+            .sh_size = self.strtab.buffer.items.len,
+            .sh_link = 0,
+            .sh_info = 0,
+            .sh_addralign = 1,
+            .sh_entsize = 0,
         });
         self.strtab_dirty = true;
         self.shdr_table_dirty = true;
     }
 
     if (self.text_section_index == null) {
-        self.text_section_index = @as(u16, @intCast(self.sections.slice().len));
+        self.text_section_index = @as(u16, @intCast(self.shdrs.items.len));
         const phdr = &self.phdrs.items[self.phdr_load_re_index.?];
-
-        try self.sections.append(gpa, .{
-            .shdr = .{
-                .sh_name = try self.shstrtab.insert(gpa, ".text"),
-                .sh_type = elf.SHT_PROGBITS,
-                .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
-                .sh_addr = phdr.p_vaddr,
-                .sh_offset = phdr.p_offset,
-                .sh_size = phdr.p_filesz,
-                .sh_link = 0,
-                .sh_info = 0,
-                .sh_addralign = 1,
-                .sh_entsize = 0,
-            },
-            .phdr_index = self.phdr_load_re_index.?,
+        try self.shdrs.append(gpa, .{
+            .sh_name = try self.shstrtab.insert(gpa, ".text"),
+            .sh_type = elf.SHT_PROGBITS,
+            .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
+            .sh_addr = phdr.p_vaddr,
+            .sh_offset = phdr.p_offset,
+            .sh_size = phdr.p_filesz,
+            .sh_link = 0,
+            .sh_info = 0,
+            .sh_addralign = 1,
+            .sh_entsize = 0,
         });
+        try self.phdr_to_shdr_table.putNoClobber(gpa, self.text_section_index.?, self.phdr_load_re_index.?);
+        try self.last_atom_and_free_list_table.putNoClobber(gpa, self.text_section_index.?, .{});
         self.shdr_table_dirty = true;
     }
 
     if (self.got_section_index == null) {
-        self.got_section_index = @as(u16, @intCast(self.sections.slice().len));
+        self.got_section_index = @as(u16, @intCast(self.shdrs.items.len));
         const phdr = &self.phdrs.items[self.phdr_got_index.?];
-
-        try self.sections.append(gpa, .{
-            .shdr = .{
-                .sh_name = try self.shstrtab.insert(gpa, ".got"),
-                .sh_type = elf.SHT_PROGBITS,
-                .sh_flags = elf.SHF_ALLOC,
-                .sh_addr = phdr.p_vaddr,
-                .sh_offset = phdr.p_offset,
-                .sh_size = phdr.p_filesz,
-                .sh_link = 0,
-                .sh_info = 0,
-                .sh_addralign = @as(u16, ptr_size),
-                .sh_entsize = 0,
-            },
-            .phdr_index = self.phdr_got_index.?,
+        try self.shdrs.append(gpa, .{
+            .sh_name = try self.shstrtab.insert(gpa, ".got"),
+            .sh_type = elf.SHT_PROGBITS,
+            .sh_flags = elf.SHF_ALLOC,
+            .sh_addr = phdr.p_vaddr,
+            .sh_offset = phdr.p_offset,
+            .sh_size = phdr.p_filesz,
+            .sh_link = 0,
+            .sh_info = 0,
+            .sh_addralign = @as(u16, ptr_size),
+            .sh_entsize = 0,
         });
+        try self.phdr_to_shdr_table.putNoClobber(gpa, self.got_section_index.?, self.phdr_got_index.?);
         self.shdr_table_dirty = true;
     }
 
     if (self.rodata_section_index == null) {
-        self.rodata_section_index = @as(u16, @intCast(self.sections.slice().len));
+        self.rodata_section_index = @as(u16, @intCast(self.shdrs.items.len));
         const phdr = &self.phdrs.items[self.phdr_load_ro_index.?];
-
-        try self.sections.append(gpa, .{
-            .shdr = .{
-                .sh_name = try self.shstrtab.insert(gpa, ".rodata"),
-                .sh_type = elf.SHT_PROGBITS,
-                .sh_flags = elf.SHF_ALLOC,
-                .sh_addr = phdr.p_vaddr,
-                .sh_offset = phdr.p_offset,
-                .sh_size = phdr.p_filesz,
-                .sh_link = 0,
-                .sh_info = 0,
-                .sh_addralign = 1,
-                .sh_entsize = 0,
-            },
-            .phdr_index = self.phdr_load_ro_index.?,
+        try self.shdrs.append(gpa, .{
+            .sh_name = try self.shstrtab.insert(gpa, ".rodata"),
+            .sh_type = elf.SHT_PROGBITS,
+            .sh_flags = elf.SHF_ALLOC,
+            .sh_addr = phdr.p_vaddr,
+            .sh_offset = phdr.p_offset,
+            .sh_size = phdr.p_filesz,
+            .sh_link = 0,
+            .sh_info = 0,
+            .sh_addralign = 1,
+            .sh_entsize = 0,
         });
+        try self.phdr_to_shdr_table.putNoClobber(gpa, self.rodata_section_index.?, self.phdr_load_ro_index.?);
+        try self.last_atom_and_free_list_table.putNoClobber(gpa, self.rodata_section_index.?, .{});
         self.shdr_table_dirty = true;
     }
 
     if (self.data_section_index == null) {
-        self.data_section_index = @as(u16, @intCast(self.sections.slice().len));
+        self.data_section_index = @as(u16, @intCast(self.shdrs.items.len));
         const phdr = &self.phdrs.items[self.phdr_load_rw_index.?];
-
-        try self.sections.append(gpa, .{
-            .shdr = .{
-                .sh_name = try self.shstrtab.insert(gpa, ".data"),
-                .sh_type = elf.SHT_PROGBITS,
-                .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
-                .sh_addr = phdr.p_vaddr,
-                .sh_offset = phdr.p_offset,
-                .sh_size = phdr.p_filesz,
-                .sh_link = 0,
-                .sh_info = 0,
-                .sh_addralign = @as(u16, ptr_size),
-                .sh_entsize = 0,
-            },
-            .phdr_index = self.phdr_load_rw_index.?,
+        try self.shdrs.append(gpa, .{
+            .sh_name = try self.shstrtab.insert(gpa, ".data"),
+            .sh_type = elf.SHT_PROGBITS,
+            .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
+            .sh_addr = phdr.p_vaddr,
+            .sh_offset = phdr.p_offset,
+            .sh_size = phdr.p_filesz,
+            .sh_link = 0,
+            .sh_info = 0,
+            .sh_addralign = @as(u16, ptr_size),
+            .sh_entsize = 0,
         });
+        try self.phdr_to_shdr_table.putNoClobber(gpa, self.data_section_index.?, self.phdr_load_rw_index.?);
+        try self.last_atom_and_free_list_table.putNoClobber(gpa, self.data_section_index.?, .{});
         self.shdr_table_dirty = true;
     }
 
     if (self.symtab_section_index == null) {
-        self.symtab_section_index = @as(u16, @intCast(self.sections.slice().len));
+        self.symtab_section_index = @as(u16, @intCast(self.shdrs.items.len));
         const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
         const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
         const file_size = self.base.options.symbol_count_hint * each_size;
         const off = self.findFreeSpace(file_size, min_align);
         log.debug("found symtab free space 0x{x} to 0x{x}", .{ off, off + file_size });
-
-        try self.sections.append(gpa, .{
-            .shdr = .{
-                .sh_name = try self.shstrtab.insert(gpa, ".symtab"),
-                .sh_type = elf.SHT_SYMTAB,
-                .sh_flags = 0,
-                .sh_addr = 0,
-                .sh_offset = off,
-                .sh_size = file_size,
-                // The section header index of the associated string table.
-                .sh_link = self.strtab_section_index.?,
-                .sh_info = @as(u32, @intCast(self.symbols.items.len)),
-                .sh_addralign = min_align,
-                .sh_entsize = each_size,
-            },
-            .phdr_index = undefined,
+        try self.shdrs.append(gpa, .{
+            .sh_name = try self.shstrtab.insert(gpa, ".symtab"),
+            .sh_type = elf.SHT_SYMTAB,
+            .sh_flags = 0,
+            .sh_addr = 0,
+            .sh_offset = off,
+            .sh_size = file_size,
+            // The section header index of the associated string table.
+            .sh_link = self.strtab_section_index.?,
+            .sh_info = @as(u32, @intCast(self.symbols.items.len)),
+            .sh_addralign = min_align,
+            .sh_entsize = each_size,
         });
         self.shdr_table_dirty = true;
     }
 
     if (self.dwarf) |*dw| {
         if (self.debug_str_section_index == null) {
-            self.debug_str_section_index = @as(u16, @intCast(self.sections.slice().len));
+            self.debug_str_section_index = @as(u16, @intCast(self.shdrs.items.len));
             assert(dw.strtab.buffer.items.len == 0);
             try dw.strtab.buffer.append(gpa, 0);
-            try self.sections.append(gpa, .{
-                .shdr = .{
-                    .sh_name = try self.shstrtab.insert(gpa, ".debug_str"),
-                    .sh_type = elf.SHT_PROGBITS,
-                    .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
-                    .sh_addr = 0,
-                    .sh_offset = 0,
-                    .sh_size = 0,
-                    .sh_link = 0,
-                    .sh_info = 0,
-                    .sh_addralign = 1,
-                    .sh_entsize = 1,
-                },
-                .phdr_index = undefined,
+            try self.shdrs.append(gpa, .{
+                .sh_name = try self.shstrtab.insert(gpa, ".debug_str"),
+                .sh_type = elf.SHT_PROGBITS,
+                .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
+                .sh_addr = 0,
+                .sh_offset = 0,
+                .sh_size = 0,
+                .sh_link = 0,
+                .sh_info = 0,
+                .sh_addralign = 1,
+                .sh_entsize = 1,
             });
             self.debug_strtab_dirty = true;
             self.shdr_table_dirty = true;
         }
 
         if (self.debug_info_section_index == null) {
-            self.debug_info_section_index = @as(u16, @intCast(self.sections.slice().len));
-
+            self.debug_info_section_index = @as(u16, @intCast(self.shdrs.items.len));
             const file_size_hint = 200;
             const p_align = 1;
             const off = self.findFreeSpace(file_size_hint, p_align);
@@ -720,28 +699,24 @@ pub fn populateMissingMetadata(self: *Elf) !void {
                 off,
                 off + file_size_hint,
             });
-            try self.sections.append(gpa, .{
-                .shdr = .{
-                    .sh_name = try self.shstrtab.insert(gpa, ".debug_info"),
-                    .sh_type = elf.SHT_PROGBITS,
-                    .sh_flags = 0,
-                    .sh_addr = 0,
-                    .sh_offset = off,
-                    .sh_size = file_size_hint,
-                    .sh_link = 0,
-                    .sh_info = 0,
-                    .sh_addralign = p_align,
-                    .sh_entsize = 0,
-                },
-                .phdr_index = undefined,
+            try self.shdrs.append(gpa, .{
+                .sh_name = try self.shstrtab.insert(gpa, ".debug_info"),
+                .sh_type = elf.SHT_PROGBITS,
+                .sh_flags = 0,
+                .sh_addr = 0,
+                .sh_offset = off,
+                .sh_size = file_size_hint,
+                .sh_link = 0,
+                .sh_info = 0,
+                .sh_addralign = p_align,
+                .sh_entsize = 0,
             });
             self.shdr_table_dirty = true;
             self.debug_info_header_dirty = true;
         }
 
         if (self.debug_abbrev_section_index == null) {
-            self.debug_abbrev_section_index = @as(u16, @intCast(self.sections.slice().len));
-
+            self.debug_abbrev_section_index = @as(u16, @intCast(self.shdrs.items.len));
             const file_size_hint = 128;
             const p_align = 1;
             const off = self.findFreeSpace(file_size_hint, p_align);
@@ -749,28 +724,24 @@ pub fn populateMissingMetadata(self: *Elf) !void {
                 off,
                 off + file_size_hint,
             });
-            try self.sections.append(gpa, .{
-                .shdr = .{
-                    .sh_name = try self.shstrtab.insert(gpa, ".debug_abbrev"),
-                    .sh_type = elf.SHT_PROGBITS,
-                    .sh_flags = 0,
-                    .sh_addr = 0,
-                    .sh_offset = off,
-                    .sh_size = file_size_hint,
-                    .sh_link = 0,
-                    .sh_info = 0,
-                    .sh_addralign = p_align,
-                    .sh_entsize = 0,
-                },
-                .phdr_index = undefined,
+            try self.shdrs.append(gpa, .{
+                .sh_name = try self.shstrtab.insert(gpa, ".debug_abbrev"),
+                .sh_type = elf.SHT_PROGBITS,
+                .sh_flags = 0,
+                .sh_addr = 0,
+                .sh_offset = off,
+                .sh_size = file_size_hint,
+                .sh_link = 0,
+                .sh_info = 0,
+                .sh_addralign = p_align,
+                .sh_entsize = 0,
             });
             self.shdr_table_dirty = true;
             self.debug_abbrev_section_dirty = true;
         }
 
         if (self.debug_aranges_section_index == null) {
-            self.debug_aranges_section_index = @as(u16, @intCast(self.sections.slice().len));
-
+            self.debug_aranges_section_index = @as(u16, @intCast(self.shdrs.items.len));
             const file_size_hint = 160;
             const p_align = 16;
             const off = self.findFreeSpace(file_size_hint, p_align);
@@ -778,28 +749,24 @@ pub fn populateMissingMetadata(self: *Elf) !void {
                 off,
                 off + file_size_hint,
             });
-            try self.sections.append(gpa, .{
-                .shdr = .{
-                    .sh_name = try self.shstrtab.insert(gpa, ".debug_aranges"),
-                    .sh_type = elf.SHT_PROGBITS,
-                    .sh_flags = 0,
-                    .sh_addr = 0,
-                    .sh_offset = off,
-                    .sh_size = file_size_hint,
-                    .sh_link = 0,
-                    .sh_info = 0,
-                    .sh_addralign = p_align,
-                    .sh_entsize = 0,
-                },
-                .phdr_index = undefined,
+            try self.shdrs.append(gpa, .{
+                .sh_name = try self.shstrtab.insert(gpa, ".debug_aranges"),
+                .sh_type = elf.SHT_PROGBITS,
+                .sh_flags = 0,
+                .sh_addr = 0,
+                .sh_offset = off,
+                .sh_size = file_size_hint,
+                .sh_link = 0,
+                .sh_info = 0,
+                .sh_addralign = p_align,
+                .sh_entsize = 0,
             });
             self.shdr_table_dirty = true;
             self.debug_aranges_section_dirty = true;
         }
 
         if (self.debug_line_section_index == null) {
-            self.debug_line_section_index = @as(u16, @intCast(self.sections.slice().len));
-
+            self.debug_line_section_index = @as(u16, @intCast(self.shdrs.items.len));
             const file_size_hint = 250;
             const p_align = 1;
             const off = self.findFreeSpace(file_size_hint, p_align);
@@ -807,20 +774,17 @@ pub fn populateMissingMetadata(self: *Elf) !void {
                 off,
                 off + file_size_hint,
             });
-            try self.sections.append(gpa, .{
-                .shdr = .{
-                    .sh_name = try self.shstrtab.insert(gpa, ".debug_line"),
-                    .sh_type = elf.SHT_PROGBITS,
-                    .sh_flags = 0,
-                    .sh_addr = 0,
-                    .sh_offset = off,
-                    .sh_size = file_size_hint,
-                    .sh_link = 0,
-                    .sh_info = 0,
-                    .sh_addralign = p_align,
-                    .sh_entsize = 0,
-                },
-                .phdr_index = undefined,
+            try self.shdrs.append(gpa, .{
+                .sh_name = try self.shstrtab.insert(gpa, ".debug_line"),
+                .sh_type = elf.SHT_PROGBITS,
+                .sh_flags = 0,
+                .sh_addr = 0,
+                .sh_offset = off,
+                .sh_size = file_size_hint,
+                .sh_link = 0,
+                .sh_info = 0,
+                .sh_addralign = p_align,
+                .sh_entsize = 0,
             });
             self.shdr_table_dirty = true;
             self.debug_line_header_dirty = true;
@@ -836,7 +800,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
         .p64 => @alignOf(elf.Elf64_Shdr),
     };
     if (self.shdr_table_offset == null) {
-        self.shdr_table_offset = self.findFreeSpace(self.sections.slice().len * shsize, shalign);
+        self.shdr_table_offset = self.findFreeSpace(self.shdrs.items.len * shsize, shalign);
         self.shdr_table_dirty = true;
     }
 
@@ -854,7 +818,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
         // offset + it's filesize.
         var max_file_offset: u64 = 0;
 
-        for (self.sections.items(.shdr)) |shdr| {
+        for (self.shdrs.items) |shdr| {
             if (shdr.sh_offset + shdr.sh_size > max_file_offset) {
                 max_file_offset = shdr.sh_offset + shdr.sh_size;
             }
@@ -885,19 +849,17 @@ pub fn populateMissingMetadata(self: *Elf) !void {
 
 pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
     // TODO Also detect virtual address collisions.
-    const shdr = &self.sections.items(.shdr)[shdr_index];
-    const phdr_index = self.sections.items(.phdr_index)[shdr_index];
+    const shdr = &self.shdrs.items[shdr_index];
+    const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
     const phdr = &self.phdrs.items[phdr_index];
-    const last_atom_index = self.sections.items(.last_atom_index)[shdr_index];
 
     if (needed_size > self.allocatedSize(shdr.sh_offset)) {
         // Must move the entire section.
         const new_offset = self.findFreeSpace(needed_size, self.page_size);
-        const existing_size = if (self.atom(last_atom_index)) |last| blk: {
+        const existing_size = if (self.last_atom_and_free_list_table.get(shdr_index)) |meta| blk: {
+            const last = self.atom(meta.last_atom_index) orelse break :blk 0;
             break :blk (last.value + last.size) - phdr.p_vaddr;
-        } else if (shdr_index == self.got_section_index.?) blk: {
-            break :blk shdr.sh_size;
-        } else 0;
+        } else shdr.sh_size;
         shdr.sh_size = 0;
 
         log.debug("new '{?s}' file offset 0x{x} to 0x{x}", .{
@@ -927,7 +889,7 @@ pub fn growNonAllocSection(
     min_alignment: u32,
     requires_file_copy: bool,
 ) !void {
-    const shdr = &self.sections.items(.shdr)[shdr_index];
+    const shdr = &self.shdrs.items[shdr_index];
 
     if (needed_size > self.allocatedSize(shdr.sh_offset)) {
         const existing_size = if (self.symtab_section_index.? == shdr_index) blk: {
@@ -940,7 +902,12 @@ pub fn growNonAllocSection(
         shdr.sh_size = 0;
         // Move all the symbols to a new file location.
         const new_offset = self.findFreeSpace(needed_size, min_alignment);
-        log.debug("moving '{?s}' from 0x{x} to 0x{x}", .{ self.shstrtab.get(shdr.sh_name), shdr.sh_offset, new_offset });
+
+        log.debug("moving '{?s}' from 0x{x} to 0x{x}", .{
+            self.shstrtab.get(shdr.sh_name),
+            shdr.sh_offset,
+            new_offset,
+        });
 
         if (requires_file_copy) {
             const amt = try self.base.file.?.copyRangeAll(
@@ -1071,7 +1038,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
             const atom_index = entry.key_ptr.*;
             const relocs = entry.value_ptr.*;
             const atom_ptr = self.atom(atom_index).?;
-            const source_shdr = self.sections.items(.shdr)[atom_ptr.output_section_index];
+            const source_shdr = &self.shdrs.items[atom_ptr.output_section_index];
 
             log.debug("relocating '{s}'", .{atom_ptr.name(self)});
 
@@ -1209,9 +1176,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
 
     {
         const shdr_index = self.shstrtab_section_index.?;
-        if (self.shstrtab_dirty or self.shstrtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
+        if (self.shstrtab_dirty or self.shstrtab.buffer.items.len != self.shdrs.items[shdr_index].sh_size) {
             try self.growNonAllocSection(shdr_index, self.shstrtab.buffer.items.len, 1, false);
-            const shstrtab_sect = self.sections.items(.shdr)[shdr_index];
+            const shstrtab_sect = &self.shdrs.items[shdr_index];
             try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shstrtab_sect.sh_offset);
             self.shstrtab_dirty = false;
         }
@@ -1219,9 +1186,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
 
     {
         const shdr_index = self.strtab_section_index.?;
-        if (self.strtab_dirty or self.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
+        if (self.strtab_dirty or self.strtab.buffer.items.len != self.shdrs.items[shdr_index].sh_size) {
             try self.growNonAllocSection(shdr_index, self.strtab.buffer.items.len, 1, false);
-            const strtab_sect = self.sections.items(.shdr)[shdr_index];
+            const strtab_sect = self.shdrs.items[shdr_index];
             try self.base.file.?.pwriteAll(self.strtab.buffer.items, strtab_sect.sh_offset);
             self.strtab_dirty = false;
         }
@@ -1229,9 +1196,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
 
     if (self.dwarf) |dwarf| {
         const shdr_index = self.debug_str_section_index.?;
-        if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
+        if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.shdrs.items[shdr_index].sh_size) {
             try self.growNonAllocSection(shdr_index, dwarf.strtab.buffer.items.len, 1, false);
-            const debug_strtab_sect = self.sections.items(.shdr)[shdr_index];
+            const debug_strtab_sect = self.shdrs.items[shdr_index];
             try self.base.file.?.pwriteAll(dwarf.strtab.buffer.items, debug_strtab_sect.sh_offset);
             self.debug_strtab_dirty = false;
         }
@@ -1247,7 +1214,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
             .p64 => @alignOf(elf.Elf64_Shdr),
         };
         const allocated_size = self.allocatedSize(self.shdr_table_offset.?);
-        const needed_size = self.sections.slice().len * shsize;
+        const needed_size = self.shdrs.items.len * shsize;
 
         if (needed_size > allocated_size) {
             self.shdr_table_offset = null; // free the space
@@ -1256,12 +1223,11 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
 
         switch (self.ptr_width) {
             .p32 => {
-                const slice = self.sections.slice();
-                const buf = try gpa.alloc(elf.Elf32_Shdr, slice.len);
+                const buf = try gpa.alloc(elf.Elf32_Shdr, self.shdrs.items.len);
                 defer gpa.free(buf);
 
                 for (buf, 0..) |*shdr, i| {
-                    shdr.* = shdrTo32(slice.items(.shdr)[i]);
+                    shdr.* = shdrTo32(self.shdrs.items[i]);
                     log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
                     if (foreign_endian) {
                         mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);
@@ -1270,12 +1236,11 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
                 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
             },
             .p64 => {
-                const slice = self.sections.slice();
-                const buf = try gpa.alloc(elf.Elf64_Shdr, slice.len);
+                const buf = try gpa.alloc(elf.Elf64_Shdr, self.shdrs.items.len);
                 defer gpa.free(buf);
 
                 for (buf, 0..) |*shdr, i| {
-                    shdr.* = slice.items(.shdr)[i];
+                    shdr.* = self.shdrs.items[i];
                     log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
                     if (foreign_endian) {
                         mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);
@@ -2118,7 +2083,7 @@ fn writeElfHeader(self: *Elf) !void {
     mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);
     index += 2;
 
-    const e_shnum = @as(u16, @intCast(self.sections.slice().len));
+    const e_shnum = @as(u16, @intCast(self.shdrs.items.len));
     mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);
     index += 2;
 
@@ -2305,9 +2270,9 @@ fn updateDeclCode(
         try self.got.writeEntry(self, got_index);
     }
 
-    const phdr_index = self.sections.items(.phdr_index)[shdr_index];
+    const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
     const section_offset = sym.value - self.phdrs.items[phdr_index].p_vaddr;
-    const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
+    const file_offset = self.shdrs.items[shdr_index].sh_offset + section_offset;
 
     if (self.base.child_pid) |pid| {
         switch (builtin.os.tag) {
@@ -2510,7 +2475,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
     };
 
     const local_sym = self.symbol(symbol_index);
-    const phdr_index = self.sections.items(.phdr_index)[local_sym.output_section_index];
+    const phdr_index = self.phdr_to_shdr_table.get(local_sym.output_section_index).?;
     local_sym.name_offset = name_str_index;
     const local_esym = local_sym.sourceSymbol(self);
     local_esym.st_name = name_str_index;
@@ -2537,7 +2502,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
     try self.got.writeEntry(self, got_index);
 
     const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
-    const file_offset = self.sections.items(.shdr)[local_sym.output_section_index].sh_offset + section_offset;
+    const file_offset = self.shdrs.items[local_sym.output_section_index].sh_offset + section_offset;
     try self.base.file.?.pwriteAll(code, file_offset);
 }
 
@@ -2584,7 +2549,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
 
     const required_alignment = typed_value.ty.abiAlignment(mod);
     const shdr_index = self.rodata_section_index.?;
-    const phdr_index = self.sections.items(.phdr_index)[shdr_index];
+    const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
     const local_sym = self.symbol(sym_index);
     local_sym.name_offset = name_str_index;
     const local_esym = local_sym.sourceSymbol(self);
@@ -2607,7 +2572,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
     try unnamed_consts.append(gpa, atom_ptr.atom_index);
 
     const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
-    const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
+    const file_offset = self.shdrs.items[shdr_index].sh_offset + section_offset;
     try self.base.file.?.pwriteAll(code, file_offset);
 
     return sym_index;
@@ -2775,7 +2740,7 @@ fn addLinkerDefinedSymbols(self: *Elf) !void {
 fn allocateLinkerDefinedSymbols(self: *Elf) void {
     // _DYNAMIC
     if (self.dynamic_section_index) |shndx| {
-        const shdr = self.sections.items(.shdr)[shndx];
+        const shdr = &self.shdrs.items[shndx];
         const symbol_ptr = self.symbol(self.dynamic_index.?);
         symbol_ptr.value = shdr.sh_addr;
         symbol_ptr.output_section_index = shndx;
@@ -2792,7 +2757,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
     if (self.sectionByName(".init_array")) |shndx| {
         const start_sym = self.symbol(self.init_array_start_index.?);
         const end_sym = self.symbol(self.init_array_end_index.?);
-        const shdr = &self.sections.items(.shdr)[shndx];
+        const shdr = &self.shdrs.items[shndx];
         start_sym.output_section_index = shndx;
         start_sym.value = shdr.sh_addr;
         end_sym.output_section_index = shndx;
@@ -2803,7 +2768,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
     if (self.sectionByName(".fini_array")) |shndx| {
         const start_sym = self.symbol(self.fini_array_start_index.?);
         const end_sym = self.symbol(self.fini_array_end_index.?);
-        const shdr = &self.sections.items(.shdr)[shndx];
+        const shdr = &self.shdrs.items[shndx];
         start_sym.output_section_index = shndx;
         start_sym.value = shdr.sh_addr;
         end_sym.output_section_index = shndx;
@@ -2814,7 +2779,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
     if (self.sectionByName(".preinit_array")) |shndx| {
         const start_sym = self.symbol(self.preinit_array_start_index.?);
         const end_sym = self.symbol(self.preinit_array_end_index.?);
-        const shdr = &self.sections.items(.shdr)[shndx];
+        const shdr = &self.shdrs.items[shndx];
         start_sym.output_section_index = shndx;
         start_sym.value = shdr.sh_addr;
         end_sym.output_section_index = shndx;
@@ -2823,7 +2788,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
 
     // _GLOBAL_OFFSET_TABLE_
     if (self.got_plt_section_index) |shndx| {
-        const shdr = &self.sections.items(.shdr)[shndx];
+        const shdr = &self.shdrs.items[shndx];
         const symbol_ptr = self.symbol(self.got_index.?);
         symbol_ptr.value = shdr.sh_addr;
         symbol_ptr.output_section_index = shndx;
@@ -2831,7 +2796,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
 
     // _PROCEDURE_LINKAGE_TABLE_
     if (self.plt_section_index) |shndx| {
-        const shdr = &self.sections.items(.shdr)[shndx];
+        const shdr = &self.shdrs.items[shndx];
         const symbol_ptr = self.symbol(self.plt_index.?);
         symbol_ptr.value = shdr.sh_addr;
         symbol_ptr.output_section_index = shndx;
@@ -2839,7 +2804,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
 
     // __dso_handle
     if (self.dso_handle_index) |index| {
-        const shdr = &self.sections.items(.shdr)[1];
+        const shdr = &self.shdrs.items[1];
         const symbol_ptr = self.symbol(index);
         symbol_ptr.value = shdr.sh_addr;
         symbol_ptr.output_section_index = 0;
@@ -2847,7 +2812,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
 
     // __GNU_EH_FRAME_HDR
     if (self.eh_frame_hdr_section_index) |shndx| {
-        const shdr = &self.sections.items(.shdr)[shndx];
+        const shdr = &self.shdrs.items[shndx];
         const symbol_ptr = self.symbol(self.gnu_eh_frame_hdr_index.?);
         symbol_ptr.value = shdr.sh_addr;
         symbol_ptr.output_section_index = shndx;
@@ -2856,7 +2821,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
     // __rela_iplt_start, __rela_iplt_end
     if (self.rela_dyn_section_index) |shndx| blk: {
         if (self.base.options.link_mode != .Static or self.base.options.pie) break :blk;
-        const shdr = &self.sections.items(.shdr)[shndx];
+        const shdr = &self.shdrs.items[shndx];
         const end_addr = shdr.sh_addr + shdr.sh_size;
         const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
         const start_sym = self.symbol(self.rela_iplt_start_index.?);
@@ -2870,7 +2835,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
     // _end
     {
         const end_symbol = self.symbol(self.end_index.?);
-        for (self.sections.items(.shdr), 0..) |shdr, shndx| {
+        for (self.shdrs.items, 0..) |*shdr, shndx| {
             if (shdr.sh_flags & elf.SHF_ALLOC != 0) {
                 end_symbol.value = shdr.sh_addr + shdr.sh_size;
                 end_symbol.output_section_index = @intCast(shndx);
@@ -2886,7 +2851,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
             const name = start.name(self);
             const stop = self.symbol(self.start_stop_indexes.items[index + 1]);
             const shndx = self.sectionByName(name["__start_".len..]).?;
-            const shdr = self.sections.items(.shdr)[shndx];
+            const shdr = &self.shdrs.items[shndx];
             start.value = shdr.sh_addr;
             start.output_section_index = shndx;
             stop.value = shdr.sh_addr + shdr.sh_size;
@@ -2916,7 +2881,7 @@ fn updateSymtabSize(self: *Elf) !void {
         sizes.nlocals += linker_defined.output_symtab_size.nlocals;
     }
 
-    const shdr = &self.sections.items(.shdr)[self.symtab_section_index.?];
+    const shdr = &self.shdrs.items[self.symtab_section_index.?];
     shdr.sh_info = sizes.nlocals + 1;
     self.markDirty(self.symtab_section_index.?, null);
 
@@ -2934,7 +2899,7 @@ fn updateSymtabSize(self: *Elf) !void {
 
 fn writeSymtab(self: *Elf) !void {
     const gpa = self.base.allocator;
-    const shdr = &self.sections.items(.shdr)[self.symtab_section_index.?];
+    const shdr = &self.shdrs.items[self.symtab_section_index.?];
     const sym_size: u64 = switch (self.ptr_width) {
         .p32 => @sizeOf(elf.Elf32_Sym),
         .p64 => @sizeOf(elf.Elf64_Sym),
@@ -3031,7 +2996,7 @@ fn writeShdr(self: *Elf, index: usize) !void {
     switch (self.ptr_width) {
         .p32 => {
             var shdr: [1]elf.Elf32_Shdr = undefined;
-            shdr[0] = shdrTo32(self.sections.items(.shdr)[index]);
+            shdr[0] = shdrTo32(self.shdrs.items[index]);
             if (foreign_endian) {
                 mem.byteSwapAllFields(elf.Elf32_Shdr, &shdr[0]);
             }
@@ -3039,7 +3004,7 @@ fn writeShdr(self: *Elf, index: usize) !void {
             return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
         },
         .p64 => {
-            var shdr = [1]elf.Elf64_Shdr{self.sections.items(.shdr)[index]};
+            var shdr = [1]elf.Elf64_Shdr{self.shdrs.items[index]};
             if (foreign_endian) {
                 mem.byteSwapAllFields(elf.Elf64_Shdr, &shdr[0]);
             }
@@ -3327,7 +3292,7 @@ pub fn defaultEntryAddress(self: Elf) u64 {
 }
 
 pub fn sectionByName(self: *Elf, name: [:0]const u8) ?u16 {
-    for (self.sections.items(.shdr), 0..) |shdr, i| {
+    for (self.shdrs.items, 0..) |*shdr, i| {
         const this_name = self.shstrtab.getAssumeExists(shdr.sh_name);
         if (mem.eql(u8, this_name, name)) return @as(u16, @intCast(i));
     } else return null;
@@ -3481,10 +3446,7 @@ const default_entry_addr = 0x8000000;
 
 pub const base_tag: link.File.Tag = .elf;
 
-const Section = struct {
-    shdr: elf.Elf64_Shdr,
-    phdr_index: u16,
-
+const LastAtomAndFreeList = struct {
     /// Index of the last allocated atom in this section.
     last_atom_index: Atom.Index = 0,