authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-24 17:41:28+02:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-25 04:27:44-04:00
loge1248b693ff53266d20d6fc88a9c70a13432322f
tree550f5fd31f8ae88442e9b1aa974e8cb0819f5789
parent0a04bd87bab4842dbf63133952d1d6eee3aa46bc

elf: allocate PHDR table always succeeding the EHDR

While this is a less flexible approach to being able to allocated the PHDR anywhere in file, it is sadly generally expected by the tooling in the wild.

1 files changed, 28 insertions(+), 17 deletions(-)

src/link/Elf.zig+28-17
...@@ -48,7 +48,7 @@ phdr_zig_load_zerofill_index: ?u16 = null,...@@ -48,7 +48,7 @@ phdr_zig_load_zerofill_index: ?u16 = null,
48/// PT_PHDR48/// PT_PHDR
49phdr_table_index: ?u16 = null,49phdr_table_index: ?u16 = null,
50/// PT_LOAD for PHDR table50/// PT_LOAD for PHDR table
51/// We add this special load segment to ensure the PHDR table is always51/// We add this special load segment to ensure the EHDR and PHDR table are always
52/// loaded into memory.52/// loaded into memory.
53phdr_table_load_index: ?u16 = null,53phdr_table_load_index: ?u16 = null,
54/// PT_INTERP54/// PT_INTERP
...@@ -289,22 +289,28 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -289,22 +289,28 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
289 .p64 => @alignOf(elf.Elf64_Phdr),289 .p64 => @alignOf(elf.Elf64_Phdr),
290 };290 };
291 const image_base = self.calcImageBase();291 const image_base = self.calcImageBase();
292 const offset: u64 = switch (self.ptr_width) {292 const ehdr_size: u64 = switch (self.ptr_width) {
293 .p32 => @sizeOf(elf.Elf32_Ehdr),293 .p32 => @sizeOf(elf.Elf32_Ehdr),
294 .p64 => @sizeOf(elf.Elf64_Ehdr),294 .p64 => @sizeOf(elf.Elf64_Ehdr),
295 };295 };
296 const reserved: u64 = 2 * self.page_size;
296 self.phdr_table_index = try self.addPhdr(.{297 self.phdr_table_index = try self.addPhdr(.{
297 .type = elf.PT_PHDR,298 .type = elf.PT_PHDR,
298 .flags = elf.PF_R,299 .flags = elf.PF_R,
299 .@"align" = p_align,300 .@"align" = p_align,
300 .addr = image_base + offset,301 .addr = image_base + ehdr_size,
301 .offset = offset,302 .offset = ehdr_size,
303 .filesz = reserved,
304 .memsz = reserved,
302 });305 });
303 self.phdr_table_load_index = try self.addPhdr(.{306 self.phdr_table_load_index = try self.addPhdr(.{
304 .type = elf.PT_LOAD,307 .type = elf.PT_LOAD,
305 .flags = elf.PF_R,308 .flags = elf.PF_R,
306 .@"align" = self.page_size,309 .@"align" = self.page_size,
307 .addr = image_base,310 .addr = image_base,
311 .offset = 0,
312 .filesz = reserved + ehdr_size,
313 .memsz = reserved + ehdr_size,
308 });314 });
309 }315 }
310316
...@@ -870,10 +876,10 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {...@@ -870,10 +876,10 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
870 const is_zerofill = shdr.sh_type == elf.SHT_NOBITS;876 const is_zerofill = shdr.sh_type == elf.SHT_NOBITS;
871877
872 if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {878 if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {
873 // Must move the entire section.
874 const new_offset = self.findFreeSpace(needed_size, self.page_size);
875 const existing_size = shdr.sh_size;879 const existing_size = shdr.sh_size;
876 shdr.sh_size = 0;880 shdr.sh_size = 0;
881 // Must move the entire section.
882 const new_offset = self.findFreeSpace(needed_size, self.page_size);
877883
878 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{884 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
879 self.shstrtab.getAssumeExists(shdr.sh_name),885 self.shstrtab.getAssumeExists(shdr.sh_name),
...@@ -1602,7 +1608,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1602,7 +1608,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1602 try self.setVersionSymtab();1608 try self.setVersionSymtab();
1603 try self.updateSectionSizes();1609 try self.updateSectionSizes();
16041610
1605 self.allocatePhdrTable();1611 try self.allocatePhdrTable();
1606 try self.allocateAllocSections();1612 try self.allocateAllocSections();
1607 try self.sortPhdrs();1613 try self.sortPhdrs();
1608 try self.allocateNonAllocSections();1614 try self.allocateNonAllocSections();
...@@ -4655,30 +4661,35 @@ fn calcNumberOfSegments(self: *Elf) usize {...@@ -4655,30 +4661,35 @@ fn calcNumberOfSegments(self: *Elf) usize {
4655}4661}
46564662
4657/// Allocates PHDR table in virtual memory and in file.4663/// Allocates PHDR table in virtual memory and in file.
4658fn allocatePhdrTable(self: *Elf) void {4664fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {
4659 const new_load_segments = self.calcNumberOfSegments();4665 const new_load_segments = self.calcNumberOfSegments();
4660 const phdr_table = &self.phdrs.items[self.phdr_table_index.?];4666 const phdr_table = &self.phdrs.items[self.phdr_table_index.?];
4661 const phdr_table_load = &self.phdrs.items[self.phdr_table_load_index.?];4667 const phdr_table_load = &self.phdrs.items[self.phdr_table_load_index.?];
46624668
4669 const ehsize: u64 = switch (self.ptr_width) {
4670 .p32 => @sizeOf(elf.Elf32_Ehdr),
4671 .p64 => @sizeOf(elf.Elf64_Ehdr),
4672 };
4663 const phsize: u64 = switch (self.ptr_width) {4673 const phsize: u64 = switch (self.ptr_width) {
4664 .p32 => @sizeOf(elf.Elf32_Phdr),4674 .p32 => @sizeOf(elf.Elf32_Phdr),
4665 .p64 => @sizeOf(elf.Elf64_Phdr),4675 .p64 => @sizeOf(elf.Elf64_Phdr),
4666 };4676 };
4667 const needed_size = (self.phdrs.items.len + new_load_segments) * phsize;4677 const needed_size = (self.phdrs.items.len + new_load_segments) * phsize;
4678 const available_space = self.allocatedSize(phdr_table.p_offset);
46684679
4669 if (needed_size > self.allocatedSize(phdr_table.p_offset)) {4680 if (needed_size > self.allocatedSize(phdr_table.p_offset)) {
4670 phdr_table.p_offset = 0;4681 // TODO in this case, we have two options:
4671 phdr_table.p_offset = self.findFreeSpace(needed_size, phdr_table.p_align);4682 // 1. increase the available padding for EHDR + PHDR table so that we don't overflow it
4683 // (I think we are in good position to estimate required size without running out of space)
4684 // 2. shift everything in file to free more space for EHDR + PHDR table
4685 var err = try self.addErrorWithNotes(1);
4686 try err.addMsg(self, "fatal linker error: not enough space reserved for EHDR and PHDR table", .{});
4687 try err.addNote(self, "required 0x{x}, available 0x{x}", .{ needed_size, available_space });
4672 }4688 }
46734689
4674 phdr_table_load.p_offset = mem.alignBackward(u64, phdr_table.p_offset, phdr_table_load.p_align);4690 phdr_table_load.p_filesz = needed_size + ehsize;
4675 const load_align_offset = phdr_table.p_offset - phdr_table_load.p_offset;4691 phdr_table_load.p_memsz = needed_size + ehsize;
4676 phdr_table_load.p_filesz = load_align_offset + needed_size;
4677 phdr_table_load.p_memsz = load_align_offset + needed_size;
4678
4679 phdr_table.p_filesz = needed_size;4692 phdr_table.p_filesz = needed_size;
4680 phdr_table.p_vaddr = phdr_table_load.p_vaddr + load_align_offset;
4681 phdr_table.p_paddr = phdr_table_load.p_paddr + load_align_offset;
4682 phdr_table.p_memsz = needed_size;4693 phdr_table.p_memsz = needed_size;
4683}4694}
46844695