| ... | @@ -48,7 +48,7 @@ phdr_zig_load_zerofill_index: ?u16 = null, | ... | @@ -48,7 +48,7 @@ phdr_zig_load_zerofill_index: ?u16 = null, |
| 48 | /// PT_PHDR | 48 | /// PT_PHDR |
| 49 | phdr_table_index: ?u16 = null, | 49 | phdr_table_index: ?u16 = null, |
| 50 | /// PT_LOAD for PHDR table | 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 | /// loaded into memory. | 52 | /// loaded into memory. |
| 53 | phdr_table_load_index: ?u16 = null, | 53 | phdr_table_load_index: ?u16 = null, |
| 54 | /// PT_INTERP | 54 | /// 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 | } |
| 310 | | 316 | |
| ... | @@ -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; |
| 871 | | 877 | |
| 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); |
| 877 | | 883 | |
| 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(); |
| 1604 | | 1610 | |
| 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 | } |
| 4656 | | 4662 | |
| 4657 | /// Allocates PHDR table in virtual memory and in file. | 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 | 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.?]; |
| 4662 | | 4668 | |
| | 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); |
| 4668 | | 4679 | |
| 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 | } |
| 4673 | | 4689 | |
| 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 | } |
| 4684 | | 4695 | |