| ... | ... | @@ -256,22 +256,11 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 256 | 256 | try self.atoms.append(allocator, .{}); |
| 257 | 257 | // Append null file at index 0 |
| 258 | 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 | 259 | // Append null byte to string tables |
| 273 | 260 | try self.shstrtab.buffer.append(allocator, 0); |
| 274 | 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 | 265 | const is_obj_or_ar = switch (options.output_mode) { |
| 277 | 266 | .Obj => true, |
| ... | ... | @@ -886,30 +875,13 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 886 | 875 | } |
| 887 | 876 | |
| 888 | 877 | const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr); |
| 889 | | if (needed_size > mem_capacity) { |
| 890 | | // We are exceeding our allocated VM capacity so we need to shift everything in memory |
| 891 | | // and grow. |
| 892 | | { |
| 893 | | const dirty_addr = phdr.p_vaddr + phdr.p_memsz; |
| 894 | | const got_addresses_dirty = for (self.got.entries.items) |entry| { |
| 895 | | if (self.symbol(entry.symbol_index).value >= dirty_addr) break true; |
| 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 | | } |
| 878 | if (needed_size <= mem_capacity) { |
| 879 | var err = try self.addErrorWithNotes(2); |
| 880 | try err.addMsg(self, "fatal linker error: cannot expand load segment phdr({d}) in virtual memory", .{ |
| 881 | phdr_index, |
| 882 | }); |
| 883 | try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{}); |
| 884 | try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{}); |
| 913 | 885 | } |
| 914 | 886 | |
| 915 | 887 | phdr.p_memsz = needed_size; |
| ... | ... | @@ -917,62 +889,6 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 917 | 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 | 892 | pub fn growNonAllocSection( |
| 977 | 893 | self: *Elf, |
| 978 | 894 | shdr_index: u16, |
| ... | ... | @@ -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 | 4070 | const name = self.shstrtab.getAssumeExists(shdr.sh_name); |
| 4154 | 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 | 4090 | switch (shdr.sh_type) { |
| 4156 | 4091 | elf.SHT_NULL => return 0, |
| 4157 | 4092 | elf.SHT_DYNSYM => return 2, |
| ... | ... | @@ -4200,9 +4135,7 @@ fn sortSections(self: *Elf) !void { |
| 4200 | 4135 | shndx: u16, |
| 4201 | 4136 | |
| 4202 | 4137 | pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool { |
| 4203 | | const lhs_shdr = elf_file.shdrs.items[lhs.shndx]; |
| 4204 | | const rhs_shdr = elf_file.shdrs.items[rhs.shndx]; |
| 4205 | | return elf_file.sectionRank(lhs_shdr) < elf_file.sectionRank(rhs_shdr); |
| 4138 | return elf_file.sectionRank(lhs.shndx) < elf_file.sectionRank(rhs.shndx); |
| 4206 | 4139 | } |
| 4207 | 4140 | }; |
| 4208 | 4141 | |
| ... | ... | @@ -4250,6 +4183,16 @@ fn sortSections(self: *Elf) !void { |
| 4250 | 4183 | &self.copy_rel_section_index, |
| 4251 | 4184 | &self.versym_section_index, |
| 4252 | 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 | 4196 | }) |maybe_index| { |
| 4254 | 4197 | if (maybe_index.*) |*index| { |
| 4255 | 4198 | index.* = backlinks[index.*]; |
| ... | ... | @@ -4512,6 +4455,7 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4512 | 4455 | var shndx = for (self.shdrs.items, 0..) |shdr, in| { |
| 4513 | 4456 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4514 | 4457 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 4458 | if (self.isZigSection(@intCast(in))) continue; |
| 4515 | 4459 | break @as(u16, @intCast(in)); |
| 4516 | 4460 | } else @as(u16, @intCast(self.shdrs.items.len)); |
| 4517 | 4461 | |
| ... | ... | @@ -5343,6 +5287,21 @@ pub fn isDynLib(self: Elf) bool { |
| 5343 | 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 | 5305 | fn addPhdr(self: *Elf, opts: struct { |
| 5347 | 5306 | type: u32 = 0, |
| 5348 | 5307 | flags: u32 = 0, |