authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-26 11:12:31+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-27 09:59:59+02:00
log1200a5a2401cd4a13d818499f9d534c0051c3724
treeaac835a704b309e6dd8fef3956c3c354834d22f5
parentde4d1ea250f37c03cf2eec6c6bdf7436c8816893

elf: allow expanding segments in virtual memory


6 files changed, 177 insertions(+), 79 deletions(-)

src/link/Elf.zig+96-52
......@@ -1,4 +1,5 @@
11base: link.File,
2
23dwarf: ?Dwarf = null,
34
45ptr_width: PtrWidth,
......@@ -103,6 +104,7 @@ phdr_table_dirty: bool = false,
103104shdr_table_dirty: bool = false,
104105shstrtab_dirty: bool = false,
105106strtab_dirty: bool = false,
107got_dirty: bool = false,
106108
107109debug_strtab_dirty: bool = false,
108110debug_abbrev_section_dirty: bool = false,
......@@ -411,7 +413,6 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
411413const AllocateSegmentOpts = struct {
412414 size: u64,
413415 alignment: u64,
414 addr: ?u64 = null, // TODO find free VM space
415416 flags: u32 = elf.PF_R,
416417};
417418
......@@ -422,7 +423,7 @@ pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}
422423 // Memory is always allocated in sequence.
423424 // TODO is this correct? Or should we implement something similar to `findFreeSpace`?
424425 // How would that impact HCS?
425 const addr = opts.addr orelse blk: {
426 const addr = blk: {
426427 assert(self.phdr_table_load_index != null);
427428 const phdr = &self.phdrs.items[index - 1];
428429 break :blk mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, opts.alignment);
......@@ -568,7 +569,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
568569
569570 if (self.phdr_load_re_index == null) {
570571 self.phdr_load_re_index = try self.allocateSegment(.{
571 .addr = self.defaultEntryAddress(),
572572 .size = self.base.options.program_code_size_hint,
573573 .alignment = self.page_size,
574574 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
......@@ -577,15 +577,10 @@ pub fn populateMissingMetadata(self: *Elf) !void {
577577 }
578578
579579 if (self.phdr_got_index == null) {
580 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
581 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
582 // else in virtual memory.
583 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
584580 // We really only need ptr alignment but since we are using PROGBITS, linux requires
585581 // page align.
586582 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
587583 self.phdr_got_index = try self.allocateSegment(.{
588 .addr = addr,
589584 .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint,
590585 .alignment = alignment,
591586 .flags = elf.PF_R | elf.PF_W,
......@@ -593,12 +588,9 @@ pub fn populateMissingMetadata(self: *Elf) !void {
593588 }
594589
595590 if (self.phdr_load_ro_index == null) {
596 // TODO Same as for GOT
597 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
598591 // Same reason as for GOT
599592 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
600593 self.phdr_load_ro_index = try self.allocateSegment(.{
601 .addr = addr,
602594 .size = 1024,
603595 .alignment = alignment,
604596 .flags = elf.PF_R | elf.PF_W,
......@@ -606,12 +598,9 @@ pub fn populateMissingMetadata(self: *Elf) !void {
606598 }
607599
608600 if (self.phdr_load_rw_index == null) {
609 // TODO Same as for GOT
610 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
611601 // Same reason as for GOT
612602 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
613603 self.phdr_load_rw_index = try self.allocateSegment(.{
614 .addr = addr,
615604 .size = 1024,
616605 .alignment = alignment,
617606 .flags = elf.PF_R | elf.PF_W,
......@@ -619,11 +608,8 @@ pub fn populateMissingMetadata(self: *Elf) !void {
619608 }
620609
621610 if (self.phdr_load_zerofill_index == null) {
622 // TODO Same as for GOT
623 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000;
624611 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
625612 self.phdr_load_zerofill_index = try self.allocateSegment(.{
626 .addr = addr,
627613 .size = 0,
628614 .alignment = alignment,
629615 .flags = elf.PF_R | elf.PF_W,
......@@ -858,7 +844,19 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
858844 }
859845
860846 const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr);
861 assert(needed_size <= mem_capacity); // TODO grow section in virtual memory
847 if (needed_size > mem_capacity) {
848 // We are exceeding our allocated VM capacity so we need to shift everything in memory
849 // and grow.
850 {
851 const dirty_addr = phdr.p_vaddr + phdr.p_memsz;
852 self.got_dirty = for (self.got.entries.items) |entry| {
853 if (self.symbol(entry.symbol_index).value >= dirty_addr) break true;
854 } else false;
855
856 // TODO mark relocs dirty
857 }
858 try self.growSegment(shdr_index, needed_size);
859 }
862860
863861 shdr.sh_size = needed_size;
864862 phdr.p_memsz = needed_size;
......@@ -870,6 +868,61 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
870868 self.markDirty(shdr_index, phdr_index);
871869}
872870
871fn growSegment(self: *Elf, shndx: u16, needed_size: u64) !void {
872 const phdr_index = self.phdr_to_shdr_table.get(shndx).?;
873 const phdr = &self.phdrs.items[phdr_index];
874 const increased_size = padToIdeal(needed_size);
875 const end_addr = phdr.p_vaddr + phdr.p_memsz;
876 const old_aligned_end = phdr.p_vaddr + mem.alignForward(u64, phdr.p_memsz, phdr.p_align);
877 const new_aligned_end = phdr.p_vaddr + mem.alignForward(u64, increased_size, phdr.p_align);
878 const diff = new_aligned_end - old_aligned_end;
879 log.debug("growing phdr({d}) in memory by {x}", .{ phdr_index, diff });
880
881 // Update symbols and atoms.
882 var files = std.ArrayList(File.Index).init(self.base.allocator);
883 defer files.deinit();
884 try files.ensureTotalCapacityPrecise(self.objects.items.len + 1);
885
886 if (self.zig_module_index) |index| files.appendAssumeCapacity(index);
887 files.appendSliceAssumeCapacity(self.objects.items);
888
889 for (files.items) |index| {
890 const file_ptr = self.file(index).?;
891
892 for (file_ptr.locals()) |sym_index| {
893 const sym = self.symbol(sym_index);
894 const atom_ptr = sym.atom(self) orelse continue;
895 if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue;
896 if (atom_ptr.value >= end_addr) sym.value += diff;
897 }
898
899 for (file_ptr.globals()) |sym_index| {
900 const sym = self.symbol(sym_index);
901 const atom_ptr = sym.atom(self) orelse continue;
902 if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue;
903 if (atom_ptr.value >= end_addr) sym.value += diff;
904 }
905
906 for (file_ptr.atoms()) |atom_index| {
907 const atom_ptr = self.atom(atom_index) orelse continue;
908 if (!atom_ptr.flags.alive or !atom_ptr.flags.allocated) continue;
909 if (atom_ptr.value >= end_addr) atom_ptr.value += diff;
910 }
911 }
912
913 // Finally, update section headers.
914 for (self.shdrs.items, 0..) |*other_shdr, other_shndx| {
915 if (other_shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
916 if (other_shndx == shndx) continue;
917 const other_phdr_index = self.phdr_to_shdr_table.get(@intCast(other_shndx)) orelse continue;
918 const other_phdr = &self.phdrs.items[other_phdr_index];
919 if (other_phdr.p_vaddr < end_addr) continue;
920 other_shdr.sh_addr += diff;
921 other_phdr.p_vaddr += diff;
922 other_phdr.p_paddr += diff;
923 }
924}
925
873926pub fn growNonAllocSection(
874927 self: *Elf,
875928 shdr_index: u16,
......@@ -1133,6 +1186,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11331186 // Scan and create missing synthetic entries such as GOT indirection.
11341187 try self.scanRelocs();
11351188
1189 if (build_options.enable_logging) {
1190 state_log.debug("{}", .{self.dumpState()});
1191 }
1192
11361193 // Allocate atoms parsed from input object files, followed by allocating
11371194 // linker-defined synthetic symbols.
11381195 try self.allocateObjects();
......@@ -1143,7 +1200,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11431200 if (self.zig_module_index) |index| {
11441201 for (self.file(index).?.zig_module.atoms.keys()) |atom_index| {
11451202 const atom_ptr = self.atom(atom_index).?;
1146 if (!atom_ptr.alive) continue;
1203 if (!atom_ptr.flags.alive) continue;
11471204 const shdr = &self.shdrs.items[atom_ptr.outputShndx().?];
11481205 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
11491206 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
......@@ -1157,6 +1214,15 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11571214 }
11581215 try self.writeObjects();
11591216
1217 if (self.got_dirty) {
1218 const shdr = &self.shdrs.items[self.got_section_index.?];
1219 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got.size(self));
1220 defer buffer.deinit();
1221 try self.got.writeAllEntries(self, buffer.writer());
1222 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
1223 self.got_dirty = false;
1224 }
1225
11601226 // Look for entry address in objects if not set by the incremental compiler.
11611227 if (self.entry_addr == null) {
11621228 const entry: ?[]const u8 = entry: {
......@@ -1537,7 +1603,7 @@ fn resolveSymbols(self: *Elf) error{Overflow}!void {
15371603 for (try object.comdatGroupMembers(cg.shndx)) |shndx| {
15381604 const atom_index = object.atoms.items[shndx];
15391605 if (self.atom(atom_index)) |atom_ptr| {
1540 atom_ptr.alive = false;
1606 atom_ptr.flags.alive = false;
15411607 // atom_ptr.markFdesDead(self);
15421608 }
15431609 }
......@@ -1645,25 +1711,26 @@ fn scanRelocs(self: *Elf) !void {
16451711fn allocateObjects(self: *Elf) !void {
16461712 for (self.objects.items) |index| {
16471713 const object = self.file(index).?.object;
1714
16481715 for (object.atoms.items) |atom_index| {
16491716 const atom_ptr = self.atom(atom_index) orelse continue;
1650 if (!atom_ptr.alive) continue;
1717 if (!atom_ptr.flags.alive or atom_ptr.flags.allocated) continue;
16511718 try atom_ptr.allocate(self);
16521719 }
16531720
16541721 for (object.locals()) |local_index| {
16551722 const local = self.symbol(local_index);
16561723 const atom_ptr = local.atom(self) orelse continue;
1657 if (!atom_ptr.alive) continue;
1658 local.value += atom_ptr.value;
1724 if (!atom_ptr.flags.alive) continue;
1725 local.value = local.elfSym(self).st_value + atom_ptr.value;
16591726 }
16601727
16611728 for (object.globals()) |global_index| {
16621729 const global = self.symbol(global_index);
16631730 const atom_ptr = global.atom(self) orelse continue;
1664 if (!atom_ptr.alive) continue;
1731 if (!atom_ptr.flags.alive) continue;
16651732 if (global.file_index == index) {
1666 global.value += atom_ptr.value;
1733 global.value = global.elfSym(self).st_value + atom_ptr.value;
16671734 }
16681735 }
16691736 }
......@@ -1676,7 +1743,7 @@ fn writeObjects(self: *Elf) !void {
16761743 const object = self.file(index).?.object;
16771744 for (object.atoms.items) |atom_index| {
16781745 const atom_ptr = self.atom(atom_index) orelse continue;
1679 if (!atom_ptr.alive) continue;
1746 if (!atom_ptr.flags.alive) continue;
16801747
16811748 const shdr = &self.shdrs.items[atom_ptr.outputShndx().?];
16821749 if (shdr.sh_type == elf.SHT_NOBITS) continue;
......@@ -2650,7 +2717,7 @@ fn updateDeclCode(
26502717 atom_ptr.output_section_index = shdr_index;
26512718
26522719 sym.name_offset = try self.strtab.insert(gpa, decl_name);
2653 atom_ptr.alive = true;
2720 atom_ptr.flags.alive = true;
26542721 atom_ptr.name_offset = sym.name_offset;
26552722 esym.st_name = sym.name_offset;
26562723 esym.st_info |= stt_bits;
......@@ -2681,11 +2748,6 @@ fn updateDeclCode(
26812748 } else {
26822749 try atom_ptr.allocate(self);
26832750 errdefer self.freeDeclMetadata(sym_index);
2684 log.debug("allocated atom for {s} at 0x{x} to 0x{x}", .{
2685 decl_name,
2686 atom_ptr.value,
2687 atom_ptr.value + atom_ptr.size,
2688 });
26892751
26902752 sym.value = atom_ptr.value;
26912753 esym.st_value = atom_ptr.value;
......@@ -2873,7 +2935,6 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
28732935 defer gpa.free(name);
28742936 break :blk try self.strtab.insert(gpa, name);
28752937 };
2876 const name = self.strtab.get(name_str_index).?;
28772938
28782939 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
28792940 mod.declPtr(owner_decl).srcLoc(mod)
......@@ -2913,7 +2974,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
29132974 local_esym.st_info |= elf.STT_OBJECT;
29142975 local_esym.st_size = code.len;
29152976 const atom_ptr = local_sym.atom(self).?;
2916 atom_ptr.alive = true;
2977 atom_ptr.flags.alive = true;
29172978 atom_ptr.name_offset = name_str_index;
29182979 atom_ptr.alignment = required_alignment;
29192980 atom_ptr.size = code.len;
......@@ -2922,12 +2983,6 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
29222983 try atom_ptr.allocate(self);
29232984 errdefer self.freeDeclMetadata(symbol_index);
29242985
2925 log.debug("allocated atom for {s} at 0x{x} to 0x{x}", .{
2926 name,
2927 atom_ptr.value,
2928 atom_ptr.value + atom_ptr.size,
2929 });
2930
29312986 local_sym.value = atom_ptr.value;
29322987 local_esym.st_value = atom_ptr.value;
29332988
......@@ -2961,7 +3016,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
29613016 defer gpa.free(name);
29623017 break :blk try self.strtab.insert(gpa, name);
29633018 };
2964 const name = self.strtab.get(name_str_index).?;
29653019
29663020 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
29673021 const sym_index = try zig_module.addAtom(self);
......@@ -2992,7 +3046,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
29923046 local_esym.st_info |= elf.STT_OBJECT;
29933047 local_esym.st_size = code.len;
29943048 const atom_ptr = local_sym.atom(self).?;
2995 atom_ptr.alive = true;
3049 atom_ptr.flags.alive = true;
29963050 atom_ptr.name_offset = name_str_index;
29973051 atom_ptr.alignment = required_alignment;
29983052 atom_ptr.size = code.len;
......@@ -3001,8 +3055,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
30013055 try atom_ptr.allocate(self);
30023056 errdefer self.freeDeclMetadata(sym_index);
30033057
3004 log.debug("allocated atom for {s} at 0x{x} to 0x{x}", .{ name, atom_ptr.value, atom_ptr.value + atom_ptr.size });
3005
30063058 local_sym.value = atom_ptr.value;
30073059 local_esym.st_value = atom_ptr.value;
30083060
......@@ -3740,14 +3792,6 @@ pub fn calcImageBase(self: Elf) u64 {
37403792 };
37413793}
37423794
3743pub fn defaultEntryAddress(self: Elf) u64 {
3744 if (self.entry_addr) |addr| return addr;
3745 return switch (self.base.options.target.cpu.arch) {
3746 .spu_2 => 0,
3747 else => default_entry_addr,
3748 };
3749}
3750
37513795pub fn isDynLib(self: Elf) bool {
37523796 return self.base.options.output_mode == .Lib and self.base.options.link_mode == .Dynamic;
37533797}
src/link/Elf/Atom.zig+37-16
......@@ -25,11 +25,8 @@ relocs_section_index: Index = 0,
2525/// Index of this atom in the linker's atoms table.
2626atom_index: Index = 0,
2727
28/// Specifies whether this atom is alive or has been garbage collected.
29alive: bool = false,
30
31/// Specifies if the atom has been visited during garbage collection.
32visited: bool = false,
28/// Flags we use for state tracking.
29flags: Flags = .{},
3330
3431/// Start index of FDEs referencing this atom.
3532fde_start: u32 = 0,
......@@ -48,8 +45,12 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {
4845 return elf_file.strtab.getAssumeExists(self.name_offset);
4946}
5047
48pub fn file(self: Atom, elf_file: *Elf) ?File {
49 return elf_file.file(self.file_index);
50}
51
5152pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr {
52 const object = elf_file.file(self.file_index).?.object;
53 const object = self.file(elf_file).?.object;
5354 return object.shdrs.items[self.input_section_index];
5455}
5556
......@@ -59,7 +60,7 @@ pub fn outputShndx(self: Atom) ?u16 {
5960}
6061
6162pub fn codeInObject(self: Atom, elf_file: *Elf) error{Overflow}![]const u8 {
62 const object = elf_file.file(self.file_index).?.object;
63 const object = self.file(elf_file).?.object;
6364 return object.shdrContents(self.input_section_index);
6465}
6566
......@@ -91,7 +92,7 @@ pub fn codeInObjectUncompressAlloc(self: Atom, elf_file: *Elf) ![]u8 {
9192}
9293
9394pub fn priority(self: Atom, elf_file: *Elf) u64 {
94 const index = elf_file.file(self.file_index).?.index();
95 const index = self.file(elf_file).?.index();
9596 return (@as(u64, @intCast(index)) << 32) | @as(u64, @intCast(self.input_section_index));
9697}
9798
......@@ -178,6 +179,13 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
178179 }
179180 };
180181
182 log.debug("allocated atom({d}) : '{s}' at 0x{x} to 0x{x}", .{
183 self.atom_index,
184 self.name(elf_file),
185 self.value,
186 self.value + self.size,
187 });
188
181189 const expand_section = if (atom_placement) |placement_index|
182190 elf_file.atom(placement_index).?.next_index == 0
183191 else
......@@ -222,6 +230,8 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
222230 if (free_list_removal) |i| {
223231 _ = free_list.swapRemove(i);
224232 }
233
234 self.flags.allocated = true;
225235}
226236
227237pub fn shrink(self: *Atom, elf_file: *Elf) void {
......@@ -238,7 +248,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
238248 log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) });
239249
240250 const gpa = elf_file.base.allocator;
241 const zig_module = elf_file.file(self.file_index).?.zig_module;
251 const zig_module = self.file(elf_file).?.zig_module;
242252 const shndx = self.outputShndx().?;
243253 const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;
244254 const free_list = &meta.free_list;
......@@ -294,7 +304,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
294304}
295305
296306pub fn relocs(self: Atom, elf_file: *Elf) error{Overflow}![]align(1) const elf.Elf64_Rela {
297 return switch (elf_file.file(self.file_index).?) {
307 return switch (self.file(elf_file).?) {
298308 .zig_module => |x| x.relocs.items[self.relocs_section_index].items,
299309 .object => |x| x.getRelocs(self.relocs_section_index),
300310 else => unreachable,
......@@ -303,7 +313,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) error{Overflow}![]align(1) const elf.E
303313
304314pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void {
305315 const gpa = elf_file.base.allocator;
306 const file_ptr = elf_file.file(self.file_index).?;
316 const file_ptr = self.file(elf_file).?;
307317 assert(file_ptr == .zig_module);
308318 const zig_module = file_ptr.zig_module;
309319 const rels = &zig_module.relocs.items[self.relocs_section_index];
......@@ -311,14 +321,14 @@ pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void {
311321}
312322
313323pub fn freeRelocs(self: Atom, elf_file: *Elf) void {
314 const file_ptr = elf_file.file(self.file_index).?;
324 const file_ptr = self.file(elf_file).?;
315325 assert(file_ptr == .zig_module);
316326 const zig_module = file_ptr.zig_module;
317327 zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity();
318328}
319329
320330pub fn scanRelocs(self: Atom, elf_file: *Elf, undefs: anytype) !void {
321 const file_ptr = elf_file.file(self.file_index).?;
331 const file_ptr = self.file(elf_file).?;
322332 const rels = try self.relocs(elf_file);
323333 var i: usize = 0;
324334 while (i < rels.len) : (i += 1) {
......@@ -392,7 +402,7 @@ fn reportUndefined(
392402 rel: elf.Elf64_Rela,
393403 undefs: anytype,
394404) !void {
395 const rel_esym = switch (elf_file.file(self.file_index).?) {
405 const rel_esym = switch (self.file(elf_file).?) {
396406 .zig_module => |x| x.elfSym(rel.r_sym()).*,
397407 .object => |x| x.symtab[rel.r_sym()],
398408 else => unreachable,
......@@ -416,7 +426,7 @@ fn reportUndefined(
416426pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void {
417427 relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
418428
419 const file_ptr = elf_file.file(self.file_index).?;
429 const file_ptr = self.file(elf_file).?;
420430 var stream = std.io.fixedBufferStream(code);
421431 const cwriter = stream.writer();
422432
......@@ -619,7 +629,7 @@ fn format2(
619629 // try writer.writeAll(" }");
620630 // }
621631 const gc_sections = if (elf_file.base.options.gc_sections) |gc_sections| gc_sections else false;
622 if (gc_sections and !atom.alive) {
632 if (gc_sections and !atom.flags.alive) {
623633 try writer.writeAll(" : [*]");
624634 }
625635}
......@@ -629,6 +639,17 @@ fn format2(
629639// future.
630640pub const Index = u16;
631641
642pub const Flags = packed struct {
643 /// Specifies whether this atom is alive or has been garbage collected.
644 alive: bool = false,
645
646 /// Specifies if the atom has been visited during garbage collection.
647 visited: bool = false,
648
649 /// Specifies whether this atom has been allocated in the output section.
650 allocated: bool = false,
651};
652
632653const x86_64 = struct {
633654 pub fn relaxGotpcrelx(code: []u8) !void {
634655 const old_inst = disassemble(code) orelse return error.RelaxFail;
src/link/Elf/Object.zig+6-6
......@@ -180,7 +180,7 @@ fn addAtom(
180180 atom.file_index = self.index;
181181 atom.input_section_index = shndx;
182182 atom.output_section_index = try self.getOutputSectionIndex(elf_file, shdr);
183 atom.alive = true;
183 atom.flags.alive = true;
184184 self.atoms.items[shndx] = atom_index;
185185
186186 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
......@@ -424,7 +424,7 @@ fn filterRelocs(
424424pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
425425 for (self.atoms.items) |atom_index| {
426426 const atom = elf_file.atom(atom_index) orelse continue;
427 if (!atom.alive) continue;
427 if (!atom.flags.alive) continue;
428428 const shdr = atom.inputShdr(elf_file);
429429 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
430430 if (shdr.sh_type == elf.SHT_NOBITS) continue;
......@@ -458,7 +458,7 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
458458 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
459459 const atom_index = self.atoms.items[esym.st_shndx];
460460 const atom = elf_file.atom(atom_index) orelse continue;
461 if (!atom.alive) continue;
461 if (!atom.flags.alive) continue;
462462 }
463463
464464 const global = elf_file.symbol(index);
......@@ -553,7 +553,7 @@ pub fn checkDuplicates(self: *Object, elf_file: *Elf) void {
553553 if (this_sym.st_shndx != elf.SHN_ABS) {
554554 const atom_index = self.atoms.items[this_sym.st_shndx];
555555 const atom = elf_file.atom(atom_index) orelse continue;
556 if (!atom.alive) continue;
556 if (!atom.flags.alive) continue;
557557 }
558558
559559 elf_file.base.fatal("multiple definition: {}: {}: {s}", .{
......@@ -628,7 +628,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
628628pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
629629 for (self.locals()) |local_index| {
630630 const local = elf_file.symbol(local_index);
631 if (local.atom(elf_file)) |atom| if (!atom.alive) continue;
631 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
632632 const esym = local.elfSym(elf_file);
633633 switch (esym.st_type()) {
634634 elf.STT_SECTION, elf.STT_NOTYPE => continue,
......@@ -641,7 +641,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
641641 for (self.globals()) |global_index| {
642642 const global = elf_file.symbol(global_index);
643643 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
644 if (global.atom(elf_file)) |atom| if (!atom.alive) continue;
644 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
645645 global.flags.output_symtab = true;
646646 if (global.isLocal()) {
647647 self.output_symtab_size.nlocals += 1;
src/link/Elf/ZigModule.zig+7-5
......@@ -53,17 +53,19 @@ pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
5353 const gpa = elf_file.base.allocator;
5454
5555 const atom_index = try elf_file.addAtom();
56 const symbol_index = try elf_file.addSymbol();
57 const esym_index = try self.addLocalEsym(gpa);
58
5659 try self.atoms.putNoClobber(gpa, atom_index, {});
60 try self.local_symbols.append(gpa, symbol_index);
61
5762 const atom_ptr = elf_file.atom(atom_index).?;
5863 atom_ptr.file_index = self.index;
5964
60 const symbol_index = try elf_file.addSymbol();
61 try self.local_symbols.append(gpa, symbol_index);
6265 const symbol_ptr = elf_file.symbol(symbol_index);
6366 symbol_ptr.file_index = self.index;
6467 symbol_ptr.atom_index = atom_index;
6568
66 const esym_index = try self.addLocalEsym(gpa);
6769 const esym = &self.local_esyms.items[esym_index];
6870 esym.st_shndx = atom_index;
6971 symbol_ptr.esym_index = esym_index;
......@@ -86,7 +88,7 @@ pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
8688 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
8789 const atom_index = esym.st_shndx;
8890 const atom = elf_file.atom(atom_index) orelse continue;
89 if (!atom.alive) continue;
91 if (!atom.flags.alive) continue;
9092 }
9193
9294 const global = elf_file.symbol(index);
......@@ -141,7 +143,7 @@ pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {
141143pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {
142144 for (self.atoms.keys()) |atom_index| {
143145 const atom = elf_file.atom(atom_index) orelse continue;
144 if (!atom.alive) continue;
146 if (!atom.flags.alive) continue;
145147 try atom.scanRelocs(elf_file, undefs);
146148 }
147149}
src/link/Elf/file.zig+16
......@@ -89,6 +89,21 @@ pub const File = union(enum) {
8989 }
9090 }
9191
92 pub fn atoms(file: File) []const Atom.Index {
93 return switch (file) {
94 .linker_defined => unreachable,
95 .zig_module => |x| x.atoms.keys(),
96 .object => |x| x.atoms.items,
97 };
98 }
99
100 pub fn locals(file: File) []const Symbol.Index {
101 return switch (file) {
102 .linker_defined => unreachable,
103 inline else => |x| x.locals(),
104 };
105 }
106
92107 pub fn globals(file: File) []const Symbol.Index {
93108 return switch (file) {
94109 inline else => |x| x.globals(),
......@@ -110,6 +125,7 @@ const std = @import("std");
110125const elf = std.elf;
111126
112127const Allocator = std.mem.Allocator;
128const Atom = @import("Atom.zig");
113129const Elf = @import("../Elf.zig");
114130const LinkerDefined = @import("LinkerDefined.zig");
115131const Object = @import("Object.zig");
src/link/Elf/synthetic_sections.zig+15
......@@ -169,6 +169,21 @@ pub const GotSection = struct {
169169 }
170170 }
171171
172 pub fn writeAllEntries(got: GotSection, elf_file: *Elf, writer: anytype) !void {
173 assert(!got.dirty);
174 const entry_size: u16 = elf_file.archPtrWidthBytes();
175 const endian = elf_file.base.options.target.cpu.arch.endian();
176 for (got.entries.items) |entry| {
177 const value = elf_file.symbol(entry.symbol_index).value;
178 switch (entry_size) {
179 2 => try writer.writeInt(u16, @intCast(value), endian),
180 4 => try writer.writeInt(u32, @intCast(value), endian),
181 8 => try writer.writeInt(u64, @intCast(value), endian),
182 else => unreachable,
183 }
184 }
185 }
186
172187 // pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void {
173188 // const is_shared = elf_file.options.output_mode == .lib;
174189 // const apply_relocs = elf_file.options.apply_dynamic_relocs;