| ... | @@ -256,22 +256,11 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -256,22 +256,11 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 256 | try self.atoms.append(allocator, .{}); | 256 | try self.atoms.append(allocator, .{}); |
| 257 | // Append null file at index 0 | 257 | // Append null file at index 0 |
| 258 | try self.files.append(allocator, .null); | 258 | try self.files.append(allocator, .null); |
| 259 | // There must always be a null shdr in index 0 | | |
| 260 | try self.shdrs.append(allocator, .{ | | |
| 261 | .sh_name = 0, | | |
| 262 | .sh_type = elf.SHT_NULL, | | |
| 263 | .sh_flags = 0, | | |
| 264 | .sh_addr = 0, | | |
| 265 | .sh_offset = 0, | | |
| 266 | .sh_size = 0, | | |
| 267 | .sh_link = 0, | | |
| 268 | .sh_info = 0, | | |
| 269 | .sh_addralign = 0, | | |
| 270 | .sh_entsize = 0, | | |
| 271 | }); | | |
| 272 | // Append null byte to string tables | 259 | // Append null byte to string tables |
| 273 | try self.shstrtab.buffer.append(allocator, 0); | 260 | try self.shstrtab.buffer.append(allocator, 0); |
| 274 | try self.strtab.buffer.append(allocator, 0); | 261 | try self.strtab.buffer.append(allocator, 0); |
| | 262 | // There must always be a null shdr in index 0 |
| | 263 | _ = try self.addSection(.{ .name = "" }); |
| 275 | | 264 | |
| 276 | const is_obj_or_ar = switch (options.output_mode) { | 265 | const is_obj_or_ar = switch (options.output_mode) { |
| 277 | .Obj => true, | 266 | .Obj => true, |
| ... | @@ -886,30 +875,13 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { | ... | @@ -886,30 +875,13 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 886 | } | 875 | } |
| 887 | | 876 | |
| 888 | const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr); | 877 | const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr); |
| 889 | if (needed_size > mem_capacity) { | 878 | if (needed_size <= mem_capacity) { |
| 890 | // We are exceeding our allocated VM capacity so we need to shift everything in memory | 879 | var err = try self.addErrorWithNotes(2); |
| 891 | // and grow. | 880 | try err.addMsg(self, "fatal linker error: cannot expand load segment phdr({d}) in virtual memory", .{ |
| 892 | { | 881 | phdr_index, |
| 893 | const dirty_addr = phdr.p_vaddr + phdr.p_memsz; | 882 | }); |
| 894 | const got_addresses_dirty = for (self.got.entries.items) |entry| { | 883 | try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{}); |
| 895 | if (self.symbol(entry.symbol_index).value >= dirty_addr) break true; | 884 | try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{}); |
| 896 | } else false; | | |
| 897 | _ = got_addresses_dirty; | | |
| 898 | | | |
| 899 | // TODO mark relocs dirty | | |
| 900 | } | | |
| 901 | try self.growSegment(shdr_index, needed_size); | | |
| 902 | | | |
| 903 | if (self.zig_module_index != null) { | | |
| 904 | // TODO self-hosted backends cannot yet handle this condition correctly as the linker | | |
| 905 | // cannot update emitted virtual addresses of symbols already committed to the final file. | | |
| 906 | var err = try self.addErrorWithNotes(2); | | |
| 907 | try err.addMsg(self, "fatal linker error: cannot expand load segment phdr({d}) in virtual memory", .{ | | |
| 908 | phdr_index, | | |
| 909 | }); | | |
| 910 | try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{}); | | |
| 911 | try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{}); | | |
| 912 | } | | |
| 913 | } | 885 | } |
| 914 | | 886 | |
| 915 | phdr.p_memsz = needed_size; | 887 | phdr.p_memsz = needed_size; |
| ... | @@ -917,62 +889,6 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { | ... | @@ -917,62 +889,6 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 917 | self.markDirty(shdr_index); | 889 | self.markDirty(shdr_index); |
| 918 | } | 890 | } |
| 919 | | 891 | |
| 920 | fn growSegment(self: *Elf, shndx: u16, needed_size: u64) !void { | | |
| 921 | const phdr_index = self.phdr_to_shdr_table.get(shndx).?; | | |
| 922 | const phdr = &self.phdrs.items[phdr_index]; | | |
| 923 | const increased_size = padToIdeal(needed_size); | | |
| 924 | const end_addr = phdr.p_vaddr + phdr.p_memsz; | | |
| 925 | const old_aligned_end = phdr.p_vaddr + mem.alignForward(u64, phdr.p_memsz, phdr.p_align); | | |
| 926 | const new_aligned_end = phdr.p_vaddr + mem.alignForward(u64, increased_size, phdr.p_align); | | |
| 927 | const diff = new_aligned_end - old_aligned_end; | | |
| 928 | log.debug("growing phdr({d}) in memory by {x}", .{ phdr_index, diff }); | | |
| 929 | | | |
| 930 | // Update symbols and atoms. | | |
| 931 | var files = std.ArrayList(File.Index).init(self.base.allocator); | | |
| 932 | defer files.deinit(); | | |
| 933 | try files.ensureTotalCapacityPrecise(self.objects.items.len + 1); | | |
| 934 | | | |
| 935 | if (self.zig_module_index) |index| files.appendAssumeCapacity(index); | | |
| 936 | files.appendSliceAssumeCapacity(self.objects.items); | | |
| 937 | | | |
| 938 | for (files.items) |index| { | | |
| 939 | const file_ptr = self.file(index).?; | | |
| 940 | | | |
| 941 | for (file_ptr.locals()) |sym_index| { | | |
| 942 | const sym = self.symbol(sym_index); | | |
| 943 | const atom_ptr = sym.atom(self) orelse continue; | | |
| 944 | if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue; | | |
| 945 | if (sym.value >= end_addr) sym.value += diff; | | |
| 946 | } | | |
| 947 | | | |
| 948 | for (file_ptr.globals()) |sym_index| { | | |
| 949 | const sym = self.symbol(sym_index); | | |
| 950 | if (sym.file_index != index) continue; | | |
| 951 | const atom_ptr = sym.atom(self) orelse continue; | | |
| 952 | if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue; | | |
| 953 | if (sym.value >= end_addr) sym.value += diff; | | |
| 954 | } | | |
| 955 | | | |
| 956 | for (file_ptr.atoms()) |atom_index| { | | |
| 957 | const atom_ptr = self.atom(atom_index) orelse continue; | | |
| 958 | if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue; | | |
| 959 | if (atom_ptr.value >= end_addr) atom_ptr.value += diff; | | |
| 960 | } | | |
| 961 | } | | |
| 962 | | | |
| 963 | // Finally, update section headers. | | |
| 964 | for (self.shdrs.items, 0..) |*other_shdr, other_shndx| { | | |
| 965 | if (other_shdr.sh_flags & elf.SHF_ALLOC == 0) continue; | | |
| 966 | if (other_shndx == shndx) continue; | | |
| 967 | const other_phdr_index = self.phdr_to_shdr_table.get(@intCast(other_shndx)) orelse continue; | | |
| 968 | const other_phdr = &self.phdrs.items[other_phdr_index]; | | |
| 969 | if (other_phdr.p_vaddr < end_addr) continue; | | |
| 970 | other_shdr.sh_addr += diff; | | |
| 971 | other_phdr.p_vaddr += diff; | | |
| 972 | other_phdr.p_paddr += diff; | | |
| 973 | } | | |
| 974 | } | | |
| 975 | | | |
| 976 | pub fn growNonAllocSection( | 892 | pub fn growNonAllocSection( |
| 977 | self: *Elf, | 893 | self: *Elf, |
| 978 | shdr_index: u16, | 894 | shdr_index: u16, |
| ... | @@ -4149,9 +4065,28 @@ fn setHashSections(self: *Elf) !void { | ... | @@ -4149,9 +4065,28 @@ fn setHashSections(self: *Elf) !void { |
| 4149 | } | 4065 | } |
| 4150 | } | 4066 | } |
| 4151 | | 4067 | |
| 4152 | fn sectionRank(self: *Elf, shdr: elf.Elf64_Shdr) u8 { | 4068 | fn sectionRank(self: *Elf, shndx: u16) u8 { |
| | 4069 | const shdr = self.shdrs.items[shndx]; |
| 4153 | const name = self.shstrtab.getAssumeExists(shdr.sh_name); | 4070 | const name = self.shstrtab.getAssumeExists(shdr.sh_name); |
| 4154 | const flags = shdr.sh_flags; | 4071 | const flags = shdr.sh_flags; |
| | 4072 | |
| | 4073 | if (self.isZigSection(shndx)) { |
| | 4074 | switch (shdr.sh_type) { |
| | 4075 | elf.SHT_PROGBITS => { |
| | 4076 | assert(flags & elf.SHF_ALLOC != 0); |
| | 4077 | if (flags & elf.SHF_EXECINSTR != 0) { |
| | 4078 | return 0xe1; |
| | 4079 | } else if (flags & elf.SHF_WRITE != 0) { |
| | 4080 | return 0xe2; |
| | 4081 | } else { |
| | 4082 | return 0xe0; |
| | 4083 | } |
| | 4084 | }, |
| | 4085 | elf.SHT_NOBITS => return 0xef, |
| | 4086 | else => unreachable, |
| | 4087 | } |
| | 4088 | } |
| | 4089 | |
| 4155 | switch (shdr.sh_type) { | 4090 | switch (shdr.sh_type) { |
| 4156 | elf.SHT_NULL => return 0, | 4091 | elf.SHT_NULL => return 0, |
| 4157 | elf.SHT_DYNSYM => return 2, | 4092 | elf.SHT_DYNSYM => return 2, |
| ... | @@ -4200,9 +4135,7 @@ fn sortSections(self: *Elf) !void { | ... | @@ -4200,9 +4135,7 @@ fn sortSections(self: *Elf) !void { |
| 4200 | shndx: u16, | 4135 | shndx: u16, |
| 4201 | | 4136 | |
| 4202 | pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool { | 4137 | pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool { |
| 4203 | const lhs_shdr = elf_file.shdrs.items[lhs.shndx]; | 4138 | return elf_file.sectionRank(lhs.shndx) < elf_file.sectionRank(rhs.shndx); |
| 4204 | const rhs_shdr = elf_file.shdrs.items[rhs.shndx]; | | |
| 4205 | return elf_file.sectionRank(lhs_shdr) < elf_file.sectionRank(rhs_shdr); | | |
| 4206 | } | 4139 | } |
| 4207 | }; | 4140 | }; |
| 4208 | | 4141 | |
| ... | @@ -4250,6 +4183,16 @@ fn sortSections(self: *Elf) !void { | ... | @@ -4250,6 +4183,16 @@ fn sortSections(self: *Elf) !void { |
| 4250 | &self.copy_rel_section_index, | 4183 | &self.copy_rel_section_index, |
| 4251 | &self.versym_section_index, | 4184 | &self.versym_section_index, |
| 4252 | &self.verneed_section_index, | 4185 | &self.verneed_section_index, |
| | 4186 | &self.text_zig_section_index, |
| | 4187 | &self.got_zig_section_index, |
| | 4188 | &self.rodata_zig_section_index, |
| | 4189 | &self.data_zig_section_index, |
| | 4190 | &self.bss_zig_section_index, |
| | 4191 | &self.debug_str_section_index, |
| | 4192 | &self.debug_info_section_index, |
| | 4193 | &self.debug_abbrev_section_index, |
| | 4194 | &self.debug_aranges_section_index, |
| | 4195 | &self.debug_line_section_index, |
| 4253 | }) |maybe_index| { | 4196 | }) |maybe_index| { |
| 4254 | if (maybe_index.*) |*index| { | 4197 | if (maybe_index.*) |*index| { |
| 4255 | index.* = backlinks[index.*]; | 4198 | index.* = backlinks[index.*]; |
| ... | @@ -4512,6 +4455,7 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { | ... | @@ -4512,6 +4455,7 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4512 | var shndx = for (self.shdrs.items, 0..) |shdr, in| { | 4455 | var shndx = for (self.shdrs.items, 0..) |shdr, in| { |
| 4513 | if (shdr.sh_type == elf.SHT_NULL) continue; | 4456 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4514 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; | 4457 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| | 4458 | if (self.isZigSection(@intCast(in))) continue; |
| 4515 | break @as(u16, @intCast(in)); | 4459 | break @as(u16, @intCast(in)); |
| 4516 | } else @as(u16, @intCast(self.shdrs.items.len)); | 4460 | } else @as(u16, @intCast(self.shdrs.items.len)); |
| 4517 | | 4461 | |
| ... | @@ -5343,6 +5287,21 @@ pub fn isDynLib(self: Elf) bool { | ... | @@ -5343,6 +5287,21 @@ pub fn isDynLib(self: Elf) bool { |
| 5343 | return self.base.options.effectiveOutputMode() == .Lib and self.base.options.link_mode == .Dynamic; | 5287 | return self.base.options.effectiveOutputMode() == .Lib and self.base.options.link_mode == .Dynamic; |
| 5344 | } | 5288 | } |
| 5345 | | 5289 | |
| | 5290 | pub fn isZigSection(self: Elf, shndx: u16) bool { |
| | 5291 | inline for (&[_]?u16{ |
| | 5292 | self.text_zig_section_index, |
| | 5293 | self.rodata_zig_section_index, |
| | 5294 | self.data_zig_section_index, |
| | 5295 | self.bss_zig_section_index, |
| | 5296 | self.got_zig_section_index, |
| | 5297 | }) |maybe_index| { |
| | 5298 | if (maybe_index) |index| { |
| | 5299 | if (index == shndx) return true; |
| | 5300 | } |
| | 5301 | } |
| | 5302 | return false; |
| | 5303 | } |
| | 5304 | |
| 5346 | fn addPhdr(self: *Elf, opts: struct { | 5305 | fn addPhdr(self: *Elf, opts: struct { |
| 5347 | type: u32 = 0, | 5306 | type: u32 = 0, |
| 5348 | flags: u32 = 0, | 5307 | flags: u32 = 0, |