| ... | ... | @@ -48,7 +48,7 @@ phdr_zig_load_zerofill_index: ?u16 = null, |
| 48 | 48 | /// PT_PHDR |
| 49 | 49 | phdr_table_index: ?u16 = null, |
| 50 | 50 | /// PT_LOAD for PHDR table |
| 51 | | /// We add this special load segment to ensure the PHDR table is always |
| 51 | /// We add this special load segment to ensure the EHDR and PHDR table are always |
| 52 | 52 | /// loaded into memory. |
| 53 | 53 | phdr_table_load_index: ?u16 = null, |
| 54 | 54 | /// PT_INTERP |
| ... | ... | @@ -289,22 +289,28 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 289 | 289 | .p64 => @alignOf(elf.Elf64_Phdr), |
| 290 | 290 | }; |
| 291 | 291 | const image_base = self.calcImageBase(); |
| 292 | | const offset: u64 = switch (self.ptr_width) { |
| 292 | const ehdr_size: u64 = switch (self.ptr_width) { |
| 293 | 293 | .p32 => @sizeOf(elf.Elf32_Ehdr), |
| 294 | 294 | .p64 => @sizeOf(elf.Elf64_Ehdr), |
| 295 | 295 | }; |
| 296 | const reserved: u64 = 2 * self.page_size; |
| 296 | 297 | self.phdr_table_index = try self.addPhdr(.{ |
| 297 | 298 | .type = elf.PT_PHDR, |
| 298 | 299 | .flags = elf.PF_R, |
| 299 | 300 | .@"align" = p_align, |
| 300 | | .addr = image_base + offset, |
| 301 | | .offset = offset, |
| 301 | .addr = image_base + ehdr_size, |
| 302 | .offset = ehdr_size, |
| 303 | .filesz = reserved, |
| 304 | .memsz = reserved, |
| 302 | 305 | }); |
| 303 | 306 | self.phdr_table_load_index = try self.addPhdr(.{ |
| 304 | 307 | .type = elf.PT_LOAD, |
| 305 | 308 | .flags = elf.PF_R, |
| 306 | 309 | .@"align" = self.page_size, |
| 307 | 310 | .addr = image_base, |
| 311 | .offset = 0, |
| 312 | .filesz = reserved + ehdr_size, |
| 313 | .memsz = reserved + ehdr_size, |
| 308 | 314 | }); |
| 309 | 315 | } |
| 310 | 316 | |
| ... | ... | @@ -870,10 +876,10 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 870 | 876 | const is_zerofill = shdr.sh_type == elf.SHT_NOBITS; |
| 871 | 877 | |
| 872 | 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 | 879 | const existing_size = shdr.sh_size; |
| 876 | 880 | shdr.sh_size = 0; |
| 881 | // Must move the entire section. |
| 882 | const new_offset = self.findFreeSpace(needed_size, self.page_size); |
| 877 | 883 | |
| 878 | 884 | log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{ |
| 879 | 885 | self.shstrtab.getAssumeExists(shdr.sh_name), |
| ... | ... | @@ -1602,7 +1608,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1602 | 1608 | try self.setVersionSymtab(); |
| 1603 | 1609 | try self.updateSectionSizes(); |
| 1604 | 1610 | |
| 1605 | | self.allocatePhdrTable(); |
| 1611 | try self.allocatePhdrTable(); |
| 1606 | 1612 | try self.allocateAllocSections(); |
| 1607 | 1613 | try self.sortPhdrs(); |
| 1608 | 1614 | try self.allocateNonAllocSections(); |
| ... | ... | @@ -4655,30 +4661,35 @@ fn calcNumberOfSegments(self: *Elf) usize { |
| 4655 | 4661 | } |
| 4656 | 4662 | |
| 4657 | 4663 | /// Allocates PHDR table in virtual memory and in file. |
| 4658 | | fn allocatePhdrTable(self: *Elf) void { |
| 4664 | fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void { |
| 4659 | 4665 | const new_load_segments = self.calcNumberOfSegments(); |
| 4660 | 4666 | const phdr_table = &self.phdrs.items[self.phdr_table_index.?]; |
| 4661 | 4667 | const phdr_table_load = &self.phdrs.items[self.phdr_table_load_index.?]; |
| 4662 | 4668 | |
| 4669 | const ehsize: u64 = switch (self.ptr_width) { |
| 4670 | .p32 => @sizeOf(elf.Elf32_Ehdr), |
| 4671 | .p64 => @sizeOf(elf.Elf64_Ehdr), |
| 4672 | }; |
| 4663 | 4673 | const phsize: u64 = switch (self.ptr_width) { |
| 4664 | 4674 | .p32 => @sizeOf(elf.Elf32_Phdr), |
| 4665 | 4675 | .p64 => @sizeOf(elf.Elf64_Phdr), |
| 4666 | 4676 | }; |
| 4667 | 4677 | const needed_size = (self.phdrs.items.len + new_load_segments) * phsize; |
| 4678 | const available_space = self.allocatedSize(phdr_table.p_offset); |
| 4668 | 4679 | |
| 4669 | 4680 | if (needed_size > self.allocatedSize(phdr_table.p_offset)) { |
| 4670 | | phdr_table.p_offset = 0; |
| 4671 | | phdr_table.p_offset = self.findFreeSpace(needed_size, phdr_table.p_align); |
| 4681 | // TODO in this case, we have two options: |
| 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 | } |
| 4673 | 4689 | |
| 4674 | | phdr_table_load.p_offset = mem.alignBackward(u64, phdr_table.p_offset, phdr_table_load.p_align); |
| 4675 | | const load_align_offset = phdr_table.p_offset - phdr_table_load.p_offset; |
| 4676 | | phdr_table_load.p_filesz = load_align_offset + needed_size; |
| 4677 | | phdr_table_load.p_memsz = load_align_offset + needed_size; |
| 4678 | | |
| 4690 | phdr_table_load.p_filesz = needed_size + ehsize; |
| 4691 | phdr_table_load.p_memsz = needed_size + ehsize; |
| 4679 | 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 | 4693 | phdr_table.p_memsz = needed_size; |
| 4683 | 4694 | } |
| 4684 | 4695 | |