authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-24 16:03:29+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-30 10:00:50+02:00
log669f28594393e90e4d1aacd0d28f67ebe015b922
tree08f6d4e19a0b8dfc431171214fffdb6e6d956883
parentf1fedb3a51d4d9a37e4568ce1a80149bb5a610f7

elf: move ownership of atoms into objects


15 files changed, 464 insertions(+), 353 deletions(-)

src/link/Elf.zig+39-99
......@@ -54,7 +54,7 @@ phdr_to_shdr_table: std.AutoHashMapUnmanaged(u32, u32) = .{},
5454shdr_table_offset: ?u64 = null,
5555/// Table of lists of atoms per output section.
5656/// This table is not used to track incrementally generated atoms.
57output_sections: std.AutoArrayHashMapUnmanaged(u32, std.ArrayListUnmanaged(Atom.Index)) = .{},
57output_sections: std.AutoArrayHashMapUnmanaged(u32, std.ArrayListUnmanaged(Ref)) = .{},
5858output_rela_sections: std.AutoArrayHashMapUnmanaged(u32, RelaSection) = .{},
5959
6060/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
......@@ -203,10 +203,6 @@ resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
203203has_text_reloc: bool = false,
204204num_ifunc_dynrelocs: usize = 0,
205205
206/// List of atoms that are owned directly by the linker.
207atoms: std.ArrayListUnmanaged(Atom) = .{},
208atoms_extra: std.ArrayListUnmanaged(u32) = .{},
209
210206/// List of range extension thunks.
211207thunks: std.ArrayListUnmanaged(Thunk) = .{},
212208
......@@ -375,9 +371,6 @@ pub fn createEmpty(
375371 try self.symbols.append(gpa, .{});
376372 // Index 0 is always a null symbol.
377373 try self.symbols_extra.append(gpa, 0);
378 // Allocate atom index 0 to null atom
379 try self.atoms.append(gpa, .{});
380 try self.atoms_extra.append(gpa, 0);
381374 // Append null file at index 0
382375 try self.files.append(gpa, .null);
383376 // Append null byte to string tables
......@@ -499,8 +492,6 @@ pub fn deinit(self: *Elf) void {
499492 self.resolver.deinit(gpa);
500493 self.start_stop_indexes.deinit(gpa);
501494
502 self.atoms.deinit(gpa);
503 self.atoms_extra.deinit(gpa);
504495 for (self.thunks.items) |*th| {
505496 th.deinit(gpa);
506497 }
......@@ -1305,6 +1296,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
13051296 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
13061297 self.files.set(index, .{ .linker_defined = .{ .index = index } });
13071298 self.linker_defined_index = index;
1299 const object = self.file(index).?.linker_defined;
1300 try object.init(gpa);
13081301 }
13091302
13101303 // Now, we are ready to resolve the symbols across all input files.
......@@ -1379,15 +1372,15 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
13791372
13801373 // Beyond this point, everything has been allocated a virtual address and we can resolve
13811374 // the relocations, and commit objects to file.
1382 if (self.zigObjectPtr()) |zig_object| {
1375 if (self.zigObjectPtr()) |zo| {
13831376 var has_reloc_errors = false;
1384 for (zig_object.atoms.items) |atom_index| {
1385 const atom_ptr = self.atom(atom_index) orelse continue;
1377 for (zo.atoms_indexes.items) |atom_index| {
1378 const atom_ptr = zo.atom(atom_index) orelse continue;
13861379 if (!atom_ptr.flags.alive) continue;
13871380 const out_shndx = atom_ptr.outputShndx() orelse continue;
13881381 const shdr = &self.shdrs.items[out_shndx];
13891382 if (shdr.sh_type == elf.SHT_NOBITS) continue;
1390 const code = try zig_object.codeAlloc(self, atom_index);
1383 const code = try zo.codeAlloc(self, atom_index);
13911384 defer gpa.free(code);
13921385 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
13931386 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
......@@ -2012,8 +2005,8 @@ pub fn resolveSymbols(self: *Elf) void {
20122005 const cg_owner = self.comdatGroupOwner(cg.owner);
20132006 if (cg_owner.file != index) {
20142007 for (cg.comdatGroupMembers(self)) |shndx| {
2015 const atom_index = object.atoms.items[shndx];
2016 if (self.atom(atom_index)) |atom_ptr| {
2008 const atom_index = object.atoms_indexes.items[shndx];
2009 if (object.atom(atom_index)) |atom_ptr| {
20172010 atom_ptr.flags.alive = false;
20182011 atom_ptr.markFdesDead(self);
20192012 }
......@@ -2117,7 +2110,7 @@ fn claimUnresolved(self: *Elf) void {
21172110fn scanRelocs(self: *Elf) !void {
21182111 const gpa = self.base.comp.gpa;
21192112
2120 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Atom.Index)).init(gpa);
2113 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa);
21212114 defer {
21222115 var it = undefs.iterator();
21232116 while (it.next()) |entry| {
......@@ -3721,11 +3714,11 @@ fn sortInitFini(self: *Elf) !void {
37213714
37223715 const Entry = struct {
37233716 priority: i32,
3724 atom_index: Atom.Index,
3717 atom_ref: Ref,
37253718
37263719 pub fn lessThan(ctx: *Elf, lhs: @This(), rhs: @This()) bool {
37273720 if (lhs.priority == rhs.priority) {
3728 return ctx.atom(lhs.atom_index).?.priority(ctx) < ctx.atom(rhs.atom_index).?.priority(ctx);
3721 return ctx.atom(lhs.atom_ref).?.priority(ctx) < ctx.atom(rhs.atom_ref).?.priority(ctx);
37293722 }
37303723 return lhs.priority < rhs.priority;
37313724 }
......@@ -3756,8 +3749,8 @@ fn sortInitFini(self: *Elf) !void {
37563749 try entries.ensureTotalCapacityPrecise(atom_list.items.len);
37573750 defer entries.deinit();
37583751
3759 for (atom_list.items) |atom_index| {
3760 const atom_ptr = self.atom(atom_index).?;
3752 for (atom_list.items) |ref| {
3753 const atom_ptr = self.atom(ref).?;
37613754 const object = atom_ptr.file(self).?.object;
37623755 const priority = blk: {
37633756 if (is_ctor_dtor) {
......@@ -3770,14 +3763,14 @@ fn sortInitFini(self: *Elf) !void {
37703763 const priority = std.fmt.parseUnsigned(u16, it.first(), 10) catch default;
37713764 break :blk priority;
37723765 };
3773 entries.appendAssumeCapacity(.{ .priority = priority, .atom_index = atom_index });
3766 entries.appendAssumeCapacity(.{ .priority = priority, .atom_ref = ref });
37743767 }
37753768
37763769 mem.sort(Entry, entries.items, self, Entry.lessThan);
37773770
37783771 atom_list.clearRetainingCapacity();
37793772 for (entries.items) |entry| {
3780 atom_list.appendAssumeCapacity(entry.atom_index);
3773 atom_list.appendAssumeCapacity(entry.atom_ref);
37813774 }
37823775 }
37833776}
......@@ -4143,23 +4136,23 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
41434136 }
41444137 }
41454138
4146 if (self.zigObjectPtr()) |zig_object| {
4147 for (zig_object.atoms.items) |atom_index| {
4148 const atom_ptr = self.atom(atom_index) orelse continue;
4139 if (self.zigObjectPtr()) |zo| {
4140 for (zo.atoms_indexes.items) |atom_index| {
4141 const atom_ptr = zo.atom(atom_index) orelse continue;
41494142 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
41504143 }
41514144
4152 for (zig_object.locals()) |local_index| {
4145 for (zo.locals()) |local_index| {
41534146 const local = self.symbol(local_index);
41544147 local.output_section_index = backlinks[local.output_section_index];
41554148 }
41564149
4157 for (zig_object.globals()) |global_index| {
4150 for (zo.globals()) |global_index| {
41584151 const global = self.symbol(global_index);
41594152 const atom_ptr = global.atom(self) orelse continue;
41604153 if (!atom_ptr.flags.alive) continue;
41614154 // TODO claim unresolved for objects
4162 if (global.file(self).?.index() != zig_object.index) continue;
4155 if (global.file(self).?.index() != zo.index) continue;
41634156 const out_shndx = global.outputShndx() orelse continue;
41644157 global.output_section_index = backlinks[out_shndx];
41654158 }
......@@ -4182,8 +4175,8 @@ fn updateSectionSizes(self: *Elf) !void {
41824175 const shdr = &self.shdrs.items[shndx];
41834176 if (atom_list.items.len == 0) continue;
41844177 if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue;
4185 for (atom_list.items) |atom_index| {
4186 const atom_ptr = self.atom(atom_index) orelse continue;
4178 for (atom_list.items) |ref| {
4179 const atom_ptr = self.atom(ref) orelse continue;
41874180 if (!atom_ptr.flags.alive) continue;
41884181 const offset = atom_ptr.alignment.forward(shdr.sh_size);
41894182 const padding = offset - shdr.sh_size;
......@@ -4618,7 +4611,7 @@ fn allocateSpecialPhdrs(self: *Elf) void {
46184611fn writeAtoms(self: *Elf) !void {
46194612 const gpa = self.base.comp.gpa;
46204613
4621 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Atom.Index)).init(gpa);
4614 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa);
46224615 defer {
46234616 var it = undefs.iterator();
46244617 while (it.next()) |entry| {
......@@ -4666,21 +4659,21 @@ fn writeAtoms(self: *Elf) !void {
46664659 0;
46674660 @memset(buffer, padding_byte);
46684661
4669 for (atom_list.items) |atom_index| {
4670 const atom_ptr = self.atom(atom_index).?;
4662 for (atom_list.items) |ref| {
4663 const atom_ptr = self.atom(ref).?;
46714664 assert(atom_ptr.flags.alive);
46724665
46734666 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(base_offset))) orelse
46744667 return error.Overflow;
46754668 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
46764669
4677 log.debug("writing atom({d}) at 0x{x}", .{ atom_index, sh_offset + offset });
4670 log.debug("writing atom({}) at 0x{x}", .{ ref, sh_offset + offset });
46784671
46794672 // TODO decompress directly into provided buffer
46804673 const out_code = buffer[offset..][0..size];
46814674 const in_code = switch (atom_ptr.file(self).?) {
4682 .object => |x| try x.codeDecompressAlloc(self, atom_index),
4683 .zig_object => |x| try x.codeAlloc(self, atom_index),
4675 .object => |x| try x.codeDecompressAlloc(self, ref.index),
4676 .zig_object => |x| try x.codeAlloc(self, ref.index),
46844677 else => unreachable,
46854678 };
46864679 defer gpa.free(in_code);
......@@ -5598,64 +5591,6 @@ fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
55985591 return null;
55995592}
56005593
5601pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom {
5602 if (atom_index == 0) return null;
5603 assert(atom_index < self.atoms.items.len);
5604 return &self.atoms.items[atom_index];
5605}
5606
5607pub fn addAtom(self: *Elf) !Atom.Index {
5608 const gpa = self.base.comp.gpa;
5609 const index = @as(Atom.Index, @intCast(self.atoms.items.len));
5610 const atom_ptr = try self.atoms.addOne(gpa);
5611 atom_ptr.* = .{ .atom_index = index };
5612 return index;
5613}
5614
5615pub fn addAtomExtra(self: *Elf, extra: Atom.Extra) !u32 {
5616 const fields = @typeInfo(Atom.Extra).Struct.fields;
5617 try self.atoms_extra.ensureUnusedCapacity(self.base.comp.gpa, fields.len);
5618 return self.addAtomExtraAssumeCapacity(extra);
5619}
5620
5621pub fn addAtomExtraAssumeCapacity(self: *Elf, extra: Atom.Extra) u32 {
5622 const index = @as(u32, @intCast(self.atoms_extra.items.len));
5623 const fields = @typeInfo(Atom.Extra).Struct.fields;
5624 inline for (fields) |field| {
5625 self.atoms_extra.appendAssumeCapacity(switch (field.type) {
5626 u32 => @field(extra, field.name),
5627 else => @compileError("bad field type"),
5628 });
5629 }
5630 return index;
5631}
5632
5633pub fn atomExtra(self: *Elf, index: u32) ?Atom.Extra {
5634 if (index == 0) return null;
5635 const fields = @typeInfo(Atom.Extra).Struct.fields;
5636 var i: usize = index;
5637 var result: Atom.Extra = undefined;
5638 inline for (fields) |field| {
5639 @field(result, field.name) = switch (field.type) {
5640 u32 => self.atoms_extra.items[i],
5641 else => @compileError("bad field type"),
5642 };
5643 i += 1;
5644 }
5645 return result;
5646}
5647
5648pub fn setAtomExtra(self: *Elf, index: u32, extra: Atom.Extra) void {
5649 assert(index > 0);
5650 const fields = @typeInfo(Atom.Extra).Struct.fields;
5651 inline for (fields, 0..) |field, i| {
5652 self.atoms_extra.items[index + i] = switch (field.type) {
5653 u32 => @field(extra, field.name),
5654 else => @compileError("bad field type"),
5655 };
5656 }
5657}
5658
56595594pub fn addThunk(self: *Elf) !Thunk.Index {
56605595 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));
56615596 const th = try self.thunks.addOne(self.base.comp.gpa);
......@@ -5692,6 +5627,11 @@ pub fn fileHandle(self: Elf, index: File.HandleIndex) File.Handle {
56925627 return self.file_handles.items[index];
56935628}
56945629
5630pub fn atom(self: *Elf, ref: Ref) ?*Atom {
5631 const file_ptr = self.file(ref.file) orelse return null;
5632 return file_ptr.atom(ref.index);
5633}
5634
56955635/// Returns pointer-to-symbol described at sym_index.
56965636pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {
56975637 return &self.symbols.items[sym_index];
......@@ -5938,9 +5878,9 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
59385878 var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes);
59395879 try err.addMsg("undefined symbol: {s}", .{self.symbol(undef_index).name(self)});
59405880
5941 for (atoms[0..natoms]) |atom_index| {
5942 const atom_ptr = self.atom(atom_index).?;
5943 const file_ptr = self.file(atom_ptr.file_index).?;
5881 for (atoms[0..natoms]) |ref| {
5882 const atom_ptr = self.atom(ref).?;
5883 const file_ptr = self.file(ref.file).?;
59445884 try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
59455885 }
59465886
......@@ -6401,7 +6341,7 @@ const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u32, LastAtomAndF
64016341
64026342const RelaSection = struct {
64036343 shndx: u32,
6404 atom_list: std.ArrayListUnmanaged(Atom.Index) = .{},
6344 atom_list: std.ArrayListUnmanaged(Ref) = .{},
64056345};
64066346const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
64076347
src/link/Elf/Atom.zig+29-27
......@@ -68,7 +68,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
6868
6969pub fn thunk(self: Atom, elf_file: *Elf) *Thunk {
7070 assert(self.flags.thunk);
71 const extras = self.extra(elf_file).?;
71 const extras = self.extra(elf_file);
7272 return elf_file.thunk(extras.thunk);
7373}
7474
......@@ -99,7 +99,8 @@ pub fn priority(self: Atom, elf_file: *Elf) u64 {
9999/// File offset relocation happens transparently, so it is not included in
100100/// this calculation.
101101pub fn capacity(self: Atom, elf_file: *Elf) u64 {
102 const next_addr = if (elf_file.atom(self.next_index)) |next|
102 const zo = elf_file.zigObjectPtr().?;
103 const next_addr = if (zo.atom(self.next_index)) |next|
103104 next.address(elf_file)
104105 else
105106 std.math.maxInt(u32);
......@@ -107,8 +108,9 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
107108}
108109
109110pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
111 const zo = elf_file.zigObjectPtr().?;
110112 // No need to keep a free list node for the last block.
111 const next = elf_file.atom(self.next_index) orelse return false;
113 const next = zo.atom(self.next_index) orelse return false;
112114 const cap: u64 = @intCast(next.address(elf_file) - self.address(elf_file));
113115 const ideal_cap = Elf.padToIdeal(self.size);
114116 if (cap <= ideal_cap) return false;
......@@ -117,6 +119,7 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
117119}
118120
119121pub fn allocate(self: *Atom, elf_file: *Elf) !void {
122 const zo = elf_file.zigObjectPtr().?;
120123 const shdr = &elf_file.shdrs.items[self.outputShndx().?];
121124 const meta = elf_file.last_atom_and_free_list_table.getPtr(self.outputShndx().?).?;
122125 const free_list = &meta.free_list;
......@@ -137,7 +140,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
137140 var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;
138141 while (i < free_list.items.len) {
139142 const big_atom_index = free_list.items[i];
140 const big_atom = elf_file.atom(big_atom_index).?;
143 const big_atom = zo.atom(big_atom_index).?;
141144 // We now have a pointer to a live atom that has too much capacity.
142145 // Is it enough that we could fit this new atom?
143146 const cap = big_atom.capacity(elf_file);
......@@ -169,7 +172,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
169172 free_list_removal = i;
170173 }
171174 break :blk @intCast(new_start_vaddr);
172 } else if (elf_file.atom(last_atom_index.*)) |last| {
175 } else if (zo.atom(last_atom_index.*)) |last| {
173176 const ideal_capacity = Elf.padToIdeal(last.size);
174177 const ideal_capacity_end_vaddr = @as(u64, @intCast(last.value)) + ideal_capacity;
175178 const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);
......@@ -189,7 +192,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
189192 });
190193
191194 const expand_section = if (atom_placement) |placement_index|
192 elf_file.atom(placement_index).?.next_index == 0
195 zo.atom(placement_index).?.next_index == 0
193196 else
194197 true;
195198 if (expand_section) {
......@@ -214,15 +217,15 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
214217 // This function can also reallocate an atom.
215218 // In this case we need to "unplug" it from its previous location before
216219 // plugging it in to its new location.
217 if (elf_file.atom(self.prev_index)) |prev| {
220 if (zo.atom(self.prev_index)) |prev| {
218221 prev.next_index = self.next_index;
219222 }
220 if (elf_file.atom(self.next_index)) |next| {
223 if (zo.atom(self.next_index)) |next| {
221224 next.prev_index = self.prev_index;
222225 }
223226
224227 if (atom_placement) |big_atom_index| {
225 const big_atom = elf_file.atom(big_atom_index).?;
228 const big_atom = zo.atom(big_atom_index).?;
226229 self.prev_index = big_atom_index;
227230 self.next_index = big_atom.next_index;
228231 big_atom.next_index = self.atom_index;
......@@ -250,6 +253,7 @@ pub fn grow(self: *Atom, elf_file: *Elf) !void {
250253pub fn free(self: *Atom, elf_file: *Elf) void {
251254 log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) });
252255
256 const zo = elf_file.zigObjectPtr().?;
253257 const comp = elf_file.base.comp;
254258 const gpa = comp.gpa;
255259 const shndx = self.outputShndx().?;
......@@ -272,9 +276,9 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
272276 }
273277 }
274278
275 if (elf_file.atom(last_atom_index.*)) |last_atom| {
279 if (zo.atom(last_atom_index.*)) |last_atom| {
276280 if (last_atom.atom_index == self.atom_index) {
277 if (elf_file.atom(self.prev_index)) |_| {
281 if (zo.atom(self.prev_index)) |_| {
278282 // TODO shrink the section size here
279283 last_atom_index.* = self.prev_index;
280284 } else {
......@@ -283,7 +287,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
283287 }
284288 }
285289
286 if (elf_file.atom(self.prev_index)) |prev| {
290 if (zo.atom(self.prev_index)) |prev| {
287291 prev.next_index = self.next_index;
288292 if (!already_have_free_list_node and prev.*.freeListEligible(elf_file)) {
289293 // The free list is heuristics, it doesn't have to be perfect, so we can
......@@ -294,7 +298,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
294298 self.prev_index = 0;
295299 }
296300
297 if (elf_file.atom(self.next_index)) |next| {
301 if (zo.atom(self.next_index)) |next| {
298302 next.prev_index = self.prev_index;
299303 } else {
300304 self.next_index = 0;
......@@ -313,7 +317,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela {
313317 switch (self.file(elf_file).?) {
314318 .zig_object => |x| return x.relocs.items[shndx].items,
315319 .object => |x| {
316 const extras = self.extra(elf_file).?;
320 const extras = self.extra(elf_file);
317321 return x.relocs.items[extras.rel_index..][0..extras.rel_count];
318322 },
319323 else => unreachable,
......@@ -367,7 +371,7 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
367371
368372pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
369373 if (!self.flags.fde) return &[0]Fde{};
370 const extras = self.extra(elf_file).?;
374 const extras = self.extra(elf_file);
371375 const object = self.file(elf_file).?.object;
372376 return object.fdes.items[extras.fde_start..][0..extras.fde_count];
373377}
......@@ -712,9 +716,9 @@ fn reportUndefined(
712716 {
713717 const gop = try undefs.getOrPut(sym_index);
714718 if (!gop.found_existing) {
715 gop.value_ptr.* = std.ArrayList(Atom.Index).init(gpa);
719 gop.value_ptr.* = std.ArrayList(Elf.Ref).init(gpa);
716720 }
717 try gop.value_ptr.append(self.atom_index);
721 try gop.value_ptr.append(.{ .index = self.atom_index, .file = self.file_index });
718722 return true;
719723 }
720724
......@@ -1001,25 +1005,23 @@ const AddExtraOpts = struct {
10011005 rel_count: ?u32 = null,
10021006};
10031007
1004pub fn addExtra(atom: *Atom, opts: AddExtraOpts, elf_file: *Elf) !void {
1005 if (atom.extra(elf_file) == null) {
1006 atom.extra_index = try elf_file.addAtomExtra(.{});
1007 }
1008 var extras = atom.extra(elf_file).?;
1008pub fn addExtra(atom: *Atom, opts: AddExtraOpts, elf_file: *Elf) void {
1009 const file_ptr = atom.file(elf_file).?;
1010 var extras = file_ptr.atomExtra(atom.extra_index);
10091011 inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {
10101012 if (@field(opts, field.name)) |x| {
10111013 @field(extras, field.name) = x;
10121014 }
10131015 }
1014 atom.setExtra(extras, elf_file);
1016 file_ptr.setAtomExtra(atom.extra_index, extras);
10151017}
10161018
1017pub inline fn extra(atom: Atom, elf_file: *Elf) ?Extra {
1018 return elf_file.atomExtra(atom.extra_index);
1019pub inline fn extra(atom: Atom, elf_file: *Elf) Extra {
1020 return atom.file(elf_file).?.atomExtra(atom.extra_index);
10191021}
10201022
10211023pub inline fn setExtra(atom: Atom, extras: Extra, elf_file: *Elf) void {
1022 elf_file.setAtomExtra(atom.extra_index, extras);
1024 atom.file(elf_file).?.setAtomExtra(atom.extra_index, extras);
10231025}
10241026
10251027pub fn format(
......@@ -1063,7 +1065,7 @@ fn format2(
10631065 });
10641066 if (atom.flags.fde) {
10651067 try writer.writeAll(" : fdes{ ");
1066 const extras = atom.extra(elf_file).?;
1068 const extras = atom.extra(elf_file);
10671069 for (atom.fdes(elf_file), extras.fde_start..) |fde, i| {
10681070 try writer.print("{d}", .{i});
10691071 if (!fde.alive) try writer.writeAll("([*])");
src/link/Elf/LinkerDefined.zig+8-1
......@@ -1,4 +1,5 @@
11index: File.Index,
2
23symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
34strtab: std.ArrayListUnmanaged(u8) = .{},
45symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
......@@ -11,6 +12,11 @@ pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
1112 self.symbols.deinit(allocator);
1213}
1314
15pub fn init(self: *LinkerDefined, allocator: Allocator) !void {
16 // Null byte in strtab
17 try self.strtab.append(allocator, 0);
18}
19
1420pub fn addGlobal(self: *LinkerDefined, name: [:0]const u8, elf_file: *Elf) !u32 {
1521 const comp = elf_file.base.comp;
1622 const gpa = comp.gpa;
......@@ -41,7 +47,7 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
4147 const global = elf_file.symbol(index);
4248 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
4349 global.value = 0;
44 global.atom_index = 0;
50 global.atom_ref = .{ .index = 0, .file = 0 };
4551 global.file_index = self.index;
4652 global.esym_index = sym_idx;
4753 global.version_index = elf_file.default_sym_version;
......@@ -127,6 +133,7 @@ const mem = std.mem;
127133const std = @import("std");
128134
129135const Allocator = mem.Allocator;
136const Atom = @import("Atom.zig");
130137const Elf = @import("../Elf.zig");
131138const File = @import("file.zig").File;
132139const LinkerDefined = @This();
src/link/Elf/Object.zig+199-123
......@@ -10,9 +10,12 @@ symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
1010strtab: std.ArrayListUnmanaged(u8) = .{},
1111first_global: ?Symbol.Index = null,
1212symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
13atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
1413relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
1514
15atoms: std.ArrayListUnmanaged(Atom) = .{},
16atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
17atoms_extra: std.ArrayListUnmanaged(u32) = .{},
18
1619comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .{},
1720comdat_group_data: std.ArrayListUnmanaged(u32) = .{},
1821
......@@ -49,6 +52,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
4952 self.strtab.deinit(allocator);
5053 self.symbols.deinit(allocator);
5154 self.atoms.deinit(allocator);
55 self.atoms_indexes.deinit(allocator);
56 self.atoms_extra.deinit(allocator);
5257 self.comdat_groups.deinit(allocator);
5358 self.comdat_group_data.deinit(allocator);
5459 self.relocs.deinit(allocator);
......@@ -71,15 +76,17 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
7176
7277 // Append null input merge section
7378 try self.input_merge_sections.append(gpa, .{});
79 // Allocate atom index 0 to null atom
80 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) });
7481
7582 try self.initAtoms(gpa, handle, elf_file);
7683 try self.initSymtab(gpa, elf_file);
7784
7885 for (self.shdrs.items, 0..) |shdr, i| {
79 const atom = elf_file.atom(self.atoms.items[i]) orelse continue;
80 if (!atom.flags.alive) continue;
86 const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue;
87 if (!atom_ptr.flags.alive) continue;
8188 if ((cpu_arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or
82 mem.eql(u8, atom.name(elf_file), ".eh_frame"))
89 mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame"))
8390 {
8491 try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file);
8592 }
......@@ -179,8 +186,11 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
179186
180187fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void {
181188 const shdrs = self.shdrs.items;
182 try self.atoms.resize(allocator, shdrs.len);
183 @memset(self.atoms.items, 0);
189 try self.atoms.ensureTotalCapacityPrecise(allocator, shdrs.len);
190 try self.atoms_extra.ensureTotalCapacityPrecise(allocator, shdrs.len * @sizeOf(Atom.Extra));
191 try self.atoms_indexes.ensureTotalCapacityPrecise(allocator, shdrs.len);
192 try self.atoms_indexes.resize(allocator, shdrs.len);
193 @memset(self.atoms_indexes.items, 0);
184194
185195 for (shdrs, 0..) |shdr, i| {
186196 if (shdr.sh_flags & elf.SHF_EXCLUDE != 0 and
......@@ -242,7 +252,19 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
242252 else => {
243253 const shndx = @as(u32, @intCast(i));
244254 if (self.skipShdr(shndx, elf_file)) continue;
245 try self.addAtom(allocator, handle, shdr, shndx, elf_file);
255 const size, const alignment = if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) blk: {
256 const data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
257 defer allocator.free(data);
258 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
259 break :blk .{ chdr.ch_size, Alignment.fromNonzeroByteUnits(chdr.ch_addralign) };
260 } else .{ shdr.sh_size, Alignment.fromNonzeroByteUnits(shdr.sh_addralign) };
261 const atom_index = self.addAtomAssumeCapacity(.{
262 .name = shdr.sh_name,
263 .shndx = shndx,
264 .size = size,
265 .alignment = alignment,
266 });
267 self.atoms_indexes.items[shndx] = atom_index;
246268 },
247269 }
248270 }
......@@ -250,14 +272,14 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
250272 // Parse relocs sections if any.
251273 for (shdrs, 0..) |shdr, i| switch (shdr.sh_type) {
252274 elf.SHT_REL, elf.SHT_RELA => {
253 const atom_index = self.atoms.items[shdr.sh_info];
254 if (elf_file.atom(atom_index)) |atom| {
275 const atom_index = self.atoms_indexes.items[shdr.sh_info];
276 if (self.atom(atom_index)) |atom_ptr| {
255277 const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i));
256278 defer allocator.free(relocs);
257 atom.relocs_section_index = @intCast(i);
279 atom_ptr.relocs_section_index = @intCast(i);
258280 const rel_index: u32 = @intCast(self.relocs.items.len);
259281 const rel_count: u32 = @intCast(relocs.len);
260 try atom.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, elf_file);
282 atom_ptr.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, elf_file);
261283 try self.relocs.appendUnalignedSlice(allocator, relocs);
262284 if (elf_file.getTarget().cpu.arch == .riscv64) {
263285 sortRelocs(self.relocs.items[rel_index..][0..rel_count]);
......@@ -268,27 +290,6 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
268290 };
269291}
270292
271fn addAtom(self: *Object, allocator: Allocator, handle: std.fs.File, shdr: elf.Elf64_Shdr, shndx: u32, elf_file: *Elf) !void {
272 const atom_index = try elf_file.addAtom();
273 const atom = elf_file.atom(atom_index).?;
274 atom.atom_index = atom_index;
275 atom.name_offset = shdr.sh_name;
276 atom.file_index = self.index;
277 atom.input_section_index = shndx;
278 self.atoms.items[shndx] = atom_index;
279
280 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
281 const data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
282 defer allocator.free(data);
283 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
284 atom.size = chdr.ch_size;
285 atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign);
286 } else {
287 atom.size = shdr.sh_size;
288 atom.alignment = Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
289 }
290}
291
292293fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u32 {
293294 const name = blk: {
294295 const name = self.getString(shdr.sh_name);
......@@ -368,8 +369,10 @@ fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
368369 sym_ptr.value = @intCast(sym.st_value);
369370 sym_ptr.name_offset = sym.st_name;
370371 sym_ptr.esym_index = @as(u32, @intCast(i));
371 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];
372372 sym_ptr.file_index = self.index;
373 if (sym.st_shndx != elf.SHN_ABS) {
374 sym_ptr.atom_ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index };
375 }
373376 }
374377
375378 for (self.symtab.items[first_global..]) |sym| {
......@@ -456,15 +459,15 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
456459 var i: u32 = @as(u32, @intCast(fdes_start));
457460 while (i < self.fdes.items.len) {
458461 const fde = self.fdes.items[i];
459 const atom = fde.atom(elf_file);
462 const atom_ptr = fde.atom(elf_file);
460463 const start = i;
461464 i += 1;
462465 while (i < self.fdes.items.len) : (i += 1) {
463466 const next_fde = self.fdes.items[i];
464 if (atom.atom_index != next_fde.atom(elf_file).atom_index) break;
467 if (atom_ptr.atom_index != next_fde.atom(elf_file).atom_index) break;
465468 }
466 try atom.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);
467 atom.flags.fde = true;
469 atom_ptr.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);
470 atom_ptr.flags.fde = true;
468471 }
469472}
470473
......@@ -507,19 +510,19 @@ fn filterRelocs(
507510pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
508511 const comp = elf_file.base.comp;
509512 const gpa = comp.gpa;
510 for (self.atoms.items) |atom_index| {
511 const atom = elf_file.atom(atom_index) orelse continue;
512 if (!atom.flags.alive) continue;
513 const shdr = atom.inputShdr(elf_file);
513 for (self.atoms_indexes.items) |atom_index| {
514 const atom_ptr = self.atom(atom_index) orelse continue;
515 if (!atom_ptr.flags.alive) continue;
516 const shdr = atom_ptr.inputShdr(elf_file);
514517 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
515518 if (shdr.sh_type == elf.SHT_NOBITS) continue;
516 if (atom.scanRelocsRequiresCode(elf_file)) {
519 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
517520 // TODO ideally, we don't have to decompress at this stage (should already be done)
518521 // and we just fetch the code slice.
519522 const code = try self.codeDecompressAlloc(elf_file, atom_index);
520523 defer gpa.free(code);
521 try atom.scanRelocs(elf_file, code, undefs);
522 } else try atom.scanRelocs(elf_file, null, undefs);
524 try atom_ptr.scanRelocs(elf_file, code, undefs);
525 } else try atom_ptr.scanRelocs(elf_file, null, undefs);
523526 }
524527
525528 for (self.cies.items) |cie| {
......@@ -547,19 +550,21 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
547550 if (esym.st_shndx == elf.SHN_UNDEF) continue;
548551
549552 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
550 const atom_index = self.atoms.items[esym.st_shndx];
551 const atom = elf_file.atom(atom_index) orelse continue;
552 if (!atom.flags.alive) continue;
553 const atom_index = self.atoms_indexes.items[esym.st_shndx];
554 const atom_ptr = self.atom(atom_index) orelse continue;
555 if (!atom_ptr.flags.alive) continue;
553556 }
554557
555558 const global = elf_file.symbol(index);
556559 if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) {
557 const atom_index = switch (esym.st_shndx) {
558 elf.SHN_ABS, elf.SHN_COMMON => 0,
559 else => self.atoms.items[esym.st_shndx],
560 };
560 switch (esym.st_shndx) {
561 elf.SHN_ABS, elf.SHN_COMMON => {},
562 else => global.atom_ref = .{
563 .index = self.atoms_indexes.items[esym.st_shndx],
564 .file = self.index,
565 },
566 }
561567 global.value = @intCast(esym.st_value);
562 global.atom_index = atom_index;
563568 global.esym_index = esym_index;
564569 global.file_index = self.index;
565570 global.version_index = elf_file.default_sym_version;
......@@ -588,7 +593,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
588593 };
589594
590595 global.value = 0;
591 global.atom_index = 0;
596 global.atom_ref = .{ .index = 0, .file = 0 };
592597 global.esym_index = esym_index;
593598 global.file_index = self.index;
594599 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
......@@ -609,7 +614,7 @@ pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
609614 }
610615
611616 global.value = 0;
612 global.atom_index = 0;
617 global.atom_ref = .{ .index = 0, .file = 0 };
613618 global.esym_index = esym_index;
614619 global.file_index = self.index;
615620 }
......@@ -633,13 +638,13 @@ pub fn markLive(self: *Object, elf_file: *Elf) void {
633638 }
634639}
635640
636pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void {
641pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {
637642 const cpu_arch = elf_file.getTarget().cpu.arch;
638 for (self.atoms.items) |atom_index| {
639 const atom = elf_file.atom(atom_index) orelse continue;
640 const is_eh_frame = (cpu_arch == .x86_64 and atom.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND) or
641 mem.eql(u8, atom.name(elf_file), ".eh_frame");
642 if (atom.flags.alive and is_eh_frame) atom.flags.alive = false;
643 for (self.atoms_indexes.items) |atom_index| {
644 const atom_ptr = self.atom(atom_index) orelse continue;
645 const is_eh_frame = (cpu_arch == .x86_64 and atom_ptr.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND) or
646 mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame");
647 if (atom_ptr.flags.alive and is_eh_frame) atom_ptr.flags.alive = false;
643648 }
644649}
645650
......@@ -657,9 +662,9 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO
657662 sym.st_shndx == elf.SHN_COMMON) continue;
658663
659664 if (sym.st_shndx != elf.SHN_ABS) {
660 const atom_index = self.atoms.items[sym.st_shndx];
661 const atom = elf_file.atom(atom_index) orelse continue;
662 if (!atom.flags.alive) continue;
665 const atom_index = self.atoms_indexes.items[sym.st_shndx];
666 const atom_ptr = self.atom(atom_index) orelse continue;
667 if (!atom_ptr.flags.alive) continue;
663668 }
664669
665670 const gop = try dupes.getOrPut(index);
......@@ -680,8 +685,8 @@ pub fn initMergeSections(self: *Object, elf_file: *Elf) !void {
680685 for (self.shdrs.items, 0..) |shdr, shndx| {
681686 if (shdr.sh_flags & elf.SHF_MERGE == 0) continue;
682687
683 const atom_index = self.atoms.items[shndx];
684 const atom_ptr = elf_file.atom(atom_index) orelse continue;
688 const atom_index = self.atoms_indexes.items[shndx];
689 const atom_ptr = self.atom(atom_index) orelse continue;
685690 if (!atom_ptr.flags.alive) continue;
686691 if (atom_ptr.relocs(elf_file).len > 0) continue;
687692
......@@ -755,7 +760,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
755760 const imsec = self.inputMergeSection(index) orelse continue;
756761 if (imsec.offsets.items.len == 0) continue;
757762 const msec = elf_file.mergeSection(imsec.merge_section_index);
758 const atom_ptr = elf_file.atom(imsec.atom_index).?;
763 const atom_ptr = self.atom(imsec.atom_index).?;
759764 const isec = atom_ptr.inputShdr(elf_file);
760765
761766 try imsec.subsections.resize(gpa, imsec.strings.items.len);
......@@ -802,10 +807,10 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
802807 sym.value = offset;
803808 }
804809
805 for (self.atoms.items) |atom_index| {
806 const atom_ptr = elf_file.atom(atom_index) orelse continue;
810 for (self.atoms_indexes.items) |atom_index| {
811 const atom_ptr = self.atom(atom_index) orelse continue;
807812 if (!atom_ptr.flags.alive) continue;
808 const extras = atom_ptr.extra(elf_file) orelse continue;
813 const extras = atom_ptr.extra(elf_file);
809814 const relocs = self.relocs.items[extras.rel_index..][0..extras.rel_count];
810815 for (relocs) |*rel| {
811816 const esym = self.symtab.items[rel.r_sym()];
......@@ -867,21 +872,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
867872 const comp = elf_file.base.comp;
868873 const gpa = comp.gpa;
869874
870 const atom_index = try elf_file.addAtom();
871 try self.atoms.append(gpa, atom_index);
872
873875 const is_tls = global.type(elf_file) == elf.STT_TLS;
874876 const name = if (is_tls) ".tls_common" else ".common";
875
876 const atom = elf_file.atom(atom_index).?;
877877 const name_offset = @as(u32, @intCast(self.strtab.items.len));
878878 try self.strtab.writer(gpa).print("{s}\x00", .{name});
879 atom.atom_index = atom_index;
880 atom.name_offset = name_offset;
881 atom.file_index = self.index;
882 atom.size = this_sym.st_size;
883 const alignment = this_sym.st_value;
884 atom.alignment = Alignment.fromNonzeroByteUnits(alignment);
885879
886880 var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;
887881 if (is_tls) sh_flags |= elf.SHF_TLS;
......@@ -897,38 +891,45 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
897891 .sh_size = sh_size,
898892 .sh_link = 0,
899893 .sh_info = 0,
900 .sh_addralign = alignment,
894 .sh_addralign = this_sym.st_value,
901895 .sh_entsize = 0,
902896 };
903 atom.input_section_index = shndx;
897
898 const atom_index = try self.addAtom(gpa, .{
899 .name = name_offset,
900 .shndx = shndx,
901 .size = this_sym.st_size,
902 .alignment = Alignment.fromNonzeroByteUnits(this_sym.st_value),
903 });
904 try self.atoms_indexes.append(gpa, atom_index);
904905
905906 global.value = 0;
906 global.atom_index = atom_index;
907 global.atom_ref = .{ .index = atom_index, .file = self.index };
907908 global.flags.weak = false;
908909 }
909910}
910911
911pub fn initOutputSections(self: Object, elf_file: *Elf) !void {
912 for (self.atoms.items) |atom_index| {
913 const atom = elf_file.atom(atom_index) orelse continue;
914 if (!atom.flags.alive) continue;
915 const shdr = atom.inputShdr(elf_file);
912pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
913 for (self.atoms_indexes.items) |atom_index| {
914 const atom_ptr = self.atom(atom_index) orelse continue;
915 if (!atom_ptr.flags.alive) continue;
916 const shdr = atom_ptr.inputShdr(elf_file);
916917 _ = try self.initOutputSection(elf_file, shdr);
917918 }
918919}
919920
920921pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
921 for (self.atoms.items) |atom_index| {
922 const atom = elf_file.atom(atom_index) orelse continue;
923 if (!atom.flags.alive) continue;
924 const shdr = atom.inputShdr(elf_file);
925 atom.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
922 for (self.atoms_indexes.items) |atom_index| {
923 const atom_ptr = self.atom(atom_index) orelse continue;
924 if (!atom_ptr.flags.alive) continue;
925 const shdr = atom_ptr.inputShdr(elf_file);
926 atom_ptr.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
926927
927928 const comp = elf_file.base.comp;
928929 const gpa = comp.gpa;
929 const gop = try elf_file.output_sections.getOrPut(gpa, atom.output_section_index);
930 const gop = try elf_file.output_sections.getOrPut(gpa, atom_ptr.output_section_index);
930931 if (!gop.found_existing) gop.value_ptr.* = .{};
931 try gop.value_ptr.append(gpa, atom_index);
932 try gop.value_ptr.append(gpa, .{ .index = atom_index, .file = self.index });
932933 }
933934
934935 for (self.locals()) |local_index| {
......@@ -938,9 +939,9 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
938939 local.output_section_index = msub.mergeSection(elf_file).output_section_index;
939940 continue;
940941 }
941 const atom = local.atom(elf_file) orelse continue;
942 if (!atom.flags.alive) continue;
943 local.output_section_index = atom.output_section_index;
942 const atom_ptr = local.atom(elf_file) orelse continue;
943 if (!atom_ptr.flags.alive) continue;
944 local.output_section_index = atom_ptr.output_section_index;
944945 }
945946
946947 for (self.globals()) |global_index| {
......@@ -951,9 +952,9 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
951952 global.output_section_index = msub.mergeSection(elf_file).output_section_index;
952953 continue;
953954 }
954 const atom = global.atom(elf_file) orelse continue;
955 if (!atom.flags.alive) continue;
956 global.output_section_index = atom.output_section_index;
955 const atom_ptr = global.atom(elf_file) orelse continue;
956 if (!atom_ptr.flags.alive) continue;
957 global.output_section_index = atom_ptr.output_section_index;
957958 }
958959
959960 for (self.symbols.items[self.symtab.items.len..]) |local_index| {
......@@ -964,11 +965,11 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
964965 }
965966}
966967
967pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
968 for (self.atoms.items) |atom_index| {
969 const atom = elf_file.atom(atom_index) orelse continue;
970 if (!atom.flags.alive) continue;
971 const shndx = atom.relocsShndx() orelse continue;
968pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {
969 for (self.atoms_indexes.items) |atom_index| {
970 const atom_ptr = self.atom(atom_index) orelse continue;
971 if (!atom_ptr.flags.alive) continue;
972 const shndx = atom_ptr.relocsShndx() orelse continue;
972973 const shdr = self.shdrs.items[shndx];
973974 const out_shndx = try self.initOutputSection(elf_file, shdr);
974975 const out_shdr = &elf_file.shdrs.items[out_shndx];
......@@ -978,24 +979,24 @@ pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
978979 }
979980}
980981
981pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void {
982 for (self.atoms.items) |atom_index| {
983 const atom = elf_file.atom(atom_index) orelse continue;
984 if (!atom.flags.alive) continue;
982pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void {
983 for (self.atoms_indexes.items) |atom_index| {
984 const atom_ptr = self.atom(atom_index) orelse continue;
985 if (!atom_ptr.flags.alive) continue;
985986 const shndx = blk: {
986 const shndx = atom.relocsShndx() orelse continue;
987 const shndx = atom_ptr.relocsShndx() orelse continue;
987988 const shdr = self.shdrs.items[shndx];
988989 break :blk self.initOutputSection(elf_file, shdr) catch unreachable;
989990 };
990991 const shdr = &elf_file.shdrs.items[shndx];
991 shdr.sh_info = atom.outputShndx().?;
992 shdr.sh_info = atom_ptr.outputShndx().?;
992993 shdr.sh_link = elf_file.symtab_section_index.?;
993994
994995 const comp = elf_file.base.comp;
995996 const gpa = comp.gpa;
996 const gop = try elf_file.output_rela_sections.getOrPut(gpa, atom.outputShndx().?);
997 const gop = try elf_file.output_rela_sections.getOrPut(gpa, atom_ptr.outputShndx().?);
997998 if (!gop.found_existing) gop.value_ptr.* = .{ .shndx = shndx };
998 try gop.value_ptr.atom_list.append(gpa, atom_index);
999 try gop.value_ptr.atom_list.append(gpa, .{ .index = atom_index, .file = self.index });
9991000 }
10001001}
10011002
......@@ -1129,11 +1130,10 @@ pub fn globals(self: Object) []const Symbol.Index {
11291130
11301131/// Returns atom's code and optionally uncompresses data if required (for compressed sections).
11311132/// Caller owns the memory.
1132pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
1133pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
11331134 const comp = elf_file.base.comp;
11341135 const gpa = comp.gpa;
1135 const atom_ptr = elf_file.atom(atom_index).?;
1136 assert(atom_ptr.file_index == self.index);
1136 const atom_ptr = self.atom(atom_index).?;
11371137 const shdr = atom_ptr.inputShdr(elf_file);
11381138 const handle = elf_file.fileHandle(self.file_handle);
11391139 const data = try self.preadShdrContentsAlloc(gpa, handle, atom_ptr.input_section_index);
......@@ -1194,6 +1194,82 @@ fn preadRelocsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, shn
11941194 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
11951195}
11961196
1197const AddAtomArgs = struct {
1198 name: u32,
1199 shndx: u32,
1200 size: u64,
1201 alignment: Alignment,
1202};
1203
1204fn addAtom(self: *Object, allocator: Allocator, args: AddAtomArgs) !Atom.Index {
1205 try self.atoms.ensureUnusedCapacity(allocator, 1);
1206 try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
1207 return self.addAtomAssumeCapacity(args);
1208}
1209
1210fn addAtomAssumeCapacity(self: *Object, args: AddAtomArgs) Atom.Index {
1211 const atom_index: Atom.Index = @intCast(self.atoms.items.len);
1212 const atom_ptr = self.atoms.addOneAssumeCapacity();
1213 atom_ptr.* = .{
1214 .atom_index = atom_index,
1215 .name_offset = args.name,
1216 .file_index = self.index,
1217 .input_section_index = args.shndx,
1218 .extra_index = self.addAtomExtraAssumeCapacity(.{}),
1219 .size = args.size,
1220 .alignment = args.alignment,
1221 };
1222 return atom_index;
1223}
1224
1225pub fn atom(self: *Object, atom_index: Atom.Index) ?*Atom {
1226 if (atom_index == 0) return null;
1227 assert(atom_index < self.atoms.items.len);
1228 return &self.atoms.items[atom_index];
1229}
1230
1231pub fn addAtomExtra(self: *Object, allocator: Allocator, extra: Atom.Extra) !u32 {
1232 const fields = @typeInfo(Atom.Extra).Struct.fields;
1233 try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
1234 return self.addAtomExtraAssumeCapacity(extra);
1235}
1236
1237pub fn addAtomExtraAssumeCapacity(self: *Object, extra: Atom.Extra) u32 {
1238 const index = @as(u32, @intCast(self.atoms_extra.items.len));
1239 const fields = @typeInfo(Atom.Extra).Struct.fields;
1240 inline for (fields) |field| {
1241 self.atoms_extra.appendAssumeCapacity(switch (field.type) {
1242 u32 => @field(extra, field.name),
1243 else => @compileError("bad field type"),
1244 });
1245 }
1246 return index;
1247}
1248
1249pub fn atomExtra(self: *Object, index: u32) Atom.Extra {
1250 const fields = @typeInfo(Atom.Extra).Struct.fields;
1251 var i: usize = index;
1252 var result: Atom.Extra = undefined;
1253 inline for (fields) |field| {
1254 @field(result, field.name) = switch (field.type) {
1255 u32 => self.atoms_extra.items[i],
1256 else => @compileError("bad field type"),
1257 };
1258 i += 1;
1259 }
1260 return result;
1261}
1262
1263pub fn setAtomExtra(self: *Object, index: u32, extra: Atom.Extra) void {
1264 const fields = @typeInfo(Atom.Extra).Struct.fields;
1265 inline for (fields, 0..) |field, i| {
1266 self.atoms_extra.items[index + i] = switch (field.type) {
1267 u32 => @field(extra, field.name),
1268 else => @compileError("bad field type"),
1269 };
1270 }
1271}
1272
11971273fn addInputMergeSection(self: *Object, allocator: Allocator) !InputMergeSection.Index {
11981274 const index: InputMergeSection.Index = @intCast(self.input_merge_sections.items.len);
11991275 const msec = try self.input_merge_sections.addOne(allocator);
......@@ -1280,9 +1356,9 @@ fn formatAtoms(
12801356 _ = options;
12811357 const object = ctx.object;
12821358 try writer.writeAll(" atoms\n");
1283 for (object.atoms.items) |atom_index| {
1284 const atom = ctx.elf_file.atom(atom_index) orelse continue;
1285 try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
1359 for (object.atoms_indexes.items) |atom_index| {
1360 const atom_ptr = object.atom(atom_index) orelse continue;
1361 try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)});
12861362 }
12871363}
12881364
......@@ -1354,9 +1430,9 @@ fn formatComdatGroups(
13541430 try writer.print(" COMDAT({d})\n", .{cg_index});
13551431 const cg_members = cg.comdatGroupMembers(elf_file);
13561432 for (cg_members) |shndx| {
1357 const atom_index = object.atoms.items[shndx];
1358 const atom = elf_file.atom(atom_index) orelse continue;
1359 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom.name(elf_file) });
1433 const atom_index = object.atoms_indexes.items[shndx];
1434 const atom_ptr = object.atom(atom_index) orelse continue;
1435 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom_ptr.name(elf_file) });
13601436 }
13611437 }
13621438}
src/link/Elf/SharedObject.zig+1-1
......@@ -232,7 +232,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
232232 const global = elf_file.symbol(index);
233233 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
234234 global.value = @intCast(this_sym.st_value);
235 global.atom_index = 0;
235 global.atom_ref = .{ .index = 0, .file = 0 };
236236 global.esym_index = esym_index;
237237 global.version_index = self.versyms.items[esym_index];
238238 global.file_index = self.index;
src/link/Elf/Symbol.zig+4-4
......@@ -9,10 +9,9 @@ name_offset: u32 = 0,
99/// Index of file where this symbol is defined.
1010file_index: File.Index = 0,
1111
12/// Index of atom containing this symbol.
13/// Index of 0 means there is no associated atom with this symbol.
12/// Reference to Atom containing this symbol if any.
1413/// Use `atom` to get the pointer to the atom.
15atom_index: Atom.Index = 0,
14atom_ref: Elf.Ref = .{ .index = 0, .file = 0 },
1615
1716/// Assigned output section index for this symbol.
1817output_section_index: u32 = 0,
......@@ -68,7 +67,8 @@ pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
6867}
6968
7069pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {
71 return elf_file.atom(symbol.atom_index);
70 const file_ptr = elf_file.file(symbol.atom_ref.file) orelse return null;
71 return file_ptr.atom(symbol.atom_ref.index);
7272}
7373
7474pub fn mergeSubsection(symbol: Symbol, elf_file: *Elf) ?*MergeSubsection {
src/link/Elf/ZigObject.zig+124-61
......@@ -15,7 +15,9 @@ local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
1515global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
1616globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
1717
18atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
18atoms: std.ArrayListUnmanaged(Atom) = .{},
19atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
20atoms_extra: std.ArrayListUnmanaged(u32) = .{},
1921relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
2022
2123num_dynrelocs: u32 = 0,
......@@ -80,7 +82,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
8082 const comp = elf_file.base.comp;
8183 const gpa = comp.gpa;
8284
83 try self.atoms.append(gpa, 0); // null input section
85 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section
8486 try self.relocs.append(gpa, .{}); // null relocs section
8587 try self.strtab.buffer.append(gpa, 0);
8688
......@@ -117,6 +119,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
117119 self.global_symbols.deinit(allocator);
118120 self.globals_lookup.deinit(allocator);
119121 self.atoms.deinit(allocator);
122 self.atoms_indexes.deinit(allocator);
123 self.atoms_extra.deinit(allocator);
120124 for (self.relocs.items) |*list| {
121125 list.deinit(allocator);
122126 }
......@@ -276,24 +280,20 @@ pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
276280 return index | global_symbol_bit;
277281}
278282
279pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
283pub fn newAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
280284 const gpa = elf_file.base.comp.gpa;
281 const atom_index = try elf_file.addAtom();
285 const atom_index = try self.addAtom(gpa);
282286 const symbol_index = try elf_file.addSymbol();
283287 const esym_index = try self.addLocalEsym(gpa);
284288
285 const shndx = @as(u32, @intCast(self.atoms.items.len));
286 try self.atoms.append(gpa, atom_index);
289 try self.atoms_indexes.append(gpa, atom_index);
287290 try self.local_symbols.append(gpa, symbol_index);
288291
289 const atom_ptr = elf_file.atom(atom_index).?;
290 atom_ptr.file_index = self.index;
291
292292 const symbol_ptr = elf_file.symbol(symbol_index);
293293 symbol_ptr.file_index = self.index;
294 symbol_ptr.atom_index = atom_index;
294 symbol_ptr.atom_ref = .{ .index = atom_index, .file = self.index };
295295
296 self.local_esyms.items(.shndx)[esym_index] = shndx;
296 self.local_esyms.items(.shndx)[esym_index] = atom_index;
297297 self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;
298298 symbol_ptr.esym_index = esym_index;
299299
......@@ -301,21 +301,22 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
301301 const relocs_index = @as(u32, @intCast(self.relocs.items.len));
302302 const relocs = try self.relocs.addOne(gpa);
303303 relocs.* = .{};
304
305 const atom_ptr = self.atom(atom_index).?;
304306 atom_ptr.relocs_section_index = relocs_index;
305307
306308 return symbol_index;
307309}
308310
309311/// TODO actually create fake input shdrs and return that instead.
310pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr {
311 _ = self;
312 const atom = elf_file.atom(atom_index) orelse return Elf.null_shdr;
313 const shndx = atom.outputShndx() orelse return Elf.null_shdr;
312pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr {
313 const atom_ptr = self.atom(atom_index) orelse return Elf.null_shdr;
314 const shndx = atom_ptr.outputShndx() orelse return Elf.null_shdr;
314315 var shdr = elf_file.shdrs.items[shndx];
315316 shdr.sh_addr = 0;
316317 shdr.sh_offset = 0;
317 shdr.sh_size = atom.size;
318 shdr.sh_addralign = atom.alignment.toByteUnits() orelse 1;
318 shdr.sh_size = atom_ptr.size;
319 shdr.sh_addralign = atom_ptr.alignment.toByteUnits() orelse 1;
319320 return shdr;
320321}
321322
......@@ -329,24 +330,23 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
329330
330331 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
331332 assert(esym.st_shndx == SHN_ATOM);
332 const atom_index = self.atoms.items[shndx];
333 const atom = elf_file.atom(atom_index) orelse continue;
334 if (!atom.flags.alive) continue;
333 const atom_ptr = self.atom(shndx) orelse continue;
334 if (!atom_ptr.flags.alive) continue;
335335 }
336336
337337 const global = elf_file.symbol(index);
338338 if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {
339339 const atom_index = switch (esym.st_shndx) {
340340 elf.SHN_ABS, elf.SHN_COMMON => 0,
341 SHN_ATOM => self.atoms.items[shndx],
341 SHN_ATOM => shndx,
342342 else => unreachable,
343343 };
344 const output_section_index = if (elf_file.atom(atom_index)) |atom|
345 atom.outputShndx().?
344 const output_section_index = if (self.atom(atom_index)) |atom_ptr|
345 atom_ptr.outputShndx().?
346346 else
347347 elf.SHN_UNDEF;
348348 global.value = @intCast(esym.st_value);
349 global.atom_index = atom_index;
349 global.atom_ref = .{ .index = atom_index, .file = self.index };
350350 global.esym_index = esym_index;
351351 global.file_index = self.index;
352352 global.output_section_index = output_section_index;
......@@ -376,7 +376,7 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
376376 };
377377
378378 global.value = 0;
379 global.atom_index = 0;
379 global.atom_ref = .{ .index = 0, .file = 0 };
380380 global.esym_index = esym_index;
381381 global.file_index = self.index;
382382 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
......@@ -397,7 +397,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
397397 }
398398
399399 global.value = 0;
400 global.atom_index = 0;
400 global.atom_ref = .{ .index = 0, .file = 0 };
401401 global.esym_index = esym_index;
402402 global.file_index = self.index;
403403 }
......@@ -405,19 +405,19 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
405405
406406pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
407407 const gpa = elf_file.base.comp.gpa;
408 for (self.atoms.items) |atom_index| {
409 const atom = elf_file.atom(atom_index) orelse continue;
410 if (!atom.flags.alive) continue;
411 const shdr = atom.inputShdr(elf_file);
408 for (self.atoms_indexes.items) |atom_index| {
409 const atom_ptr = self.atom(atom_index) orelse continue;
410 if (!atom_ptr.flags.alive) continue;
411 const shdr = atom_ptr.inputShdr(elf_file);
412412 if (shdr.sh_type == elf.SHT_NOBITS) continue;
413 if (atom.scanRelocsRequiresCode(elf_file)) {
413 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
414414 // TODO ideally we don't have to fetch the code here.
415415 // Perhaps it would make sense to save the code until flushModule where we
416416 // would free all of generated code?
417417 const code = try self.codeAlloc(elf_file, atom_index);
418418 defer gpa.free(code);
419 try atom.scanRelocs(elf_file, code, undefs);
420 } else try atom.scanRelocs(elf_file, null, undefs);
419 try atom_ptr.scanRelocs(elf_file, code, undefs);
420 } else try atom_ptr.scanRelocs(elf_file, null, undefs);
421421 }
422422}
423423
......@@ -450,9 +450,8 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O
450450 esym.st_shndx == elf.SHN_COMMON) continue;
451451
452452 if (esym.st_shndx == SHN_ATOM) {
453 const atom_index = self.atoms.items[shndx];
454 const atom = elf_file.atom(atom_index) orelse continue;
455 if (!atom.flags.alive) continue;
453 const atom_ptr = self.atom(shndx) orelse continue;
454 if (!atom_ptr.flags.alive) continue;
456455 }
457456
458457 const gop = try dupes.getOrPut(index);
......@@ -517,20 +516,20 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void {
517516 try writer.writeAll(self.data.items);
518517}
519518
520pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {
521 for (self.atoms.items) |atom_index| {
522 const atom = elf_file.atom(atom_index) orelse continue;
523 if (!atom.flags.alive) continue;
524 const rela_shndx = atom.relocsShndx() orelse continue;
519pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
520 for (self.atoms_indexes.items) |atom_index| {
521 const atom_ptr = self.atom(atom_index) orelse continue;
522 if (!atom_ptr.flags.alive) continue;
523 const rela_shndx = atom_ptr.relocsShndx() orelse continue;
525524 // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level
526525 if (self.relocs.items[rela_shndx].items.len == 0) continue;
527 const out_shndx = atom.outputShndx().?;
526 const out_shndx = atom_ptr.outputShndx().?;
528527 const out_shdr = elf_file.shdrs.items[out_shndx];
529528 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
530529
531530 const gpa = elf_file.base.comp.gpa;
532531 const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;
533 try sec.atom_list.append(gpa, atom_index);
532 try sec.atom_list.append(gpa, .{ .index = atom_index, .file = self.index });
534533 }
535534}
536535
......@@ -561,7 +560,7 @@ pub fn globals(self: ZigObject) []const Symbol.Index {
561560pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
562561 for (self.locals()) |local_index| {
563562 const local = elf_file.symbol(local_index);
564 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
563 if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.flags.alive) continue;
565564 const esym = local.elfSym(elf_file);
566565 switch (esym.st_type()) {
567566 elf.STT_SECTION, elf.STT_NOTYPE => continue,
......@@ -577,7 +576,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
577576 const global = elf_file.symbol(global_index);
578577 const file_ptr = global.file(elf_file) orelse continue;
579578 if (file_ptr.index() != self.index) continue;
580 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
579 if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.flags.alive) continue;
581580 global.flags.output_symtab = true;
582581 if (global.isLocal(elf_file)) {
583582 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
......@@ -621,11 +620,10 @@ pub fn asFile(self: *ZigObject) File {
621620
622621/// Returns atom's code.
623622/// Caller owns the memory.
624pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
623pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
625624 const gpa = elf_file.base.comp.gpa;
626 const atom = elf_file.atom(atom_index).?;
627 assert(atom.file_index == self.index);
628 const shdr = &elf_file.shdrs.items[atom.outputShndx().?];
625 const atom_ptr = self.atom(atom_index).?;
626 const shdr = &elf_file.shdrs.items[atom_ptr.outputShndx().?];
629627
630628 if (shdr.sh_flags & elf.SHF_TLS != 0) {
631629 const tlv = self.tls_variables.get(atom_index).?;
......@@ -633,13 +631,13 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8
633631 return code;
634632 }
635633
636 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom.value));
637 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
634 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
635 const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow;
638636 const code = try gpa.alloc(u8, size);
639637 errdefer gpa.free(code);
640638 const amt = try elf_file.base.file.?.preadAll(code, file_offset);
641639 if (amt != code.len) {
642 log.err("fetching code for {s} failed", .{atom.name(elf_file)});
640 log.err("fetching code for {s} failed", .{atom_ptr.name(elf_file)});
643641 return error.InputOutput;
644642 }
645643 return code;
......@@ -760,7 +758,7 @@ pub fn getOrCreateMetadataForLazySymbol(
760758 };
761759 switch (metadata.state.*) {
762760 .unused => {
763 const symbol_index = try self.addAtom(elf_file);
761 const symbol_index = try self.newAtom(elf_file);
764762 const sym = elf_file.symbol(symbol_index);
765763 sym.flags.needs_zig_got = true;
766764 metadata.symbol_index.* = symbol_index;
......@@ -824,7 +822,7 @@ pub fn getOrCreateMetadataForDecl(
824822 const gop = try self.decls.getOrPut(gpa, decl_index);
825823 if (!gop.found_existing) {
826824 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
827 const symbol_index = try self.addAtom(elf_file);
825 const symbol_index = try self.newAtom(elf_file);
828826 const mod = elf_file.base.comp.module.?;
829827 const decl = mod.declPtr(decl_index);
830828 const sym = elf_file.symbol(symbol_index);
......@@ -1048,7 +1046,7 @@ fn updateTlv(
10481046 {
10491047 const gop = try elf_file.output_sections.getOrPut(gpa, atom_ptr.output_section_index);
10501048 if (!gop.found_existing) gop.value_ptr.* = .{};
1051 try gop.value_ptr.append(gpa, atom_ptr.atom_index);
1049 try gop.value_ptr.append(gpa, .{ .index = atom_ptr.atom_index, .file = self.index });
10521050 }
10531051}
10541052
......@@ -1307,8 +1305,7 @@ pub fn lowerUnnamedConst(
13071305 return error.CodegenFail;
13081306 },
13091307 };
1310 const sym = elf_file.symbol(sym_index);
1311 try unnamed_consts.append(gpa, sym.atom_index);
1308 try unnamed_consts.append(gpa, sym_index);
13121309 return sym_index;
13131310}
13141311
......@@ -1332,7 +1329,7 @@ fn lowerConst(
13321329 var code_buffer = std.ArrayList(u8).init(gpa);
13331330 defer code_buffer.deinit();
13341331
1335 const sym_index = try self.addAtom(elf_file);
1332 const sym_index = try self.newAtom(elf_file);
13361333
13371334 const res = try codegen.generateSymbol(
13381335 &elf_file.base,
......@@ -1530,6 +1527,72 @@ pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
15301527 return self.strtab.getAssumeExists(off);
15311528}
15321529
1530fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
1531 try self.atoms.ensureUnusedCapacity(allocator, 1);
1532 try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
1533 return self.addAtomAssumeCapacity();
1534}
1535
1536fn addAtomAssumeCapacity(self: *ZigObject) Atom.Index {
1537 const atom_index: Atom.Index = @intCast(self.atoms.items.len);
1538 const atom_ptr = self.atoms.addOneAssumeCapacity();
1539 atom_ptr.* = .{
1540 .file_index = self.index,
1541 .atom_index = atom_index,
1542 .extra_index = self.addAtomExtraAssumeCapacity(.{}),
1543 };
1544 return atom_index;
1545}
1546
1547pub fn atom(self: *ZigObject, atom_index: Atom.Index) ?*Atom {
1548 if (atom_index == 0) return null;
1549 assert(atom_index < self.atoms.items.len);
1550 return &self.atoms.items[atom_index];
1551}
1552
1553fn addAtomExtra(self: *ZigObject, allocator: Allocator, extra: Atom.Extra) !u32 {
1554 const fields = @typeInfo(Atom.Extra).Struct.fields;
1555 try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
1556 return self.addAtomExtraAssumeCapacity(extra);
1557}
1558
1559fn addAtomExtraAssumeCapacity(self: *ZigObject, extra: Atom.Extra) u32 {
1560 const index = @as(u32, @intCast(self.atoms_extra.items.len));
1561 const fields = @typeInfo(Atom.Extra).Struct.fields;
1562 inline for (fields) |field| {
1563 self.atoms_extra.appendAssumeCapacity(switch (field.type) {
1564 u32 => @field(extra, field.name),
1565 else => @compileError("bad field type"),
1566 });
1567 }
1568 return index;
1569}
1570
1571pub fn atomExtra(self: ZigObject, index: u32) Atom.Extra {
1572 const fields = @typeInfo(Atom.Extra).Struct.fields;
1573 var i: usize = index;
1574 var result: Atom.Extra = undefined;
1575 inline for (fields) |field| {
1576 @field(result, field.name) = switch (field.type) {
1577 u32 => self.atoms_extra.items[i],
1578 else => @compileError("bad field type"),
1579 };
1580 i += 1;
1581 }
1582 return result;
1583}
1584
1585pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {
1586 assert(index > 0);
1587 const fields = @typeInfo(Atom.Extra).Struct.fields;
1588 inline for (fields, 0..) |field, i| {
1589 self.atoms_extra.items[index + i] = switch (field.type) {
1590 u32 => @field(extra, field.name),
1591 else => @compileError("bad field type"),
1592 };
1593 }
1594}
1595
15331596pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
15341597 return .{ .data = .{
15351598 .self = self,
......@@ -1578,9 +1641,9 @@ fn formatAtoms(
15781641 _ = unused_fmt_string;
15791642 _ = options;
15801643 try writer.writeAll(" atoms\n");
1581 for (ctx.self.atoms.items) |atom_index| {
1582 const atom = ctx.elf_file.atom(atom_index) orelse continue;
1583 try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
1644 for (ctx.self.atoms_indexes.items) |atom_index| {
1645 const atom_ptr = ctx.self.atom(atom_index) orelse continue;
1646 try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)});
15841647 }
15851648}
15861649
src/link/Elf/eh_frame.zig+2-2
......@@ -42,8 +42,8 @@ pub const Fde = struct {
4242 const object = elf_file.file(fde.file_index).?.object;
4343 const rel = fde.relocs(elf_file)[0];
4444 const sym = object.symtab.items[rel.r_sym()];
45 const atom_index = object.atoms.items[sym.st_shndx];
46 return elf_file.atom(atom_index).?;
45 const atom_index = object.atoms_indexes.items[sym.st_shndx];
46 return object.atom(atom_index).?;
4747 }
4848
4949 pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
src/link/Elf/file.zig+26-3
......@@ -98,11 +98,34 @@ pub const File = union(enum) {
9898 }
9999 }
100100
101 pub fn atom(file: File, atom_index: Atom.Index) ?*Atom {
102 return switch (file) {
103 .shared_object => unreachable,
104 .linker_defined => null,
105 inline else => |x| x.atom(atom_index),
106 };
107 }
108
101109 pub fn atoms(file: File) []const Atom.Index {
102110 return switch (file) {
103 .linker_defined, .shared_object => &[0]Atom.Index{},
104 .zig_object => |x| x.atoms.items,
105 .object => |x| x.atoms.items,
111 .shared_object => unreachable,
112 .linker_defined => &[0]Atom.Index{},
113 .zig_object => |x| x.atoms_indexes.items,
114 .object => |x| x.atoms_indexes.items,
115 };
116 }
117
118 pub fn atomExtra(file: File, extra_index: u32) Atom.Extra {
119 return switch (file) {
120 .shared_object, .linker_defined => unreachable,
121 inline else => |x| x.atomExtra(extra_index),
122 };
123 }
124
125 pub fn setAtomExtra(file: File, extra_index: u32, extra: Atom.Extra) void {
126 return switch (file) {
127 .shared_object, .linker_defined => unreachable,
128 inline else => |x| x.setAtomExtra(extra_index, extra),
106129 };
107130 }
108131
src/link/Elf/gc.zig+7-5
......@@ -35,7 +35,7 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil
3535 const file = elf_file.file(index).?;
3636
3737 for (file.atoms()) |atom_index| {
38 const atom = elf_file.atom(atom_index) orelse continue;
38 const atom = file.atom(atom_index) orelse continue;
3939 if (!atom.flags.alive) continue;
4040
4141 const shdr = atom.inputShdr(elf_file);
......@@ -120,8 +120,9 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {
120120
121121fn prune(files: []const File.Index, elf_file: *Elf) void {
122122 for (files) |index| {
123 for (elf_file.file(index).?.atoms()) |atom_index| {
124 const atom = elf_file.atom(atom_index) orelse continue;
123 const file = elf_file.file(index).?;
124 for (file.atoms()) |atom_index| {
125 const atom = file.atom(atom_index) orelse continue;
125126 if (atom.flags.alive and !atom.flags.visited) {
126127 atom.flags.alive = false;
127128 atom.markFdesDead(elf_file);
......@@ -133,8 +134,9 @@ fn prune(files: []const File.Index, elf_file: *Elf) void {
133134pub fn dumpPrunedAtoms(elf_file: *Elf) !void {
134135 const stderr = std.io.getStdErr().writer();
135136 for (elf_file.objects.items) |index| {
136 for (elf_file.file(index).?.object.atoms.items) |atom_index| {
137 const atom = elf_file.atom(atom_index) orelse continue;
137 const file = elf_file.file(index).?;
138 for (file.atoms()) |atom_index| {
139 const atom = file.atom(atom_index) orelse continue;
138140 if (!atom.flags.alive)
139141 // TODO should we simply print to stderr?
140142 try stderr.print("link: removing unused section '{s}' in file '{}'\n", .{
src/link/Elf/relocatable.zig+12-12
......@@ -341,8 +341,8 @@ fn initComdatGroups(elf_file: *Elf) !void {
341341fn updateSectionSizes(elf_file: *Elf) !void {
342342 for (elf_file.output_sections.keys(), elf_file.output_sections.values()) |shndx, atom_list| {
343343 const shdr = &elf_file.shdrs.items[shndx];
344 for (atom_list.items) |atom_index| {
345 const atom_ptr = elf_file.atom(atom_index) orelse continue;
344 for (atom_list.items) |ref| {
345 const atom_ptr = elf_file.atom(ref) orelse continue;
346346 if (!atom_ptr.flags.alive) continue;
347347 const offset = atom_ptr.alignment.forward(shdr.sh_size);
348348 const padding = offset - shdr.sh_size;
......@@ -354,8 +354,8 @@ fn updateSectionSizes(elf_file: *Elf) !void {
354354
355355 for (elf_file.output_rela_sections.values()) |sec| {
356356 const shdr = &elf_file.shdrs.items[sec.shndx];
357 for (sec.atom_list.items) |atom_index| {
358 const atom_ptr = elf_file.atom(atom_index) orelse continue;
357 for (sec.atom_list.items) |ref| {
358 const atom_ptr = elf_file.atom(ref) orelse continue;
359359 if (!atom_ptr.flags.alive) continue;
360360 const relocs = atom_ptr.relocs(elf_file);
361361 shdr.sh_size += shdr.sh_entsize * relocs.len;
......@@ -448,16 +448,16 @@ fn writeAtoms(elf_file: *Elf) !void {
448448 0;
449449 @memset(buffer, padding_byte);
450450
451 for (atom_list.items) |atom_index| {
452 const atom_ptr = elf_file.atom(atom_index).?;
451 for (atom_list.items) |ref| {
452 const atom_ptr = elf_file.atom(ref).?;
453453 assert(atom_ptr.flags.alive);
454454
455455 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse
456456 return error.Overflow;
457457 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
458458
459 log.debug("writing atom({d}) from 0x{x} to 0x{x}", .{
460 atom_index,
459 log.debug("writing atom({}) from 0x{x} to 0x{x}", .{
460 ref,
461461 sh_offset + offset,
462462 sh_offset + offset + size,
463463 });
......@@ -465,8 +465,8 @@ fn writeAtoms(elf_file: *Elf) !void {
465465 // TODO decompress directly into provided buffer
466466 const out_code = buffer[offset..][0..size];
467467 const in_code = switch (atom_ptr.file(elf_file).?) {
468 .object => |x| try x.codeDecompressAlloc(elf_file, atom_index),
469 .zig_object => |x| try x.codeAlloc(elf_file, atom_index),
468 .object => |x| try x.codeDecompressAlloc(elf_file, ref.index),
469 .zig_object => |x| try x.codeAlloc(elf_file, ref.index),
470470 else => unreachable,
471471 };
472472 defer gpa.free(in_code);
......@@ -490,8 +490,8 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
490490 var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs);
491491 defer relocs.deinit();
492492
493 for (sec.atom_list.items) |atom_index| {
494 const atom_ptr = elf_file.atom(atom_index) orelse continue;
493 for (sec.atom_list.items) |ref| {
494 const atom_ptr = elf_file.atom(ref) orelse continue;
495495 if (!atom_ptr.flags.alive) continue;
496496 try atom_ptr.writeRelocs(elf_file, &relocs);
497497 }
src/link/Elf/synthetic_sections.zig+4-4
......@@ -1705,14 +1705,14 @@ pub const ComdatGroupSection = struct {
17051705 const shdr = object.shdrs.items[shndx];
17061706 switch (shdr.sh_type) {
17071707 elf.SHT_RELA => {
1708 const atom_index = object.atoms.items[shdr.sh_info];
1709 const atom = elf_file.atom(atom_index).?;
1708 const atom_index = object.atoms_indexes.items[shdr.sh_info];
1709 const atom = object.atom(atom_index).?;
17101710 const rela = elf_file.output_rela_sections.get(atom.outputShndx().?).?;
17111711 try writer.writeInt(u32, rela.shndx, .little);
17121712 },
17131713 else => {
1714 const atom_index = object.atoms.items[shndx];
1715 const atom = elf_file.atom(atom_index).?;
1714 const atom_index = object.atoms_indexes.items[shndx];
1715 const atom = object.atom(atom_index).?;
17161716 try writer.writeInt(u32, atom.outputShndx().?, .little);
17171717 },
17181718 }
src/link/Elf/thunks.zig+7-8
......@@ -6,8 +6,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
66 const atoms = elf_file.output_sections.get(shndx).?.items;
77 assert(atoms.len > 0);
88
9 for (atoms) |atom_index| {
10 elf_file.atom(atom_index).?.value = -1;
9 for (atoms) |ref| {
10 elf_file.atom(ref).?.value = -1;
1111 }
1212
1313 var i: usize = 0;
......@@ -19,8 +19,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
1919 i += 1;
2020
2121 while (i < atoms.len) : (i += 1) {
22 const atom_index = atoms[i];
23 const atom = elf_file.atom(atom_index).?;
22 const atom = elf_file.atom(atoms[i]).?;
2423 assert(atom.flags.alive);
2524 if (@as(i64, @intCast(atom.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance)
2625 break;
......@@ -33,10 +32,10 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
3332 thunk.output_section_index = shndx;
3433
3534 // Scan relocs in the group and create trampolines for any unreachable callsite
36 for (atoms[start..i]) |atom_index| {
37 const atom = elf_file.atom(atom_index).?;
35 for (atoms[start..i]) |ref| {
36 const atom = elf_file.atom(ref).?;
3837 const file = atom.file(elf_file).?;
39 log.debug("atom({d}) {s}", .{ atom_index, atom.name(elf_file) });
38 log.debug("atom({}) {s}", .{ ref, atom.name(elf_file) });
4039 for (atom.relocs(elf_file)) |rel| {
4140 const is_reachable = switch (cpu_arch) {
4241 .aarch64 => aarch64.isReachable(atom, rel, elf_file),
......@@ -51,7 +50,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
5150 };
5251 try thunk.symbols.put(gpa, target, {});
5352 }
54 try atom.addExtra(.{ .thunk = thunk_index }, elf_file);
53 atom.addExtra(.{ .thunk = thunk_index }, elf_file);
5554 atom.flags.thunk = true;
5655 }
5756
src/link/MachO/InternalObject.zig+1-2
......@@ -45,8 +45,7 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void {
4545
4646pub fn init(self: *InternalObject, allocator: Allocator) !void {
4747 // Atom at index 0 is reserved as null atom.
48 try self.atoms.append(allocator, .{});
49 try self.atoms_extra.append(allocator, 0);
48 try self.atoms.append(allocator, .{ .extra = try self.addAtomExtra(allocator, .{}) });
5049 // Null byte in strtab
5150 try self.strtab.append(allocator, 0);
5251}
src/link/MachO/ZigObject.zig+1-1
......@@ -1634,7 +1634,7 @@ fn isThreadlocal(macho_file: *MachO, decl_index: InternPool.DeclIndex) bool {
16341634
16351635fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
16361636 try self.atoms.ensureUnusedCapacity(allocator, 1);
1637 try self.atoms_extra.ensureUnusedCapacity(allocator, 1);
1637 try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
16381638 return self.addAtomAssumeCapacity();
16391639}
16401640