authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-08 21:09:45+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-08 21:09:45+02:00
log69738a07c2309530463873538a5fd62d6174a26c
treec41387ed1828fe5b053f5555bea6c880206999bc
parent6ad5db030c576ab9cf944b4a9432954681af649c

elf: store Index rather than ?Index in Atom; gen ABS STT_FILE for zig source


4 files changed, 69 insertions(+), 56 deletions(-)

src/link/Elf.zig+25-11
...@@ -834,10 +834,23 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -834,10 +834,23 @@ pub fn populateMissingMetadata(self: *Elf) !void {
834 try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);834 try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);
835 }835 }
836836
837 if (self.zig_module_index == null) {837 if (self.base.options.module) |module| {
838 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));838 if (self.zig_module_index == null) {
839 self.files.set(index, .{ .zig_module = .{ .index = index } });839 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
840 self.zig_module_index = index;840 self.files.set(index, .{ .zig_module = .{
841 .index = index,
842 .path = module.main_pkg.root_src_path,
843 } });
844 self.zig_module_index = index;
845 const zig_module = self.file(index).?.zig_module;
846 const sym_index = try zig_module.addLocal(self);
847 const sym = self.symbol(sym_index);
848 const esym = sym.sourceSymbol(self);
849 const name_off = try self.strtab.insert(gpa, std.fs.path.stem(module.main_pkg.root_src_path));
850 sym.name_offset = name_off;
851 esym.st_name = name_off;
852 esym.st_info |= elf.STT_FILE;
853 }
841 }854 }
842}855}
843856
...@@ -846,13 +859,12 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {...@@ -846,13 +859,12 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
846 const shdr = &self.sections.items(.shdr)[shdr_index];859 const shdr = &self.sections.items(.shdr)[shdr_index];
847 const phdr_index = self.sections.items(.phdr_index)[shdr_index];860 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
848 const phdr = &self.program_headers.items[phdr_index];861 const phdr = &self.program_headers.items[phdr_index];
849 const maybe_last_atom_index = self.sections.items(.last_atom_index)[shdr_index];862 const last_atom_index = self.sections.items(.last_atom_index)[shdr_index];
850863
851 if (needed_size > self.allocatedSize(shdr.sh_offset)) {864 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
852 // Must move the entire section.865 // Must move the entire section.
853 const new_offset = self.findFreeSpace(needed_size, self.page_size);866 const new_offset = self.findFreeSpace(needed_size, self.page_size);
854 const existing_size = if (maybe_last_atom_index) |last_atom_index| blk: {867 const existing_size = if (self.atom(last_atom_index)) |last| blk: {
855 const last = self.atom(last_atom_index);
856 break :blk (last.value + last.size) - phdr.p_vaddr;868 break :blk (last.value + last.size) - phdr.p_vaddr;
857 } else if (shdr_index == self.got_section_index.?) blk: {869 } else if (shdr_index == self.got_section_index.?) blk: {
858 break :blk shdr.sh_size;870 break :blk shdr.sh_size;
...@@ -1016,7 +1028,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1016,7 +1028,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1016 while (it.next()) |entry| {1028 while (it.next()) |entry| {
1017 const atom_index = entry.key_ptr.*;1029 const atom_index = entry.key_ptr.*;
1018 const relocs = entry.value_ptr.*;1030 const relocs = entry.value_ptr.*;
1019 const atom_ptr = self.atom(atom_index);1031 const atom_ptr = self.atom(atom_index).?;
1020 const source_shdr = self.sections.items(.shdr)[atom_ptr.output_section_index];1032 const source_shdr = self.sections.items(.shdr)[atom_ptr.output_section_index];
10211033
1022 log.debug("relocating '{s}'", .{atom_ptr.name(self)});1034 log.debug("relocating '{s}'", .{atom_ptr.name(self)});
...@@ -2753,6 +2765,7 @@ fn writeSymtab(self: *Elf) !void {...@@ -2753,6 +2765,7 @@ fn writeSymtab(self: *Elf) !void {
27532765
2754 const symtab = try gpa.alloc(elf.Elf64_Sym, nsyms);2766 const symtab = try gpa.alloc(elf.Elf64_Sym, nsyms);
2755 defer gpa.free(symtab);2767 defer gpa.free(symtab);
2768 symtab[0] = null_sym;
27562769
2757 var ctx: struct { ilocal: usize, iglobal: usize, symtab: []elf.Elf64_Sym } = .{2770 var ctx: struct { ilocal: usize, iglobal: usize, symtab: []elf.Elf64_Sym } = .{
2758 .ilocal = 1,2771 .ilocal = 1,
...@@ -3083,7 +3096,8 @@ const CsuObjects = struct {...@@ -3083,7 +3096,8 @@ const CsuObjects = struct {
3083 }3096 }
3084};3097};
30853098
3086pub fn atom(self: *Elf, atom_index: Atom.Index) *Atom {3099pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom {
3100 if (atom_index == 0) return null;
3087 assert(atom_index < self.atoms.items.len);3101 assert(atom_index < self.atoms.items.len);
3088 return &self.atoms.items[atom_index];3102 return &self.atoms.items[atom_index];
3089}3103}
...@@ -3210,7 +3224,7 @@ fn fmtDumpState(...@@ -3210,7 +3224,7 @@ fn fmtDumpState(
32103224
3211 if (self.zig_module_index) |index| {3225 if (self.zig_module_index) |index| {
3212 const zig_module = self.file(index).?.zig_module;3226 const zig_module = self.file(index).?.zig_module;
3213 try writer.print("zig_module({d}) : (zig module)\n", .{index});3227 try writer.print("zig_module({d}) : {s}\n", .{ index, zig_module.path });
3214 try writer.print("{}\n", .{zig_module.fmtSymtab(self)});3228 try writer.print("{}\n", .{zig_module.fmtSymtab(self)});
3215 }3229 }
3216 if (self.linker_defined_index) |index| {3230 if (self.linker_defined_index) |index| {
...@@ -3230,7 +3244,7 @@ const Section = struct {...@@ -3230,7 +3244,7 @@ const Section = struct {
3230 phdr_index: u16,3244 phdr_index: u16,
32313245
3232 /// Index of the last allocated atom in this section.3246 /// Index of the last allocated atom in this section.
3233 last_atom_index: ?Atom.Index = null,3247 last_atom_index: Atom.Index = 0,
32343248
3235 /// A list of atoms that have surplus capacity. This list can have false3249 /// A list of atoms that have surplus capacity. This list can have false
3236 /// positives, as functions grow and shrink over time, only sometimes being added3250 /// positives, as functions grow and shrink over time, only sometimes being added
src/link/Elf/Atom.zig+27-33
...@@ -39,8 +39,8 @@ fde_end: u32 = 0,...@@ -39,8 +39,8 @@ fde_end: u32 = 0,
3939
40/// Points to the previous and next neighbors, based on the `text_offset`.40/// Points to the previous and next neighbors, based on the `text_offset`.
41/// This can be used to find, for example, the capacity of this `TextBlock`.41/// This can be used to find, for example, the capacity of this `TextBlock`.
42prev_index: ?Index = null,42prev_index: Index = 0,
43next_index: ?Index = null,43next_index: Index = 0,
4444
45pub fn name(self: Atom, elf_file: *Elf) []const u8 {45pub fn name(self: Atom, elf_file: *Elf) []const u8 {
46 return elf_file.strtab.getAssumeExists(self.name_offset);46 return elf_file.strtab.getAssumeExists(self.name_offset);
...@@ -50,14 +50,13 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {...@@ -50,14 +50,13 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {
50/// File offset relocation happens transparently, so it is not included in50/// File offset relocation happens transparently, so it is not included in
51/// this calculation.51/// this calculation.
52pub fn capacity(self: Atom, elf_file: *Elf) u64 {52pub fn capacity(self: Atom, elf_file: *Elf) u64 {
53 const next_value = if (self.next_index) |next_index| elf_file.atom(next_index).value else std.math.maxInt(u32);53 const next_value = if (elf_file.atom(self.next_index)) |next| next.value else std.math.maxInt(u32);
54 return next_value - self.value;54 return next_value - self.value;
55}55}
5656
57pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {57pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
58 // No need to keep a free list node for the last block.58 // No need to keep a free list node for the last block.
59 const next_index = self.next_index orelse return false;59 const next = elf_file.atom(self.next_index) orelse return false;
60 const next = elf_file.atom(next_index);
61 const cap = next.value - self.value;60 const cap = next.value - self.value;
62 const ideal_cap = Elf.padToIdeal(self.size);61 const ideal_cap = Elf.padToIdeal(self.size);
63 if (cap <= ideal_cap) return false;62 if (cap <= ideal_cap) return false;
...@@ -84,7 +83,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -84,7 +83,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
84 const phdr = &elf_file.program_headers.items[phdr_index];83 const phdr = &elf_file.program_headers.items[phdr_index];
85 const shdr = &elf_file.sections.items(.shdr)[self.output_section_index];84 const shdr = &elf_file.sections.items(.shdr)[self.output_section_index];
86 const free_list = &elf_file.sections.items(.free_list)[self.output_section_index];85 const free_list = &elf_file.sections.items(.free_list)[self.output_section_index];
87 const maybe_last_atom_index = &elf_file.sections.items(.last_atom_index)[self.output_section_index];86 const last_atom_index = &elf_file.sections.items(.last_atom_index)[self.output_section_index];
88 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);87 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
89 const alignment = try std.math.powi(u64, 2, self.alignment);88 const alignment = try std.math.powi(u64, 2, self.alignment);
9089
...@@ -102,7 +101,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -102,7 +101,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
102 var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;101 var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;
103 while (i < free_list.items.len) {102 while (i < free_list.items.len) {
104 const big_atom_index = free_list.items[i];103 const big_atom_index = free_list.items[i];
105 const big_atom = elf_file.atom(big_atom_index);104 const big_atom = elf_file.atom(big_atom_index).?;
106 // We now have a pointer to a live atom that has too much capacity.105 // We now have a pointer to a live atom that has too much capacity.
107 // Is it enough that we could fit this new atom?106 // Is it enough that we could fit this new atom?
108 const cap = big_atom.capacity(elf_file);107 const cap = big_atom.capacity(elf_file);
...@@ -134,13 +133,12 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -134,13 +133,12 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
134 free_list_removal = i;133 free_list_removal = i;
135 }134 }
136 break :blk new_start_vaddr;135 break :blk new_start_vaddr;
137 } else if (maybe_last_atom_index.*) |last_index| {136 } else if (elf_file.atom(last_atom_index.*)) |last| {
138 const last = elf_file.atom(last_index);
139 const ideal_capacity = Elf.padToIdeal(last.size);137 const ideal_capacity = Elf.padToIdeal(last.size);
140 const ideal_capacity_end_vaddr = last.value + ideal_capacity;138 const ideal_capacity_end_vaddr = last.value + ideal_capacity;
141 const new_start_vaddr = std.mem.alignForward(u64, ideal_capacity_end_vaddr, alignment);139 const new_start_vaddr = std.mem.alignForward(u64, ideal_capacity_end_vaddr, alignment);
142 // Set up the metadata to be updated, after errors are no longer possible.140 // Set up the metadata to be updated, after errors are no longer possible.
143 atom_placement = last_index;141 atom_placement = last.atom_index;
144 break :blk new_start_vaddr;142 break :blk new_start_vaddr;
145 } else {143 } else {
146 break :blk phdr.p_vaddr;144 break :blk phdr.p_vaddr;
...@@ -148,13 +146,13 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -148,13 +146,13 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
148 };146 };
149147
150 const expand_section = if (atom_placement) |placement_index|148 const expand_section = if (atom_placement) |placement_index|
151 elf_file.atom(placement_index).next_index == null149 elf_file.atom(placement_index).?.next_index == 0
152 else150 else
153 true;151 true;
154 if (expand_section) {152 if (expand_section) {
155 const needed_size = (self.value + self.size) - phdr.p_vaddr;153 const needed_size = (self.value + self.size) - phdr.p_vaddr;
156 try elf_file.growAllocSection(self.output_section_index, needed_size);154 try elf_file.growAllocSection(self.output_section_index, needed_size);
157 maybe_last_atom_index.* = self.atom_index;155 last_atom_index.* = self.atom_index;
158156
159 if (elf_file.dwarf) |_| {157 if (elf_file.dwarf) |_| {
160 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address158 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
...@@ -172,23 +170,21 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -172,23 +170,21 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
172 // This function can also reallocate an atom.170 // This function can also reallocate an atom.
173 // In this case we need to "unplug" it from its previous location before171 // In this case we need to "unplug" it from its previous location before
174 // plugging it in to its new location.172 // plugging it in to its new location.
175 if (self.prev_index) |prev_index| {173 if (elf_file.atom(self.prev_index)) |prev| {
176 const prev = elf_file.atom(prev_index);
177 prev.next_index = self.next_index;174 prev.next_index = self.next_index;
178 }175 }
179 if (self.next_index) |next_index| {176 if (elf_file.atom(self.next_index)) |next| {
180 const next = elf_file.atom(next_index);
181 next.prev_index = self.prev_index;177 next.prev_index = self.prev_index;
182 }178 }
183179
184 if (atom_placement) |big_atom_index| {180 if (atom_placement) |big_atom_index| {
185 const big_atom = elf_file.atom(big_atom_index);181 const big_atom = elf_file.atom(big_atom_index).?;
186 self.prev_index = big_atom_index;182 self.prev_index = big_atom_index;
187 self.next_index = big_atom.next_index;183 self.next_index = big_atom.next_index;
188 big_atom.next_index = self.atom_index;184 big_atom.next_index = self.atom_index;
189 } else {185 } else {
190 self.prev_index = null;186 self.prev_index = 0;
191 self.next_index = null;187 self.next_index = 0;
192 }188 }
193 if (free_list_removal) |i| {189 if (free_list_removal) |i| {
194 _ = free_list.swapRemove(i);190 _ = free_list.swapRemove(i);
...@@ -231,35 +227,33 @@ pub fn free(self: *Atom, elf_file: *Elf) void {...@@ -231,35 +227,33 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
231 }227 }
232 }228 }
233229
234 const maybe_last_atom_index = &elf_file.sections.items(.last_atom_index)[shndx];230 const last_atom_index = &elf_file.sections.items(.last_atom_index)[shndx];
235 if (maybe_last_atom_index.*) |last_atom_index| {231 if (elf_file.atom(last_atom_index.*)) |last_atom| {
236 if (last_atom_index == self.atom_index) {232 if (last_atom.atom_index == self.atom_index) {
237 if (self.prev_index) |prev_index| {233 if (elf_file.atom(self.prev_index)) |_| {
238 // TODO shrink the section size here234 // TODO shrink the section size here
239 maybe_last_atom_index.* = prev_index;235 last_atom_index.* = self.prev_index;
240 } else {236 } else {
241 maybe_last_atom_index.* = null;237 last_atom_index.* = 0;
242 }238 }
243 }239 }
244 }240 }
245241
246 if (self.prev_index) |prev_index| {242 if (elf_file.atom(self.prev_index)) |prev| {
247 const prev = elf_file.atom(prev_index);
248 prev.next_index = self.next_index;243 prev.next_index = self.next_index;
249
250 if (!already_have_free_list_node and prev.*.freeListEligible(elf_file)) {244 if (!already_have_free_list_node and prev.*.freeListEligible(elf_file)) {
251 // The free list is heuristics, it doesn't have to be perfect, so we can245 // The free list is heuristics, it doesn't have to be perfect, so we can
252 // ignore the OOM here.246 // ignore the OOM here.
253 free_list.append(gpa, prev_index) catch {};247 free_list.append(gpa, prev.atom_index) catch {};
254 }248 }
255 } else {249 } else {
256 self.prev_index = null;250 self.prev_index = 0;
257 }251 }
258252
259 if (self.next_index) |next_index| {253 if (elf_file.atom(self.next_index)) |next| {
260 elf_file.atom(next_index).prev_index = self.prev_index;254 next.prev_index = self.prev_index;
261 } else {255 } else {
262 self.next_index = null;256 self.next_index = 0;
263 }257 }
264258
265 self.* = .{};259 self.* = .{};
src/link/Elf/Symbol.zig+2-2
...@@ -36,7 +36,7 @@ pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {...@@ -36,7 +36,7 @@ pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
36 const file_ptr = symbol.file(elf_file).?;36 const file_ptr = symbol.file(elf_file).?;
37 // if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS;37 // if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS;
38 return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.output_section_index == 0 and38 return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.output_section_index == 0 and
39 file_ptr != .linker_defined and file_ptr != .zig_module;39 file_ptr != .linker_defined;
40}40}
4141
42pub fn isLocal(symbol: Symbol) bool {42pub fn isLocal(symbol: Symbol) bool {
...@@ -175,7 +175,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {...@@ -175,7 +175,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
175 const st_shndx = blk: {175 const st_shndx = blk: {
176 // if (symbol.flags.copy_rel) break :blk elf_file.copy_rel_sect_index.?;176 // if (symbol.flags.copy_rel) break :blk elf_file.copy_rel_sect_index.?;
177 // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;177 // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
178 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined and file_ptr != .zig_module)178 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
179 break :blk elf.SHN_ABS;179 break :blk elf.SHN_ABS;
180 break :blk symbol.output_section_index;180 break :blk symbol.output_section_index;
181 };181 };
src/link/Elf/ZigModule.zig+15-10
...@@ -1,3 +1,5 @@...@@ -1,3 +1,5 @@
1/// Path is owned by Module and lives as long as *Module.
2path: []const u8,
1index: File.Index,3index: File.Index,
24
3elf_local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},5elf_local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
...@@ -23,26 +25,29 @@ pub fn deinit(self: *ZigModule, allocator: Allocator) void {...@@ -23,26 +25,29 @@ pub fn deinit(self: *ZigModule, allocator: Allocator) void {
23pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index {25pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index {
24 const gpa = elf_file.base.allocator;26 const gpa = elf_file.base.allocator;
25 const atom_index = try elf_file.addAtom();27 const atom_index = try elf_file.addAtom();
26 const symbol_index = try elf_file.addSymbol();28 const symbol_index = try self.addLocal(elf_file);
2729 const atom_ptr = elf_file.atom(atom_index).?;
28 const atom_ptr = elf_file.atom(atom_index);
29 atom_ptr.file_index = self.index;30 atom_ptr.file_index = self.index;
30 atom_ptr.output_section_index = output_section_index;31 atom_ptr.output_section_index = output_section_index;
31
32 const symbol_ptr = elf_file.symbol(symbol_index);32 const symbol_ptr = elf_file.symbol(symbol_index);
33 symbol_ptr.file_index = self.index;
34 symbol_ptr.atom_index = atom_index;33 symbol_ptr.atom_index = atom_index;
35 symbol_ptr.output_section_index = output_section_index;34 symbol_ptr.output_section_index = output_section_index;
36 symbol_ptr.esym_index = @as(Symbol.Index, @intCast(self.elf_local_symbols.items.len));35 const local_esym = symbol_ptr.sourceSymbol(elf_file);
36 local_esym.st_shndx = output_section_index;
37 try self.atoms.append(gpa, atom_index);
38 return symbol_index;
39}
3740
41pub fn addLocal(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
42 const gpa = elf_file.base.allocator;
43 const symbol_index = try elf_file.addSymbol();
44 const symbol_ptr = elf_file.symbol(symbol_index);
45 symbol_ptr.file_index = self.index;
46 symbol_ptr.esym_index = @as(Symbol.Index, @intCast(self.elf_local_symbols.items.len));
38 const local_esym = try self.elf_local_symbols.addOne(gpa);47 const local_esym = try self.elf_local_symbols.addOne(gpa);
39 local_esym.* = Elf.null_sym;48 local_esym.* = Elf.null_sym;
40 local_esym.st_info = elf.STB_LOCAL << 4;49 local_esym.st_info = elf.STB_LOCAL << 4;
41 local_esym.st_shndx = output_section_index;
42
43 try self.atoms.append(gpa, atom_index);
44 try self.local_symbols.putNoClobber(gpa, symbol_index, {});50 try self.local_symbols.putNoClobber(gpa, symbol_index, {});
45
46 return symbol_index;51 return symbol_index;
47}52}
4853