authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-13 13:37:49+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:05+02:00
log9b6337ab06e90b23c7d494b49fb8a728ac9d75e2
tree5d9fe64129500ec87a6aa97c5187477f7eeea702
parent9da6574f7bd3a08fd5aabc771ff5331e14b9c90a

elf: exclude Zig special sections from bulk alloc


1 files changed, 56 insertions(+), 97 deletions(-)

src/link/Elf.zig+56-97
......@@ -256,22 +256,11 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
256256 try self.atoms.append(allocator, .{});
257257 // Append null file at index 0
258258 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 });
272259 // Append null byte to string tables
273260 try self.shstrtab.buffer.append(allocator, 0);
274261 try self.strtab.buffer.append(allocator, 0);
262 // There must always be a null shdr in index 0
263 _ = try self.addSection(.{ .name = "" });
275264
276265 const is_obj_or_ar = switch (options.output_mode) {
277266 .Obj => true,
......@@ -886,30 +875,13 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
886875 }
887876
888877 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", .{});
913885 }
914886
915887 phdr.p_memsz = needed_size;
......@@ -917,62 +889,6 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
917889 self.markDirty(shdr_index);
918890}
919891
920fn 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
976892pub fn growNonAllocSection(
977893 self: *Elf,
978894 shdr_index: u16,
......@@ -4149,9 +4065,28 @@ fn setHashSections(self: *Elf) !void {
41494065 }
41504066}
41514067
4152fn sectionRank(self: *Elf, shdr: elf.Elf64_Shdr) u8 {
4068fn sectionRank(self: *Elf, shndx: u16) u8 {
4069 const shdr = self.shdrs.items[shndx];
41534070 const name = self.shstrtab.getAssumeExists(shdr.sh_name);
41544071 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
41554090 switch (shdr.sh_type) {
41564091 elf.SHT_NULL => return 0,
41574092 elf.SHT_DYNSYM => return 2,
......@@ -4200,9 +4135,7 @@ fn sortSections(self: *Elf) !void {
42004135 shndx: u16,
42014136
42024137 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);
42064139 }
42074140 };
42084141
......@@ -4250,6 +4183,16 @@ fn sortSections(self: *Elf) !void {
42504183 &self.copy_rel_section_index,
42514184 &self.versym_section_index,
42524185 &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,
42534196 }) |maybe_index| {
42544197 if (maybe_index.*) |*index| {
42554198 index.* = backlinks[index.*];
......@@ -4512,6 +4455,7 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
45124455 var shndx = for (self.shdrs.items, 0..) |shdr, in| {
45134456 if (shdr.sh_type == elf.SHT_NULL) continue;
45144457 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
4458 if (self.isZigSection(@intCast(in))) continue;
45154459 break @as(u16, @intCast(in));
45164460 } else @as(u16, @intCast(self.shdrs.items.len));
45174461
......@@ -5343,6 +5287,21 @@ pub fn isDynLib(self: Elf) bool {
53435287 return self.base.options.effectiveOutputMode() == .Lib and self.base.options.link_mode == .Dynamic;
53445288}
53455289
5290pub 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
53465305fn addPhdr(self: *Elf, opts: struct {
53475306 type: u32 = 0,
53485307 flags: u32 = 0,