Commit 9fd460821f

Jacob Young <jacobly0@users.noreply.github.com>
2023-04-03 19:55:20
elf: cleanup phdr tracking
Since one of the program header entries is now the program header table itself, we can avoid tracking it explicitly and just track it as yet another program segment.
1 parent c0e9b84
Changed files (1)
src
link
src/link/Elf.zig
@@ -391,17 +391,6 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
 
     const end = start + padToIdeal(size);
 
-    if (self.phdr_table_index) |index| {
-        const off = self.program_headers.items[index].p_offset;
-        const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr);
-        const tight_size = self.program_headers.items.len * phdr_size;
-        const increased_size = padToIdeal(tight_size);
-        const test_end = off + increased_size;
-        if (end > off and start < test_end) {
-            return test_end;
-        }
-    }
-
     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;
@@ -433,10 +422,6 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
     if (start == 0)
         return 0;
     var min_pos: u64 = std.math.maxInt(u64);
-    if (self.phdr_table_index) |index| {
-        const off = self.program_headers.items[index].p_offset;
-        if (off > start and off < min_pos) min_pos = off;
-    }
     if (self.shdr_table_offset) |off| {
         if (off > start and off < min_pos) min_pos = off;
     }
@@ -469,151 +454,133 @@ pub fn populateMissingMetadata(self: *Elf) !void {
     };
     const ptr_size: u8 = self.ptrWidthBytes();
 
-    { // Program Headers
-        var new_phdr_table_index: ?u16 = null;
-        if (self.phdr_table_index == null) {
-            new_phdr_table_index = @intCast(u16, self.program_headers.items.len);
-            const p_align: u16 = switch (self.ptr_width) {
-                .p32 => @alignOf(elf.Elf32_Phdr),
-                .p64 => @alignOf(elf.Elf64_Phdr),
-            };
-            const off = self.findFreeSpace(1, p_align);
-            try self.program_headers.append(gpa, .{
-                .p_type = elf.PT_PHDR,
-                .p_offset = off,
-                .p_filesz = 1,
-                .p_vaddr = 0,
-                .p_paddr = 0,
-                .p_memsz = 0,
-                .p_align = p_align,
-                .p_flags = elf.PF_R,
-            });
-            self.phdr_table_dirty = true;
-        }
-
-        if (self.phdr_table_load_index == null) {
-            self.phdr_table_load_index = @intCast(u16, self.program_headers.items.len);
-            // TODO Same as for GOT
-            const phdr_addr: u64 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x1000000 else 0x1000;
-            const p_align = self.page_size;
-            const off = self.findFreeSpace(1, p_align);
-            const file_size: u32 = 1;
-            log.debug("found PT_LOAD free space 0x{x} to 0x{x}", .{ off, off + file_size });
-            try self.program_headers.append(gpa, .{
-                .p_type = elf.PT_LOAD,
-                .p_offset = off,
-                .p_filesz = file_size,
-                .p_vaddr = phdr_addr,
-                .p_paddr = phdr_addr,
-                .p_memsz = file_size,
-                .p_align = p_align,
-                .p_flags = elf.PF_R,
-            });
-            self.phdr_table_dirty = true;
-        }
-
-        if (self.phdr_load_re_index == null) {
-            self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
-            const file_size = self.base.options.program_code_size_hint;
-            const p_align = self.page_size;
-            const off = self.findFreeSpace(file_size, p_align);
-            log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
-            const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;
-            try self.program_headers.append(gpa, .{
-                .p_type = elf.PT_LOAD,
-                .p_offset = off,
-                .p_filesz = file_size,
-                .p_vaddr = entry_addr,
-                .p_paddr = entry_addr,
-                .p_memsz = file_size,
-                .p_align = p_align,
-                .p_flags = elf.PF_X | elf.PF_R | elf.PF_W,
-            });
-            self.entry_addr = null;
-            self.phdr_table_dirty = true;
-        }
-
-        if (self.phdr_got_index == null) {
-            self.phdr_got_index = @intCast(u16, self.program_headers.items.len);
-            const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
-            // We really only need ptr alignment but since we are using PROGBITS, linux requires
-            // page align.
-            const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
-            const off = self.findFreeSpace(file_size, p_align);
-            log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size });
-            // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
-            // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
-            // else in virtual memory.
-            const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
-            try self.program_headers.append(gpa, .{
-                .p_type = elf.PT_LOAD,
-                .p_offset = off,
-                .p_filesz = file_size,
-                .p_vaddr = got_addr,
-                .p_paddr = got_addr,
-                .p_memsz = file_size,
-                .p_align = p_align,
-                .p_flags = elf.PF_R | elf.PF_W,
-            });
-            self.phdr_table_dirty = true;
-        }
-
-        if (self.phdr_load_ro_index == null) {
-            self.phdr_load_ro_index = @intCast(u16, self.program_headers.items.len);
-            // TODO Find a hint about how much data need to be in rodata ?
-            const file_size = 1024;
-            // Same reason as for GOT
-            const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
-            const off = self.findFreeSpace(file_size, p_align);
-            log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
-            // TODO Same as for GOT
-            const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
-            try self.program_headers.append(gpa, .{
-                .p_type = elf.PT_LOAD,
-                .p_offset = off,
-                .p_filesz = file_size,
-                .p_vaddr = rodata_addr,
-                .p_paddr = rodata_addr,
-                .p_memsz = file_size,
-                .p_align = p_align,
-                .p_flags = elf.PF_R | elf.PF_W,
-            });
-            self.phdr_table_dirty = true;
-        }
-
-        if (self.phdr_load_rw_index == null) {
-            self.phdr_load_rw_index = @intCast(u16, self.program_headers.items.len);
-            // TODO Find a hint about how much data need to be in data ?
-            const file_size = 1024;
-            // Same reason as for GOT
-            const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
-            const off = self.findFreeSpace(file_size, p_align);
-            log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
-            // TODO Same as for GOT
-            const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
-            try self.program_headers.append(gpa, .{
-                .p_type = elf.PT_LOAD,
-                .p_offset = off,
-                .p_filesz = file_size,
-                .p_vaddr = rwdata_addr,
-                .p_paddr = rwdata_addr,
-                .p_memsz = file_size,
-                .p_align = p_align,
-                .p_flags = elf.PF_R | elf.PF_W,
-            });
-            self.phdr_table_dirty = true;
-        }
-
-        if (new_phdr_table_index) |index| {
-            const phsize: u64 = switch (self.ptr_width) {
-                .p32 => @sizeOf(elf.Elf32_Phdr),
-                .p64 => @sizeOf(elf.Elf64_Phdr),
-            };
-            const phdr_table = &self.program_headers.items[index];
-            phdr_table.p_offset = self.findFreeSpace(self.program_headers.items.len * phsize, @intCast(u32, phdr_table.p_align));
-            self.phdr_table_index = index;
-            self.phdr_table_dirty = true;
-        }
+    if (self.phdr_table_index == null) {
+        self.phdr_table_index = @intCast(u16, self.program_headers.items.len);
+        const p_align: u16 = switch (self.ptr_width) {
+            .p32 => @alignOf(elf.Elf32_Phdr),
+            .p64 => @alignOf(elf.Elf64_Phdr),
+        };
+        try self.program_headers.append(gpa, .{
+            .p_type = elf.PT_PHDR,
+            .p_offset = 0,
+            .p_filesz = 0,
+            .p_vaddr = 0,
+            .p_paddr = 0,
+            .p_memsz = 0,
+            .p_align = p_align,
+            .p_flags = elf.PF_R,
+        });
+        self.phdr_table_dirty = true;
+    }
+
+    if (self.phdr_table_load_index == null) {
+        self.phdr_table_load_index = @intCast(u16, self.program_headers.items.len);
+        // TODO Same as for GOT
+        const phdr_addr: u64 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x1000000 else 0x1000;
+        const p_align = self.page_size;
+        try self.program_headers.append(gpa, .{
+            .p_type = elf.PT_LOAD,
+            .p_offset = 0,
+            .p_filesz = 0,
+            .p_vaddr = phdr_addr,
+            .p_paddr = phdr_addr,
+            .p_memsz = 0,
+            .p_align = p_align,
+            .p_flags = elf.PF_R,
+        });
+        self.phdr_table_dirty = true;
+    }
+
+    if (self.phdr_load_re_index == null) {
+        self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
+        const file_size = self.base.options.program_code_size_hint;
+        const p_align = self.page_size;
+        const off = self.findFreeSpace(file_size, p_align);
+        log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
+        const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;
+        try self.program_headers.append(gpa, .{
+            .p_type = elf.PT_LOAD,
+            .p_offset = off,
+            .p_filesz = file_size,
+            .p_vaddr = entry_addr,
+            .p_paddr = entry_addr,
+            .p_memsz = file_size,
+            .p_align = p_align,
+            .p_flags = elf.PF_X | elf.PF_R | elf.PF_W,
+        });
+        self.entry_addr = null;
+        self.phdr_table_dirty = true;
+    }
+
+    if (self.phdr_got_index == null) {
+        self.phdr_got_index = @intCast(u16, self.program_headers.items.len);
+        const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
+        // We really only need ptr alignment but since we are using PROGBITS, linux requires
+        // page align.
+        const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
+        const off = self.findFreeSpace(file_size, p_align);
+        log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size });
+        // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
+        // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
+        // else in virtual memory.
+        const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
+        try self.program_headers.append(gpa, .{
+            .p_type = elf.PT_LOAD,
+            .p_offset = off,
+            .p_filesz = file_size,
+            .p_vaddr = got_addr,
+            .p_paddr = got_addr,
+            .p_memsz = file_size,
+            .p_align = p_align,
+            .p_flags = elf.PF_R | elf.PF_W,
+        });
+        self.phdr_table_dirty = true;
+    }
+
+    if (self.phdr_load_ro_index == null) {
+        self.phdr_load_ro_index = @intCast(u16, self.program_headers.items.len);
+        // TODO Find a hint about how much data need to be in rodata ?
+        const file_size = 1024;
+        // Same reason as for GOT
+        const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
+        const off = self.findFreeSpace(file_size, p_align);
+        log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
+        // TODO Same as for GOT
+        const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
+        try self.program_headers.append(gpa, .{
+            .p_type = elf.PT_LOAD,
+            .p_offset = off,
+            .p_filesz = file_size,
+            .p_vaddr = rodata_addr,
+            .p_paddr = rodata_addr,
+            .p_memsz = file_size,
+            .p_align = p_align,
+            .p_flags = elf.PF_R | elf.PF_W,
+        });
+        self.phdr_table_dirty = true;
+    }
+
+    if (self.phdr_load_rw_index == null) {
+        self.phdr_load_rw_index = @intCast(u16, self.program_headers.items.len);
+        // TODO Find a hint about how much data need to be in data ?
+        const file_size = 1024;
+        // Same reason as for GOT
+        const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
+        const off = self.findFreeSpace(file_size, p_align);
+        log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
+        // TODO Same as for GOT
+        const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
+        try self.program_headers.append(gpa, .{
+            .p_type = elf.PT_LOAD,
+            .p_offset = off,
+            .p_filesz = file_size,
+            .p_vaddr = rwdata_addr,
+            .p_paddr = rwdata_addr,
+            .p_memsz = file_size,
+            .p_align = p_align,
+            .p_flags = elf.PF_R | elf.PF_W,
+        });
+        self.phdr_table_dirty = true;
     }
 
     if (self.shstrtab_index == null) {
@@ -1186,8 +1153,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
         const needed_size = self.program_headers.items.len * phsize;
 
         if (needed_size > allocated_size) {
-            self.phdr_table_index = null; // free the space
-            defer self.phdr_table_index = phdr_table_index;
+            phdr_table.p_offset = 0; // free the space
             phdr_table.p_offset = self.findFreeSpace(needed_size, @intCast(u32, phdr_table.p_align));
         }
 
@@ -1227,6 +1193,11 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
                 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
             },
         }
+
+        // We don't actually care if the phdr load section overlaps, only the phdr section matters.
+        phdr_table_load.p_offset = 0;
+        phdr_table_load.p_filesz = 0;
+
         self.phdr_table_dirty = false;
     }