Commit ea95c74948
Changed files (3)
src
link
src/link/Elf/Atom.zig
@@ -166,15 +166,16 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
try elf_file.growAllocSection(self.outputShndx().?, needed_size);
last_atom_index.* = self.atom_index;
- if (elf_file.zigObjectPtr().?.dwarf) |_| {
+ const zig_object = elf_file.zigObjectPtr().?;
+ if (zig_object.dwarf) |_| {
// The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
// range of the compilation unit. When we expand the text section, this range changes,
// so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
- elf_file.debug_info_header_dirty = true;
+ zig_object.debug_info_header_dirty = true;
// This becomes dirty for the same reason. We could potentially make this more
// fine-grained with the addition of support for more compilation units. It is planned to
// model each package as a different compilation unit.
- elf_file.debug_aranges_section_dirty = true;
+ zig_object.debug_aranges_section_dirty = true;
}
}
shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);
src/link/Elf/ZigObject.zig
@@ -52,6 +52,20 @@ unnamed_consts: UnnamedConstTable = .{},
/// Table of tracked AnonDecls.
anon_decls: AnonDeclTable = .{},
+debug_strtab_dirty: bool = false,
+debug_abbrev_section_dirty: bool = false,
+debug_aranges_section_dirty: bool = false,
+debug_info_header_dirty: bool = false,
+debug_line_header_dirty: bool = false,
+
+/// Size contribution of Zig's metadata to each debug section.
+/// Used to track start of metadata from input object files.
+debug_info_section_zig_size: u64 = 0,
+debug_abbrev_section_zig_size: u64 = 0,
+debug_str_section_zig_size: u64 = 0,
+debug_aranges_section_zig_size: u64 = 0,
+debug_line_section_zig_size: u64 = 0,
+
pub const global_symbol_bit: u32 = 0x80000000;
pub const symbol_mask: u32 = 0x7fffffff;
pub const SHN_ATOM: u16 = 0x100;
@@ -123,6 +137,103 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
}
}
+pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
+ // Handle any lazy symbols that were emitted by incremental compilation.
+ if (self.lazy_syms.getPtr(.none)) |metadata| {
+ const module = elf_file.base.options.module.?;
+
+ // Most lazy symbols can be updated on first use, but
+ // anyerror needs to wait for everything to be flushed.
+ if (metadata.text_state != .unused) self.updateLazySymbol(
+ elf_file,
+ link.File.LazySymbol.initDecl(.code, null, module),
+ metadata.text_symbol_index,
+ ) catch |err| return switch (err) {
+ error.CodegenFail => error.FlushFailure,
+ else => |e| e,
+ };
+ if (metadata.rodata_state != .unused) self.updateLazySymbol(
+ elf_file,
+ link.File.LazySymbol.initDecl(.const_data, null, module),
+ metadata.rodata_symbol_index,
+ ) catch |err| return switch (err) {
+ error.CodegenFail => error.FlushFailure,
+ else => |e| e,
+ };
+ }
+ for (self.lazy_syms.values()) |*metadata| {
+ if (metadata.text_state != .unused) metadata.text_state = .flushed;
+ if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
+ }
+
+ if (self.dwarf) |*dw| {
+ try dw.flushModule(elf_file.base.options.module.?);
+
+ // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
+ // extracted from input object files correctly.
+ if (self.debug_abbrev_section_dirty) {
+ try dw.writeDbgAbbrev();
+ self.debug_abbrev_section_dirty = false;
+ }
+
+ if (self.debug_info_header_dirty) {
+ const text_phdr = &elf_file.phdrs.items[elf_file.phdr_zig_load_re_index.?];
+ const low_pc = text_phdr.p_vaddr;
+ const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
+ try dw.writeDbgInfoHeader(elf_file.base.options.module.?, low_pc, high_pc);
+ self.debug_info_header_dirty = false;
+ }
+
+ if (self.debug_aranges_section_dirty) {
+ const text_phdr = &elf_file.phdrs.items[elf_file.phdr_zig_load_re_index.?];
+ try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
+ self.debug_aranges_section_dirty = false;
+ }
+
+ if (self.debug_line_header_dirty) {
+ try dw.writeDbgLineHeader();
+ self.debug_line_header_dirty = false;
+ }
+
+ if (elf_file.debug_str_section_index) |shndx| {
+ if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != elf_file.shdrs.items[shndx].sh_size) {
+ try elf_file.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);
+ const shdr = elf_file.shdrs.items[shndx];
+ try elf_file.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);
+ self.debug_strtab_dirty = false;
+ }
+ }
+
+ self.saveDebugSectionsSizes(elf_file);
+ }
+
+ // The point of flushModule() is to commit changes, so in theory, nothing should
+ // be dirty after this. However, it is possible for some things to remain
+ // dirty because they fail to be written in the event of compile errors,
+ // such as debug_line_header_dirty and debug_info_header_dirty.
+ assert(!self.debug_abbrev_section_dirty);
+ assert(!self.debug_aranges_section_dirty);
+ assert(!self.debug_strtab_dirty);
+}
+
+fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
+ if (elf_file.debug_info_section_index) |shndx| {
+ self.debug_info_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
+ }
+ if (elf_file.debug_abbrev_section_index) |shndx| {
+ self.debug_abbrev_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
+ }
+ if (elf_file.debug_str_section_index) |shndx| {
+ self.debug_str_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
+ }
+ if (elf_file.debug_aranges_section_index) |shndx| {
+ self.debug_aranges_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
+ }
+ if (elf_file.debug_line_section_index) |shndx| {
+ self.debug_line_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
+ }
+}
+
pub fn addLocalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
try self.local_esyms.ensureUnusedCapacity(allocator, 1);
const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));
@@ -837,7 +948,7 @@ pub fn updateDecl(
return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
}
-pub fn updateLazySymbol(
+fn updateLazySymbol(
self: *ZigObject,
elf_file: *Elf,
sym: link.File.LazySymbol,
src/link/Elf.zig
@@ -113,14 +113,6 @@ debug_str_section_index: ?u16 = null,
debug_aranges_section_index: ?u16 = null,
debug_line_section_index: ?u16 = null,
-/// Size contribution of Zig's metadata to each debug section.
-/// Used to track start of metadata from input object files.
-debug_info_section_zig_size: u64 = 0,
-debug_abbrev_section_zig_size: u64 = 0,
-debug_str_section_zig_size: u64 = 0,
-debug_aranges_section_zig_size: u64 = 0,
-debug_line_section_zig_size: u64 = 0,
-
copy_rel_section_index: ?u16 = null,
dynamic_section_index: ?u16 = null,
dynstrtab_section_index: ?u16 = null,
@@ -170,12 +162,6 @@ symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
has_text_reloc: bool = false,
num_ifunc_dynrelocs: usize = 0,
-debug_strtab_dirty: bool = false,
-debug_abbrev_section_dirty: bool = false,
-debug_aranges_section_dirty: bool = false,
-debug_info_header_dirty: bool = false,
-debug_line_header_dirty: bool = false,
-
error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},
misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
@@ -696,7 +682,8 @@ pub fn initMetadata(self: *Elf) !void {
try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
}
- if (self.zigObjectPtr().?.dwarf) |*dw| {
+ const zig_object = self.zigObjectPtr().?;
+ if (zig_object.dwarf) |*dw| {
if (self.debug_str_section_index == null) {
assert(dw.strtab.buffer.items.len == 0);
try dw.strtab.buffer.append(gpa, 0);
@@ -706,7 +693,7 @@ pub fn initMetadata(self: *Elf) !void {
.flags = elf.SHF_MERGE | elf.SHF_STRINGS,
.entsize = 1,
});
- self.debug_strtab_dirty = true;
+ zig_object.debug_strtab_dirty = true;
}
if (self.debug_info_section_index == null) {
@@ -715,7 +702,7 @@ pub fn initMetadata(self: *Elf) !void {
.size = 200,
.alignment = 1,
});
- self.debug_info_header_dirty = true;
+ zig_object.debug_info_header_dirty = true;
}
if (self.debug_abbrev_section_index == null) {
@@ -724,7 +711,7 @@ pub fn initMetadata(self: *Elf) !void {
.size = 128,
.alignment = 1,
});
- self.debug_abbrev_section_dirty = true;
+ zig_object.debug_abbrev_section_dirty = true;
}
if (self.debug_aranges_section_index == null) {
@@ -733,7 +720,7 @@ pub fn initMetadata(self: *Elf) !void {
.size = 160,
.alignment = 16,
});
- self.debug_aranges_section_dirty = true;
+ zig_object.debug_aranges_section_dirty = true;
}
if (self.debug_line_section_index == null) {
@@ -742,7 +729,7 @@ pub fn initMetadata(self: *Elf) !void {
.size = 250,
.alignment = 1,
});
- self.debug_line_header_dirty = true;
+ zig_object.debug_line_header_dirty = true;
}
}
}
@@ -833,17 +820,18 @@ pub fn growNonAllocSection(
}
pub fn markDirty(self: *Elf, shdr_index: u16) void {
- if (self.zigObjectPtr().?.dwarf) |_| {
+ const zig_object = self.zigObjectPtr().?;
+ if (zig_object.dwarf) |_| {
if (self.debug_info_section_index.? == shdr_index) {
- self.debug_info_header_dirty = true;
+ zig_object.debug_info_header_dirty = true;
} else if (self.debug_line_section_index.? == shdr_index) {
- self.debug_line_header_dirty = true;
+ zig_object.debug_line_header_dirty = true;
} else if (self.debug_abbrev_section_index.? == shdr_index) {
- self.debug_abbrev_section_dirty = true;
+ zig_object.debug_abbrev_section_dirty = true;
} else if (self.debug_str_section_index.? == shdr_index) {
- self.debug_strtab_dirty = true;
+ zig_object.debug_strtab_dirty = true;
} else if (self.debug_aranges_section_index.? == shdr_index) {
- self.debug_aranges_section_dirty = true;
+ zig_object.debug_aranges_section_dirty = true;
}
}
}
@@ -1343,39 +1331,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
try self.handleAndReportParseError(obj.path, err, &parse_ctx);
}
- if (self.zigObjectPtr()) |zig_object| {
- // Handle any lazy symbols that were emitted by incremental compilation.
- if (zig_object.lazy_syms.getPtr(.none)) |metadata| {
- const module = self.base.options.module.?;
-
- // Most lazy symbols can be updated on first use, but
- // anyerror needs to wait for everything to be flushed.
- if (metadata.text_state != .unused) zig_object.updateLazySymbol(
- self,
- link.File.LazySymbol.initDecl(.code, null, module),
- metadata.text_symbol_index,
- ) catch |err| return switch (err) {
- error.CodegenFail => error.FlushFailure,
- else => |e| e,
- };
- if (metadata.rodata_state != .unused) zig_object.updateLazySymbol(
- self,
- link.File.LazySymbol.initDecl(.const_data, null, module),
- metadata.rodata_symbol_index,
- ) catch |err| return switch (err) {
- error.CodegenFail => error.FlushFailure,
- else => |e| e,
- };
- }
- for (zig_object.lazy_syms.values()) |*metadata| {
- if (metadata.text_state != .unused) metadata.text_state = .flushed;
- if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
- }
-
- if (zig_object.dwarf) |*dw| {
- try dw.flushModule(self.base.options.module.?);
- }
- }
+ if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
// Dedup shared objects
{
@@ -1437,47 +1393,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
// Scan and create missing synthetic entries such as GOT indirection.
try self.scanRelocs();
- if (self.zigObjectPtr()) |zig_object| {
- // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
- // extracted from input object files correctly.
- if (zig_object.dwarf) |*dw| {
- if (self.debug_abbrev_section_dirty) {
- try dw.writeDbgAbbrev();
- self.debug_abbrev_section_dirty = false;
- }
-
- if (self.debug_info_header_dirty) {
- const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
- const low_pc = text_phdr.p_vaddr;
- const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
- try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc);
- self.debug_info_header_dirty = false;
- }
-
- if (self.debug_aranges_section_dirty) {
- const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
- try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
- self.debug_aranges_section_dirty = false;
- }
-
- if (self.debug_line_header_dirty) {
- try dw.writeDbgLineHeader();
- self.debug_line_header_dirty = false;
- }
-
- if (self.debug_str_section_index) |shndx| {
- if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[shndx].sh_size) {
- try self.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);
- const shdr = self.shdrs.items[shndx];
- try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);
- self.debug_strtab_dirty = false;
- }
- }
-
- self.saveDebugSectionsSizes();
- }
- }
-
// Generate and emit non-incremental sections.
try self.initSections();
try self.initSpecialPhdrs();
@@ -1542,14 +1457,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
self.error_flags.no_entry_point_found = false;
try self.writeHeader();
}
-
- // The point of flush() is to commit changes, so in theory, nothing should
- // be dirty after this. However, it is possible for some things to remain
- // dirty because they fail to be written in the event of compile errors,
- // such as debug_line_header_dirty and debug_info_header_dirty.
- assert(!self.debug_abbrev_section_dirty);
- assert(!self.debug_aranges_section_dirty);
- assert(!self.debug_strtab_dirty);
}
const ParseError = error{
@@ -3815,24 +3722,6 @@ fn sortShdrs(self: *Elf) !void {
}
}
-fn saveDebugSectionsSizes(self: *Elf) void {
- if (self.debug_info_section_index) |shndx| {
- self.debug_info_section_zig_size = self.shdrs.items[shndx].sh_size;
- }
- if (self.debug_abbrev_section_index) |shndx| {
- self.debug_abbrev_section_zig_size = self.shdrs.items[shndx].sh_size;
- }
- if (self.debug_str_section_index) |shndx| {
- self.debug_str_section_zig_size = self.shdrs.items[shndx].sh_size;
- }
- if (self.debug_aranges_section_index) |shndx| {
- self.debug_aranges_section_zig_size = self.shdrs.items[shndx].sh_size;
- }
- if (self.debug_line_section_index) |shndx| {
- self.debug_line_section_zig_size = self.shdrs.items[shndx].sh_size;
- }
-}
-
fn updateSectionSizes(self: *Elf) !void {
for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
if (atom_list.items.len == 0) continue;
@@ -4189,12 +4078,18 @@ fn allocateNonAllocSections(self: *Elf) !void {
shdr.sh_offset,
new_offset,
});
+ const zig_object = self.zigObjectPtr().?;
const existing_size = blk: {
- if (shndx == self.debug_info_section_index.?) break :blk self.debug_info_section_zig_size;
- if (shndx == self.debug_abbrev_section_index.?) break :blk self.debug_abbrev_section_zig_size;
- if (shndx == self.debug_str_section_index.?) break :blk self.debug_str_section_zig_size;
- if (shndx == self.debug_aranges_section_index.?) break :blk self.debug_aranges_section_zig_size;
- if (shndx == self.debug_line_section_index.?) break :blk self.debug_line_section_zig_size;
+ if (shndx == self.debug_info_section_index.?)
+ break :blk zig_object.debug_info_section_zig_size;
+ if (shndx == self.debug_abbrev_section_index.?)
+ break :blk zig_object.debug_abbrev_section_zig_size;
+ if (shndx == self.debug_str_section_index.?)
+ break :blk zig_object.debug_str_section_zig_size;
+ if (shndx == self.debug_aranges_section_index.?)
+ break :blk zig_object.debug_aranges_section_zig_size;
+ if (shndx == self.debug_line_section_index.?)
+ break :blk zig_object.debug_line_section_zig_size;
unreachable;
};
const amt = try self.base.file.?.copyRangeAll(
@@ -4296,11 +4191,17 @@ fn writeAtoms(self: *Elf) !void {
// TODO really, really handle debug section separately
const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
- if (shndx == self.debug_info_section_index.?) break :blk self.debug_info_section_zig_size;
- if (shndx == self.debug_abbrev_section_index.?) break :blk self.debug_abbrev_section_zig_size;
- if (shndx == self.debug_str_section_index.?) break :blk self.debug_str_section_zig_size;
- if (shndx == self.debug_aranges_section_index.?) break :blk self.debug_aranges_section_zig_size;
- if (shndx == self.debug_line_section_index.?) break :blk self.debug_line_section_zig_size;
+ const zig_object = self.zigObjectPtr().?;
+ if (shndx == self.debug_info_section_index.?)
+ break :blk zig_object.debug_info_section_zig_size;
+ if (shndx == self.debug_abbrev_section_index.?)
+ break :blk zig_object.debug_abbrev_section_zig_size;
+ if (shndx == self.debug_str_section_index.?)
+ break :blk zig_object.debug_str_section_zig_size;
+ if (shndx == self.debug_aranges_section_index.?)
+ break :blk zig_object.debug_aranges_section_zig_size;
+ if (shndx == self.debug_line_section_index.?)
+ break :blk zig_object.debug_line_section_zig_size;
unreachable;
} else 0;
const sh_offset = shdr.sh_offset + base_offset;