authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-30 20:36:34+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-30 20:36:34+01:00
logea95c74948b6cbc615452c661180874213cb5f9c
tree1132796c12795cea08af7fd88a9cbdc99099b1f8
parentb1a735ac65126c9fb383ae894e31fb53b94ce0b8

elf: encapsulate ZigObject-specific logic in flushModule hook


3 files changed, 153 insertions(+), 140 deletions(-)

src/link/Elf.zig+37-136
......@@ -113,14 +113,6 @@ debug_str_section_index: ?u16 = null,
113113debug_aranges_section_index: ?u16 = null,
114114debug_line_section_index: ?u16 = null,
115115
116/// Size contribution of Zig's metadata to each debug section.
117/// Used to track start of metadata from input object files.
118debug_info_section_zig_size: u64 = 0,
119debug_abbrev_section_zig_size: u64 = 0,
120debug_str_section_zig_size: u64 = 0,
121debug_aranges_section_zig_size: u64 = 0,
122debug_line_section_zig_size: u64 = 0,
123
124116copy_rel_section_index: ?u16 = null,
125117dynamic_section_index: ?u16 = null,
126118dynstrtab_section_index: ?u16 = null,
......@@ -170,12 +162,6 @@ symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
170162has_text_reloc: bool = false,
171163num_ifunc_dynrelocs: usize = 0,
172164
173debug_strtab_dirty: bool = false,
174debug_abbrev_section_dirty: bool = false,
175debug_aranges_section_dirty: bool = false,
176debug_info_header_dirty: bool = false,
177debug_line_header_dirty: bool = false,
178
179165error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},
180166misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
181167
......@@ -696,7 +682,8 @@ pub fn initMetadata(self: *Elf) !void {
696682 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
697683 }
698684
699 if (self.zigObjectPtr().?.dwarf) |*dw| {
685 const zig_object = self.zigObjectPtr().?;
686 if (zig_object.dwarf) |*dw| {
700687 if (self.debug_str_section_index == null) {
701688 assert(dw.strtab.buffer.items.len == 0);
702689 try dw.strtab.buffer.append(gpa, 0);
......@@ -706,7 +693,7 @@ pub fn initMetadata(self: *Elf) !void {
706693 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
707694 .entsize = 1,
708695 });
709 self.debug_strtab_dirty = true;
696 zig_object.debug_strtab_dirty = true;
710697 }
711698
712699 if (self.debug_info_section_index == null) {
......@@ -715,7 +702,7 @@ pub fn initMetadata(self: *Elf) !void {
715702 .size = 200,
716703 .alignment = 1,
717704 });
718 self.debug_info_header_dirty = true;
705 zig_object.debug_info_header_dirty = true;
719706 }
720707
721708 if (self.debug_abbrev_section_index == null) {
......@@ -724,7 +711,7 @@ pub fn initMetadata(self: *Elf) !void {
724711 .size = 128,
725712 .alignment = 1,
726713 });
727 self.debug_abbrev_section_dirty = true;
714 zig_object.debug_abbrev_section_dirty = true;
728715 }
729716
730717 if (self.debug_aranges_section_index == null) {
......@@ -733,7 +720,7 @@ pub fn initMetadata(self: *Elf) !void {
733720 .size = 160,
734721 .alignment = 16,
735722 });
736 self.debug_aranges_section_dirty = true;
723 zig_object.debug_aranges_section_dirty = true;
737724 }
738725
739726 if (self.debug_line_section_index == null) {
......@@ -742,7 +729,7 @@ pub fn initMetadata(self: *Elf) !void {
742729 .size = 250,
743730 .alignment = 1,
744731 });
745 self.debug_line_header_dirty = true;
732 zig_object.debug_line_header_dirty = true;
746733 }
747734 }
748735}
......@@ -833,17 +820,18 @@ pub fn growNonAllocSection(
833820}
834821
835822pub fn markDirty(self: *Elf, shdr_index: u16) void {
836 if (self.zigObjectPtr().?.dwarf) |_| {
823 const zig_object = self.zigObjectPtr().?;
824 if (zig_object.dwarf) |_| {
837825 if (self.debug_info_section_index.? == shdr_index) {
838 self.debug_info_header_dirty = true;
826 zig_object.debug_info_header_dirty = true;
839827 } else if (self.debug_line_section_index.? == shdr_index) {
840 self.debug_line_header_dirty = true;
828 zig_object.debug_line_header_dirty = true;
841829 } else if (self.debug_abbrev_section_index.? == shdr_index) {
842 self.debug_abbrev_section_dirty = true;
830 zig_object.debug_abbrev_section_dirty = true;
843831 } else if (self.debug_str_section_index.? == shdr_index) {
844 self.debug_strtab_dirty = true;
832 zig_object.debug_strtab_dirty = true;
845833 } else if (self.debug_aranges_section_index.? == shdr_index) {
846 self.debug_aranges_section_dirty = true;
834 zig_object.debug_aranges_section_dirty = true;
847835 }
848836 }
849837}
......@@ -1343,39 +1331,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
13431331 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
13441332 }
13451333
1346 if (self.zigObjectPtr()) |zig_object| {
1347 // Handle any lazy symbols that were emitted by incremental compilation.
1348 if (zig_object.lazy_syms.getPtr(.none)) |metadata| {
1349 const module = self.base.options.module.?;
1350
1351 // Most lazy symbols can be updated on first use, but
1352 // anyerror needs to wait for everything to be flushed.
1353 if (metadata.text_state != .unused) zig_object.updateLazySymbol(
1354 self,
1355 link.File.LazySymbol.initDecl(.code, null, module),
1356 metadata.text_symbol_index,
1357 ) catch |err| return switch (err) {
1358 error.CodegenFail => error.FlushFailure,
1359 else => |e| e,
1360 };
1361 if (metadata.rodata_state != .unused) zig_object.updateLazySymbol(
1362 self,
1363 link.File.LazySymbol.initDecl(.const_data, null, module),
1364 metadata.rodata_symbol_index,
1365 ) catch |err| return switch (err) {
1366 error.CodegenFail => error.FlushFailure,
1367 else => |e| e,
1368 };
1369 }
1370 for (zig_object.lazy_syms.values()) |*metadata| {
1371 if (metadata.text_state != .unused) metadata.text_state = .flushed;
1372 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
1373 }
1374
1375 if (zig_object.dwarf) |*dw| {
1376 try dw.flushModule(self.base.options.module.?);
1377 }
1378 }
1334 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
13791335
13801336 // Dedup shared objects
13811337 {
......@@ -1437,47 +1393,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14371393 // Scan and create missing synthetic entries such as GOT indirection.
14381394 try self.scanRelocs();
14391395
1440 if (self.zigObjectPtr()) |zig_object| {
1441 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
1442 // extracted from input object files correctly.
1443 if (zig_object.dwarf) |*dw| {
1444 if (self.debug_abbrev_section_dirty) {
1445 try dw.writeDbgAbbrev();
1446 self.debug_abbrev_section_dirty = false;
1447 }
1448
1449 if (self.debug_info_header_dirty) {
1450 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
1451 const low_pc = text_phdr.p_vaddr;
1452 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1453 try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc);
1454 self.debug_info_header_dirty = false;
1455 }
1456
1457 if (self.debug_aranges_section_dirty) {
1458 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
1459 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
1460 self.debug_aranges_section_dirty = false;
1461 }
1462
1463 if (self.debug_line_header_dirty) {
1464 try dw.writeDbgLineHeader();
1465 self.debug_line_header_dirty = false;
1466 }
1467
1468 if (self.debug_str_section_index) |shndx| {
1469 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[shndx].sh_size) {
1470 try self.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);
1471 const shdr = self.shdrs.items[shndx];
1472 try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);
1473 self.debug_strtab_dirty = false;
1474 }
1475 }
1476
1477 self.saveDebugSectionsSizes();
1478 }
1479 }
1480
14811396 // Generate and emit non-incremental sections.
14821397 try self.initSections();
14831398 try self.initSpecialPhdrs();
......@@ -1542,14 +1457,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
15421457 self.error_flags.no_entry_point_found = false;
15431458 try self.writeHeader();
15441459 }
1545
1546 // The point of flush() is to commit changes, so in theory, nothing should
1547 // be dirty after this. However, it is possible for some things to remain
1548 // dirty because they fail to be written in the event of compile errors,
1549 // such as debug_line_header_dirty and debug_info_header_dirty.
1550 assert(!self.debug_abbrev_section_dirty);
1551 assert(!self.debug_aranges_section_dirty);
1552 assert(!self.debug_strtab_dirty);
15531460}
15541461
15551462const ParseError = error{
......@@ -3815,24 +3722,6 @@ fn sortShdrs(self: *Elf) !void {
38153722 }
38163723}
38173724
3818fn saveDebugSectionsSizes(self: *Elf) void {
3819 if (self.debug_info_section_index) |shndx| {
3820 self.debug_info_section_zig_size = self.shdrs.items[shndx].sh_size;
3821 }
3822 if (self.debug_abbrev_section_index) |shndx| {
3823 self.debug_abbrev_section_zig_size = self.shdrs.items[shndx].sh_size;
3824 }
3825 if (self.debug_str_section_index) |shndx| {
3826 self.debug_str_section_zig_size = self.shdrs.items[shndx].sh_size;
3827 }
3828 if (self.debug_aranges_section_index) |shndx| {
3829 self.debug_aranges_section_zig_size = self.shdrs.items[shndx].sh_size;
3830 }
3831 if (self.debug_line_section_index) |shndx| {
3832 self.debug_line_section_zig_size = self.shdrs.items[shndx].sh_size;
3833 }
3834}
3835
38363725fn updateSectionSizes(self: *Elf) !void {
38373726 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
38383727 if (atom_list.items.len == 0) continue;
......@@ -4189,12 +4078,18 @@ fn allocateNonAllocSections(self: *Elf) !void {
41894078 shdr.sh_offset,
41904079 new_offset,
41914080 });
4081 const zig_object = self.zigObjectPtr().?;
41924082 const existing_size = blk: {
4193 if (shndx == self.debug_info_section_index.?) break :blk self.debug_info_section_zig_size;
4194 if (shndx == self.debug_abbrev_section_index.?) break :blk self.debug_abbrev_section_zig_size;
4195 if (shndx == self.debug_str_section_index.?) break :blk self.debug_str_section_zig_size;
4196 if (shndx == self.debug_aranges_section_index.?) break :blk self.debug_aranges_section_zig_size;
4197 if (shndx == self.debug_line_section_index.?) break :blk self.debug_line_section_zig_size;
4083 if (shndx == self.debug_info_section_index.?)
4084 break :blk zig_object.debug_info_section_zig_size;
4085 if (shndx == self.debug_abbrev_section_index.?)
4086 break :blk zig_object.debug_abbrev_section_zig_size;
4087 if (shndx == self.debug_str_section_index.?)
4088 break :blk zig_object.debug_str_section_zig_size;
4089 if (shndx == self.debug_aranges_section_index.?)
4090 break :blk zig_object.debug_aranges_section_zig_size;
4091 if (shndx == self.debug_line_section_index.?)
4092 break :blk zig_object.debug_line_section_zig_size;
41984093 unreachable;
41994094 };
42004095 const amt = try self.base.file.?.copyRangeAll(
......@@ -4296,11 +4191,17 @@ fn writeAtoms(self: *Elf) !void {
42964191
42974192 // TODO really, really handle debug section separately
42984193 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
4299 if (shndx == self.debug_info_section_index.?) break :blk self.debug_info_section_zig_size;
4300 if (shndx == self.debug_abbrev_section_index.?) break :blk self.debug_abbrev_section_zig_size;
4301 if (shndx == self.debug_str_section_index.?) break :blk self.debug_str_section_zig_size;
4302 if (shndx == self.debug_aranges_section_index.?) break :blk self.debug_aranges_section_zig_size;
4303 if (shndx == self.debug_line_section_index.?) break :blk self.debug_line_section_zig_size;
4194 const zig_object = self.zigObjectPtr().?;
4195 if (shndx == self.debug_info_section_index.?)
4196 break :blk zig_object.debug_info_section_zig_size;
4197 if (shndx == self.debug_abbrev_section_index.?)
4198 break :blk zig_object.debug_abbrev_section_zig_size;
4199 if (shndx == self.debug_str_section_index.?)
4200 break :blk zig_object.debug_str_section_zig_size;
4201 if (shndx == self.debug_aranges_section_index.?)
4202 break :blk zig_object.debug_aranges_section_zig_size;
4203 if (shndx == self.debug_line_section_index.?)
4204 break :blk zig_object.debug_line_section_zig_size;
43044205 unreachable;
43054206 } else 0;
43064207 const sh_offset = shdr.sh_offset + base_offset;
src/link/Elf/Atom.zig+4-3
......@@ -166,15 +166,16 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
166166 try elf_file.growAllocSection(self.outputShndx().?, needed_size);
167167 last_atom_index.* = self.atom_index;
168168
169 if (elf_file.zigObjectPtr().?.dwarf) |_| {
169 const zig_object = elf_file.zigObjectPtr().?;
170 if (zig_object.dwarf) |_| {
170171 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
171172 // range of the compilation unit. When we expand the text section, this range changes,
172173 // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
173 elf_file.debug_info_header_dirty = true;
174 zig_object.debug_info_header_dirty = true;
174175 // This becomes dirty for the same reason. We could potentially make this more
175176 // fine-grained with the addition of support for more compilation units. It is planned to
176177 // model each package as a different compilation unit.
177 elf_file.debug_aranges_section_dirty = true;
178 zig_object.debug_aranges_section_dirty = true;
178179 }
179180 }
180181 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);
src/link/Elf/ZigObject.zig+112-1
......@@ -52,6 +52,20 @@ unnamed_consts: UnnamedConstTable = .{},
5252/// Table of tracked AnonDecls.
5353anon_decls: AnonDeclTable = .{},
5454
55debug_strtab_dirty: bool = false,
56debug_abbrev_section_dirty: bool = false,
57debug_aranges_section_dirty: bool = false,
58debug_info_header_dirty: bool = false,
59debug_line_header_dirty: bool = false,
60
61/// Size contribution of Zig's metadata to each debug section.
62/// Used to track start of metadata from input object files.
63debug_info_section_zig_size: u64 = 0,
64debug_abbrev_section_zig_size: u64 = 0,
65debug_str_section_zig_size: u64 = 0,
66debug_aranges_section_zig_size: u64 = 0,
67debug_line_section_zig_size: u64 = 0,
68
5569pub const global_symbol_bit: u32 = 0x80000000;
5670pub const symbol_mask: u32 = 0x7fffffff;
5771pub const SHN_ATOM: u16 = 0x100;
......@@ -123,6 +137,103 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
123137 }
124138}
125139
140pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
141 // Handle any lazy symbols that were emitted by incremental compilation.
142 if (self.lazy_syms.getPtr(.none)) |metadata| {
143 const module = elf_file.base.options.module.?;
144
145 // Most lazy symbols can be updated on first use, but
146 // anyerror needs to wait for everything to be flushed.
147 if (metadata.text_state != .unused) self.updateLazySymbol(
148 elf_file,
149 link.File.LazySymbol.initDecl(.code, null, module),
150 metadata.text_symbol_index,
151 ) catch |err| return switch (err) {
152 error.CodegenFail => error.FlushFailure,
153 else => |e| e,
154 };
155 if (metadata.rodata_state != .unused) self.updateLazySymbol(
156 elf_file,
157 link.File.LazySymbol.initDecl(.const_data, null, module),
158 metadata.rodata_symbol_index,
159 ) catch |err| return switch (err) {
160 error.CodegenFail => error.FlushFailure,
161 else => |e| e,
162 };
163 }
164 for (self.lazy_syms.values()) |*metadata| {
165 if (metadata.text_state != .unused) metadata.text_state = .flushed;
166 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
167 }
168
169 if (self.dwarf) |*dw| {
170 try dw.flushModule(elf_file.base.options.module.?);
171
172 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
173 // extracted from input object files correctly.
174 if (self.debug_abbrev_section_dirty) {
175 try dw.writeDbgAbbrev();
176 self.debug_abbrev_section_dirty = false;
177 }
178
179 if (self.debug_info_header_dirty) {
180 const text_phdr = &elf_file.phdrs.items[elf_file.phdr_zig_load_re_index.?];
181 const low_pc = text_phdr.p_vaddr;
182 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
183 try dw.writeDbgInfoHeader(elf_file.base.options.module.?, low_pc, high_pc);
184 self.debug_info_header_dirty = false;
185 }
186
187 if (self.debug_aranges_section_dirty) {
188 const text_phdr = &elf_file.phdrs.items[elf_file.phdr_zig_load_re_index.?];
189 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
190 self.debug_aranges_section_dirty = false;
191 }
192
193 if (self.debug_line_header_dirty) {
194 try dw.writeDbgLineHeader();
195 self.debug_line_header_dirty = false;
196 }
197
198 if (elf_file.debug_str_section_index) |shndx| {
199 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != elf_file.shdrs.items[shndx].sh_size) {
200 try elf_file.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);
201 const shdr = elf_file.shdrs.items[shndx];
202 try elf_file.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);
203 self.debug_strtab_dirty = false;
204 }
205 }
206
207 self.saveDebugSectionsSizes(elf_file);
208 }
209
210 // The point of flushModule() is to commit changes, so in theory, nothing should
211 // be dirty after this. However, it is possible for some things to remain
212 // dirty because they fail to be written in the event of compile errors,
213 // such as debug_line_header_dirty and debug_info_header_dirty.
214 assert(!self.debug_abbrev_section_dirty);
215 assert(!self.debug_aranges_section_dirty);
216 assert(!self.debug_strtab_dirty);
217}
218
219fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
220 if (elf_file.debug_info_section_index) |shndx| {
221 self.debug_info_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
222 }
223 if (elf_file.debug_abbrev_section_index) |shndx| {
224 self.debug_abbrev_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
225 }
226 if (elf_file.debug_str_section_index) |shndx| {
227 self.debug_str_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
228 }
229 if (elf_file.debug_aranges_section_index) |shndx| {
230 self.debug_aranges_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
231 }
232 if (elf_file.debug_line_section_index) |shndx| {
233 self.debug_line_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
234 }
235}
236
126237pub fn addLocalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
127238 try self.local_esyms.ensureUnusedCapacity(allocator, 1);
128239 const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));
......@@ -837,7 +948,7 @@ pub fn updateDecl(
837948 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
838949}
839950
840pub fn updateLazySymbol(
951fn updateLazySymbol(
841952 self: *ZigObject,
842953 elf_file: *Elf,
843954 sym: link.File.LazySymbol,