authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-07-30 02:33:51-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-03 11:00:53-04:00
log79bb28aa57b3712116dc75288d60f2d29ba31cfb
tree7ee962f502f1c03c23189a416d0b4c234b564d3b
parente78ea8f2cb3677c0a104319b8aa5e37ea64d9cfa

Elf2: implement dwarf unwind info

Other debug info is still in progress. Closes #25421

21 files changed, 4429 insertions(+), 853 deletions(-)

CMakeLists.txt+1
...@@ -383,6 +383,7 @@ set(ZIG_STAGE2_SOURCES...@@ -383,6 +383,7 @@ set(ZIG_STAGE2_SOURCES
383 src/link/ConstPool.zig383 src/link/ConstPool.zig
384 src/link/Coff.zig384 src/link/Coff.zig
385 src/link/Dwarf.zig385 src/link/Dwarf.zig
386 src/link/Dwarf2.zig
386 src/link/Elf.zig387 src/link/Elf.zig
387 src/link/Elf/Archive.zig388 src/link/Elf/Archive.zig
388 src/link/Elf/Atom.zig389 src/link/Elf/Atom.zig
lib/std/debug/Dwarf/Unwind.zig+16-7
...@@ -362,8 +362,7 @@ pub const CommonInformationEntry = struct {...@@ -362,8 +362,7 @@ pub const CommonInformationEntry = struct {
362 if (aug_str.len == 0) break :aug .none;362 if (aug_str.len == 0) break :aug .none;
363 if (aug_str[0] == 'z') break :aug .lsb_z;363 if (aug_str[0] == 'z') break :aug .lsb_z;
364 if (std.mem.eql(u8, aug_str, "eh")) break :aug .gcc_eh;364 if (std.mem.eql(u8, aug_str, "eh")) break :aug .gcc_eh;
365 // We can't finish parsing the CIE if we don't know what its augmentation means.365 return error.UnsupportedAugmentation;
366 return bad();
367 };366 };
368367
369 switch (aug_kind) {368 switch (aug_kind) {
...@@ -396,7 +395,7 @@ pub const CommonInformationEntry = struct {...@@ -396,7 +395,7 @@ pub const CommonInformationEntry = struct {
396 'R' => fde_pointer_enc = @bitCast(try aug_data.takeByte()),395 'R' => fde_pointer_enc = @bitCast(try aug_data.takeByte()),
397 'S' => is_signal_frame = true,396 'S' => is_signal_frame = true,
398 'B', 'G' => {},397 'B', 'G' => {},
399 else => return bad(),398 else => return error.UnsupportedAugmentation,
400 };399 };
401 break :aug .{ fde_pointer_enc, is_signal_frame };400 break :aug .{ fde_pointer_enc, is_signal_frame };
402 };401 };
...@@ -502,7 +501,15 @@ pub fn prepare(...@@ -502,7 +501,15 @@ pub fn prepare(
502 const idx = unwind.cie_list.len;501 const idx = unwind.cie_list.len;
503 try unwind.cie_list.append(gpa, .{502 try unwind.cie_list.append(gpa, .{
504 .offset = entry_offset,503 .offset = entry_offset,
505 .cie = try .parse(cie_info.format, try r.take(bytes_len), section.id, addr_size_bytes),504 .cie = CommonInformationEntry.parse(cie_info.format, try r.take(bytes_len), section.id, addr_size_bytes) catch |err| switch (err) {
505 error.UnsupportedDwarfVersion,
506 error.UnsupportedAugmentation,
507 => {
508 // These are recoverable by just skipping the CIE.
509 continue;
510 },
511 else => |e| return e,
512 },
506 });513 });
507 errdefer _ = unwind.cie_list.pop().?;514 errdefer _ = unwind.cie_list.pop().?;
508 try VirtualMachine.populateCieLastRow(gpa, &unwind.cie_list.items(.cie)[idx], addr_size_bytes, endian);515 try VirtualMachine.populateCieLastRow(gpa, &unwind.cie_list.items(.cie)[idx], addr_size_bytes, endian);
...@@ -514,8 +521,10 @@ pub fn prepare(...@@ -514,8 +521,10 @@ pub fn prepare(
514 try r.discardAll(bytes_len);521 try r.discardAll(bytes_len);
515 continue;522 continue;
516 }523 }
517 const cie = unwind.findCie(fde_info.cie_offset) orelse return error.InvalidDebugInfo;524 const fde_vaddr = section.vaddr + r.seek;
518 const fde: FrameDescriptionEntry = try .parse(section.vaddr + r.seek, try r.take(bytes_len), cie, endian);525 const fde_bytes = try r.take(bytes_len);
526 const cie = unwind.findCie(fde_info.cie_offset) orelse continue;
527 const fde: FrameDescriptionEntry = try .parse(fde_vaddr, fde_bytes, cie, endian);
519 try fde_list.append(gpa, .{528 try fde_list.append(gpa, .{
520 .pc_begin = fde.pc_begin,529 .pc_begin = fde.pc_begin,
521 .fde_offset = entry_offset,530 .fde_offset = entry_offset,
...@@ -612,7 +621,7 @@ pub fn getFde(unwind: *const Unwind, fde_offset: u64, endian: Endian) !struct {...@@ -612,7 +621,7 @@ pub fn getFde(unwind: *const Unwind, fde_offset: u64, endian: Endian) !struct {
612 .cie, .terminator => return bad(), // This is meant to be an FDE621 .cie, .terminator => return bad(), // This is meant to be an FDE
613 };622 };
614623
615 const cie = unwind.findCie(fde_info.cie_offset) orelse return error.InvalidDebugInfo;624 const cie = unwind.findCie(fde_info.cie_offset) orelse return bad();
616 const fde: FrameDescriptionEntry = try .parse(625 const fde: FrameDescriptionEntry = try .parse(
617 section.vaddr + fde_offset + fde_reader.seek,626 section.vaddr + fde_offset + fde_reader.seek,
618 try fde_reader.take(cast(usize, fde_info.bytes_len) orelse return error.EndOfStream),627 try fde_reader.take(cast(usize, fde_info.bytes_len) orelse return error.EndOfStream),
lib/std/debug/SelfInfo/Elf.zig-1
...@@ -340,7 +340,6 @@ const Module = struct {...@@ -340,7 +340,6 @@ const Module = struct {
340 error.InvalidOperation,340 error.InvalidOperation,
341 => return error.InvalidDebugInfo,341 => return error.InvalidDebugInfo,
342 error.UnsupportedAddrSize,342 error.UnsupportedAddrSize,
343 error.UnsupportedDwarfVersion,
344 error.UnimplementedUserOpcode,343 error.UnimplementedUserOpcode,
345 => return error.UnsupportedDebugInfo,344 => return error.UnsupportedDebugInfo,
346 };345 };
lib/std/debug/SelfInfo/MachO.zig-1
...@@ -578,7 +578,6 @@ const Module = struct {...@@ -578,7 +578,6 @@ const Module = struct {
578 error.InvalidOperation,578 error.InvalidOperation,
579 => return error.InvalidDebugInfo,579 => return error.InvalidDebugInfo,
580 error.UnsupportedAddrSize,580 error.UnsupportedAddrSize,
581 error.UnsupportedDwarfVersion,
582 error.UnimplementedUserOpcode,581 error.UnimplementedUserOpcode,
583 => return error.UnsupportedDebugInfo,582 => return error.UnsupportedDebugInfo,
584 };583 };
src/codegen.zig+4-3
...@@ -26,6 +26,7 @@ pub const aarch64 = @import("codegen/aarch64.zig");...@@ -26,6 +26,7 @@ pub const aarch64 = @import("codegen/aarch64.zig");
26pub const loongarch = @import("codegen/loongarch.zig");26pub const loongarch = @import("codegen/loongarch.zig");
2727
28pub const Error = link.Error;28pub const Error = link.Error;
29pub const EmitError = Error || std.Io.Writer.Error || error{MappedFileIo};
2930
30fn devFeatureForBackend(backend: std.lang.CompilerBackend) dev.Feature {31fn devFeatureForBackend(backend: std.lang.CompilerBackend) dev.Feature {
31 return switch (backend) {32 return switch (backend) {
...@@ -196,7 +197,7 @@ pub fn emitFunction(...@@ -196,7 +197,7 @@ pub fn emitFunction(
196 any_mir: *const AnyMir,197 any_mir: *const AnyMir,
197 w: *std.Io.Writer,198 w: *std.Io.Writer,
198 debug_output: link.File.DebugInfoOutput,199 debug_output: link.File.DebugInfoOutput,
199) (Error || std.Io.Writer.Error)!void {200) EmitError!void {
200 const zcu = pt.zcu;201 const zcu = pt.zcu;
201 const func = zcu.funcInfo(func_index);202 const func = zcu.funcInfo(func_index);
202 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;203 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
...@@ -228,7 +229,7 @@ pub fn generateLazyFunction(...@@ -228,7 +229,7 @@ pub fn generateLazyFunction(
228 atom_id: link.File.AtomId,229 atom_id: link.File.AtomId,
229 w: *std.Io.Writer,230 w: *std.Io.Writer,
230 debug_output: link.File.DebugInfoOutput,231 debug_output: link.File.DebugInfoOutput,
231) (Error || std.Io.Writer.Error)!void {232) EmitError!void {
232 const zcu = pt.zcu;233 const zcu = pt.zcu;
233 const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index|234 const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index|
234 &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result235 &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result
...@@ -252,7 +253,7 @@ pub fn generateLazySymbol(...@@ -252,7 +253,7 @@ pub fn generateLazySymbol(
252 w: *std.Io.Writer,253 w: *std.Io.Writer,
253 debug_output: link.File.DebugInfoOutput,254 debug_output: link.File.DebugInfoOutput,
254 reloc_parent: link.File.RelocInfo.Parent,255 reloc_parent: link.File.RelocInfo.Parent,
255) (Error || std.Io.Writer.Error)!void {256) EmitError!void {
256 const tracy = trace(@src());257 const tracy = trace(@src());
257 defer tracy.end();258 defer tracy.end();
258 tracy.addTextFmt("{t}, {f}", .{ lazy_sym.kind, Type.fromInterned(lazy_sym.ty).fmt(pt) });259 tracy.addTextFmt("{t}, {f}", .{ lazy_sym.kind, Type.fromInterned(lazy_sym.ty).fmt(pt) });
src/codegen/riscv64/CodeGen.zig+1-1
...@@ -856,7 +856,7 @@ pub fn generateLazy(...@@ -856,7 +856,7 @@ pub fn generateLazy(
856 atom_index: link.File.AtomId,856 atom_index: link.File.AtomId,
857 w: *std.Io.Writer,857 w: *std.Io.Writer,
858 debug_output: link.File.DebugInfoOutput,858 debug_output: link.File.DebugInfoOutput,
859) (codegen.Error || std.Io.Writer.Error)!void {859) codegen.EmitError!void {
860 _ = atom_index;860 _ = atom_index;
861 const comp = bin_file.comp;861 const comp = bin_file.comp;
862 const gpa = comp.gpa;862 const gpa = comp.gpa;
src/codegen/riscv64/Emit.zig+9-8
...@@ -13,7 +13,7 @@ prev_di_pc: usize,...@@ -13,7 +13,7 @@ prev_di_pc: usize,
13code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,13code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
14relocs: std.ArrayList(Reloc) = .empty,14relocs: std.ArrayList(Reloc) = .empty,
1515
16pub const Error = Lower.Error || std.Io.Writer.Error || error{16pub const Error = Lower.Error || codegen.EmitError || error{
17 EmitFail,17 EmitFail,
18};18};
1919
...@@ -118,14 +118,14 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -118,14 +118,14 @@ pub fn emitMir(emit: *Emit) Error!void {
118 else => unreachable,118 else => unreachable,
119 .pseudo_dbg_prologue_end => {119 .pseudo_dbg_prologue_end => {
120 switch (emit.debug_output) {120 switch (emit.debug_output) {
121 .dwarf => |dw| {121 inline .dwarf, .dwarf2 => |dw| {
122 try dw.setPrologueEnd();122 try dw.setPrologueEnd();
123 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{123 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
124 emit.prev_di_line, emit.prev_di_column,124 emit.prev_di_line, emit.prev_di_column,
125 });125 });
126 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);126 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
127 },127 },
128 .none => {},128 .eh_frame, .none => {},
129 }129 }
130 },130 },
131 .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine(131 .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine(
...@@ -134,14 +134,14 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -134,14 +134,14 @@ pub fn emitMir(emit: *Emit) Error!void {
134 ),134 ),
135 .pseudo_dbg_epilogue_begin => {135 .pseudo_dbg_epilogue_begin => {
136 switch (emit.debug_output) {136 switch (emit.debug_output) {
137 .dwarf => |dw| {137 inline .dwarf, .dwarf2 => |dw| {
138 try dw.setEpilogueBegin();138 try dw.setEpilogueBegin();
139 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{139 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
140 emit.prev_di_line, emit.prev_di_column,140 emit.prev_di_line, emit.prev_di_column,
141 });141 });
142 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);142 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
143 },143 },
144 .none => {},144 .eh_frame, .none => {},
145 }145 }
146 },146 },
147 .pseudo_dead => {},147 .pseudo_dead => {},
...@@ -190,15 +190,15 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {...@@ -190,15 +190,15 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
190 const delta_pc: usize = emit.w.end - emit.prev_di_pc;190 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
191 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });191 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });
192 switch (emit.debug_output) {192 switch (emit.debug_output) {
193 .dwarf => |dw| {193 inline .dwarf, .dwarf2 => |dw| {
194 if (column != emit.prev_di_column) try dw.setColumn(column);194 if (column != emit.prev_di_column) try dw.setColumn(column);
195 if (delta_line == 0) return; // TODO: fix these edge cases.195 if (delta_line == 0) return; // TODO: fix these edge cases.
196 try dw.advancePCAndLine(delta_line, delta_pc);196 try dw.advancePcAndLine(delta_line, delta_pc);
197 emit.prev_di_line = line;197 emit.prev_di_line = line;
198 emit.prev_di_column = column;198 emit.prev_di_column = column;
199 emit.prev_di_pc = emit.w.end;199 emit.prev_di_pc = emit.w.end;
200 },200 },
201 .none => {},201 .eh_frame, .none => {},
202 }202 }
203}203}
204204
...@@ -209,6 +209,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {...@@ -209,6 +209,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error {
209 };209 };
210}210}
211211
212const codegen = @import("../../codegen.zig");
212const link = @import("../../link.zig");213const link = @import("../../link.zig");
213const log = std.log.scoped(.emit);214const log = std.log.scoped(.emit);
214const mem = std.mem;215const mem = std.mem;
src/codegen/riscv64/Mir.zig+1-1
...@@ -111,7 +111,7 @@ pub fn emit(...@@ -111,7 +111,7 @@ pub fn emit(
111 atom_index: link.File.AtomId,111 atom_index: link.File.AtomId,
112 w: *std.Io.Writer,112 w: *std.Io.Writer,
113 debug_output: link.File.DebugInfoOutput,113 debug_output: link.File.DebugInfoOutput,
114) (codegen.Error || std.Io.Writer.Error)!void {114) codegen.EmitError!void {
115 _ = atom_index;115 _ = atom_index;
116 const zcu = pt.zcu;116 const zcu = pt.zcu;
117 const comp = zcu.comp;117 const comp = zcu.comp;
src/codegen/sparc64/Emit.zig+9-9
...@@ -4,6 +4,7 @@...@@ -4,6 +4,7 @@
4const std = @import("std");4const std = @import("std");
5const Endian = std.lang.Endian;5const Endian = std.lang.Endian;
6const assert = std.debug.assert;6const assert = std.debug.assert;
7const codegen = @import("../../codegen.zig");
7const link = @import("../../link.zig");8const link = @import("../../link.zig");
8const Zcu = @import("../../Zcu.zig");9const Zcu = @import("../../Zcu.zig");
9const ErrorMsg = Zcu.ErrorMsg;10const ErrorMsg = Zcu.ErrorMsg;
...@@ -40,8 +41,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayList(M...@@ -40,8 +41,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayList(M
40/// instruction41/// instruction
41code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,42code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
4243
43const InnerError = std.Io.Writer.Error || error{44const InnerError = codegen.EmitError || error{
44 OutOfMemory,
45 EmitFail,45 EmitFail,
46};46};
4747
...@@ -175,21 +175,21 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -175,21 +175,21 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
175175
176fn mirDebugPrologueEnd(emit: *Emit) !void {176fn mirDebugPrologueEnd(emit: *Emit) !void {
177 switch (emit.debug_output) {177 switch (emit.debug_output) {
178 .dwarf => |dbg_out| {178 inline .dwarf, .dwarf2 => |dbg_out| {
179 try dbg_out.setPrologueEnd();179 try dbg_out.setPrologueEnd();
180 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);180 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
181 },181 },
182 .none => {},182 .eh_frame, .none => {},
183 }183 }
184}184}
185185
186fn mirDebugEpilogueBegin(emit: *Emit) !void {186fn mirDebugEpilogueBegin(emit: *Emit) !void {
187 switch (emit.debug_output) {187 switch (emit.debug_output) {
188 .dwarf => |dbg_out| {188 inline .dwarf, .dwarf2 => |dbg_out| {
189 try dbg_out.setEpilogueBegin();189 try dbg_out.setEpilogueBegin();
190 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);190 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
191 },191 },
192 .none => {},192 .eh_frame, .none => {},
193 }193 }
194}194}
195195
...@@ -496,13 +496,13 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {...@@ -496,13 +496,13 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {
496 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));496 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));
497 const delta_pc: usize = emit.w.end - emit.prev_di_pc;497 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
498 switch (emit.debug_output) {498 switch (emit.debug_output) {
499 .dwarf => |dbg_out| {499 inline .dwarf, .dwarf2 => |dbg_out| {
500 try dbg_out.advancePCAndLine(delta_line, delta_pc);500 try dbg_out.advancePcAndLine(delta_line, delta_pc);
501 emit.prev_di_line = line;501 emit.prev_di_line = line;
502 emit.prev_di_column = column;502 emit.prev_di_column = column;
503 emit.prev_di_pc = emit.w.end;503 emit.prev_di_pc = emit.w.end;
504 },504 },
505 else => {},505 .eh_frame, .none => {},
506 }506 }
507}507}
508508
src/codegen/sparc64/Mir.zig+1-1
...@@ -382,7 +382,7 @@ pub fn emit(...@@ -382,7 +382,7 @@ pub fn emit(
382 atom_index: link.File.AtomId,382 atom_index: link.File.AtomId,
383 w: *std.Io.Writer,383 w: *std.Io.Writer,
384 debug_output: link.File.DebugInfoOutput,384 debug_output: link.File.DebugInfoOutput,
385) (codegen.Error || std.Io.Writer.Error)!void {385) codegen.EmitError!void {
386 _ = atom_index;386 _ = atom_index;
387 const zcu = pt.zcu;387 const zcu = pt.zcu;
388 const func = zcu.funcInfo(func_index);388 const func = zcu.funcInfo(func_index);
src/codegen/x86_64/CodeGen.zig+1-1
...@@ -1120,7 +1120,7 @@ pub fn generateLazy(...@@ -1120,7 +1120,7 @@ pub fn generateLazy(
1120 atom_id: link.File.AtomId,1120 atom_id: link.File.AtomId,
1121 w: *std.Io.Writer,1121 w: *std.Io.Writer,
1122 debug_output: link.File.DebugInfoOutput,1122 debug_output: link.File.DebugInfoOutput,
1123) codegen.Error!void {1123) codegen.EmitError!void {
1124 const gpa = pt.zcu.gpa;1124 const gpa = pt.zcu.gpa;
1125 // This function is for generating global code, so we use the root module.1125 // This function is for generating global code, so we use the root module.
1126 const mod = pt.zcu.comp.root_mod;1126 const mod = pt.zcu.comp.root_mod;
src/codegen/x86_64/Emit.zig+193-192
...@@ -16,10 +16,8 @@ code_offset_mapping: std.ArrayList(u32),...@@ -16,10 +16,8 @@ code_offset_mapping: std.ArrayList(u32),
16relocs: std.ArrayList(Reloc),16relocs: std.ArrayList(Reloc),
17table_relocs: std.ArrayList(TableReloc),17table_relocs: std.ArrayList(TableReloc),
1818
19pub const Error = Lower.Error || error{19pub const Error = Lower.Error || codegen.EmitError || error{
20 AlreadyReported,
21 EmitFail,20 EmitFail,
22 NotFile,
23} || std.posix.MMapError || std.posix.MRemapError || link.File.UpdateDebugInfoError;21} || std.posix.MMapError || std.posix.MRemapError || link.File.UpdateDebugInfoError;
2422
25pub fn emitMir(emit: *Emit) Error!void {23pub fn emitMir(emit: *Emit) Error!void {
...@@ -38,7 +36,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -38,7 +36,7 @@ pub fn emitMir(emit: *Emit) Error!void {
38 if (lowered_inst.prefix == .directive) {36 if (lowered_inst.prefix == .directive) {
39 const start_offset: u32 = @intCast(emit.w.end);37 const start_offset: u32 = @intCast(emit.w.end);
40 switch (emit.debug_output) {38 switch (emit.debug_output) {
41 .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) {39 inline .dwarf, .eh_frame, .dwarf2 => |dwarf| switch (lowered_inst.encoding.mnemonic) {
42 .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{40 .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{
43 .reg = lowered_inst.ops[0].reg.dwarfNum(),41 .reg = lowered_inst.ops[0].reg.dwarfNum(),
44 .off = lowered_inst.ops[1].imm.signed,42 .off = lowered_inst.ops[1].imm.signed,
...@@ -460,204 +458,207 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -460,204 +458,207 @@ pub fn emitMir(emit: *Emit) Error!void {
460458
461 if (lowered.insts.len == 0) {459 if (lowered.insts.len == 0) {
462 const mir_inst = emit.lower.mir.instructions.get(mir_index);460 const mir_inst = emit.lower.mir.instructions.get(mir_index);
463 switch (mir_inst.tag) {461 assert(mir_inst.tag == .pseudo);
462 switch (mir_inst.ops) {
464 else => unreachable,463 else => unreachable,
465 .pseudo => switch (mir_inst.ops) {464 .pseudo_dbg_prologue_end_none => switch (emit.debug_output) {
466 else => unreachable,465 inline .dwarf, .dwarf2 => |dwarf| try dwarf.setPrologueEnd(),
467 .pseudo_dbg_prologue_end_none => switch (emit.debug_output) {466 .eh_frame, .none => {},
468 .dwarf => |dwarf| try dwarf.setPrologueEnd(),467 },
469 .none => {},468 .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePcAndLine(.{
470 },469 .line = mir_inst.data.line_column.line,
471 .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePCAndLine(.{470 .column = mir_inst.data.line_column.column,
472 .line = mir_inst.data.line_column.line,471 .is_stmt = true,
473 .column = mir_inst.data.line_column.column,472 }),
474 .is_stmt = true,473 .pseudo_dbg_line_line_column => try emit.dbgAdvancePcAndLine(.{
475 }),474 .line = mir_inst.data.line_column.line,
476 .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine(.{475 .column = mir_inst.data.line_column.column,
477 .line = mir_inst.data.line_column.line,476 .is_stmt = false,
478 .column = mir_inst.data.line_column.column,477 }),
479 .is_stmt = false,478 .pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) {
480 }),479 inline .dwarf, .dwarf2 => |dwarf| {
481 .pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) {480 try dwarf.setEpilogueBegin();
482 .dwarf => |dwarf| {481 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
483 try dwarf.setEpilogueBegin();482 emit.prev_di_loc.line, emit.prev_di_loc.column,
484 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{483 });
485 emit.prev_di_loc.line, emit.prev_di_loc.column,484 try emit.dbgAdvancePcAndLine(emit.prev_di_loc);
486 });
487 try emit.dbgAdvancePCAndLine(emit.prev_di_loc);
488 },
489 .none => {},
490 },485 },
491 .pseudo_dbg_enter_block_none => switch (emit.debug_output) {486 .eh_frame, .none => {},
492 .dwarf => |dwarf| {487 },
493 log.debug("mirDbgEnterBlock (line={d}, col={d})", .{488 .pseudo_dbg_enter_block_none => switch (emit.debug_output) {
494 emit.prev_di_loc.line, emit.prev_di_loc.column,489 inline .dwarf, .dwarf2 => |dwarf| {
495 });490 log.debug("mirDbgEnterBlock (line={d}, col={d})", .{
496 try dwarf.enterBlock(emit.w.end);491 emit.prev_di_loc.line, emit.prev_di_loc.column,
497 },492 });
498 .none => {},493 try dwarf.enterBlock(emit.w.end);
499 },494 },
500 .pseudo_dbg_leave_block_none => switch (emit.debug_output) {495 .eh_frame, .none => {},
501 .dwarf => |dwarf| {496 },
502 log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{497 .pseudo_dbg_leave_block_none => switch (emit.debug_output) {
503 emit.prev_di_loc.line, emit.prev_di_loc.column,498 inline .dwarf, .dwarf2 => |dwarf| {
504 });499 log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{
505 try dwarf.leaveBlock(emit.w.end);500 emit.prev_di_loc.line, emit.prev_di_loc.column,
506 },501 });
507 .none => {},502 try dwarf.leaveBlock(emit.w.end);
508 },503 },
509 .pseudo_dbg_enter_inline_func => switch (emit.debug_output) {504 .eh_frame, .none => {},
510 .dwarf => |dwarf| {505 },
511 log.debug("mirDbgEnterInline (line={d}, col={d})", .{506 .pseudo_dbg_enter_inline_func => switch (emit.debug_output) {
512 emit.prev_di_loc.line, emit.prev_di_loc.column,507 inline .dwarf, .dwarf2 => |dwarf| {
513 });508 log.debug("mirDbgEnterInline (line={d}, col={d})", .{
514 try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column);509 emit.prev_di_loc.line, emit.prev_di_loc.column,
515 },510 });
516 .none => {},511 try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column);
517 },512 },
518 .pseudo_dbg_leave_inline_func => switch (emit.debug_output) {513 .eh_frame, .none => {},
519 .dwarf => |dwarf| {514 },
520 log.debug("mirDbgLeaveInline (line={d}, col={d})", .{515 .pseudo_dbg_leave_inline_func => switch (emit.debug_output) {
521 emit.prev_di_loc.line, emit.prev_di_loc.column,516 inline .dwarf, .dwarf2 => |dwarf| {
522 });517 log.debug("mirDbgLeaveInline (line={d}, col={d})", .{
523 try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end);518 emit.prev_di_loc.line, emit.prev_di_loc.column,
524 },519 });
525 .none => {},520 try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end);
526 },521 },
527 .pseudo_dbg_arg_none,522 .eh_frame, .none => {},
528 .pseudo_dbg_arg_i_s,523 },
529 .pseudo_dbg_arg_i_u,524 .pseudo_dbg_arg_none,
530 .pseudo_dbg_arg_i_64,525 .pseudo_dbg_arg_i_s,
531 .pseudo_dbg_arg_ro,526 .pseudo_dbg_arg_i_u,
532 .pseudo_dbg_arg_fa,527 .pseudo_dbg_arg_i_64,
533 .pseudo_dbg_arg_m,528 .pseudo_dbg_arg_ro,
534 .pseudo_dbg_var_none,529 .pseudo_dbg_arg_fa,
535 .pseudo_dbg_var_i_s,530 .pseudo_dbg_arg_m,
536 .pseudo_dbg_var_i_u,531 .pseudo_dbg_var_none,
537 .pseudo_dbg_var_i_64,532 .pseudo_dbg_var_i_s,
538 .pseudo_dbg_var_ro,533 .pseudo_dbg_var_i_u,
539 .pseudo_dbg_var_fa,534 .pseudo_dbg_var_i_64,
540 .pseudo_dbg_var_m,535 .pseudo_dbg_var_ro,
541 => switch (emit.debug_output) {536 .pseudo_dbg_var_fa,
542 .dwarf => |dwarf| {537 .pseudo_dbg_var_m,
543 var loc_buf: [2]link.File.Dwarf.Loc = undefined;538 => switch (emit.debug_output) {
544 const loc: link.File.Dwarf.Loc = loc: switch (mir_inst.ops) {539 inline .dwarf, .dwarf2 => |dwarf, tag| {
540 const DwarfLoc = switch (tag) {
541 .dwarf => link.File.Dwarf.Loc,
542 .dwarf2 => link.File.Dwarf2.Loc,
543 .eh_frame, .none => comptime unreachable,
544 };
545 var loc_buf: [2]DwarfLoc = undefined;
546 const loc: DwarfLoc = loc: switch (mir_inst.ops) {
547 else => unreachable,
548 .pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty,
549 .pseudo_dbg_arg_i_s,
550 .pseudo_dbg_arg_i_u,
551 .pseudo_dbg_var_i_s,
552 .pseudo_dbg_var_i_u,
553 => .{ .stack_value = stack_value: {
554 loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.i.i)) {
555 .signed => |s| .{ .consts = s },
556 .unsigned => |u| .{ .constu = u },
557 };
558 break :stack_value &loc_buf[0];
559 } },
560 .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => .{ .stack_value = stack_value: {
561 loc_buf[0] = .{ .constu = mir_inst.data.i64 };
562 break :stack_value &loc_buf[0];
563 } },
564 .pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => {
565 const reg_off = emit.lower.mir.resolveFrameAddr(mir_inst.data.fa);
566 break :loc .{ .plus = .{
567 reg: {
568 loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() };
569 break :reg &loc_buf[0];
570 },
571 off: {
572 loc_buf[1] = .{ .consts = reg_off.off };
573 break :off &loc_buf[1];
574 },
575 } };
576 },
577 .pseudo_dbg_arg_m, .pseudo_dbg_var_m => {
578 const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode();
579 break :loc .{ .plus = .{
580 base: {
581 loc_buf[0] = switch (mem.base()) {
582 .none => .{ .constu = 0 },
583 .reg => |reg| .{ .breg = reg.dwarfNum() },
584 .frame, .table, .rip_inst => unreachable,
585 .nav => |nav| .{ .addr_reloc = try codegen.genNavRef(
586 emit.bin_file,
587 emit.pt,
588 nav,
589 ) },
590 .uav => |uav| .{ .addr_reloc = try emit.bin_file.lowerUav(
591 emit.pt,
592 uav.val,
593 Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu),
594 ) },
595 .lazy_sym, .extern_func => unreachable,
596 };
597 break :base &loc_buf[0];
598 },
599 disp: {
600 loc_buf[1] = switch (mem.disp()) {
601 .signed => |s| .{ .consts = s },
602 .unsigned => |u| .{ .constu = u },
603 };
604 break :disp &loc_buf[1];
605 },
606 } };
607 },
608 };
609
610 const local = &emit.lower.mir.locals[local_index];
611 local_index += 1;
612 try dwarf.genLocalVarDebugInfo(
613 switch (mir_inst.ops) {
545 else => unreachable,614 else => unreachable,
546 .pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty,615 .pseudo_dbg_arg_none,
547 .pseudo_dbg_arg_i_s,616 .pseudo_dbg_arg_i_s,
548 .pseudo_dbg_arg_i_u,617 .pseudo_dbg_arg_i_u,
618 .pseudo_dbg_arg_i_64,
619 .pseudo_dbg_arg_ro,
620 .pseudo_dbg_arg_fa,
621 .pseudo_dbg_arg_m,
622 .pseudo_dbg_arg_val,
623 => .arg,
624 .pseudo_dbg_var_none,
549 .pseudo_dbg_var_i_s,625 .pseudo_dbg_var_i_s,
550 .pseudo_dbg_var_i_u,626 .pseudo_dbg_var_i_u,
551 => .{ .stack_value = stack_value: {627 .pseudo_dbg_var_i_64,
552 loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.i.i)) {628 .pseudo_dbg_var_ro,
553 .signed => |s| .{ .consts = s },629 .pseudo_dbg_var_fa,
554 .unsigned => |u| .{ .constu = u },630 .pseudo_dbg_var_m,
555 };631 .pseudo_dbg_var_val,
556 break :stack_value &loc_buf[0];632 => .local_var,
557 } },633 },
558 .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => .{ .stack_value = stack_value: {634 local.name.toSlice(&emit.lower.mir),
559 loc_buf[0] = .{ .constu = mir_inst.data.i64 };635 .fromInterned(local.type),
560 break :stack_value &loc_buf[0];636 loc,
561 } },637 );
562 .pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => {
563 const reg_off = emit.lower.mir.resolveFrameAddr(mir_inst.data.fa);
564 break :loc .{ .plus = .{
565 reg: {
566 loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() };
567 break :reg &loc_buf[0];
568 },
569 off: {
570 loc_buf[1] = .{ .consts = reg_off.off };
571 break :off &loc_buf[1];
572 },
573 } };
574 },
575 .pseudo_dbg_arg_m, .pseudo_dbg_var_m => {
576 const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode();
577 break :loc .{ .plus = .{
578 base: {
579 loc_buf[0] = switch (mem.base()) {
580 .none => .{ .constu = 0 },
581 .reg => |reg| .{ .breg = reg.dwarfNum() },
582 .frame, .table, .rip_inst => unreachable,
583 .nav => |nav| .{ .addr_reloc = try codegen.genNavRef(
584 emit.bin_file,
585 emit.pt,
586 nav,
587 ) },
588 .uav => |uav| .{ .addr_reloc = try emit.bin_file.lowerUav(
589 emit.pt,
590 uav.val,
591 Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu),
592 ) },
593 .lazy_sym, .extern_func => unreachable,
594 };
595 break :base &loc_buf[0];
596 },
597 disp: {
598 loc_buf[1] = switch (mem.disp()) {
599 .signed => |s| .{ .consts = s },
600 .unsigned => |u| .{ .constu = u },
601 };
602 break :disp &loc_buf[1];
603 },
604 } };
605 },
606 };
607
608 const local = &emit.lower.mir.locals[local_index];
609 local_index += 1;
610 try dwarf.genLocalVarDebugInfo(
611 switch (mir_inst.ops) {
612 else => unreachable,
613 .pseudo_dbg_arg_none,
614 .pseudo_dbg_arg_i_s,
615 .pseudo_dbg_arg_i_u,
616 .pseudo_dbg_arg_i_64,
617 .pseudo_dbg_arg_ro,
618 .pseudo_dbg_arg_fa,
619 .pseudo_dbg_arg_m,
620 .pseudo_dbg_arg_val,
621 => .arg,
622 .pseudo_dbg_var_none,
623 .pseudo_dbg_var_i_s,
624 .pseudo_dbg_var_i_u,
625 .pseudo_dbg_var_i_64,
626 .pseudo_dbg_var_ro,
627 .pseudo_dbg_var_fa,
628 .pseudo_dbg_var_m,
629 .pseudo_dbg_var_val,
630 => .local_var,
631 },
632 local.name.toSlice(&emit.lower.mir),
633 .fromInterned(local.type),
634 loc,
635 );
636 },
637 .none => local_index += 1,
638 },
639 .pseudo_dbg_arg_val, .pseudo_dbg_var_val => switch (emit.debug_output) {
640 .dwarf => |dwarf| {
641 const local = &emit.lower.mir.locals[local_index];
642 local_index += 1;
643 try dwarf.genLocalConstDebugInfo(
644 switch (mir_inst.ops) {
645 else => unreachable,
646 .pseudo_dbg_arg_val => .comptime_arg,
647 .pseudo_dbg_var_val => .local_const,
648 },
649 local.name.toSlice(&emit.lower.mir),
650 .fromInterned(mir_inst.data.ip_index),
651 );
652 },
653 .none => local_index += 1,
654 },638 },
655 .pseudo_dbg_var_args_none => switch (emit.debug_output) {639 .eh_frame, .none => local_index += 1,
656 .dwarf => |dwarf| try dwarf.genVarArgsDebugInfo(),640 },
657 .none => {},641 .pseudo_dbg_arg_val, .pseudo_dbg_var_val => switch (emit.debug_output) {
642 inline .dwarf, .dwarf2 => |dwarf| {
643 const local = &emit.lower.mir.locals[local_index];
644 local_index += 1;
645 try dwarf.genLocalConstDebugInfo(
646 switch (mir_inst.ops) {
647 else => unreachable,
648 .pseudo_dbg_arg_val => .comptime_arg,
649 .pseudo_dbg_var_val => .local_const,
650 },
651 local.name.toSlice(&emit.lower.mir),
652 .fromInterned(mir_inst.data.ip_index),
653 );
658 },654 },
659 .pseudo_dead_none => {},655 .eh_frame, .none => local_index += 1,
656 },
657 .pseudo_dbg_var_args_none => switch (emit.debug_output) {
658 inline .dwarf, .dwarf2 => |dwarf| try dwarf.genVarArgsDebugInfo(),
659 .eh_frame, .none => {},
660 },660 },
661 .pseudo_dead_none => {},
661 }662 }
662 }663 }
663 }664 }
...@@ -974,19 +975,19 @@ const Loc = struct {...@@ -974,19 +975,19 @@ const Loc = struct {
974 is_stmt: bool,975 is_stmt: bool,
975};976};
976977
977fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void {978fn dbgAdvancePcAndLine(emit: *Emit, loc: Loc) Error!void {
978 const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line);979 const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line);
979 const delta_pc: usize = emit.w.end - emit.prev_di_pc;980 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
980 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });981 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });
981 switch (emit.debug_output) {982 switch (emit.debug_output) {
982 .dwarf => |dwarf| {983 inline .dwarf, .dwarf2 => |dwarf| {
983 if (loc.is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt();984 if (loc.is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt();
984 if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column);985 if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column);
985 try dwarf.advancePCAndLine(delta_line, delta_pc);986 try dwarf.advancePcAndLine(delta_line, delta_pc);
986 emit.prev_di_loc = loc;987 emit.prev_di_loc = loc;
987 emit.prev_di_pc = emit.w.end;988 emit.prev_di_pc = emit.w.end;
988 },989 },
989 .none => {},990 .eh_frame, .none => {},
990 }991 }
991}992}
992993
src/codegen/x86_64/Mir.zig+14-11
...@@ -1978,7 +1978,7 @@ pub fn emit(...@@ -1978,7 +1978,7 @@ pub fn emit(
1978 atom_id: link.File.AtomId,1978 atom_id: link.File.AtomId,
1979 w: *std.Io.Writer,1979 w: *std.Io.Writer,
1980 debug_output: link.File.DebugInfoOutput,1980 debug_output: link.File.DebugInfoOutput,
1981) codegen.Error!void {1981) codegen.EmitError!void {
1982 const zcu = pt.zcu;1982 const zcu = pt.zcu;
1983 const comp = zcu.comp;1983 const comp = zcu.comp;
1984 const gpa = comp.gpa;1984 const gpa = comp.gpa;
...@@ -1986,7 +1986,7 @@ pub fn emit(...@@ -1986,7 +1986,7 @@ pub fn emit(
1986 const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?;1986 const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?;
1987 const nav = func.owner_nav;1987 const nav = func.owner_nav;
1988 const mod = zcu.navFileScope(nav).mod.?;1988 const mod = zcu.navFileScope(nav).mod.?;
1989 var e: Emit = .{1989 var em: Emit = .{
1990 .lower = .{1990 .lower = .{
1991 .target = &mod.resolved_target.result,1991 .target = &mod.resolved_target.result,
1992 .allocator = gpa,1992 .allocator = gpa,
...@@ -2006,7 +2006,8 @@ pub fn emit(...@@ -2006,7 +2006,8 @@ pub fn emit(
2006 .column = func.lbrace_column,2006 .column = func.lbrace_column,
2007 .is_stmt = switch (debug_output) {2007 .is_stmt = switch (debug_output) {
2008 .dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt,2008 .dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt,
2009 .none => undefined,2009 .dwarf2 => |dwarf| dwarf.wip_nav.dwarf.debug_line.header.default_is_stmt,
2010 .eh_frame, .none => undefined,
2010 },2011 },
2011 },2012 },
2012 .prev_di_pc = 0,2013 .prev_di_pc = 0,
...@@ -2015,11 +2016,12 @@ pub fn emit(...@@ -2015,11 +2016,12 @@ pub fn emit(
2015 .relocs = .empty,2016 .relocs = .empty,
2016 .table_relocs = .empty,2017 .table_relocs = .empty,
2017 };2018 };
2018 defer e.deinit();2019 defer em.deinit();
2019 e.emitMir() catch |err| switch (err) {2020 em.emitMir() catch |err| switch (err) {
2020 error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, e.lower.err_msg.?),2021 error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, em.lower.err_msg.?),
2021 error.InvalidInstruction, error.CannotEncode => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),2022 error.InvalidInstruction, error.CannotEncode => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
2022 else => return zcu.codegenFail(nav, "emit MIR failed: {s}", .{@errorName(err)}),2023 else => return zcu.codegenFail(nav, "emit MIR failed: {s}", .{@errorName(err)}),
2024 error.AlreadyReported, error.Canceled, error.MappedFileIo, error.WriteFailed => |e| return e,
2023 };2025 };
2024}2026}
20252027
...@@ -2031,12 +2033,12 @@ pub fn emitLazy(...@@ -2031,12 +2033,12 @@ pub fn emitLazy(
2031 atom_id: link.File.AtomId,2033 atom_id: link.File.AtomId,
2032 w: *std.Io.Writer,2034 w: *std.Io.Writer,
2033 debug_output: link.File.DebugInfoOutput,2035 debug_output: link.File.DebugInfoOutput,
2034) codegen.Error!void {2036) codegen.EmitError!void {
2035 const zcu = pt.zcu;2037 const zcu = pt.zcu;
2036 const comp = zcu.comp;2038 const comp = zcu.comp;
2037 const gpa = comp.gpa;2039 const gpa = comp.gpa;
2038 const mod = comp.root_mod;2040 const mod = comp.root_mod;
2039 var e: Emit = .{2041 var em: Emit = .{
2040 .lower = .{2042 .lower = .{
2041 .target = &mod.resolved_target.result,2043 .target = &mod.resolved_target.result,
2042 .allocator = gpa,2044 .allocator = gpa,
...@@ -2058,11 +2060,12 @@ pub fn emitLazy(...@@ -2058,11 +2060,12 @@ pub fn emitLazy(
2058 .relocs = .empty,2060 .relocs = .empty,
2059 .table_relocs = .empty,2061 .table_relocs = .empty,
2060 };2062 };
2061 defer e.deinit();2063 defer em.deinit();
2062 e.emitMir() catch |err| switch (err) {2064 em.emitMir() catch |err| switch (err) {
2063 error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, e.lower.err_msg.?),2065 error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, em.lower.err_msg.?),
2064 error.InvalidInstruction, error.CannotEncode => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),2066 error.InvalidInstruction, error.CannotEncode => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
2065 else => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s}", .{@errorName(err)}),2067 else => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s}", .{@errorName(err)}),
2068 error.AlreadyReported, error.Canceled, error.MappedFileIo, error.WriteFailed => |e| return e,
2066 };2069 };
2067}2070}
20682071
src/link.zig+3
...@@ -757,6 +757,8 @@ pub const File = struct {...@@ -757,6 +757,8 @@ pub const File = struct {
757757
758 pub const DebugInfoOutput = union(enum) {758 pub const DebugInfoOutput = union(enum) {
759 dwarf: *Dwarf.WipNav,759 dwarf: *Dwarf.WipNav,
760 eh_frame: *Dwarf2.WipNav,
761 dwarf2: *Dwarf2.WipNav.Debug,
760 none,762 none,
761 };763 };
762 pub const UpdateDebugInfoError = Dwarf.UpdateError;764 pub const UpdateDebugInfoError = Dwarf.UpdateError;
...@@ -1391,6 +1393,7 @@ pub const File = struct {...@@ -1391,6 +1393,7 @@ pub const File = struct {
1391 pub const SpirV = @import("link/SpirV.zig");1393 pub const SpirV = @import("link/SpirV.zig");
1392 pub const Wasm = @import("link/Wasm.zig");1394 pub const Wasm = @import("link/Wasm.zig");
1393 pub const Dwarf = @import("link/Dwarf.zig");1395 pub const Dwarf = @import("link/Dwarf.zig");
1396 pub const Dwarf2 = @import("link/Dwarf2.zig");
1394};1397};
13951398
1396pub const PrelinkTask = union(enum) {1399pub const PrelinkTask = union(enum) {
src/link/Dwarf.zig+14-15
...@@ -1626,12 +1626,12 @@ pub const WipNav = struct {...@@ -1626,12 +1626,12 @@ pub const WipNav = struct {
1626 wip_nav.any_children = true;1626 wip_nav.any_children = true;
1627 }1627 }
16281628
1629 pub fn advancePCAndLine(wip_nav: *WipNav, delta_line: i33, delta_pc: u64) Allocator.Error!void {1629 pub fn advancePcAndLine(wip_nav: *WipNav, delta_line: i33, delta_pc: u64) Allocator.Error!void {
1630 return wip_nav.advancePCAndLineWriterError(delta_line, delta_pc) catch |err| switch (err) {1630 return wip_nav.advancePcAndLineWriterError(delta_line, delta_pc) catch |err| switch (err) {
1631 error.WriteFailed => error.OutOfMemory,1631 error.WriteFailed => error.OutOfMemory,
1632 };1632 };
1633 }1633 }
1634 fn advancePCAndLineWriterError(1634 fn advancePcAndLineWriterError(
1635 wip_nav: *WipNav,1635 wip_nav: *WipNav,
1636 delta_line: i33,1636 delta_line: i33,
1637 delta_pc: u64,1637 delta_pc: u64,
...@@ -1990,7 +1990,7 @@ pub const WipNav = struct {...@@ -1990,7 +1990,7 @@ pub const WipNav = struct {
1990 try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);1990 try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
1991 }1991 }
1992 } = .{ .wip_nav = wip_nav };1992 } = .{ .wip_nav = wip_nav };
1993 try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);1993 try adapter.writer().writeUleb128(counter.dw.fullCount());
1994 try loc.write(adapter);1994 try loc.write(adapter);
1995 }1995 }
19961996
...@@ -2032,7 +2032,7 @@ pub const WipNav = struct {...@@ -2032,7 +2032,7 @@ pub const WipNav = struct {
2032 try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0);2032 try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0);
2033 }2033 }
2034 } = .{ .wip_nav = wip_nav };2034 } = .{ .wip_nav = wip_nav };
2035 try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end);2035 try adapter.writer().writeUleb128(counter.dw.fullCount());
2036 try loc.write(adapter);2036 try loc.write(adapter);
2037 }2037 }
20382038
...@@ -2105,20 +2105,20 @@ pub const WipNav = struct {...@@ -2105,20 +2105,20 @@ pub const WipNav = struct {
2105 const size = ty.abiSize(wip_nav.pt.zcu);2105 const size = ty.abiSize(wip_nav.pt.zcu);
2106 try diw.writeUleb128(size);2106 try diw.writeUleb128(size);
2107 if (size == 0) return;2107 if (size == 0) return;
2108 const old_end = wip_nav.debug_info.writer.end;2108 const old_end = diw.end;
2109 try codegen.generateSymbol(2109 try codegen.generateSymbol(
2110 wip_nav.dwarf.bin_file,2110 wip_nav.dwarf.bin_file,
2111 wip_nav.pt,2111 wip_nav.pt,
2112 val,2112 val,
2113 &wip_nav.debug_info.writer,2113 diw,
2114 .{ .debug_output = .{ .dwarf = wip_nav } },2114 .{ .debug_output = .{ .dwarf = wip_nav } },
2115 );2115 );
2116 if (old_end + size != wip_nav.debug_info.writer.end) {2116 if (old_end + size != diw.end) {
2117 std.debug.print("{f} [{}]: {} != {}\n", .{2117 std.debug.print("{f} [{}]: {} != {}\n", .{
2118 ty.fmt(wip_nav.pt),2118 ty.fmt(wip_nav.pt),
2119 ty.toIntern(),2119 ty.toIntern(),
2120 size,2120 size,
2121 wip_nav.debug_info.writer.end - old_end,2121 diw.end - old_end,
2122 });2122 });
2123 unreachable;2123 unreachable;
2124 }2124 }
...@@ -2278,10 +2278,9 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {...@@ -2278,10 +2278,9 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
22782278
2279pub fn init(lf: *link.File, format: DW.Format) Dwarf {2279pub fn init(lf: *link.File, format: DW.Format) Dwarf {
2280 const comp = lf.comp;2280 const comp = lf.comp;
2281 const gpa = comp.gpa;
2282 const target = &comp.root_mod.resolved_target.result;2281 const target = &comp.root_mod.resolved_target.result;
2283 return .{2282 return .{
2284 .gpa = gpa,2283 .gpa = comp.gpa,
2285 .bin_file = lf,2284 .bin_file = lf,
2286 .format = format,2285 .format = format,
2287 .address_size = switch (target.ptrBitWidth()) {2286 .address_size = switch (target.ptrBitWidth()) {
...@@ -2774,7 +2773,7 @@ fn initWipNavInner(...@@ -2774,7 +2773,7 @@ fn initWipNavInner(
2774 try dlw.writeByte(DW.LNS.set_column);2773 try dlw.writeByte(DW.LNS.set_column);
2775 try dlw.writeUleb128(func.lbrace_column + 1);2774 try dlw.writeUleb128(func.lbrace_column + 1);
27762775
2777 try wip_nav.advancePCAndLine(func.lbrace_line, 0);2776 try wip_nav.advancePcAndLine(func.lbrace_line, 0);
2778 } else {2777 } else {
2779 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));2778 try dlw.writeUleb128(1 + @backingInt(dwarf.address_size));
2780 try dlw.writeByte(DW.LNE.set_address);2779 try dlw.writeByte(DW.LNE.set_address);
...@@ -2791,7 +2790,7 @@ fn initWipNavInner(...@@ -2791,7 +2790,7 @@ fn initWipNavInner(
2791 try dlw.writeByte(DW.LNS.set_column);2790 try dlw.writeByte(DW.LNS.set_column);
2792 try dlw.writeUleb128(func.lbrace_column + 1);2791 try dlw.writeUleb128(func.lbrace_column + 1);
27932792
2794 try wip_nav.advancePCAndLine(@intCast(decl.src_line + func.lbrace_line), 0);2793 try wip_nav.advancePcAndLine(@intCast(decl.src_line + func.lbrace_line), 0);
2795 }2794 }
2796 },2795 },
2797 else => {2796 else => {
...@@ -6362,14 +6361,14 @@ fn uleb128Bytes(value: anytype) u32 {...@@ -6362,14 +6361,14 @@ fn uleb128Bytes(value: anytype) u32 {
6362 var buf: [64]u8 = undefined;6361 var buf: [64]u8 = undefined;
6363 var dw: Writer.Discarding = .init(&buf);6362 var dw: Writer.Discarding = .init(&buf);
6364 dw.writer.writeUleb128(value) catch unreachable;6363 dw.writer.writeUleb128(value) catch unreachable;
6365 return @intCast(dw.count + dw.writer.end);6364 return @intCast(dw.fullCount());
6366}6365}
63676366
6368fn sleb128Bytes(value: anytype) u32 {6367fn sleb128Bytes(value: anytype) u32 {
6369 var buf: [64]u8 = undefined;6368 var buf: [64]u8 = undefined;
6370 var dw: Writer.Discarding = .init(&buf);6369 var dw: Writer.Discarding = .init(&buf);
6371 dw.writer.writeSleb128(value) catch unreachable;6370 dw.writer.writeSleb128(value) catch unreachable;
6372 return @intCast(dw.count + dw.writer.end);6371 return @intCast(dw.fullCount());
6373}6372}
63746373
6375/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional6374/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
src/link/Dwarf2.zig created+2685
...@@ -0,0 +1,2685 @@
1tag: link.File.Tag,
2format: DW.Format,
3endian: std.lang.Endian,
4address_size: AddressSize,
5const_pool: link.ConstPool,
6
7units: std.array_hash_map.Auto(*Module, Unit),
8/// Indices are `link.ConstPool.Index`.
9values: std.ArrayList(struct {
10 debug_info_ni: MappedFile.Node.Index,
11}),
12globals: std.array_hash_map.Auto(InternPool.Nav.Index, Global),
13funcs: std.array_hash_map.Auto(InternPool.Nav.Index, Func),
14
15frame: Frame,
16debug_info: DebugInfo,
17debug_line: DebugLine,
18
19pub const UpdateError = link.Error || error{MappedFileIo};
20
21pub const AddressSize = enum(u8) { @"32" = 4, @"64" = 8, _ };
22
23pub const Unit = struct {
24 frame_ni: MappedFile.Node.Index.Optional,
25 cie_ni: MappedFile.Node.Index.Optional,
26
27 pub const Index = enum(u32) {
28 _,
29
30 pub fn mod(ui: Unit.Index, dwarf: *Dwarf) *Module {
31 return dwarf.units.keys()[@backingInt(ui)];
32 }
33
34 pub fn get(ui: Unit.Index, dwarf: *Dwarf) *Unit {
35 return &dwarf.units.values()[@backingInt(ui)];
36 }
37 };
38};
39
40pub const Global = struct {
41 debug_info_ni: MappedFile.Node.Index.Optional,
42
43 pub const Index = enum(u32) {
44 _,
45
46 pub fn nav(gi: Global.Index, dwarf: *Dwarf) InternPool.Nav.Index {
47 return dwarf.globals.keys()[@backingInt(gi)];
48 }
49
50 pub fn get(gi: Global.Index, dwarf: *Dwarf) *Global {
51 return &dwarf.globals.values()[@backingInt(gi)];
52 }
53 };
54};
55
56pub const Func = struct {
57 fde_ni: MappedFile.Node.Index.Optional,
58 debug_info_ni: MappedFile.Node.Index.Optional,
59 debug_line_ni: MappedFile.Node.Index.Optional,
60
61 pub const Index = enum(u32) {
62 _,
63
64 pub fn nav(fi: Func.Index, dwarf: *Dwarf) InternPool.Nav.Index {
65 return dwarf.funcs.keys()[@backingInt(fi)];
66 }
67
68 pub fn get(fi: Func.Index, dwarf: *Dwarf) *Func {
69 return &dwarf.funcs.values()[@backingInt(fi)];
70 }
71 };
72};
73
74pub const Frame = struct {
75 header: Header,
76 section_index: SectionIndex,
77
78 pub const Header = struct {
79 code_alignment_factor: u32,
80 data_alignment_factor: i32,
81 return_address_register: u32,
82 initial_instructions: []const Cfa,
83 };
84
85 pub const Format = std.debug.Dwarf.Unwind.Section;
86};
87
88pub const DebugInfo = struct {
89 section_index: SectionIndex,
90};
91
92pub const DebugLine = struct {
93 header: Header,
94 section_index: SectionIndex,
95
96 pub const Header = struct {
97 minimum_instruction_length: u8,
98 maximum_operations_per_instruction: u8,
99 default_is_stmt: bool,
100 line_base: i8,
101 line_range: u8,
102 opcode_base: u8,
103 };
104};
105
106pub const SectionIndex = enum(u32) { none = std.math.maxInt(u32), _ };
107
108pub const Loc = union(enum) {
109 empty,
110 addr_reloc: link.File.SymbolId,
111 deref: *const Loc,
112 constu: u64,
113 consts: i64,
114 plus: Bin,
115 reg: u32,
116 breg: u32,
117 push_object_address,
118 call: struct {
119 args: []const Loc = &.{},
120 node: MappedFile.Node.Index,
121 },
122 form_tls_address: *const Loc,
123 implicit_value: []const u8,
124 stack_value: *const Loc,
125 implicit_pointer: struct {
126 node: MappedFile.Node.Index,
127 offset: i65,
128 },
129 wasm_ext: union(enum) {
130 local: u32,
131 global: u32,
132 operand_stack: u32,
133 },
134
135 pub const Bin = struct { *const Loc, *const Loc };
136
137 fn getConst(loc: Loc, comptime Int: type) ?Int {
138 return switch (loc) {
139 .constu => |constu| std.math.cast(Int, constu),
140 .consts => |consts| std.math.cast(Int, consts),
141 else => null,
142 };
143 }
144
145 fn getBaseReg(loc: Loc) ?u32 {
146 return switch (loc) {
147 .breg => |breg| breg,
148 else => null,
149 };
150 }
151
152 fn writeReg(reg: u32, op0: u8, opx: u8, writer: *Writer) Writer.Error!void {
153 if (std.math.cast(u5, reg)) |small_reg| {
154 try writer.writeByte(op0 + small_reg);
155 } else {
156 try writer.writeByte(opx);
157 try writer.writeUleb128(reg);
158 }
159 }
160
161 fn write(loc: Loc, adapter: anytype) (UpdateError || Writer.Error)!void {
162 const writer = adapter.writer();
163 switch (loc) {
164 .empty => {},
165 .addr_reloc => |si| {
166 try writer.writeByte(DW.OP.addr);
167 try adapter.addrSym(si);
168 },
169 .deref => |addr| {
170 try addr.write(adapter);
171 try writer.writeByte(DW.OP.deref);
172 },
173 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
174 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
175 } else if (std.math.cast(u8, constu)) |const1u| {
176 try writer.writeAll(&.{ DW.OP.const1u, const1u });
177 } else if (std.math.cast(u16, constu)) |const2u| {
178 try writer.writeByte(DW.OP.const2u);
179 try writer.writeInt(u16, const2u, adapter.endian());
180 } else if (std.math.cast(u21, constu)) |const3u| {
181 try writer.writeByte(DW.OP.constu);
182 try writer.writeUleb128(const3u);
183 } else if (std.math.cast(u32, constu)) |const4u| {
184 try writer.writeByte(DW.OP.const4u);
185 try writer.writeInt(u32, const4u, adapter.endian());
186 } else if (std.math.cast(u49, constu)) |const7u| {
187 try writer.writeByte(DW.OP.constu);
188 try writer.writeUleb128(const7u);
189 } else {
190 try writer.writeByte(DW.OP.const8u);
191 try writer.writeInt(u64, constu, adapter.endian());
192 },
193 .consts => |consts| if (std.math.cast(i8, consts)) |const1s| {
194 try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) });
195 } else if (std.math.cast(i16, consts)) |const2s| {
196 try writer.writeByte(DW.OP.const2s);
197 try writer.writeInt(i16, const2s, adapter.endian());
198 } else if (std.math.cast(i21, consts)) |const3s| {
199 try writer.writeByte(DW.OP.consts);
200 try writer.writeSleb128(const3s);
201 } else if (std.math.cast(i32, consts)) |const4s| {
202 try writer.writeByte(DW.OP.const4s);
203 try writer.writeInt(i32, const4s, adapter.endian());
204 } else if (std.math.cast(i49, consts)) |const7s| {
205 try writer.writeByte(DW.OP.consts);
206 try writer.writeSleb128(const7s);
207 } else {
208 try writer.writeByte(DW.OP.const8s);
209 try writer.writeInt(i64, consts, adapter.endian());
210 },
211 .plus => |plus| done: {
212 if (plus[0].getConst(u0)) |_| {
213 try plus[1].write(adapter);
214 break :done;
215 }
216 if (plus[1].getConst(u0)) |_| {
217 try plus[0].write(adapter);
218 break :done;
219 }
220 if (plus[0].getBaseReg()) |breg| {
221 if (plus[1].getConst(i65)) |offset| {
222 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
223 try writer.writeSleb128(offset);
224 break :done;
225 }
226 }
227 if (plus[1].getBaseReg()) |breg| {
228 if (plus[0].getConst(i65)) |offset| {
229 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
230 try writer.writeSleb128(offset);
231 break :done;
232 }
233 }
234 if (plus[0].getConst(u64)) |uconst| {
235 try plus[1].write(adapter);
236 try writer.writeByte(DW.OP.plus_uconst);
237 try writer.writeUleb128(uconst);
238 break :done;
239 }
240 if (plus[1].getConst(u64)) |uconst| {
241 try plus[0].write(adapter);
242 try writer.writeByte(DW.OP.plus_uconst);
243 try writer.writeUleb128(uconst);
244 break :done;
245 }
246 try plus[0].write(adapter);
247 try plus[1].write(adapter);
248 try writer.writeByte(DW.OP.plus);
249 },
250 .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer),
251 .breg => |breg| {
252 try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer);
253 try writer.writeSleb128(0);
254 },
255 .push_object_address => try writer.writeByte(DW.OP.push_object_address),
256 .call => |call| {
257 for (call.args) |arg| try arg.write(adapter);
258 try writer.writeByte(DW.OP.call_ref);
259 try adapter.infoEntry(call.node);
260 },
261 .form_tls_address => |addr| {
262 try addr.write(adapter);
263 try writer.writeByte(DW.OP.form_tls_address);
264 },
265 .implicit_value => |value| {
266 try writer.writeByte(DW.OP.implicit_value);
267 try writer.writeUleb128(value.len);
268 try writer.writeAll(value);
269 },
270 .stack_value => |value| {
271 try value.write(adapter);
272 try writer.writeByte(DW.OP.stack_value);
273 },
274 .implicit_pointer => |implicit_pointer| {
275 try writer.writeByte(DW.OP.implicit_pointer);
276 try adapter.infoEntry(implicit_pointer.node);
277 try writer.writeSleb128(implicit_pointer.offset);
278 },
279 .wasm_ext => |wasm_ext| {
280 try writer.writeByte(DW.OP.WASM_location);
281 switch (wasm_ext) {
282 .local => |local| {
283 try writer.writeByte(DW.OP.WASM_local);
284 try writer.writeUleb128(local);
285 },
286 .global => |global| if (std.math.cast(u21, global)) |global_u21| {
287 try writer.writeByte(DW.OP.WASM_global);
288 try writer.writeUleb128(global_u21);
289 } else {
290 try writer.writeByte(DW.OP.WASM_global_u32);
291 try writer.writeInt(u32, global, adapter.endian());
292 },
293 .operand_stack => |operand_stack| {
294 try writer.writeByte(DW.OP.WASM_operand_stack);
295 try writer.writeUleb128(operand_stack);
296 },
297 }
298 },
299 }
300 }
301};
302
303pub const Cfa = union(enum) {
304 nop,
305 advance_loc: u32,
306 offset: RegOff,
307 rel_offset: RegOff,
308 restore: u32,
309 undefined: u32,
310 same_value: u32,
311 register: [2]u32,
312 remember_state,
313 restore_state,
314 def_cfa: RegOff,
315 def_cfa_register: u32,
316 def_cfa_offset: i64,
317 adjust_cfa_offset: i64,
318 def_cfa_expression: Loc,
319 expression: RegExpr,
320 val_offset: RegOff,
321 val_expression: RegExpr,
322 escape: []const u8,
323
324 const RegOff = struct { reg: u32, off: i64 };
325 const RegExpr = struct { reg: u32, expr: Loc };
326
327 fn write(cfa: Cfa, wip_nav: *WipNav) (UpdateError || Writer.Error)!void {
328 const dfw = &wip_nav.fde_writer.interface;
329 switch (cfa) {
330 .nop => try dfw.writeByte(DW.CFA.nop),
331 .advance_loc => |loc| {
332 const delta =
333 @divExact(loc - wip_nav.cfi.loc, wip_nav.dwarf.frame.header.code_alignment_factor);
334 if (delta == 0) {} else if (std.math.cast(u6, delta)) |small_delta|
335 try dfw.writeByte(@as(u8, DW.CFA.advance_loc) + small_delta)
336 else if (std.math.cast(u8, delta)) |ubyte_delta|
337 try dfw.writeAll(&.{ DW.CFA.advance_loc1, ubyte_delta })
338 else if (std.math.cast(u16, delta)) |uhalf_delta| {
339 try dfw.writeByte(DW.CFA.advance_loc2);
340 try dfw.writeInt(u16, uhalf_delta, wip_nav.dwarf.endian);
341 } else if (std.math.cast(u32, delta)) |uword_delta| {
342 try dfw.writeByte(DW.CFA.advance_loc4);
343 try dfw.writeInt(u32, uword_delta, wip_nav.dwarf.endian);
344 }
345 wip_nav.cfi.loc = loc;
346 },
347 .offset, .rel_offset => |reg_off| {
348 const factored_off = @divExact(reg_off.off - switch (cfa) {
349 else => unreachable,
350 .offset => 0,
351 .rel_offset => wip_nav.cfi.cfa.off,
352 }, wip_nav.dwarf.frame.header.data_alignment_factor);
353 if (std.math.cast(u63, factored_off)) |unsigned_off| {
354 if (std.math.cast(u6, reg_off.reg)) |small_reg| {
355 try dfw.writeByte(@as(u8, DW.CFA.offset) + small_reg);
356 } else {
357 try dfw.writeByte(DW.CFA.offset_extended);
358 try dfw.writeUleb128(reg_off.reg);
359 }
360 try dfw.writeUleb128(unsigned_off);
361 } else {
362 try dfw.writeByte(DW.CFA.offset_extended_sf);
363 try dfw.writeUleb128(reg_off.reg);
364 try dfw.writeSleb128(factored_off);
365 }
366 },
367 .restore => |reg| if (std.math.cast(u6, reg)) |small_reg|
368 try dfw.writeByte(@as(u8, DW.CFA.restore) + small_reg)
369 else {
370 try dfw.writeByte(DW.CFA.restore_extended);
371 try dfw.writeUleb128(reg);
372 },
373 .undefined => |reg| {
374 try dfw.writeByte(DW.CFA.undefined);
375 try dfw.writeUleb128(reg);
376 },
377 .same_value => |reg| {
378 try dfw.writeByte(DW.CFA.same_value);
379 try dfw.writeUleb128(reg);
380 },
381 .register => |regs| if (regs[0] != regs[1]) {
382 try dfw.writeByte(DW.CFA.register);
383 for (regs) |reg| try dfw.writeUleb128(reg);
384 } else {
385 try dfw.writeByte(DW.CFA.same_value);
386 try dfw.writeUleb128(regs[0]);
387 },
388 .remember_state => try dfw.writeByte(DW.CFA.remember_state),
389 .restore_state => try dfw.writeByte(DW.CFA.restore_state),
390 .def_cfa, .def_cfa_register, .def_cfa_offset, .adjust_cfa_offset => {
391 const reg_off: RegOff = switch (cfa) {
392 else => unreachable,
393 .def_cfa => |reg_off| reg_off,
394 .def_cfa_register => |reg| .{ .reg = reg, .off = wip_nav.cfi.cfa.off },
395 .def_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = off },
396 .adjust_cfa_offset => |off| .{
397 .reg = wip_nav.cfi.cfa.reg,
398 .off = wip_nav.cfi.cfa.off + off,
399 },
400 };
401 const changed_reg = reg_off.reg != wip_nav.cfi.cfa.reg;
402 const unsigned_off = std.math.cast(u63, reg_off.off);
403 if (reg_off.off == wip_nav.cfi.cfa.off) {
404 if (changed_reg) {
405 try dfw.writeByte(DW.CFA.def_cfa_register);
406 try dfw.writeUleb128(reg_off.reg);
407 }
408 } else if (switch (wip_nav.dwarf.frame.header.data_alignment_factor) {
409 0 => unreachable,
410 1 => unsigned_off != null,
411 else => |data_alignment_factor| @rem(reg_off.off, data_alignment_factor) != 0,
412 }) {
413 try dfw.writeByte(if (changed_reg) DW.CFA.def_cfa else DW.CFA.def_cfa_offset);
414 if (changed_reg) try dfw.writeUleb128(reg_off.reg);
415 try dfw.writeUleb128(unsigned_off.?);
416 } else {
417 try dfw.writeByte(if (changed_reg) DW.CFA.def_cfa_sf else DW.CFA.def_cfa_offset_sf);
418 if (changed_reg) try dfw.writeUleb128(reg_off.reg);
419 try dfw.writeSleb128(
420 @divExact(reg_off.off, wip_nav.dwarf.frame.header.data_alignment_factor),
421 );
422 }
423 wip_nav.cfi.cfa = reg_off;
424 },
425 .def_cfa_expression => |expr| {
426 try dfw.writeByte(DW.CFA.def_cfa_expression);
427 try wip_nav.frameExprLoc(expr);
428 },
429 .expression => |reg_expr| {
430 try dfw.writeByte(DW.CFA.expression);
431 try dfw.writeUleb128(reg_expr.reg);
432 try wip_nav.frameExprLoc(reg_expr.expr);
433 },
434 .val_offset => |reg_off| {
435 const factored_off =
436 @divExact(reg_off.off, wip_nav.dwarf.frame.header.data_alignment_factor);
437 if (std.math.cast(u63, factored_off)) |unsigned_off| {
438 try dfw.writeByte(DW.CFA.val_offset);
439 try dfw.writeUleb128(reg_off.reg);
440 try dfw.writeUleb128(unsigned_off);
441 } else {
442 try dfw.writeByte(DW.CFA.val_offset_sf);
443 try dfw.writeUleb128(reg_off.reg);
444 try dfw.writeSleb128(factored_off);
445 }
446 },
447 .val_expression => |reg_expr| {
448 try dfw.writeByte(DW.CFA.val_expression);
449 try dfw.writeUleb128(reg_expr.reg);
450 try wip_nav.frameExprLoc(reg_expr.expr);
451 },
452 .escape => |bytes| try dfw.writeAll(bytes),
453 }
454 }
455};
456
457pub const WipNav = struct {
458 dwarf: *Dwarf,
459 unit: Unit.Index,
460 func: ?Func.Index,
461 func_si: link.File.SymbolId,
462 cfi: struct {
463 loc: u32,
464 cfa: Cfa.RegOff,
465 },
466 frame_format: Frame.Format,
467 fde_writer: MappedFile.Node.Writer,
468 frame_func_length_offset: usize,
469
470 pub const Debug = struct {
471 wip_nav: WipNav,
472 pt: Zcu.PerThread,
473 any_children: bool,
474 blocks: std.ArrayList(struct {
475 abbrev_code: u32,
476 low_pc_off: u64,
477 high_pc: u32,
478 }),
479 info_writer: MappedFile.Node.Writer,
480 line_writer: MappedFile.Node.Writer,
481
482 pub fn deinit(debug: *Debug, gpa: Allocator) void {
483 debug.line_writer.deinit();
484 debug.info_writer.deinit();
485 debug.blocks.deinit(gpa);
486 debug.wip_nav.deinit(gpa);
487 debug.* = undefined;
488 }
489
490 pub fn genFuncHeaders(debug: *Debug) UpdateError!void {
491 try debug.wip_nav.genFuncHeaders();
492 }
493
494 pub fn genDebugFrame(debug: *Debug, loc: u32, cfa: Cfa) UpdateError!void {
495 return debug.wip_nav.genDebugFrame(loc, cfa);
496 }
497
498 pub const LocalVarTag = enum { arg, local_var };
499 pub fn genLocalVarDebugInfo(
500 debug: *Debug,
501 tag: LocalVarTag,
502 opt_name: ?[]const u8,
503 ty: Type,
504 loc: Loc,
505 ) UpdateError!void {
506 if (true) return;
507 return debug.genLocalVarDebugInfoInner(tag, opt_name, ty, loc) catch |err| switch (err) {
508 error.WriteFailed => debug.info_writer.err.?,
509 else => |e| e,
510 };
511 }
512 fn genLocalVarDebugInfoInner(
513 debug: *Debug,
514 tag: LocalVarTag,
515 opt_name: ?[]const u8,
516 ty: Type,
517 loc: Loc,
518 ) (UpdateError || Writer.Error)!void {
519 assert(debug.wip_nav.func != null);
520 try debug.abbrevCode(switch (tag) {
521 .arg => if (opt_name) |_| .arg else .unnamed_arg,
522 .local_var => if (opt_name) |_| .local_var else unreachable,
523 });
524 if (opt_name) |name| try debug.strp(name);
525 try debug.refType(ty);
526 try debug.infoExprLoc(loc);
527 debug.any_children = true;
528 }
529
530 pub const LocalConstTag = enum { comptime_arg, local_const };
531 pub fn genLocalConstDebugInfo(
532 debug: *Debug,
533 tag: LocalConstTag,
534 opt_name: ?[]const u8,
535 val: Value,
536 ) UpdateError!void {
537 if (true) return;
538 return debug.genLocalConstDebugInfoInner(tag, opt_name, val) catch |err| switch (err) {
539 error.WriteFailed => debug.info_writer.err.?,
540 else => |e| e,
541 };
542 }
543 fn genLocalConstDebugInfoInner(
544 debug: *Debug,
545 tag: LocalConstTag,
546 opt_name: ?[]const u8,
547 val: Value,
548 ) (UpdateError || Writer.Error)!void {
549 assert(debug.wip_nav.func != null);
550 const zcu = debug.pt.zcu;
551 const ty = val.typeOf(zcu);
552 const has_runtime_bits = ty.hasRuntimeBits(zcu);
553 const has_comptime_state = ty.comptimeOnly(zcu);
554 try debug.abbrevCode(if (has_runtime_bits and has_comptime_state) switch (tag) {
555 .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits_comptime_state else .unnamed_comptime_arg_runtime_bits_comptime_state,
556 .local_const => if (opt_name) |_| .local_const_runtime_bits_comptime_state else unreachable,
557 } else if (has_comptime_state) switch (tag) {
558 .comptime_arg => if (opt_name) |_| .comptime_arg_comptime_state else .unnamed_comptime_arg_comptime_state,
559 .local_const => if (opt_name) |_| .local_const_comptime_state else unreachable,
560 } else if (has_runtime_bits) switch (tag) {
561 .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits else .unnamed_comptime_arg_runtime_bits,
562 .local_const => if (opt_name) |_| .local_const_runtime_bits else unreachable,
563 } else switch (tag) {
564 .comptime_arg => if (opt_name) |_| .comptime_arg else .unnamed_comptime_arg,
565 .local_const => if (opt_name) |_| .local_const else unreachable,
566 });
567 if (opt_name) |name| try debug.strp(name);
568 try debug.refType(ty);
569 if (has_runtime_bits) try debug.blockValue(val);
570 if (has_comptime_state) try debug.refValue(val);
571 debug.any_children = true;
572 }
573
574 pub fn genVarArgsDebugInfo(debug: *Debug) UpdateError!void {
575 if (true) return;
576 return debug.genVarArgsDebugInfoInner() catch |err| switch (err) {
577 error.WriteFailed => debug.info_writer.err.?,
578 else => |e| e,
579 };
580 }
581 fn genVarArgsDebugInfoInner(debug: *Debug) (UpdateError || Writer.Error)!void {
582 assert(debug.wip_nav.func != null);
583 try debug.abbrevCode(.is_var_args);
584 debug.any_children = true;
585 }
586
587 pub fn advancePcAndLine(debug: *Debug, delta_line: i33, delta_pc: u64) UpdateError!void {
588 if (true) return;
589 return debug.advancePcAndLineInner(delta_line, delta_pc) catch |err| switch (err) {
590 error.WriteFailed => debug.line_writer.err.?,
591 };
592 }
593 fn advancePcAndLineInner(debug: *Debug, delta_line: i33, delta_pc: u64) Writer.Error!void {
594 const dlw = &debug.line_writer.interface;
595
596 const header = debug.wip_nav.dwarf.debug_line.header;
597 assert(header.maximum_operations_per_instruction == 1);
598 const delta_op: u64 = 0;
599
600 const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or
601 delta_line - header.line_base >= header.line_range)
602 remaining: {
603 assert(delta_line != 0);
604 try dlw.writeByte(DW.LNS.advance_line);
605 try dlw.writeSleb128(delta_line);
606 break :remaining 0;
607 } else delta_line);
608
609 const op_advance = @divExact(delta_pc, header.minimum_instruction_length) *
610 header.maximum_operations_per_instruction + delta_op;
611 const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range;
612 const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: {
613 try dlw.writeByte(DW.LNS.advance_pc);
614 try dlw.writeUleb128(op_advance);
615 break :remaining 0;
616 } else if (op_advance >= max_op_advance) remaining: {
617 try dlw.writeByte(DW.LNS.const_add_pc);
618 break :remaining op_advance - max_op_advance;
619 } else op_advance);
620
621 if (remaining_delta_line == 0 and remaining_op_advance == 0)
622 try dlw.writeByte(DW.LNS.copy)
623 else
624 try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) +
625 (header.line_range * remaining_op_advance) + header.opcode_base));
626 }
627
628 pub fn setColumn(debug: *Debug, column: u32) UpdateError!void {
629 if (true) return;
630 return debug.setColumnInner(column) catch |err| switch (err) {
631 error.WriteFailed => debug.line_writer.err.?,
632 };
633 }
634 fn setColumnInner(debug: *Debug, column: u32) Writer.Error!void {
635 const dlw = &debug.line_writer.interface;
636 try dlw.writeByte(DW.LNS.set_column);
637 try dlw.writeUleb128(column + 1);
638 }
639
640 pub fn negateStmt(debug: *Debug) UpdateError!void {
641 if (true) return;
642 return debug.negateStmtInner() catch |err| switch (err) {
643 error.WriteFailed => debug.line_writer.err.?,
644 };
645 }
646 fn negateStmtInner(debug: *Debug) Writer.Error!void {
647 try debug.line_writer.interface.writeByte(DW.LNS.negate_stmt);
648 }
649
650 pub fn setPrologueEnd(debug: *Debug) UpdateError!void {
651 if (true) return;
652 return debug.setPrologueEndInner() catch |err| switch (err) {
653 error.WriteFailed => debug.line_writer.err.?,
654 };
655 }
656 fn setPrologueEndInner(debug: *Debug) Writer.Error!void {
657 try debug.line_writer.interface.writeByte(DW.LNS.set_prologue_end);
658 }
659
660 pub fn setEpilogueBegin(debug: *Debug) UpdateError!void {
661 if (true) return;
662 return debug.setEpilogueBeginInner() catch |err| switch (err) {
663 error.WriteFailed => debug.line_writer.err.?,
664 };
665 }
666 fn setEpilogueBeginInner(debug: *Debug) Writer.Error!void {
667 try debug.line_writer.interface.writeByte(DW.LNS.set_epilogue_begin);
668 }
669
670 pub fn enterBlock(debug: *Debug, code_off: u64) UpdateError!void {
671 if (true) return;
672 return debug.enterBlockInner(code_off) catch |err| switch (err) {
673 error.WriteFailed => debug.info_writer.err.?,
674 else => |e| e,
675 };
676 }
677 fn enterBlockInner(debug: *Debug, code_off: u64) (UpdateError || Writer.Error)!void {
678 const dwarf = debug.wip_nav.dwarf;
679 const diw = &debug.info_writer.interface;
680 const block = try debug.blocks.addOne(dwarf.linkFile().comp.gpa);
681
682 block.abbrev_code = @intCast(diw.end);
683 try debug.abbrevCode(.block);
684 block.low_pc_off = code_off;
685 try debug.infoAddrSym(debug.wip_nav.func_si, code_off);
686 block.high_pc = @intCast(diw.end);
687 try diw.writeInt(u32, 0, dwarf.endian);
688 debug.any_children = false;
689 }
690
691 pub fn leaveBlock(debug: *Debug, code_off: u64) UpdateError!void {
692 if (true) return;
693 return debug.leaveBlockInner(code_off) catch |err| switch (err) {
694 error.WriteFailed => debug.info_writer.err.?,
695 else => |e| e,
696 };
697 }
698 fn leaveBlockInner(debug: *Debug, code_off: u64) (UpdateError || Writer.Error)!void {
699 const dwarf = debug.wip_nav.dwarf;
700 const block_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.block));
701 const block = debug.blocks.pop().?;
702 if (debug.any_children)
703 try debug.info_writer.interface.writeUleb128(@backingInt(AbbrevCode.null))
704 else
705 std.leb.writeUnsignedFixed(
706 block_bytes,
707 debug.info_writer.interface.buffered()[block.abbrev_code..][0..block_bytes],
708 @intCast(try dwarf.refAbbrevCode(.empty_block)),
709 );
710 std.mem.writeInt(
711 u32,
712 debug.info_writer.interface.buffered()[block.high_pc..][0..4],
713 @intCast(code_off - block.low_pc_off),
714 dwarf.endian,
715 );
716 debug.any_children = true;
717 }
718
719 pub fn enterInlineFunc(
720 debug: *Debug,
721 func: InternPool.Index,
722 code_off: u64,
723 line: u32,
724 column: u32,
725 ) UpdateError!void {
726 if (true) return;
727 return debug.enterInlineFuncInner(func, code_off, line, column) catch |err| switch (err) {
728 error.WriteFailed => debug.info_writer.err.?,
729 else => |e| e,
730 };
731 }
732 fn enterInlineFuncInner(
733 debug: *Debug,
734 func: InternPool.Index,
735 code_off: u64,
736 line: u32,
737 column: u32,
738 ) (UpdateError || Writer.Error)!void {
739 const dwarf = debug.wip_nav.dwarf;
740 const zcu = debug.pt.zcu;
741 const diw = &debug.info_writer.interface;
742 const block = try debug.blocks.addOne(zcu.gpa);
743
744 block.abbrev_code = @intCast(diw.end);
745 try debug.abbrevCode(.inlined_func);
746 try debug.refNav(zcu.funcInfo(func).owner_nav);
747 try diw.writeUleb128(zcu.navSrcLine(debug.wip_nav.func.?.nav(dwarf)) + line + 1);
748 try diw.writeUleb128(column + 1);
749 block.low_pc_off = code_off;
750 try debug.infoAddrSym(debug.wip_nav.func_si, code_off);
751 block.high_pc = @intCast(diw.end);
752 try diw.writeInt(u32, 0, dwarf.endian);
753 try debug.setInlineFunc(func);
754 debug.any_children = false;
755 }
756
757 pub fn leaveInlineFunc(debug: *Debug, func: InternPool.Index, code_off: u64) UpdateError!void {
758 if (true) return;
759 return debug.leaveInlineFuncInner(func, code_off) catch |err| switch (err) {
760 error.WriteFailed => debug.info_writer.err.?,
761 else => |e| e,
762 };
763 }
764 fn leaveInlineFuncInner(
765 debug: *Debug,
766 func: InternPool.Index,
767 code_off: u64,
768 ) (UpdateError || Writer.Error)!void {
769 const dwarf = debug.wip_nav.dwarf;
770 const inlined_func_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.inlined_func));
771 const block = debug.blocks.pop().?;
772 if (debug.any_children)
773 try debug.info_writer.interface.writeUleb128(@backingInt(AbbrevCode.null))
774 else
775 std.leb.writeUnsignedFixed(
776 inlined_func_bytes,
777 debug.info_writer.interface.buffered()[block.abbrev_code..][0..inlined_func_bytes],
778 @intCast(try dwarf.refAbbrevCode(.empty_inlined_func)),
779 );
780 std.mem.writeInt(
781 u32,
782 debug.info_writer.interface.buffered()[block.high_pc..][0..4],
783 @intCast(code_off - block.low_pc_off),
784 dwarf.endian,
785 );
786 try debug.setInlineFunc(func);
787 debug.any_children = true;
788 }
789
790 pub fn setInlineFunc(debug: *Debug, func: InternPool.Index) UpdateError!void {
791 return debug.setInlineFuncInner(func) catch |err| switch (err) {
792 error.WriteFailed => debug.line_writer.err.?,
793 else => |e| e,
794 };
795 }
796 fn setInlineFuncInner(debug: *Debug, func: InternPool.Index) (UpdateError || Writer.Error)!void {
797 const wip_nav = &debug.wip_nav;
798 const zcu = debug.pt.zcu;
799 const dwarf = wip_nav.dwarf;
800
801 const func_index = try dwarf.getFunc(zcu.funcInfo(func).owner_nav);
802 if (wip_nav.func == func_index) return;
803
804 if (true) @panic("TODO");
805 const new_func_info = zcu.funcInfo(func);
806 const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav);
807 const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod.?);
808
809 const dlw = &debug.line_writer.interface;
810 if (zcu.comp.config.incremental) {
811 const new_func_gop = try dwarf.funcs.getOrPut(dwarf.gpa, new_func_info.owner_nav);
812 errdefer _ = if (!new_func_gop.found_existing) dwarf.funcs.pop();
813 if (!new_func_gop.found_existing) new_func_gop.value_ptr.* = .{
814 .frame_node = .none,
815 .debug_info_node = .none,
816 .debug_line_node = .none,
817 };
818
819 const section_offset_size: u4 = switch (dwarf.format) {
820 .@"32" => 4,
821 .@"64" => 8,
822 };
823
824 try dlw.writeByte(DW.LNS.extended_op);
825 try dlw.writeUleb128(1 + section_offset_size);
826 try dlw.writeByte(DW.LNE.ZIG_set_decl);
827 try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{
828 .source_off = @intCast(dlw.end),
829 .target_sec = .debug_info,
830 .target_unit = new_unit,
831 .target_entry = new_func_gop.value_ptr.toOptional(),
832 });
833 try dlw.splatByteAll(0, section_offset_size);
834 return;
835 }
836
837 const old_func_info = zcu.funcInfo(wip_nav.func);
838 const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav);
839 if (old_file != new_file) {
840 const mod_info = dwarf.getModInfo(wip_nav.unit);
841 try mod_info.dirs.put(dwarf.gpa, new_unit, {});
842 const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file);
843
844 try dlw.writeByte(DW.LNS.set_file);
845 try dlw.writeUleb128(file_gop.index);
846 }
847
848 const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav);
849 const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav);
850 if (new_src_line != old_src_line) {
851 try dlw.writeByte(DW.LNS.advance_line);
852 try dlw.writeSleb128(new_src_line - old_src_line);
853 }
854
855 wip_nav.func = func;
856 }
857
858 fn abbrevCode(debug: *Debug, abbrev_code: AbbrevCode) (UpdateError || Writer.Error)!void {
859 try debug.info_writer.interface.writeUleb128(try debug.wip_nav.dwarf.refAbbrevCode(abbrev_code));
860 }
861
862 fn infoExternalReloc(debug: *Debug, reloc: struct {
863 source_off: u32 = 0,
864 target_si: link.File.SymbolId,
865 target_off: u64 = 0,
866 }) Allocator.Error!void {
867 if (true) @panic("TODO");
868 try debug.wip_nav.externalReloc(&debug.wip_nav.dwarf.debug_frame.section, reloc);
869 }
870
871 fn infoSectionOffset(
872 debug: *Debug,
873 target: MappedFile.Node.Index,
874 addend: i64,
875 ) (UpdateError || Writer.Error)!void {
876 const dwarf = debug.wip_nav.dwarf;
877 const diw = &debug.info_writer.interface;
878 const offset = diw.end;
879 switch (dwarf.format) {
880 .@"32" => try diw.writeInt(u32, 0, dwarf.endian),
881 .@"64" => try diw.writeInt(u64, 0, dwarf.endian),
882 }
883 try dwarf.linkFile().cast(.elf2).?.addNodeReloc(
884 debug.info_writer.ni,
885 offset,
886 target,
887 addend,
888 switch (dwarf.format) {
889 .@"32" => .abs32,
890 .@"64" => .abs64,
891 },
892 );
893 }
894
895 fn strp(debug: *Debug, str: []const u8) (UpdateError || Writer.Error)!void {
896 if (true) @panic("TODO");
897 const dwarf = debug.wip_nav.dwarf;
898 try debug.infoSectionOffset(.debug_str, try dwarf.debug_str.addString(dwarf, str), 0);
899 }
900
901 fn strpFmt(
902 debug: *Debug,
903 comptime fmt: []const u8,
904 args: anytype,
905 ) (UpdateError || Writer.Error)!void {
906 const gpa = &debug.wip_nav.dwarf.gpa;
907 const str = try std.fmt.allocPrint(gpa, fmt, args);
908 defer gpa.free(str);
909 return debug.strp(str);
910 }
911
912 fn infoExprLoc(debug: *Debug, loc: Loc) (UpdateError || Writer.Error)!void {
913 var buf: [64]u8 = undefined;
914 var counter: ExprLocCounter = .init(debug.wip_nav.dwarf, &buf);
915 try loc.write(&counter);
916
917 const adapter: struct {
918 debug: *Debug,
919 fn writer(ctx: @This()) *Writer {
920 return &ctx.debug.info_writer.interface;
921 }
922 fn endian(ctx: @This()) std.lang.Endian {
923 return ctx.debug.wip_nav.dwarf.endian;
924 }
925 fn addrSym(ctx: @This(), si: link.File.SymbolId) (UpdateError || Writer.Error)!void {
926 try ctx.debug.infoAddrSym(si, 0);
927 }
928 fn infoEntry(
929 ctx: @This(),
930 node: MappedFile.Node.Index,
931 ) (UpdateError || Writer.Error)!void {
932 try ctx.debug.infoSectionOffset(node, 0);
933 }
934 } = .{ .debug = debug };
935 try adapter.writer().writeUleb128(counter.dw.fullCount());
936 try loc.write(adapter);
937 }
938
939 fn infoAddrSym(
940 debug: *Debug,
941 si: link.File.SymbolId,
942 sym_off: u64,
943 ) (UpdateError || Writer.Error)!void {
944 const diw = &debug.info_writer.interface;
945 try debug.infoExternalReloc(.{
946 .source_off = @intCast(diw.end),
947 .target_si = si,
948 .target_off = sym_off,
949 });
950 try diw.splatByteAll(0, @backingInt(debug.wip_nav.dwarf.address_size));
951 }
952
953 fn refNav(debug: *Debug, nav_index: InternPool.Nav.Index) (UpdateError || Writer.Error)!void {
954 try debug.infoSectionOffset(try debug.wip_nav.dwarf.getNavNode(nav_index), 0);
955 }
956
957 fn refType(debug: *Debug, ty: Type) (UpdateError || Writer.Error)!void {
958 return debug.refValue(ty.toValue());
959 }
960
961 fn refValue(debug: *Debug, value: Value) (UpdateError || Writer.Error)!void {
962 if (true) @panic("TODO");
963 try debug.infoSectionOffset(.debug_info, try debug.getValueNode(value), 0);
964 }
965
966 fn getValueNode(debug: *Debug, value: Value) UpdateError!MappedFile.Node.Index {
967 if (value.typeOf(debug.zcu).toIntern() != .type_type) {
968 assert(value.typeOf(debug.zcu).comptimeOnly(debug.zcu));
969 }
970 const dwarf = debug.wip_nav.dwarf;
971 const index = try dwarf.const_pool.get(debug.pt, .{ .dwarf = dwarf }, value.toIntern());
972 return dwarf.values.items[@backingInt(index)];
973 }
974
975 fn blockValue(debug: *Debug, val: Value) (UpdateError || Writer.Error)!void {
976 const ty = val.typeOf(debug.pt.zcu);
977 const diw = &debug.info_writer.interface;
978 const size = ty.abiSize(debug.pt.zcu);
979 try diw.writeUleb128(size);
980 if (size == 0) return;
981 const old_end = diw.end;
982 try codegen.generateSymbol(
983 debug.wip_nav.dwarf.linkFile(),
984 debug.pt,
985 val,
986 diw,
987 .{ .debug_output = .{ .dwarf2 = debug } },
988 );
989 if (old_end + size != diw.end) {
990 std.debug.print("{f} [{}]: {} != {}\n", .{
991 ty.fmt(debug.pt),
992 ty.toIntern(),
993 size,
994 diw.end - old_end,
995 });
996 unreachable;
997 }
998 }
999 };
1000
1001 pub fn deinit(wip_nav: *WipNav, gpa: Allocator) void {
1002 _ = gpa;
1003 wip_nav.fde_writer.deinit();
1004 wip_nav.* = undefined;
1005 }
1006
1007 pub fn genFuncHeaders(wip_nav: *WipNav) UpdateError!void {
1008 wip_nav.genDebugFrameHeader() catch |err| switch (err) {
1009 error.WriteFailed => return wip_nav.fde_writer.err.?,
1010 else => |e| return e,
1011 };
1012 }
1013 fn genDebugFrameHeader(wip_nav: *WipNav) (UpdateError || Writer.Error)!void {
1014 assert(wip_nav.func != null);
1015 const dwarf = wip_nav.dwarf;
1016 const dfw = &wip_nav.fde_writer.interface;
1017 switch (dwarf.format) {
1018 .@"32" => try dfw.writeInt(u32, undefined, dwarf.endian),
1019 .@"64" => {
1020 try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian);
1021 try dfw.writeInt(u64, undefined, dwarf.endian);
1022 },
1023 }
1024 const unit = wip_nav.unit.get(dwarf);
1025 switch (wip_nav.frame_format) {
1026 .eh_frame => {
1027 try dfw.writeInt(u32, undefined, dwarf.endian);
1028 {
1029 const offset = dfw.end;
1030 try dfw.writeInt(u32, 0, dwarf.endian);
1031 const elf = dwarf.linkFile().cast(.elf2).?;
1032 try elf.addReloc(
1033 @bitCast(wip_nav.fde_writer.ni),
1034 offset,
1035 wip_nav.func_si,
1036 0,
1037 .rel32(elf),
1038 );
1039 }
1040 wip_nav.frame_func_length_offset = dfw.end;
1041 try dfw.writeInt(u32, undefined, dwarf.endian);
1042 try dfw.writeUleb128(0);
1043 },
1044 .debug_frame => {
1045 try wip_nav.frameSectionOffset(unit.cie_ni.unwrap().?, 0);
1046 try wip_nav.frameAddrSym(wip_nav.func_si, 0);
1047 wip_nav.frame_func_length_offset = dfw.end;
1048 try dfw.splatByteAll(undefined, @backingInt(dwarf.address_size));
1049 },
1050 }
1051 }
1052
1053 pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) UpdateError!void {
1054 return wip_nav.genDebugFrameInner(loc, cfa) catch |err| switch (err) {
1055 error.WriteFailed => wip_nav.fde_writer.err.?,
1056 else => |e| e,
1057 };
1058 }
1059 fn genDebugFrameInner(wip_nav: *WipNav, loc: u32, cfa: Cfa) (UpdateError || Writer.Error)!void {
1060 assert(wip_nav.func != null);
1061 const loc_cfa: Cfa = .{ .advance_loc = loc };
1062 try loc_cfa.write(wip_nav);
1063 try cfa.write(wip_nav);
1064 }
1065
1066 pub fn finishDebugFrameFde(wip_nav: *WipNav, func_length: u64) void {
1067 const dwarf = wip_nav.dwarf;
1068 const fde = wip_nav.fde_writer.interface.buffer;
1069 switch (wip_nav.frame_format) {
1070 .eh_frame => std.mem.writeInt(
1071 u32,
1072 fde[wip_nav.frame_func_length_offset..][0..4],
1073 @intCast(func_length),
1074 dwarf.endian,
1075 ),
1076 .debug_frame => switch (dwarf.address_size) {
1077 _ => unreachable,
1078 .@"32" => std.mem.writeInt(
1079 u32,
1080 fde[wip_nav.frame_func_length_offset..][0..4],
1081 @intCast(func_length),
1082 dwarf.endian,
1083 ),
1084 .@"64" => std.mem.writeInt(
1085 u64,
1086 fde[wip_nav.frame_func_length_offset..][0..8],
1087 func_length,
1088 dwarf.endian,
1089 ),
1090 },
1091 }
1092 }
1093
1094 const ExprLocCounter = struct {
1095 dw: Writer.Discarding,
1096 section_offset_bytes: u32,
1097 address_size: AddressSize,
1098 fn init(dwarf: *Dwarf, buf: []u8) ExprLocCounter {
1099 return .{
1100 .dw = .init(buf),
1101 .section_offset_bytes = switch (dwarf.format) {
1102 .@"32" => 4,
1103 .@"64" => 8,
1104 },
1105 .address_size = dwarf.address_size,
1106 };
1107 }
1108 fn writer(counter: *ExprLocCounter) *Writer {
1109 return &counter.dw.writer;
1110 }
1111 fn endian(_: ExprLocCounter) std.lang.Endian {
1112 return .native;
1113 }
1114 fn addrSym(counter: *ExprLocCounter, _: link.File.SymbolId) Writer.Error!void {
1115 try counter.dw.writer.splatByteAll(undefined, @backingInt(counter.address_size));
1116 }
1117 fn infoEntry(counter: *ExprLocCounter, _: MappedFile.Node.Index) Writer.Error!void {
1118 try counter.dw.writer.splatByteAll(undefined, counter.section_offset_bytes);
1119 }
1120 };
1121
1122 fn frameSectionOffset(
1123 wip_nav: *WipNav,
1124 target: MappedFile.Node.Index,
1125 addend: i64,
1126 ) (UpdateError || Writer.Error)!void {
1127 const dwarf = wip_nav.dwarf;
1128 const dfw = &wip_nav.fde_writer.interface;
1129 const offset = dfw.end;
1130 switch (dwarf.format) {
1131 .@"32" => try dfw.writeInt(u32, 0, dwarf.endian),
1132 .@"64" => try dfw.writeInt(u64, 0, dwarf.endian),
1133 }
1134 try dwarf.linkFile().cast(.elf2).?.addNodeReloc(
1135 wip_nav.fde_writer.ni,
1136 offset,
1137 target,
1138 addend,
1139 switch (dwarf.format) {
1140 .@"32" => .abs32,
1141 .@"64" => .abs64,
1142 },
1143 );
1144 }
1145
1146 fn frameExprLoc(wip_nav: *WipNav, loc: Loc) (UpdateError || Writer.Error)!void {
1147 var buf: [64]u8 = undefined;
1148 var counter: ExprLocCounter = .init(wip_nav.dwarf, &buf);
1149 try loc.write(&counter);
1150
1151 const adapter: struct {
1152 wip_nav: *WipNav,
1153 fn writer(ctx: @This()) *Writer {
1154 return &ctx.wip_nav.fde_writer.interface;
1155 }
1156 fn endian(ctx: @This()) std.lang.Endian {
1157 return ctx.wip_nav.dwarf.endian;
1158 }
1159 fn addrSym(ctx: @This(), si: link.File.SymbolId) (UpdateError || Writer.Error)!void {
1160 try ctx.wip_nav.frameAddrSym(si, 0);
1161 }
1162 fn infoEntry(ctx: @This(), node: MappedFile.Node.Index) (UpdateError || Writer.Error)!void {
1163 try ctx.wip_nav.frameSectionOffset(node, 0);
1164 }
1165 } = .{ .wip_nav = wip_nav };
1166 try adapter.writer().writeUleb128(counter.dw.fullCount());
1167 try loc.write(adapter);
1168 }
1169
1170 fn frameAddrSym(
1171 wip_nav: *WipNav,
1172 si: link.File.SymbolId,
1173 sym_off: u64,
1174 ) (UpdateError || Writer.Error)!void {
1175 const dwarf = wip_nav.dwarf;
1176 const dfw = &wip_nav.fde_writer.interface;
1177 const offset = dfw.end;
1178 try dfw.splatByteAll(0, @backingInt(dwarf.address_size));
1179 const elf = dwarf.linkFile().cast(.elf2).?;
1180 try elf.addReloc(
1181 @bitCast(wip_nav.fde_writer.ni),
1182 offset,
1183 si,
1184 @bitCast(sym_off),
1185 switch (dwarf.format) {
1186 .@"32" => .abs32(elf),
1187 .@"64" => .abs64(elf),
1188 },
1189 );
1190 }
1191};
1192
1193pub fn init(lf: *link.File, format: DW.Format) Dwarf {
1194 const comp = lf.comp;
1195 const target = &comp.root_mod.resolved_target.result;
1196 return .{
1197 .tag = lf.tag,
1198 .format = format,
1199 .address_size = switch (target.ptrBitWidth()) {
1200 0...32 => .@"32",
1201 33...64 => .@"64",
1202 else => unreachable,
1203 },
1204 .endian = target.cpu.arch.endian(),
1205 .const_pool = .empty,
1206 .units = .empty,
1207 .values = .empty,
1208 .globals = .empty,
1209 .funcs = .empty,
1210
1211 .debug_info = .{
1212 .section_index = .none,
1213 },
1214 .debug_line = .{
1215 .header = switch (target.cpu.arch) {
1216 .x86_64, .aarch64 => .{
1217 .minimum_instruction_length = 1,
1218 .maximum_operations_per_instruction = 1,
1219 .default_is_stmt = true,
1220 .line_base = -5,
1221 .line_range = 14,
1222 .opcode_base = DW.LNS.set_isa + 1,
1223 },
1224 else => .{
1225 .minimum_instruction_length = 1,
1226 .maximum_operations_per_instruction = 1,
1227 .default_is_stmt = true,
1228 .line_base = 0,
1229 .line_range = 1,
1230 .opcode_base = DW.LNS.set_isa + 1,
1231 },
1232 },
1233 .section_index = .none,
1234 },
1235 .frame = .{
1236 .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: {
1237 dev.check(.x86_64_backend);
1238 const Register = @import("../codegen/x86_64/bits.zig").Register;
1239 break :header comptime .{
1240 .code_alignment_factor = 1,
1241 .data_alignment_factor = -8,
1242 .return_address_register = Register.rip.dwarfNum(),
1243 .initial_instructions = &.{
1244 .{ .def_cfa = .{ .reg = Register.rsp.dwarfNum(), .off = 8 } },
1245 .{ .offset = .{ .reg = Register.rip.dwarfNum(), .off = -8 } },
1246 },
1247 };
1248 } else .{
1249 .code_alignment_factor = undefined,
1250 .data_alignment_factor = undefined,
1251 .return_address_register = undefined,
1252 .initial_instructions = &.{},
1253 },
1254 .section_index = .none,
1255 },
1256 };
1257}
1258
1259pub fn deinit(dwarf: *Dwarf, gpa: Allocator) void {
1260 dwarf.const_pool.deinit(gpa);
1261 dwarf.units.deinit(gpa);
1262 dwarf.values.deinit(gpa);
1263 dwarf.globals.deinit(gpa);
1264 dwarf.funcs.deinit(gpa);
1265 dwarf.* = undefined;
1266}
1267
1268fn linkFile(dwarf: *Dwarf) *link.File {
1269 return switch (dwarf.tag) {
1270 else => unreachable,
1271 .elf2 => |tag| &@as(*tag.Type(), @alignCast(@fieldParentPtr("dwarf", dwarf))).base,
1272 };
1273}
1274
1275pub fn initUnits(dwarf: *Dwarf, zcu: *Zcu) Allocator.Error!void {
1276 try dwarf.units.ensureTotalCapacity(zcu.gpa, zcu.module_roots.count());
1277 for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, root| switch (root) {
1278 .none => {},
1279 else => dwarf.units.putAssumeCapacityNoClobber(mod, .{
1280 .frame_ni = .none,
1281 .cie_ni = .none,
1282 }),
1283 };
1284}
1285
1286fn getNavNode(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) UpdateError!MappedFile.Node.Index {
1287 if (true) @panic("TODO");
1288 const zcu = dwarf.linkFile().comp.zcu.?;
1289 const ip = &zcu.intern_pool;
1290 const nav = ip.getNav(nav_index);
1291 const unit = try dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?);
1292 const gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
1293 if (gop.found_existing) return .{ unit, gop.value_ptr.* };
1294 const entry = try dwarf.addCommonEntry(unit);
1295 gop.value_ptr.* = entry;
1296 return .{ unit, entry };
1297}
1298
1299pub fn getUnit(dwarf: *Dwarf, mod: *Module) Unit.Index {
1300 return @fromBackingInt(@intCast(dwarf.units.getIndex(mod).?));
1301}
1302
1303pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) Allocator.Error!Func.Index {
1304 const func_gop = try dwarf.funcs.getOrPut(dwarf.linkFile().comp.gpa, owner_nav);
1305 if (!func_gop.found_existing) func_gop.value_ptr.* = .{
1306 .fde_ni = .none,
1307 .debug_info_ni = .none,
1308 .debug_line_ni = .none,
1309 };
1310 return @fromBackingInt(@intCast(func_gop.index));
1311}
1312
1313pub fn updateUnitLength(dwarf: *Dwarf, header: []u8, unit_length: u64) void {
1314 switch (dwarf.format) {
1315 .@"32" => std.mem.writeInt(u32, header[0..4], @intCast(unit_length - 4), dwarf.endian),
1316 .@"64" => std.mem.writeInt(u64, header[4..12], unit_length - 12, dwarf.endian),
1317 }
1318}
1319
1320pub const EhFrameHdr = extern struct {
1321 version: u8,
1322 eh_frame_ptr_enc: std.dwarf.EH.PE,
1323 fde_count_enc: std.dwarf.EH.PE,
1324 table_enc: std.dwarf.EH.PE,
1325 eh_frame_ptr: u32,
1326};
1327pub fn genEhFrameHdr(
1328 dwarf: *Dwarf,
1329 eh_frame_hdr_ai: link.File.AtomId,
1330 eh_frame_hdr: *EhFrameHdr,
1331 eh_frame_si: link.File.SymbolId,
1332) UpdateError!void {
1333 eh_frame_hdr.* = .{
1334 .version = 1,
1335 .eh_frame_ptr_enc = .{ .type = .sdata4, .rel = .pcrel },
1336 .fde_count_enc = .omit,
1337 .table_enc = .omit,
1338 .eh_frame_ptr = undefined,
1339 };
1340 const elf = dwarf.linkFile().cast(.elf2).?;
1341 try elf.addReloc(
1342 eh_frame_hdr_ai,
1343 @offsetOf(EhFrameHdr, "eh_frame_ptr"),
1344 eh_frame_si,
1345 0,
1346 .rel32(elf),
1347 );
1348}
1349
1350pub fn genDebugFrameCie(
1351 dwarf: *Dwarf,
1352 w: *Writer,
1353 /// `null` means to generate an architecture-agnostic padding cie
1354 arch: ?std.Target.Cpu.Arch,
1355 format: Frame.Format,
1356) Writer.Error!void {
1357 switch (dwarf.format) {
1358 .@"32" => try w.writeInt(u32, undefined, dwarf.endian),
1359 .@"64" => {
1360 try w.writeInt(u32, std.math.maxInt(u32), dwarf.endian);
1361 try w.writeInt(u64, undefined, dwarf.endian);
1362 },
1363 }
1364 switch (format) {
1365 .eh_frame => try w.writeInt(u32, 0, dwarf.endian),
1366 .debug_frame => switch (dwarf.format) {
1367 .@"32" => try w.writeInt(u32, std.math.maxInt(u32), dwarf.endian),
1368 .@"64" => try w.writeInt(u64, std.math.maxInt(u64), dwarf.endian),
1369 },
1370 }
1371 try w.writeByte(if (arch) |_| switch (format) {
1372 .eh_frame => 1,
1373 .debug_frame => 4,
1374 } else 0);
1375 switch (arch orelse return) {
1376 else => unreachable,
1377 .x86_64 => {
1378 dev.check(.x86_64_backend);
1379 const Register = @import("../codegen/x86_64/bits.zig").Register;
1380 switch (format) {
1381 .eh_frame => try w.writeAll("zR\x00"),
1382 .debug_frame => {
1383 try w.writeAll("\x00");
1384 try w.writeByte(@backingInt(dwarf.address_size));
1385 try w.writeByte(0);
1386 },
1387 }
1388 try w.writeUleb128(dwarf.frame.header.code_alignment_factor);
1389 try w.writeSleb128(dwarf.frame.header.data_alignment_factor);
1390 switch (format) {
1391 .eh_frame => try w.writeByte(@intCast(dwarf.frame.header.return_address_register)),
1392 .debug_frame => try w.writeUleb128(dwarf.frame.header.return_address_register),
1393 }
1394 switch (format) {
1395 .eh_frame => {
1396 try w.writeUleb128(1);
1397 try w.writeByte(@bitCast(@as(DW.EH.PE, .{ .type = .sdata4, .rel = .pcrel })));
1398 },
1399 .debug_frame => {},
1400 }
1401 try w.writeByte(DW.CFA.def_cfa_sf);
1402 try w.writeUleb128(Register.rsp.dwarfNum());
1403 try w.writeSleb128(-1);
1404 try w.writeByte(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum());
1405 try w.writeUleb128(1);
1406 },
1407 }
1408}
1409
1410pub fn updateEhFrameFde(dwarf: *Dwarf, fde: []u8, fde_offset: u64) void {
1411 const cie_pointer_offset: usize = switch (dwarf.format) {
1412 .@"32" => 4,
1413 .@"64" => 12,
1414 };
1415 std.mem.writeInt(
1416 u32,
1417 fde[cie_pointer_offset..][0..4],
1418 @intCast(fde_offset + cie_pointer_offset),
1419 dwarf.endian,
1420 );
1421}
1422
1423fn refAbbrevCode(
1424 dwarf: *Dwarf,
1425 abbrev_code: AbbrevCode,
1426) (UpdateError || Writer.Error)!@typeInfo(AbbrevCode).@"enum".tag_type {
1427 if (true) @panic("TODO");
1428 const Entry = {};
1429 const DebugAbbrev = {};
1430 assert(abbrev_code != .null);
1431 const entry: Entry.Index = @fromBackingInt(@intCast(@backingInt(abbrev_code)));
1432 if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @backingInt(abbrev_code);
1433 var debug_abbrev_aw: Writer.Allocating = .init(dwarf.gpa);
1434 defer debug_abbrev_aw.deinit();
1435 const daw = &debug_abbrev_aw.writer;
1436 const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
1437 try daw.writeUleb128(@backingInt(abbrev_code));
1438 try daw.writeUleb128(@backingInt(abbrev.tag));
1439 try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
1440 for (abbrev.attrs) |*attr| inline for (attr) |info| try daw.writeUleb128(@backingInt(info));
1441 for (0..2) |_| try daw.writeUleb128(0);
1442 try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, debug_abbrev_aw.written());
1443 return @backingInt(abbrev_code);
1444}
1445
1446fn DeclValEnum(comptime T: type) type {
1447 const decl_names = @typeInfo(T).@"struct".decl_names;
1448 @setEvalBranchQuota(10 * decl_names.len);
1449 var field_names: [decl_names.len][]const u8 = undefined;
1450 var fields_len = 0;
1451 var min_value: ?comptime_int = null;
1452 var max_value: ?comptime_int = null;
1453 for (decl_names) |decl_name| {
1454 if (std.mem.startsWith(u8, decl_name, "HP_") or std.mem.endsWith(u8, decl_name, "_user")) continue;
1455 const value = @field(T, decl_name);
1456 field_names[fields_len] = decl_name;
1457 fields_len += 1;
1458 if (min_value == null or min_value.? > value) min_value = value;
1459 if (max_value == null or max_value.? < value) max_value = value;
1460 }
1461 if (fields_len == 0) return enum {};
1462 const TagInt = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0);
1463 var field_vals: [fields_len]TagInt = undefined;
1464 for (field_names[0..fields_len], &field_vals) |name, *val| val.* = @field(T, name);
1465 return @Enum(TagInt, .exhaustive, field_names[0..fields_len], &field_vals);
1466}
1467
1468const AbbrevCode = enum {
1469 null,
1470 // padding codes must be one byte uleb128 values to function
1471 pad_1,
1472 pad_n,
1473 // decl, generic decl, and instance codes are assumed to all have the same uleb128 length
1474 decl_alias,
1475 decl_empty_enum,
1476 decl_enum,
1477 decl_namespace_struct,
1478 decl_struct,
1479 decl_packed_struct,
1480 decl_union,
1481 decl_packed_union,
1482 decl_var,
1483 decl_const,
1484 decl_const_runtime_bits,
1485 decl_const_comptime_state,
1486 decl_const_runtime_bits_comptime_state,
1487 decl_nullary_func,
1488 decl_func,
1489 decl_nullary_func_generic,
1490 decl_func_generic,
1491 decl_extern_nullary_func,
1492 decl_extern_func,
1493 generic_decl_var,
1494 generic_decl_const,
1495 generic_decl_func,
1496 decl_instance_alias,
1497 decl_instance_empty_enum,
1498 decl_instance_enum,
1499 decl_instance_namespace_struct,
1500 decl_instance_struct,
1501 decl_instance_packed_struct,
1502 decl_instance_union,
1503 decl_instance_packed_union,
1504 decl_instance_var,
1505 decl_instance_const,
1506 decl_instance_const_runtime_bits,
1507 decl_instance_const_comptime_state,
1508 decl_instance_const_runtime_bits_comptime_state,
1509 decl_instance_nullary_func,
1510 decl_instance_func,
1511 decl_instance_nullary_func_generic,
1512 decl_instance_func_generic,
1513 decl_instance_extern_nullary_func,
1514 decl_instance_extern_func,
1515 // the rest are unrestricted other than empty variants must not be longer
1516 // than the non-empty variant, and so should appear first
1517 compile_unit,
1518 module,
1519 empty_file,
1520 file,
1521 access,
1522 enum_field,
1523 generated_field,
1524 field,
1525 field_default_runtime_bits,
1526 field_default_comptime_state,
1527 field_comptime,
1528 field_comptime_runtime_bits,
1529 field_comptime_comptime_state,
1530 packed_field,
1531 tagged_union,
1532 tagged_union_field,
1533 tagged_union_default_field,
1534 void_type,
1535 numeric_type,
1536 inferred_error_set_type,
1537 ptr_type,
1538 ptr_sentinel_type,
1539 ptr_aligned_type,
1540 ptr_aligned_sentinel_type,
1541 is_const,
1542 is_volatile,
1543 array_type,
1544 array_sentinel_type,
1545 vector_type,
1546 array_index,
1547 array_len,
1548 nullary_func_type,
1549 func_type,
1550 func_type_param,
1551 is_var_args,
1552 generated_empty_enum_type,
1553 generated_enum_type,
1554 generated_empty_struct_type,
1555 generated_struct_type,
1556 generated_union_type,
1557 empty_enum_type,
1558 enum_type,
1559 empty_struct_type,
1560 struct_type,
1561 empty_packed_struct_type,
1562 packed_struct_type,
1563 empty_union_type,
1564 union_type,
1565 empty_packed_union_type,
1566 packed_union_type,
1567 builtin_extern_nullary_func,
1568 builtin_extern_func,
1569 builtin_extern_var,
1570 empty_block,
1571 block,
1572 empty_inlined_func,
1573 inlined_func,
1574 arg,
1575 unnamed_arg,
1576 comptime_arg,
1577 unnamed_comptime_arg,
1578 comptime_arg_runtime_bits,
1579 unnamed_comptime_arg_runtime_bits,
1580 comptime_arg_comptime_state,
1581 unnamed_comptime_arg_comptime_state,
1582 comptime_arg_runtime_bits_comptime_state,
1583 unnamed_comptime_arg_runtime_bits_comptime_state,
1584 extern_param,
1585 local_var,
1586 local_const,
1587 local_const_runtime_bits,
1588 local_const_comptime_state,
1589 local_const_runtime_bits_comptime_state,
1590 undefined_comptime_value,
1591 comptime_value,
1592 location_comptime_value,
1593 aggregate_undefined_comptime_value,
1594 aggregate_comptime_value,
1595 aggregate_location_comptime_value,
1596 comptime_value_field_runtime_bits,
1597 comptime_value_field_comptime_state,
1598 comptime_value_elem_runtime_bits,
1599 comptime_value_elem_comptime_state,
1600
1601 const decl_bytes = uleb128Bytes(@backingInt(AbbrevCode.decl_instance_extern_func));
1602 comptime {
1603 assert(uleb128Bytes(@backingInt(AbbrevCode.pad_1)) == 1);
1604 assert(uleb128Bytes(@backingInt(AbbrevCode.pad_n)) == 1);
1605 assert(uleb128Bytes(@backingInt(AbbrevCode.decl_alias)) == decl_bytes);
1606 }
1607
1608 const Attr = struct {
1609 DeclValEnum(DW.AT),
1610 DeclValEnum(DW.FORM),
1611 };
1612 const decl_abbrev_common_attrs = &[_]Attr{
1613 .{ .ZIG_parent, .ref_addr },
1614 .{ .decl_line, .data4 },
1615 .{ .decl_column, .udata },
1616 .{ .accessibility, .data1 },
1617 .{ .name, .strp },
1618 };
1619 const generic_decl_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{
1620 .{ .declaration, .flag_present },
1621 };
1622 const decl_instance_abbrev_common_attrs = &[_]Attr{
1623 .{ .ZIG_parent, .ref_addr },
1624 .{ .abstract_origin, .ref_addr },
1625 };
1626 const abbrevs = std.EnumArray(AbbrevCode, struct {
1627 tag: DeclValEnum(DW.TAG),
1628 children: bool = false,
1629 attrs: []const Attr = &.{},
1630 }).init(.{
1631 .pad_1 = .{
1632 .tag = .ZIG_padding,
1633 },
1634 .pad_n = .{
1635 .tag = .ZIG_padding,
1636 .attrs = &.{
1637 .{ .ZIG_padding, .block },
1638 },
1639 },
1640 .decl_alias = .{
1641 .tag = .imported_declaration,
1642 .attrs = decl_abbrev_common_attrs ++ .{
1643 .{ .import, .ref_addr },
1644 },
1645 },
1646 .decl_empty_enum = .{
1647 .tag = .enumeration_type,
1648 .attrs = decl_abbrev_common_attrs ++ .{
1649 .{ .type, .ref_addr },
1650 },
1651 },
1652 .decl_enum = .{
1653 .tag = .enumeration_type,
1654 .children = true,
1655 .attrs = decl_abbrev_common_attrs ++ .{
1656 .{ .type, .ref_addr },
1657 },
1658 },
1659 .decl_namespace_struct = .{
1660 .tag = .structure_type,
1661 .attrs = decl_abbrev_common_attrs ++ .{
1662 .{ .declaration, .flag },
1663 },
1664 },
1665 .decl_struct = .{
1666 .tag = .structure_type,
1667 .children = true,
1668 .attrs = decl_abbrev_common_attrs ++ .{
1669 .{ .byte_size, .udata },
1670 .{ .alignment, .udata },
1671 },
1672 },
1673 .decl_packed_struct = .{
1674 .tag = .structure_type,
1675 .children = true,
1676 .attrs = decl_abbrev_common_attrs ++ .{
1677 .{ .type, .ref_addr },
1678 },
1679 },
1680 .decl_union = .{
1681 .tag = .union_type,
1682 .children = true,
1683 .attrs = decl_abbrev_common_attrs ++ .{
1684 .{ .byte_size, .udata },
1685 .{ .alignment, .udata },
1686 },
1687 },
1688 .decl_packed_union = .{
1689 .tag = .union_type,
1690 .children = true,
1691 .attrs = decl_abbrev_common_attrs ++ .{
1692 .{ .type, .ref_addr },
1693 },
1694 },
1695 .decl_var = .{
1696 .tag = .variable,
1697 .attrs = decl_abbrev_common_attrs ++ .{
1698 .{ .linkage_name, .strp },
1699 .{ .type, .ref_addr },
1700 .{ .location, .exprloc },
1701 .{ .alignment, .udata },
1702 .{ .external, .flag },
1703 },
1704 },
1705 .decl_const = .{
1706 .tag = .constant,
1707 .attrs = decl_abbrev_common_attrs ++ .{
1708 .{ .linkage_name, .strp },
1709 .{ .type, .ref_addr },
1710 .{ .alignment, .udata },
1711 .{ .external, .flag },
1712 },
1713 },
1714 .decl_const_runtime_bits = .{
1715 .tag = .constant,
1716 .attrs = decl_abbrev_common_attrs ++ .{
1717 .{ .linkage_name, .strp },
1718 .{ .type, .ref_addr },
1719 .{ .alignment, .udata },
1720 .{ .external, .flag },
1721 .{ .const_value, .block },
1722 },
1723 },
1724 .decl_const_comptime_state = .{
1725 .tag = .constant,
1726 .attrs = decl_abbrev_common_attrs ++ .{
1727 .{ .linkage_name, .strp },
1728 .{ .type, .ref_addr },
1729 .{ .alignment, .udata },
1730 .{ .external, .flag },
1731 .{ .ZIG_comptime_value, .ref_addr },
1732 },
1733 },
1734 .decl_const_runtime_bits_comptime_state = .{
1735 .tag = .constant,
1736 .attrs = decl_abbrev_common_attrs ++ .{
1737 .{ .linkage_name, .strp },
1738 .{ .type, .ref_addr },
1739 .{ .alignment, .udata },
1740 .{ .external, .flag },
1741 .{ .const_value, .block },
1742 .{ .ZIG_comptime_value, .ref_addr },
1743 },
1744 },
1745 .decl_nullary_func = .{
1746 .tag = .subprogram,
1747 .attrs = decl_abbrev_common_attrs ++ .{
1748 .{ .linkage_name, .strp },
1749 .{ .type, .ref_addr },
1750 .{ .low_pc, .addr },
1751 .{ .high_pc, .data4 },
1752 .{ .alignment, .udata },
1753 .{ .external, .flag },
1754 .{ .noreturn, .flag },
1755 },
1756 },
1757 .decl_func = .{
1758 .tag = .subprogram,
1759 .children = true,
1760 .attrs = decl_abbrev_common_attrs ++ .{
1761 .{ .linkage_name, .strp },
1762 .{ .type, .ref_addr },
1763 .{ .low_pc, .addr },
1764 .{ .high_pc, .data4 },
1765 .{ .alignment, .udata },
1766 .{ .external, .flag },
1767 .{ .noreturn, .flag },
1768 },
1769 },
1770 .decl_nullary_func_generic = .{
1771 .tag = .subprogram,
1772 .attrs = decl_abbrev_common_attrs ++ .{
1773 .{ .type, .ref_addr },
1774 },
1775 },
1776 .decl_func_generic = .{
1777 .tag = .subprogram,
1778 .children = true,
1779 .attrs = decl_abbrev_common_attrs ++ .{
1780 .{ .type, .ref_addr },
1781 },
1782 },
1783 .decl_extern_nullary_func = .{
1784 .tag = .subprogram,
1785 .attrs = decl_abbrev_common_attrs ++ .{
1786 .{ .linkage_name, .strp },
1787 .{ .type, .ref_addr },
1788 .{ .low_pc, .addr },
1789 .{ .external, .flag_present },
1790 .{ .noreturn, .flag },
1791 },
1792 },
1793 .decl_extern_func = .{
1794 .tag = .subprogram,
1795 .children = true,
1796 .attrs = decl_abbrev_common_attrs ++ .{
1797 .{ .linkage_name, .strp },
1798 .{ .type, .ref_addr },
1799 .{ .low_pc, .addr },
1800 .{ .external, .flag_present },
1801 .{ .noreturn, .flag },
1802 },
1803 },
1804 .generic_decl_var = .{
1805 .tag = .variable,
1806 .attrs = generic_decl_abbrev_common_attrs,
1807 },
1808 .generic_decl_const = .{
1809 .tag = .constant,
1810 .attrs = generic_decl_abbrev_common_attrs,
1811 },
1812 .generic_decl_func = .{
1813 .tag = .subprogram,
1814 .attrs = generic_decl_abbrev_common_attrs,
1815 },
1816 .decl_instance_alias = .{
1817 .tag = .imported_declaration,
1818 .attrs = decl_instance_abbrev_common_attrs ++ .{
1819 .{ .import, .ref_addr },
1820 },
1821 },
1822 .decl_instance_empty_enum = .{
1823 .tag = .enumeration_type,
1824 .attrs = decl_instance_abbrev_common_attrs ++ .{
1825 .{ .type, .ref_addr },
1826 },
1827 },
1828 .decl_instance_enum = .{
1829 .tag = .enumeration_type,
1830 .children = true,
1831 .attrs = decl_instance_abbrev_common_attrs ++ .{
1832 .{ .type, .ref_addr },
1833 },
1834 },
1835 .decl_instance_namespace_struct = .{
1836 .tag = .structure_type,
1837 .attrs = decl_instance_abbrev_common_attrs ++ .{
1838 .{ .declaration, .flag },
1839 },
1840 },
1841 .decl_instance_struct = .{
1842 .tag = .structure_type,
1843 .children = true,
1844 .attrs = decl_instance_abbrev_common_attrs ++ .{
1845 .{ .byte_size, .udata },
1846 .{ .alignment, .udata },
1847 },
1848 },
1849 .decl_instance_packed_struct = .{
1850 .tag = .structure_type,
1851 .children = true,
1852 .attrs = decl_instance_abbrev_common_attrs ++ .{
1853 .{ .type, .ref_addr },
1854 },
1855 },
1856 .decl_instance_union = .{
1857 .tag = .union_type,
1858 .children = true,
1859 .attrs = decl_instance_abbrev_common_attrs ++ .{
1860 .{ .byte_size, .udata },
1861 .{ .alignment, .udata },
1862 },
1863 },
1864 .decl_instance_packed_union = .{
1865 .tag = .union_type,
1866 .children = true,
1867 .attrs = decl_instance_abbrev_common_attrs ++ .{
1868 .{ .type, .ref_addr },
1869 },
1870 },
1871 .decl_instance_var = .{
1872 .tag = .variable,
1873 .attrs = decl_instance_abbrev_common_attrs ++ .{
1874 .{ .linkage_name, .strp },
1875 .{ .type, .ref_addr },
1876 .{ .location, .exprloc },
1877 .{ .alignment, .udata },
1878 .{ .external, .flag },
1879 },
1880 },
1881 .decl_instance_const = .{
1882 .tag = .constant,
1883 .attrs = decl_instance_abbrev_common_attrs ++ .{
1884 .{ .linkage_name, .strp },
1885 .{ .type, .ref_addr },
1886 .{ .alignment, .udata },
1887 .{ .external, .flag },
1888 },
1889 },
1890 .decl_instance_const_runtime_bits = .{
1891 .tag = .constant,
1892 .attrs = decl_instance_abbrev_common_attrs ++ .{
1893 .{ .linkage_name, .strp },
1894 .{ .type, .ref_addr },
1895 .{ .alignment, .udata },
1896 .{ .external, .flag },
1897 .{ .const_value, .block },
1898 },
1899 },
1900 .decl_instance_const_comptime_state = .{
1901 .tag = .constant,
1902 .attrs = decl_instance_abbrev_common_attrs ++ .{
1903 .{ .linkage_name, .strp },
1904 .{ .type, .ref_addr },
1905 .{ .alignment, .udata },
1906 .{ .external, .flag },
1907 .{ .ZIG_comptime_value, .ref_addr },
1908 },
1909 },
1910 .decl_instance_const_runtime_bits_comptime_state = .{
1911 .tag = .constant,
1912 .attrs = decl_instance_abbrev_common_attrs ++ .{
1913 .{ .linkage_name, .strp },
1914 .{ .type, .ref_addr },
1915 .{ .alignment, .udata },
1916 .{ .external, .flag },
1917 .{ .const_value, .block },
1918 .{ .ZIG_comptime_value, .ref_addr },
1919 },
1920 },
1921 .decl_instance_nullary_func = .{
1922 .tag = .subprogram,
1923 .attrs = decl_instance_abbrev_common_attrs ++ .{
1924 .{ .linkage_name, .strp },
1925 .{ .type, .ref_addr },
1926 .{ .low_pc, .addr },
1927 .{ .high_pc, .data4 },
1928 .{ .alignment, .udata },
1929 .{ .external, .flag },
1930 .{ .noreturn, .flag },
1931 },
1932 },
1933 .decl_instance_func = .{
1934 .tag = .subprogram,
1935 .children = true,
1936 .attrs = decl_instance_abbrev_common_attrs ++ .{
1937 .{ .linkage_name, .strp },
1938 .{ .type, .ref_addr },
1939 .{ .low_pc, .addr },
1940 .{ .high_pc, .data4 },
1941 .{ .alignment, .udata },
1942 .{ .external, .flag },
1943 .{ .noreturn, .flag },
1944 },
1945 },
1946 .decl_instance_nullary_func_generic = .{
1947 .tag = .subprogram,
1948 .attrs = decl_instance_abbrev_common_attrs ++ .{
1949 .{ .type, .ref_addr },
1950 },
1951 },
1952 .decl_instance_func_generic = .{
1953 .tag = .subprogram,
1954 .children = true,
1955 .attrs = decl_instance_abbrev_common_attrs ++ .{
1956 .{ .type, .ref_addr },
1957 },
1958 },
1959 .decl_instance_extern_nullary_func = .{
1960 .tag = .subprogram,
1961 .attrs = decl_instance_abbrev_common_attrs ++ .{
1962 .{ .linkage_name, .strp },
1963 .{ .type, .ref_addr },
1964 .{ .low_pc, .addr },
1965 .{ .external, .flag_present },
1966 .{ .noreturn, .flag },
1967 },
1968 },
1969 .decl_instance_extern_func = .{
1970 .tag = .subprogram,
1971 .children = true,
1972 .attrs = decl_instance_abbrev_common_attrs ++ .{
1973 .{ .linkage_name, .strp },
1974 .{ .type, .ref_addr },
1975 .{ .low_pc, .addr },
1976 .{ .external, .flag_present },
1977 .{ .noreturn, .flag },
1978 },
1979 },
1980 .compile_unit = .{
1981 .tag = .compile_unit,
1982 .children = true,
1983 .attrs = &.{
1984 .{ .language, .data1 },
1985 .{ .producer, .line_strp },
1986 .{ .comp_dir, .line_strp },
1987 .{ .name, .line_strp },
1988 .{ .base_types, .ref_addr },
1989 .{ .stmt_list, .sec_offset },
1990 .{ .rnglists_base, .sec_offset },
1991 .{ .ranges, .rnglistx },
1992 },
1993 },
1994 .module = .{
1995 .tag = .module,
1996 .children = true,
1997 .attrs = &.{
1998 .{ .name, .strp },
1999 .{ .ranges, .rnglistx },
2000 },
2001 },
2002 .empty_file = .{
2003 .tag = .structure_type,
2004 .attrs = &.{
2005 .{ .decl_file, .udata },
2006 .{ .name, .strp },
2007 },
2008 },
2009 .file = .{
2010 .tag = .structure_type,
2011 .children = true,
2012 .attrs = &.{
2013 .{ .decl_file, .udata },
2014 .{ .name, .strp },
2015 .{ .byte_size, .udata },
2016 .{ .alignment, .udata },
2017 },
2018 },
2019 .access = .{
2020 .tag = .member,
2021 .attrs = &.{
2022 .{ .name, .strp },
2023 },
2024 },
2025 .enum_field = .{
2026 .tag = .enumerator,
2027 .attrs = &.{
2028 .{ .const_value, .indirect },
2029 .{ .name, .strp },
2030 },
2031 },
2032 .generated_field = .{
2033 .tag = .member,
2034 .attrs = &.{
2035 .{ .name, .strp },
2036 .{ .type, .ref_addr },
2037 .{ .data_member_location, .udata },
2038 .{ .artificial, .flag_present },
2039 },
2040 },
2041 .field = .{
2042 .tag = .member,
2043 .attrs = &.{
2044 .{ .name, .strp },
2045 .{ .type, .ref_addr },
2046 .{ .data_member_location, .udata },
2047 .{ .alignment, .udata },
2048 },
2049 },
2050 .field_default_runtime_bits = .{
2051 .tag = .member,
2052 .attrs = &.{
2053 .{ .name, .strp },
2054 .{ .type, .ref_addr },
2055 .{ .data_member_location, .udata },
2056 .{ .alignment, .udata },
2057 .{ .default_value, .block },
2058 },
2059 },
2060 .field_default_comptime_state = .{
2061 .tag = .member,
2062 .attrs = &.{
2063 .{ .name, .strp },
2064 .{ .type, .ref_addr },
2065 .{ .data_member_location, .udata },
2066 .{ .alignment, .udata },
2067 .{ .ZIG_comptime_value, .ref_addr },
2068 },
2069 },
2070 .field_comptime = .{
2071 .tag = .member,
2072 .attrs = &.{
2073 .{ .const_expr, .flag_present },
2074 .{ .name, .strp },
2075 .{ .type, .ref_addr },
2076 },
2077 },
2078 .field_comptime_runtime_bits = .{
2079 .tag = .member,
2080 .attrs = &.{
2081 .{ .const_expr, .flag_present },
2082 .{ .name, .strp },
2083 .{ .type, .ref_addr },
2084 .{ .const_value, .block },
2085 },
2086 },
2087 .field_comptime_comptime_state = .{
2088 .tag = .member,
2089 .attrs = &.{
2090 .{ .const_expr, .flag_present },
2091 .{ .name, .strp },
2092 .{ .type, .ref_addr },
2093 .{ .ZIG_comptime_value, .ref_addr },
2094 },
2095 },
2096 .packed_field = .{
2097 .tag = .member,
2098 .attrs = &.{
2099 .{ .name, .strp },
2100 .{ .type, .ref_addr },
2101 .{ .data_bit_offset, .udata },
2102 },
2103 },
2104 .tagged_union = .{
2105 .tag = .variant_part,
2106 .children = true,
2107 .attrs = &.{
2108 .{ .discr, .ref_addr },
2109 },
2110 },
2111 .tagged_union_field = .{
2112 .tag = .variant,
2113 .children = true,
2114 .attrs = &.{
2115 .{ .discr_value, .indirect },
2116 },
2117 },
2118 .tagged_union_default_field = .{
2119 .tag = .variant,
2120 .children = true,
2121 },
2122 .void_type = .{
2123 .tag = .unspecified_type,
2124 .attrs = &.{
2125 .{ .name, .strp },
2126 },
2127 },
2128 .numeric_type = .{
2129 .tag = .base_type,
2130 .attrs = &.{
2131 .{ .name, .strp },
2132 .{ .encoding, .data1 },
2133 .{ .bit_size, .udata },
2134 .{ .byte_size, .udata },
2135 .{ .alignment, .udata },
2136 },
2137 },
2138 .inferred_error_set_type = .{
2139 .tag = .typedef,
2140 .attrs = &.{
2141 .{ .name, .strp },
2142 .{ .type, .ref_addr },
2143 },
2144 },
2145 .ptr_type = .{
2146 .tag = .pointer_type,
2147 .attrs = &.{
2148 .{ .name, .strp },
2149 .{ .address_class, .data1 },
2150 .{ .type, .ref_addr },
2151 },
2152 },
2153 .ptr_sentinel_type = .{
2154 .tag = .pointer_type,
2155 .attrs = &.{
2156 .{ .name, .strp },
2157 .{ .ZIG_sentinel, .block },
2158 .{ .address_class, .data1 },
2159 .{ .type, .ref_addr },
2160 },
2161 },
2162 .ptr_aligned_type = .{
2163 .tag = .pointer_type,
2164 .attrs = &.{
2165 .{ .name, .strp },
2166 .{ .alignment, .udata },
2167 .{ .address_class, .data1 },
2168 .{ .type, .ref_addr },
2169 },
2170 },
2171 .ptr_aligned_sentinel_type = .{
2172 .tag = .pointer_type,
2173 .attrs = &.{
2174 .{ .name, .strp },
2175 .{ .ZIG_sentinel, .block },
2176 .{ .alignment, .udata },
2177 .{ .address_class, .data1 },
2178 .{ .type, .ref_addr },
2179 },
2180 },
2181 .is_const = .{
2182 .tag = .const_type,
2183 .attrs = &.{
2184 .{ .type, .ref_addr },
2185 },
2186 },
2187 .is_volatile = .{
2188 .tag = .volatile_type,
2189 .attrs = &.{
2190 .{ .type, .ref_addr },
2191 },
2192 },
2193 .array_type = .{
2194 .tag = .array_type,
2195 .children = true,
2196 .attrs = &.{
2197 .{ .name, .strp },
2198 .{ .type, .ref_addr },
2199 },
2200 },
2201 .array_sentinel_type = .{
2202 .tag = .array_type,
2203 .children = true,
2204 .attrs = &.{
2205 .{ .name, .strp },
2206 .{ .ZIG_sentinel, .block },
2207 .{ .type, .ref_addr },
2208 },
2209 },
2210 .vector_type = .{
2211 .tag = .array_type,
2212 .children = true,
2213 .attrs = &.{
2214 .{ .name, .strp },
2215 .{ .type, .ref_addr },
2216 .{ .GNU_vector, .flag_present },
2217 },
2218 },
2219 .array_index = .{
2220 .tag = .subrange_type,
2221 .attrs = &.{
2222 .{ .lower_bound, .udata },
2223 },
2224 },
2225 .array_len = .{
2226 .tag = .subrange_type,
2227 .attrs = &.{
2228 .{ .type, .ref_addr },
2229 .{ .count, .udata },
2230 },
2231 },
2232 .nullary_func_type = .{
2233 .tag = .subroutine_type,
2234 .attrs = &.{
2235 .{ .name, .strp },
2236 .{ .calling_convention, .data1 },
2237 .{ .type, .ref_addr },
2238 },
2239 },
2240 .func_type = .{
2241 .tag = .subroutine_type,
2242 .children = true,
2243 .attrs = &.{
2244 .{ .name, .strp },
2245 .{ .calling_convention, .data1 },
2246 .{ .type, .ref_addr },
2247 },
2248 },
2249 .func_type_param = .{
2250 .tag = .formal_parameter,
2251 .attrs = &.{
2252 .{ .type, .ref_addr },
2253 },
2254 },
2255 .is_var_args = .{
2256 .tag = .unspecified_parameters,
2257 },
2258 .generated_empty_enum_type = .{
2259 .tag = .enumeration_type,
2260 .attrs = &.{
2261 .{ .name, .strp },
2262 .{ .type, .ref_addr },
2263 },
2264 },
2265 .generated_enum_type = .{
2266 .tag = .enumeration_type,
2267 .children = true,
2268 .attrs = &.{
2269 .{ .name, .strp },
2270 .{ .type, .ref_addr },
2271 },
2272 },
2273 .generated_empty_struct_type = .{
2274 .tag = .structure_type,
2275 .attrs = &.{
2276 .{ .name, .strp },
2277 .{ .declaration, .flag },
2278 },
2279 },
2280 .generated_struct_type = .{
2281 .tag = .structure_type,
2282 .children = true,
2283 .attrs = &.{
2284 .{ .name, .strp },
2285 .{ .byte_size, .udata },
2286 .{ .alignment, .udata },
2287 },
2288 },
2289 .generated_union_type = .{
2290 .tag = .union_type,
2291 .children = true,
2292 .attrs = &.{
2293 .{ .name, .strp },
2294 .{ .byte_size, .udata },
2295 .{ .alignment, .udata },
2296 },
2297 },
2298 .empty_enum_type = .{
2299 .tag = .enumeration_type,
2300 .attrs = &.{
2301 .{ .decl_file, .udata },
2302 .{ .name, .strp },
2303 .{ .type, .ref_addr },
2304 },
2305 },
2306 .enum_type = .{
2307 .tag = .enumeration_type,
2308 .children = true,
2309 .attrs = &.{
2310 .{ .decl_file, .udata },
2311 .{ .name, .strp },
2312 .{ .type, .ref_addr },
2313 },
2314 },
2315 .empty_struct_type = .{
2316 .tag = .structure_type,
2317 .attrs = &.{
2318 .{ .decl_file, .udata },
2319 .{ .name, .strp },
2320 .{ .declaration, .flag },
2321 },
2322 },
2323 .struct_type = .{
2324 .tag = .structure_type,
2325 .children = true,
2326 .attrs = &.{
2327 .{ .decl_file, .udata },
2328 .{ .name, .strp },
2329 .{ .byte_size, .udata },
2330 .{ .alignment, .udata },
2331 },
2332 },
2333 .empty_packed_struct_type = .{
2334 .tag = .structure_type,
2335 .attrs = &.{
2336 .{ .decl_file, .udata },
2337 .{ .name, .strp },
2338 .{ .type, .ref_addr },
2339 },
2340 },
2341 .packed_struct_type = .{
2342 .tag = .structure_type,
2343 .children = true,
2344 .attrs = &.{
2345 .{ .decl_file, .udata },
2346 .{ .name, .strp },
2347 .{ .type, .ref_addr },
2348 },
2349 },
2350 .empty_union_type = .{
2351 .tag = .union_type,
2352 .attrs = &.{
2353 .{ .decl_file, .udata },
2354 .{ .name, .strp },
2355 .{ .byte_size, .udata },
2356 .{ .alignment, .udata },
2357 },
2358 },
2359 .union_type = .{
2360 .tag = .union_type,
2361 .children = true,
2362 .attrs = &.{
2363 .{ .decl_file, .udata },
2364 .{ .name, .strp },
2365 .{ .byte_size, .udata },
2366 .{ .alignment, .udata },
2367 },
2368 },
2369 .empty_packed_union_type = .{
2370 .tag = .union_type,
2371 .attrs = &.{
2372 .{ .decl_file, .udata },
2373 .{ .name, .strp },
2374 .{ .type, .ref_addr },
2375 },
2376 },
2377 .packed_union_type = .{
2378 .tag = .union_type,
2379 .children = true,
2380 .attrs = &.{
2381 .{ .decl_file, .udata },
2382 .{ .name, .strp },
2383 .{ .type, .ref_addr },
2384 },
2385 },
2386 .builtin_extern_nullary_func = .{
2387 .tag = .subprogram,
2388 .attrs = &.{
2389 .{ .ZIG_parent, .ref_addr },
2390 .{ .linkage_name, .strp },
2391 .{ .type, .ref_addr },
2392 .{ .low_pc, .addr },
2393 .{ .external, .flag_present },
2394 .{ .noreturn, .flag },
2395 },
2396 },
2397 .builtin_extern_func = .{
2398 .tag = .subprogram,
2399 .children = true,
2400 .attrs = &.{
2401 .{ .ZIG_parent, .ref_addr },
2402 .{ .linkage_name, .strp },
2403 .{ .type, .ref_addr },
2404 .{ .low_pc, .addr },
2405 .{ .external, .flag_present },
2406 .{ .noreturn, .flag },
2407 },
2408 },
2409 .builtin_extern_var = .{
2410 .tag = .variable,
2411 .attrs = &.{
2412 .{ .ZIG_parent, .ref_addr },
2413 .{ .linkage_name, .strp },
2414 .{ .type, .ref_addr },
2415 .{ .location, .exprloc },
2416 .{ .external, .flag_present },
2417 },
2418 },
2419 .empty_block = .{
2420 .tag = .lexical_block,
2421 .attrs = &.{
2422 .{ .low_pc, .addr },
2423 .{ .high_pc, .data4 },
2424 },
2425 },
2426 .block = .{
2427 .tag = .lexical_block,
2428 .children = true,
2429 .attrs = &.{
2430 .{ .low_pc, .addr },
2431 .{ .high_pc, .data4 },
2432 },
2433 },
2434 .empty_inlined_func = .{
2435 .tag = .inlined_subroutine,
2436 .attrs = &.{
2437 .{ .abstract_origin, .ref_addr },
2438 .{ .call_line, .udata },
2439 .{ .call_column, .udata },
2440 .{ .low_pc, .addr },
2441 .{ .high_pc, .data4 },
2442 },
2443 },
2444 .inlined_func = .{
2445 .tag = .inlined_subroutine,
2446 .children = true,
2447 .attrs = &.{
2448 .{ .abstract_origin, .ref_addr },
2449 .{ .call_line, .udata },
2450 .{ .call_column, .udata },
2451 .{ .low_pc, .addr },
2452 .{ .high_pc, .data4 },
2453 },
2454 },
2455 .arg = .{
2456 .tag = .formal_parameter,
2457 .attrs = &.{
2458 .{ .name, .strp },
2459 .{ .type, .ref_addr },
2460 .{ .location, .exprloc },
2461 },
2462 },
2463 .unnamed_arg = .{
2464 .tag = .formal_parameter,
2465 .attrs = &.{
2466 .{ .type, .ref_addr },
2467 .{ .location, .exprloc },
2468 },
2469 },
2470 .comptime_arg = .{
2471 .tag = .formal_parameter,
2472 .attrs = &.{
2473 .{ .const_expr, .flag_present },
2474 .{ .name, .strp },
2475 .{ .type, .ref_addr },
2476 },
2477 },
2478 .unnamed_comptime_arg = .{
2479 .tag = .formal_parameter,
2480 .attrs = &.{
2481 .{ .const_expr, .flag_present },
2482 .{ .type, .ref_addr },
2483 },
2484 },
2485 .comptime_arg_runtime_bits = .{
2486 .tag = .formal_parameter,
2487 .attrs = &.{
2488 .{ .const_expr, .flag_present },
2489 .{ .name, .strp },
2490 .{ .type, .ref_addr },
2491 .{ .const_value, .block },
2492 },
2493 },
2494 .unnamed_comptime_arg_runtime_bits = .{
2495 .tag = .formal_parameter,
2496 .attrs = &.{
2497 .{ .const_expr, .flag_present },
2498 .{ .type, .ref_addr },
2499 .{ .const_value, .block },
2500 },
2501 },
2502 .comptime_arg_comptime_state = .{
2503 .tag = .formal_parameter,
2504 .attrs = &.{
2505 .{ .const_expr, .flag_present },
2506 .{ .name, .strp },
2507 .{ .type, .ref_addr },
2508 .{ .ZIG_comptime_value, .ref_addr },
2509 },
2510 },
2511 .unnamed_comptime_arg_comptime_state = .{
2512 .tag = .formal_parameter,
2513 .attrs = &.{
2514 .{ .const_expr, .flag_present },
2515 .{ .type, .ref_addr },
2516 .{ .ZIG_comptime_value, .ref_addr },
2517 },
2518 },
2519 .comptime_arg_runtime_bits_comptime_state = .{
2520 .tag = .formal_parameter,
2521 .attrs = &.{
2522 .{ .const_expr, .flag_present },
2523 .{ .name, .strp },
2524 .{ .type, .ref_addr },
2525 .{ .const_value, .block },
2526 .{ .ZIG_comptime_value, .ref_addr },
2527 },
2528 },
2529 .unnamed_comptime_arg_runtime_bits_comptime_state = .{
2530 .tag = .formal_parameter,
2531 .attrs = &.{
2532 .{ .const_expr, .flag_present },
2533 .{ .type, .ref_addr },
2534 .{ .const_value, .block },
2535 .{ .ZIG_comptime_value, .ref_addr },
2536 },
2537 },
2538 .extern_param = .{
2539 .tag = .formal_parameter,
2540 .attrs = &.{
2541 .{ .type, .ref_addr },
2542 },
2543 },
2544 .local_var = .{
2545 .tag = .variable,
2546 .attrs = &.{
2547 .{ .name, .strp },
2548 .{ .type, .ref_addr },
2549 .{ .location, .exprloc },
2550 },
2551 },
2552 .local_const = .{
2553 .tag = .constant,
2554 .attrs = &.{
2555 .{ .name, .strp },
2556 .{ .type, .ref_addr },
2557 },
2558 },
2559 .local_const_runtime_bits = .{
2560 .tag = .constant,
2561 .attrs = &.{
2562 .{ .name, .strp },
2563 .{ .type, .ref_addr },
2564 .{ .const_value, .block },
2565 },
2566 },
2567 .local_const_comptime_state = .{
2568 .tag = .constant,
2569 .attrs = &.{
2570 .{ .name, .strp },
2571 .{ .type, .ref_addr },
2572 .{ .ZIG_comptime_value, .ref_addr },
2573 },
2574 },
2575 .local_const_runtime_bits_comptime_state = .{
2576 .tag = .constant,
2577 .attrs = &.{
2578 .{ .name, .strp },
2579 .{ .type, .ref_addr },
2580 .{ .const_value, .block },
2581 .{ .ZIG_comptime_value, .ref_addr },
2582 },
2583 },
2584 .undefined_comptime_value = .{
2585 .tag = .ZIG_comptime_value,
2586 .attrs = &.{
2587 .{ .type, .ref_addr },
2588 },
2589 },
2590 .aggregate_undefined_comptime_value = .{
2591 .tag = .ZIG_comptime_value,
2592 .children = true,
2593 .attrs = &.{
2594 .{ .type, .ref_addr },
2595 },
2596 },
2597 .comptime_value = .{
2598 .tag = .ZIG_comptime_value,
2599 .attrs = &.{
2600 .{ .type, .ref_addr },
2601 .{ .const_value, .indirect },
2602 },
2603 },
2604 .aggregate_comptime_value = .{
2605 .tag = .ZIG_comptime_value,
2606 .children = true,
2607 .attrs = &.{
2608 .{ .type, .ref_addr },
2609 .{ .const_value, .indirect },
2610 },
2611 },
2612 .location_comptime_value = .{
2613 .tag = .ZIG_comptime_value,
2614 .attrs = &.{
2615 .{ .type, .ref_addr },
2616 .{ .location, .exprloc },
2617 },
2618 },
2619 .aggregate_location_comptime_value = .{
2620 .tag = .ZIG_comptime_value,
2621 .children = true,
2622 .attrs = &.{
2623 .{ .type, .ref_addr },
2624 .{ .location, .exprloc },
2625 },
2626 },
2627 .comptime_value_field_runtime_bits = .{
2628 .tag = .member,
2629 .attrs = &.{
2630 .{ .name, .strp },
2631 .{ .const_value, .block },
2632 },
2633 },
2634 .comptime_value_field_comptime_state = .{
2635 .tag = .member,
2636 .attrs = &.{
2637 .{ .name, .strp },
2638 .{ .ZIG_comptime_value, .ref_addr },
2639 },
2640 },
2641 .comptime_value_elem_runtime_bits = .{
2642 .tag = .member,
2643 .attrs = &.{
2644 .{ .const_value, .block },
2645 },
2646 },
2647 .comptime_value_elem_comptime_state = .{
2648 .tag = .member,
2649 .attrs = &.{
2650 .{ .ZIG_comptime_value, .ref_addr },
2651 },
2652 },
2653 .null = undefined,
2654 });
2655};
2656
2657fn uleb128Bytes(value: anytype) u32 {
2658 var buf: [64]u8 = undefined;
2659 var dw: Writer.Discarding = .init(&buf);
2660 dw.writer.writeUleb128(value) catch unreachable;
2661 return @intCast(dw.fullCount());
2662}
2663
2664fn sleb128Bytes(value: anytype) u32 {
2665 var buf: [64]u8 = undefined;
2666 var dw: Writer.Discarding = .init(&buf);
2667 dw.writer.writeSleb128(value) catch unreachable;
2668 return @intCast(dw.fullCount());
2669}
2670
2671const Allocator = std.mem.Allocator;
2672const assert = std.debug.assert;
2673const codegen = @import("../codegen.zig");
2674const dev = @import("../dev.zig");
2675const DW = std.dwarf;
2676const Dwarf = @This();
2677const InternPool = @import("../InternPool.zig");
2678const link = @import("../link.zig");
2679const MappedFile = @import("MappedFile.zig");
2680const Module = @import("../Module.zig");
2681const std = @import("std");
2682const Type = @import("../Type.zig");
2683const Value = @import("../Value.zig");
2684const Writer = std.Io.Writer;
2685const Zcu = @import("../Zcu.zig");
src/link/Elf/ZigObject.zig+11-16
...@@ -946,14 +946,11 @@ pub fn getNavVAddr(...@@ -946,14 +946,11 @@ pub fn getNavVAddr(
946 .r_addend = reloc_info.addend,946 .r_addend = reloc_info.addend,
947 }, self);947 }, self);
948 },948 },
949 .debug_output => |debug_output| switch (debug_output) {949 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
950 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{950 .source_off = @intCast(reloc_info.offset),
951 .source_off = @intCast(reloc_info.offset),951 .target_sym = @fromBackingInt(@intCast(this_sym_index)),
952 .target_sym = @fromBackingInt(@intCast(this_sym_index)),952 .target_off = reloc_info.addend,
953 .target_off = reloc_info.addend,953 }),
954 }),
955 .none => unreachable,
956 },
957 }954 }
958 return @intCast(vaddr);955 return @intCast(vaddr);
959}956}
...@@ -978,14 +975,11 @@ pub fn getUavVAddr(...@@ -978,14 +975,11 @@ pub fn getUavVAddr(
978 .r_addend = reloc_info.addend,975 .r_addend = reloc_info.addend,
979 }, self);976 }, self);
980 },977 },
981 .debug_output => |debug_output| switch (debug_output) {978 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
982 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{979 .source_off = @intCast(reloc_info.offset),
983 .source_off = @intCast(reloc_info.offset),980 .target_sym = @fromBackingInt(@intCast(sym_index)),
984 .target_sym = @fromBackingInt(@intCast(sym_index)),981 .target_off = reloc_info.addend,
985 .target_off = reloc_info.addend,982 }),
986 }),
987 .none => unreachable,
988 },
989 }983 }
990 return @intCast(vaddr);984 return @intCast(vaddr);
991}985}
...@@ -1555,6 +1549,7 @@ pub fn updateFunc(...@@ -1555,6 +1549,7 @@ pub fn updateFunc(
1555 if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,1549 if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,
1556 ) catch |err| switch (err) {1550 ) catch |err| switch (err) {
1557 error.WriteFailed => return error.OutOfMemory,1551 error.WriteFailed => return error.OutOfMemory,
1552 error.MappedFileIo => unreachable, // MappedFile is not being used
1558 else => |e| return e,1553 else => |e| return e,
1559 };1554 };
1560 const code = aw.written();1555 const code = aw.written();
src/link/Elf2.zig+1426-570
...@@ -1,8 +1,5 @@...@@ -1,8 +1,5 @@
1const Elf = @This();1const Elf = @This();
22
3const builtin = @import("builtin");
4const native_endian = builtin.cpu.arch.endian();
5
6const std = @import("std");3const std = @import("std");
7const Io = std.Io;4const Io = std.Io;
8const assert = std.debug.assert;5const assert = std.debug.assert;
...@@ -10,6 +7,8 @@ const log = std.log.scoped(.link);...@@ -10,6 +7,8 @@ const log = std.log.scoped(.link);
107
11const codegen = @import("../codegen.zig");8const codegen = @import("../codegen.zig");
12const Compilation = @import("../Compilation.zig");9const Compilation = @import("../Compilation.zig");
10const dev = @import("../dev.zig");
11const Dwarf = @import("Dwarf2.zig");
13const InternPool = @import("../InternPool.zig");12const InternPool = @import("../InternPool.zig");
14const link = @import("../link.zig");13const link = @import("../link.zig");
15const MappedFile = @import("MappedFile.zig");14const MappedFile = @import("MappedFile.zig");
...@@ -43,6 +42,11 @@ shndx: struct {...@@ -43,6 +42,11 @@ shndx: struct {
43 tdata: Section.Index,42 tdata: Section.Index,
44 rela_dyn: Section.Index,43 rela_dyn: Section.Index,
45 rela_plt: Section.Index,44 rela_plt: Section.Index,
45 eh_frame_hdr: Section.Index,
46 eh_frame: Section.Index,
47 debug_frame: Section.Index,
48 debug_info: Section.Index,
49 debug_line: Section.Index,
46 // These sections are created only as needed, and are initially `.UNDEF`.50 // These sections are created only as needed, and are initially `.UNDEF`.
47 init_array: Section.Index,51 init_array: Section.Index,
48 fini_array: Section.Index,52 fini_array: Section.Index,
...@@ -123,6 +127,8 @@ got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional),...@@ -123,6 +127,8 @@ got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional),
123plt: std.array_hash_map.Auto(String(.strtab), void),127plt: std.array_hash_map.Auto(String(.strtab), void),
124/// The `.plt` section contains zero or more symbol relocations starting at this index.128/// The `.plt` section contains zero or more symbol relocations starting at this index.
125plt_first_symbol_reloc: SymbolReloc.Index,129plt_first_symbol_reloc: SymbolReloc.Index,
130/// The `.eh_frame_hdr` section contains zero or more symbol relocations starting at this index.
131eh_frame_hdr_first_symbol_reloc: SymbolReloc.Index,
126132
127needed: std.array_hash_map.Auto(String(.dynstr), void),133needed: std.array_hash_map.Auto(String(.dynstr), void),
128inputs: std.ArrayList(struct {134inputs: std.ArrayList(struct {
...@@ -175,9 +181,10 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {...@@ -175,9 +181,10 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {
175}),181}),
176pending_uavs: std.ArrayList(Node.UavMapIndex),182pending_uavs: std.ArrayList(Node.UavMapIndex),
177symbol_relocs: std.ArrayList(SymbolReloc),183symbol_relocs: std.ArrayList(SymbolReloc),
178got_relocs: std.ArrayList(GotReloc),
179/// Set of relocations which must be re-applied if the size of the TLS segment changes.184/// Set of relocations which must be re-applied if the size of the TLS segment changes.
180tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),185tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),
186node_relocs: std.ArrayList(NodeReloc),
187got_relocs: std.ArrayList(GotReloc),
181/// Index matches the index into `shdrs`. Like `shdrs`, this map excludes `SHN_UNDEF`.188/// Index matches the index into `shdrs`. Like `shdrs`, this map excludes `SHN_UNDEF`.
182section_by_name: std.array_hash_map.Auto(String(.shstrtab), void),189section_by_name: std.array_hash_map.Auto(String(.shstrtab), void),
183/// Key is the name of a global symbol which has been moved to a new symtab index. Any relocation190/// Key is the name of a global symbol which has been moved to a new symtab index. Any relocation
...@@ -191,6 +198,17 @@ changed_symtab_index: std.array_hash_map.Auto(String(.strtab), void),...@@ -191,6 +198,17 @@ changed_symtab_index: std.array_hash_map.Auto(String(.strtab), void),
191/// section in `flush` only when it is actually necessary. See also `nodeWantsDsoRelocation`.198/// section in `flush` only when it is actually necessary. See also `nodeWantsDsoRelocation`.
192textrel_count: u32,199textrel_count: u32,
193200
201dwarf: Dwarf,
202dwarf_units: std.ArrayList(struct {
203 unit_frame_cie_first_target_reloc: NodeReloc.Index,
204}),
205dwarf_values: std.ArrayList(struct {}),
206dwarf_globals: std.ArrayList(struct {}),
207dwarf_funcs: std.ArrayList(struct {
208 func_frame_fde_first_symbol_reloc: SymbolReloc.Index,
209 func_frame_fde_first_node_reloc: NodeReloc.Index,
210}),
211
194overflowed_reloc_count: u32,212overflowed_reloc_count: u32,
195misaligned_reloc_count: u32,213misaligned_reloc_count: u32,
196214
...@@ -232,8 +250,9 @@ const Node = union(enum) {...@@ -232,8 +250,9 @@ const Node = union(enum) {
232 ehdr,250 ehdr,
233 shdr,251 shdr,
234 segment: u32,252 segment: u32,
235 /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`.
236 section: Section.Index,253 section: Section.Index,
254 /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`.
255 section_manual_size: Section.Index,
237 /// May contain relocations.256 /// May contain relocations.
238 input_section: InputSection.Index,257 input_section: InputSection.Index,
239 /// Value is the name of a global which has an entry in `elf.copied_globals`, so, a global for258 /// Value is the name of a global which has an entry in `elf.copied_globals`, so, a global for
...@@ -253,6 +272,15 @@ const Node = union(enum) {...@@ -253,6 +272,15 @@ const Node = union(enum) {
253 /// May contain relocations.272 /// May contain relocations.
254 lazy_const_data: LazyMapRef.Index(.const_data),273 lazy_const_data: LazyMapRef.Index(.const_data),
255274
275 value_debug_info: link.ConstPool.Index,
276 global_debug_info: Dwarf.Global.Index,
277 frame_padding,
278 unit_frame: Dwarf.Unit.Index,
279 unit_frame_cie: Dwarf.Unit.Index,
280 func_frame_fde: Dwarf.Func.Index,
281 func_debug_info: Dwarf.Func.Index,
282 func_debug_line: Dwarf.Func.Index,
283
256 pub const InputIndex = enum(u32) {284 pub const InputIndex = enum(u32) {
257 _,285 _,
258286
...@@ -373,6 +401,7 @@ const Node = union(enum) {...@@ -373,6 +401,7 @@ const Node = union(enum) {
373 data: MappedFile.Node.Index,401 data: MappedFile.Node.Index,
374 data_rel_ro: MappedFile.Node.Index,402 data_rel_ro: MappedFile.Node.Index,
375 tls: MappedFile.Node.Index.Optional,403 tls: MappedFile.Node.Index.Optional,
404 gnu_eh_frame: MappedFile.Node.Index.Optional,
376 };405 };
377406
378 comptime {407 comptime {
...@@ -649,7 +678,7 @@ const Section = struct {...@@ -649,7 +678,7 @@ const Section = struct {
649 },678 },
650 .addend = @intCast(old_free_len + 1), // list length679 .addend = @intCast(old_free_len + 1), // list length
651 };680 };
652 if (elf.targetEndian() != native_endian) {681 if (elf.targetEndian() != std.lang.Endian.native) {
653 std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(index)]);682 std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(index)]);
654 }683 }
655 },684 },
...@@ -708,7 +737,7 @@ const Section = struct {...@@ -708,7 +737,7 @@ const Section = struct {
708 },737 },
709 .addend = @intCast(opts.addend),738 .addend = @intCast(opts.addend),
710 };739 };
711 if (elf.targetEndian() != native_endian) {740 if (elf.targetEndian() != std.lang.Endian.native) {
712 std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(new_index)]);741 std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(new_index)]);
713 }742 }
714 return new_index;743 return new_index;
...@@ -807,244 +836,13 @@ const Section = struct {...@@ -807,244 +836,13 @@ const Section = struct {
807 },836 },
808 }837 }
809 }838 }
810 };
811};
812
813/// Identifies a single entry in the GOT.
814const GotKey = union(enum) {
815 /// The entry is a reserved word, initialized to zero. `initHeaders` will add as many of these
816 /// as the target machine ABI requires.
817 ///
818 /// This `u32` value exists to allow reserving multiple words with distinct keys.
819 reserved: u32,
820
821 /// Value is the address of the given symbol.
822 symbol: Symbol.Id,
823
824 /// Value is the signed offset of the given symbol from the TLS pointer.
825 tpoff: Symbol.Id,
826
827 /// Value is the TLS module ID of the DSO we are creating.
828 ///
829 /// Used for the first of the two GOT entries generated by a TLSLD relocation.
830 tlsld0,
831 /// Value is always 0.
832 ///
833 /// Used for the second of the two GOT entries generated by a TLSLD relocation.
834 tlsld1,
835
836 /// Value is the TLS module ID for the given STT_TLS symbol.
837 ///
838 /// Used for the first of the two GOT entries generated by a TLSGD relocation.
839 tlsgd0: Symbol.Id,
840 /// Value is the offset of the given STT_TLS symbol from the base of the per-module TLS area.
841 ///
842 /// Used for the second of the two GOT entries generated by a TLSGD relocation.
843 tlsgd1: Symbol.Id,
844};
845
846/// A relocation targeting a particular GOT entry.
847const GotReloc = struct {
848 /// The node containing this relocation. Possible values are:
849 /// * An input section
850 /// * A section
851 /// * A NAV, UAV, or lazy code/data
852 /// * `.none`, if this relocation was deleted (in which case it should be ignored)
853 node: MappedFile.Node.Index.Optional,
854 /// The offset of the relocation inside of `node`.
855 offset: u64,
856 target: GotKey,
857 addend: i64,
858 type: GotReloc.Type,
859 result: enum(u8) { ok, overflowed, misaligned },
860
861 /// `GotReloc.Type` has the same structure as `SymbolReloc.Type`, just with different `Target`
862 /// and `Special` enums---consult doc comments on `SymbolReloc.Type` for an overview.
863 const Type = packed struct(u16) {
864 fn simple(target: Target, action: Simple) GotReloc.Type {
865 assert(target != .special);
866 return .{ .target = target, .action = .{ .simple = action } };
867 }
868
869 fn special(s: Special) GotReloc.Type {
870 return .{ .target = .special, .action = .{ .special = s } };
871 }
872
873 target: Target,
874 action: packed union {
875 simple: Simple,
876 special: Special,
877 },
878
879 /// Like `SymbolReloc.Target`, but for GOT relocations. There are fewer tags because there
880 /// are fewer different kinds of GOT relocation.
881 const Target = enum(u3) {
882 /// This is a "special" relocation whose specific type is in the `action.special` field.
883 special,
884
885 /// Absolute address of the GOT entry.
886 abs,
887 /// Offset from the relocation itself to the GOT entry ("PC-relative").
888 rel,
889 /// Offset from the base of the GOT to the GOT entry.
890 offset,
891 };
892
893 const Simple = SymbolReloc.Type.Simple;
894
895 /// Like `SymbolReloc.Special`, but for GOT relocations.
896 const Special = enum(u13) {
897 larch_pcala_hi20,
898 larch_pcala64_lo20,
899 larch_pcala64_hi12,
900
901 sparc_op_lox10,
902 sparc_op_hix22,
903
904 fn applyInner(
905 s: Special,
906 elf: *Elf,
907 got_vaddr: u64,
908 got_offset: u64,
909 addend: u64,
910 dest_vaddr: u64,
911 dest_slice: []u8,
912 ) error{ RelocationMisaligned, RelocationOverflow }!void {
913 switch (s) {
914 .larch_pcala_hi20 => {
915 const val = got_vaddr +% got_offset +% addend;
916 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
917 elf.targetStore(inst, .{
918 .b0_4 = elf.targetLoad(inst).b0_4,
919 .j20 = link.loongarch.pcalaHi20(val, dest_vaddr),
920 .b25_31 = elf.targetLoad(inst).b25_31,
921 });
922 },
923 .larch_pcala64_lo20 => {
924 const val = got_vaddr +% got_offset +% addend;
925 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
926 elf.targetStore(inst, .{
927 .b0_4 = elf.targetLoad(inst).b0_4,
928 .j20 = link.loongarch.pcala64Lo20(val, dest_vaddr),
929 .b25_31 = elf.targetLoad(inst).b25_31,
930 });
931 },
932 .larch_pcala64_hi12 => {
933 const val = got_vaddr +% got_offset +% addend;
934 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
935 elf.targetStore(inst, .{
936 .b0_9 = elf.targetLoad(inst).b0_9,
937 .k12 = link.loongarch.pcala64Hi12(val, dest_vaddr),
938 .b22_31 = elf.targetLoad(inst).b22_31,
939 });
940 },
941 .sparc_op_lox10 => {
942 const dest_ptr: *align(1) packed struct(u32) {
943 imm13: u13,
944 b13_31: u19,
945 } = @ptrCast(dest_slice);
946 elf.targetStore(dest_ptr, .{
947 .imm13 = @as(u10, @truncate(got_offset)),
948 .b13_31 = elf.targetLoad(dest_ptr).b13_31,
949 });
950 },
951 .sparc_op_hix22 => {
952 const dest_ptr: *align(1) packed struct(u32) {
953 imm22: u22,
954 b22_31: u10,
955 } = @ptrCast(dest_slice);
956 elf.targetStore(dest_ptr, .{
957 .imm22 = @truncate(got_offset >> 10),
958 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
959 });
960 },
961 }
962 }
963 };
964 };
965
966 const Index = enum(u32) {
967 none = std.math.maxInt(u32),
968 _,
969839
970 fn get(index: GotReloc.Index, elf: *Elf) *GotReloc {840 fn debugFrameFormat(shndx: Index, elf: *Elf) ?Dwarf.Frame.Format {
971 return &elf.got_relocs.items[@backingInt(index)];841 if (shndx == elf.shndx.eh_frame) return .eh_frame;
842 if (shndx == elf.shndx.debug_frame) return .debug_frame;
843 return null;
972 }844 }
973 };845 };
974
975 fn apply(reloc: *GotReloc, elf: *Elf) void {
976 assert(elf.ehdrType() != .REL);
977 const node = reloc.node.unwrap() orelse {
978 return; // deleted
979 };
980 if (node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) {
981 // There's no point applying the relocation now, because it will be re-applied by
982 // `flushMoved` at some point anyway.
983 return;
984 }
985 switch (reloc.result) {
986 .ok => {},
987 .overflowed => elf.overflowed_reloc_count -= 1,
988 .misaligned => elf.misaligned_reloc_count -= 1,
989 }
990 if (reloc.applyInner(elf)) {
991 @branchHint(.likely);
992 reloc.result = .ok;
993 } else |err| switch (err) {
994 error.RelocationOverflow => {
995 reloc.result = .overflowed;
996 elf.overflowed_reloc_count += 1;
997 },
998 error.RelocationMisaligned => {
999 reloc.result = .misaligned;
1000 elf.misaligned_reloc_count += 1;
1001 },
1002 }
1003 }
1004 fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
1005 const node = reloc.node.unwrap().?;
1006 const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset;
1007 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
1008
1009 const got_vaddr = elf.shndx.got.vaddr(elf);
1010 const got_index: u64 = elf.got.getIndex(reloc.target).?;
1011 const got_offset: u64 = switch (elf.identClass()) {
1012 .NONE, _ => unreachable,
1013 inline else => |class| @sizeOf(class.ElfN().Addr) * got_index,
1014 };
1015 const addend: u64 = @bitCast(reloc.addend);
1016
1017 const target_val: u64 = switch (reloc.type.target) {
1018 .abs => got_vaddr +% got_offset +% addend,
1019 .rel => got_vaddr +% got_offset +% addend -% dest_vaddr,
1020 .offset => got_offset +% addend,
1021 .special => return reloc.type.action.special.applyInner(
1022 elf,
1023 got_vaddr,
1024 got_offset,
1025 addend,
1026 dest_vaddr,
1027 dest_slice,
1028 ),
1029 };
1030 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
1031 }
1032
1033 fn delete(reloc: *GotReloc, elf: *Elf) void {
1034 switch (reloc.result) {
1035 .ok => {},
1036 .overflowed => elf.overflowed_reloc_count -= 1,
1037 .misaligned => elf.misaligned_reloc_count -= 1,
1038 }
1039 reloc.* = .{
1040 .node = .none,
1041 .offset = undefined,
1042 .target = undefined,
1043 .addend = undefined,
1044 .type = undefined,
1045 .result = undefined,
1046 };
1047 }
1048};846};
1049847
1050pub const MachineRelocType = union {848pub const MachineRelocType = union {
...@@ -1118,51 +916,144 @@ pub const MachineRelocType = union {...@@ -1118,51 +916,144 @@ pub const MachineRelocType = union {
1118 pub fn globDat(elf: *const Elf) MachineRelocType {916 pub fn globDat(elf: *const Elf) MachineRelocType {
1119 return switch (elf.ehdrMachine()) {917 return switch (elf.ehdrMachine()) {
1120 .AARCH64 => .{ .AARCH64 = .GLOB_DAT },918 .AARCH64 => .{ .AARCH64 = .GLOB_DAT },
1121 .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },919 .LOONGARCH => .{ .LARCH = switch (elf.identClass()) {
920 .NONE, _ => unreachable,
921 .@"32" => .@"32",
922 .@"64" => .@"64",
923 } },
1122 .PPC64 => .{ .PPC64 = .GLOB_DAT },924 .PPC64 => .{ .PPC64 = .GLOB_DAT },
1123 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" },925 .RISCV => .{ .RISCV = switch (elf.identClass()) {
926 .NONE, _ => unreachable,
927 .@"32" => .@"32",
928 .@"64" => .@"64",
929 } },
1124 .SPARCV9 => .{ .SPARC = .GLOB_DAT },930 .SPARCV9 => .{ .SPARC = .GLOB_DAT },
1125 .X86_64 => .{ .X86_64 = .GLOB_DAT },931 .X86_64 => .{ .X86_64 = .GLOB_DAT },
1126 };932 };
1127 }933 }
1128 pub fn dtpMod(elf: *const Elf) MachineRelocType {934 pub fn dtpMod(elf: *const Elf) MachineRelocType {
1129 return switch (elf.ehdrMachine()) {935 return switch (elf.ehdrMachine()) {
1130 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .TLS_DTPMOD else .P32_TLS_DTPMOD },936 .AARCH64 => .{ .AARCH64 = switch (elf.identClass()) {
1131 .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },937 .NONE, _ => unreachable,
938 .@"32" => .P32_TLS_DTPMOD,
939 .@"64" => .TLS_DTPMOD,
940 } },
941 .LOONGARCH => .{ .LARCH = switch (elf.identClass()) {
942 .NONE, _ => unreachable,
943 .@"32" => .TLS_DTPMOD32,
944 .@"64" => .TLS_DTPMOD64,
945 } },
1132 .PPC64 => .{ .PPC64 = .DTPMOD64 },946 .PPC64 => .{ .PPC64 = .DTPMOD64 },
1133 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },947 .RISCV => .{ .RISCV = switch (elf.identClass()) {
1134 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },948 .NONE, _ => unreachable,
949 .@"32" => .TLS_DTPMOD32,
950 .@"64" => .TLS_DTPMOD64,
951 } },
952 .SPARCV9 => .{ .SPARC = switch (elf.identClass()) {
953 .NONE, _ => unreachable,
954 .@"32" => .TLS_DTPMOD32,
955 .@"64" => .TLS_DTPMOD64,
956 } },
1135 .X86_64 => .{ .X86_64 = .DTPMOD64 },957 .X86_64 => .{ .X86_64 = .DTPMOD64 },
1136 };958 };
1137 }959 }
1138 pub fn dtpOff(elf: *const Elf) MachineRelocType {960 pub fn dtpOff(elf: *const Elf) MachineRelocType {
1139 return switch (elf.ehdrMachine()) {961 return switch (elf.ehdrMachine()) {
1140 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .TLS_DTPREL else .P32_TLS_DTPREL },962 .AARCH64 => .{ .AARCH64 = switch (elf.identClass()) {
1141 .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 },963 .NONE, _ => unreachable,
964 .@"32" => .P32_TLS_DTPREL,
965 .@"64" => .TLS_DTPREL,
966 } },
967 .LOONGARCH => .{ .LARCH = switch (elf.identClass()) {
968 .NONE, _ => unreachable,
969 .@"32" => .TLS_DTPREL32,
970 .@"64" => .TLS_DTPREL64,
971 } },
1142 .PPC64 => .{ .PPC64 = .DTPREL64 },972 .PPC64 => .{ .PPC64 = .DTPREL64 },
1143 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 },973 .RISCV => .{ .RISCV = switch (elf.identClass()) {
1144 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPOFF64 else .TLS_DTPOFF32 },974 .NONE, _ => unreachable,
975 .@"32" => .TLS_DTPREL32,
976 .@"64" => .TLS_DTPREL64,
977 } },
978 .SPARCV9 => .{ .SPARC = switch (elf.identClass()) {
979 .NONE, _ => unreachable,
980 .@"32" => .TLS_DTPOFF32,
981 .@"64" => .TLS_DTPOFF64,
982 } },
1145 .X86_64 => .{ .X86_64 = .DTPOFF64 },983 .X86_64 => .{ .X86_64 = .DTPOFF64 },
1146 };984 };
1147 }985 }
1148 pub fn tpOff(elf: *const Elf) MachineRelocType {986 pub fn tpOff(elf: *const Elf) MachineRelocType {
1149 return switch (elf.ehdrMachine()) {987 return switch (elf.ehdrMachine()) {
1150 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .TLS_TPREL else .P32_TLS_TPREL },988 .AARCH64 => .{ .AARCH64 = switch (elf.identClass()) {
1151 .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 },989 .NONE, _ => unreachable,
990 .@"32" => .P32_TLS_TPREL,
991 .@"64" => .TLS_TPREL,
992 } },
993 .LOONGARCH => .{ .LARCH = switch (elf.identClass()) {
994 .NONE, _ => unreachable,
995 .@"32" => .TLS_TPREL32,
996 .@"64" => .TLS_TPREL64,
997 } },
1152 .PPC64 => .{ .PPC64 = .TPREL64 },998 .PPC64 => .{ .PPC64 = .TPREL64 },
1153 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 },999 .RISCV => .{ .RISCV = switch (elf.identClass()) {
1154 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_TPOFF64 else .TLS_TPOFF32 },1000 .NONE, _ => unreachable,
1001 .@"32" => .TLS_TPREL32,
1002 .@"64" => .TLS_TPREL64,
1003 } },
1004 .SPARCV9 => .{ .SPARC = switch (elf.identClass()) {
1005 .NONE, _ => unreachable,
1006 .@"32" => .TLS_TPOFF32,
1007 .@"64" => .TLS_TPOFF64,
1008 } },
1155 .X86_64 => .{ .X86_64 = .TPOFF64 },1009 .X86_64 => .{ .X86_64 = .TPOFF64 },
1156 };1010 };
1157 }1011 }
1158 pub fn absAddr(elf: *const Elf) MachineRelocType {1012 pub fn absAddr(elf: *const Elf) MachineRelocType {
1013 return switch (elf.identClass()) {
1014 .NONE, _ => unreachable,
1015 .@"32" => .abs32(elf),
1016 .@"64" => .abs64(elf),
1017 };
1018 }
1019 pub fn abs32(elf: *const Elf) MachineRelocType {
1159 return switch (elf.ehdrMachine()) {1020 return switch (elf.ehdrMachine()) {
1160 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .ABS64 else .P32_ABS32 },1021 .AARCH64 => .{ .AARCH64 = .P32_ABS32 },
1161 .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },1022 .LOONGARCH => .{ .LARCH = .@"32" },
1023 .PPC64 => .{ .PPC64 = .ADDR32 },
1024 .RISCV => .{ .RISCV = .@"32" },
1025 .SPARCV9 => .{ .SPARC = .@"32" },
1026 .X86_64 => .{ .X86_64 = .@"32" },
1027 };
1028 }
1029 pub fn abs64(elf: *const Elf) MachineRelocType {
1030 return switch (elf.ehdrMachine()) {
1031 .AARCH64 => .{ .AARCH64 = .ABS64 },
1032 .LOONGARCH => .{ .LARCH = .@"64" },
1162 .PPC64 => .{ .PPC64 = .ADDR64 },1033 .PPC64 => .{ .PPC64 = .ADDR64 },
1163 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" },1034 .RISCV => .{ .RISCV = .@"64" },
1164 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .@"64" else .@"32" },1035 .SPARCV9 => .{ .SPARC = .@"64" },
1165 .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .@"64" else .@"32" },1036 .X86_64 => .{ .X86_64 = .@"64" },
1037 };
1038 }
1039 pub fn rel32(elf: *const Elf) MachineRelocType {
1040 return switch (elf.ehdrMachine()) {
1041 .AARCH64 => .{ .AARCH64 = .PREL32 },
1042 .LOONGARCH => .{ .LARCH = .@"32_PCREL" },
1043 .PPC64 => .{ .PPC64 = .REL32 },
1044 .RISCV => .{ .RISCV = .@"32_PCREL" },
1045 .SPARCV9 => .{ .SPARC = .DISP32 },
1046 .X86_64 => .{ .X86_64 = .PC32 },
1047 };
1048 }
1049 pub fn rel64(elf: *const Elf) MachineRelocType {
1050 return switch (elf.ehdrMachine()) {
1051 .AARCH64 => .{ .AARCH64 = .PREL64 },
1052 .LOONGARCH => unreachable,
1053 .PPC64 => .{ .PPC64 = .REL64 },
1054 .RISCV => unreachable,
1055 .SPARCV9 => .{ .SPARC = .DISP64 },
1056 .X86_64 => .{ .X86_64 = .PC64 },
1166 };1057 };
1167 }1058 }
1168 pub fn size32(elf: *const Elf) ?MachineRelocType {1059 pub fn size32(elf: *const Elf) ?MachineRelocType {
...@@ -1265,15 +1156,6 @@ const SymbolReloc = struct {...@@ -1265,15 +1156,6 @@ const SymbolReloc = struct {
1265 return shndx;1156 return shndx;
1266 }1157 }
12671158
1268 const Index = enum(u32) {
1269 none = std.math.maxInt(u32),
1270 _,
1271
1272 fn get(index: SymbolReloc.Index, elf: *Elf) *SymbolReloc {
1273 return &elf.symbol_relocs.items[@backingInt(index)];
1274 }
1275 };
1276
1277 /// Instead of using the ELF relocation enums, we have our own internal representation for1159 /// Instead of using the ELF relocation enums, we have our own internal representation for
1278 /// relocation types. This representation is more compact (requiring only 16 bits), and allows1160 /// relocation types. This representation is more compact (requiring only 16 bits), and allows
1279 /// sharing a lot of relocation handling between multiple relocs and target architectures.1161 /// sharing a lot of relocation handling between multiple relocs and target architectures.
...@@ -1679,9 +1561,417 @@ const SymbolReloc = struct {...@@ -1679,9 +1561,417 @@ const SymbolReloc = struct {
1679 }1561 }
1680 };1562 };
16811563
1564 const Index = enum(u32) {
1565 none = std.math.maxInt(u32),
1566 _,
1567
1568 fn get(index: SymbolReloc.Index, elf: *Elf) *SymbolReloc {
1569 return &elf.symbol_relocs.items[@backingInt(index)];
1570 }
1571 };
1572
1682 fn apply(reloc: *SymbolReloc, elf: *Elf) void {1573 fn apply(reloc: *SymbolReloc, elf: *Elf) void {
1683 assert(elf.ehdrType() != .REL);1574 assert(elf.ehdrType() != .REL);
1684 if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) {1575 if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) {
1576 // There's no point applying the relocation now, because it will be re-applied by
1577 // `flushMoved` at some point anyway.
1578 return;
1579 }
1580 switch (reloc.result) {
1581 .ok => {},
1582 .overflowed => elf.overflowed_reloc_count -= 1,
1583 .misaligned => elf.misaligned_reloc_count -= 1,
1584 }
1585 if (reloc.applyInner(elf)) {
1586 @branchHint(.likely);
1587 reloc.result = .ok;
1588 } else |err| switch (err) {
1589 error.RelocationOverflow => {
1590 reloc.result = .overflowed;
1591 elf.overflowed_reloc_count += 1;
1592 },
1593 error.RelocationMisaligned => {
1594 reloc.result = .misaligned;
1595 elf.misaligned_reloc_count += 1;
1596 },
1597 }
1598 }
1599 fn applyInner(reloc: *const SymbolReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
1600 const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset;
1601 const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..];
1602
1603 const addend: u64 = @bitCast(reloc.addend);
1604 const target_val: u64 = type: switch (reloc.type.target) {
1605 .abs => reloc.target.value(elf) +% addend,
1606 .rel => reloc.target.value(elf) +% addend -% dest_vaddr,
1607 .pltabs => {
1608 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .abs;
1609 break :type plt_entry_addr +% addend;
1610 },
1611 .pltrel => {
1612 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .rel;
1613 break :type plt_entry_addr +% addend -% dest_vaddr;
1614 },
1615 .dtpoff => reloc.target.value(elf) +% addend,
1616 .tpoff => switch (elf.targetTlsVariant()) {
1617 .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend,
1618 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend,
1619 .II => {
1620 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
1621 const tls_size: u64 = switch (elf.phdrSlice()) {
1622 inline else => |phdr| tls_size: {
1623 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
1624 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);
1625 },
1626 };
1627 break :type reloc.target.value(elf) +% addend -% tls_size;
1628 },
1629 },
1630 .size => switch (elf.symPtr(reloc.target.index(elf))) {
1631 inline else => |sym| elf.targetLoad(&sym.size),
1632 },
1633 .special => return reloc.type.action.special.applyInner(
1634 elf,
1635 reloc.target,
1636 addend,
1637 dest_vaddr,
1638 dest_slice,
1639 ),
1640 };
1641
1642 // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast
1643 // is required, meaning we can handle it now and return early.
1644 if (reloc.rela_index.unwrap()) |rela_index| switch (elf.classifySymbolValue(reloc.target)) {
1645 .static => unreachable,
1646 .dynamic => return, // the relocation happens at runtime
1647 .static_relative => {
1648 // We have emitted an R_*_RELATIVE relocation to help lower an absolute-address
1649 // relocation. The value computed above is valid, but instead of writing it to the
1650 // destination slice, we actually want to write it to the runtime relocation entry.
1651 switch (elf.identClass()) {
1652 .NONE, _ => unreachable,
1653 .@"32" => assert(reloc.type.action.simple.dest == .@"32"),
1654 .@"64" => assert(reloc.type.action.simple.dest == .@"64"),
1655 }
1656 assert(reloc.type.action.simple.cast == .unsigned);
1657 assert(reloc.type.action.simple.shift == .@"0");
1658 elf.shndx.rela_dyn.relaSetRelativeOffset(elf, rela_index, target_val);
1659 return;
1660 },
1661 };
1662
1663 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
1664 }
1665
1666 fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void {
1667 assert(index.get(elf) == reloc);
1668
1669 reloc.deleteOutputRel(elf);
1670 if (reloc.type.dependsOnTlsSize(elf)) {
1671 assert(elf.tls_size_symbol_relocs.swapRemove(index));
1672 }
1673
1674 switch (reloc.prev) {
1675 .none => {
1676 const first_target_reloc = &reloc.target.index(elf).ptr(elf).first_target_reloc;
1677 assert(first_target_reloc.* == index);
1678 first_target_reloc.* = reloc.next;
1679 },
1680 else => |prev| prev.get(elf).next = reloc.next,
1681 }
1682 switch (reloc.next) {
1683 .none => {},
1684 else => |next| next.get(elf).prev = reloc.prev,
1685 }
1686 switch (reloc.result) {
1687 .ok => {},
1688 .overflowed => elf.overflowed_reloc_count -= 1,
1689 .misaligned => elf.misaligned_reloc_count -= 1,
1690 }
1691
1692 reloc.* = undefined;
1693 }
1694
1695 /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation, updating
1696 /// `elf.textrel_count` if necessary.
1697 fn deleteOutputRel(reloc: *SymbolReloc, elf: *Elf) void {
1698 const rela_index = reloc.rela_index.unwrap() orelse return;
1699 reloc.relaSection(elf).relaDeleteOne(elf, rela_index);
1700 switch (elf.ehdrType()) {
1701 .REL => {},
1702 .EXEC, .DYN => switch (elf.nodeWantsDsoRelocation(reloc.node)) {
1703 .no => unreachable, // there *was* a dynamic relocation!
1704 .yes => {},
1705 .yes_textrel => elf.textrel_count -= 1,
1706 },
1707 }
1708 reloc.rela_index = .none;
1709 }
1710};
1711
1712/// A relocation targeting an arbitrary node (within a section) with a fixed addend.
1713/// This represents a symbol reloc against the section symbol containing the node
1714/// with a variable addend that changes when the target node moves.
1715const NodeReloc = struct {
1716 node: MappedFile.Node.Index,
1717 offset: u64,
1718 target: MappedFile.Node.Index,
1719 addend: i64,
1720 type: NodeReloc.Type,
1721 next: NodeReloc.Index,
1722 prev: NodeReloc.Index,
1723 rela_index: Section.RelaIndex.Optional,
1724 result: enum(u8) { ok, overflowed, misaligned },
1725
1726 const Type = enum { abs32, abs64 };
1727
1728 const Index = enum(u32) {
1729 none = std.math.maxInt(u32),
1730 _,
1731
1732 fn get(index: NodeReloc.Index, elf: *Elf) *NodeReloc {
1733 return &elf.node_relocs.items[@backingInt(index)];
1734 }
1735 };
1736
1737 fn apply(reloc: *NodeReloc, elf: *Elf) void {
1738 assert(elf.ehdrType() != .REL);
1739 if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(&elf.mf)) {
1740 // There's no point applying the relocation now, because it will be re-applied by
1741 // `flushMoved` at some point anyway.
1742 return;
1743 }
1744 switch (reloc.result) {
1745 .ok => {},
1746 .overflowed => elf.overflowed_reloc_count -= 1,
1747 .misaligned => elf.misaligned_reloc_count -= 1,
1748 }
1749 if (reloc.applyInner(elf)) {
1750 @branchHint(.likely);
1751 reloc.result = .ok;
1752 } else |err| switch (err) {
1753 error.RelocationOverflow => {
1754 reloc.result = .overflowed;
1755 elf.overflowed_reloc_count += 1;
1756 },
1757 error.RelocationMisaligned => {
1758 reloc.result = .misaligned;
1759 elf.misaligned_reloc_count += 1;
1760 },
1761 }
1762 }
1763 fn applyInner(reloc: *const NodeReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
1764 const simple: SymbolReloc.Type.Simple = .{ .dest = switch (reloc.type) {
1765 .abs32 => .@"32",
1766 .abs64 => .@"64",
1767 }, .cast = .unsigned, .shift = .@"0" };
1768 const addend: u64 = @bitCast(reloc.addend);
1769 const target_val = elf.getNodeVAddr(reloc.target) +% addend;
1770 const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..];
1771 try simple.write(target_val, dest_slice, elf.targetEndian());
1772 }
1773
1774 fn delete(reloc: *NodeReloc, elf: *Elf) void {
1775 reloc.deleteOutputRel(elf);
1776
1777 switch (reloc.prev) {
1778 .none => {
1779 const first_target_reloc = switch (elf.getNode(reloc.target)) {
1780 else => unreachable,
1781 .unit_frame_cie => |ui| &elf.dwarf_units.items[@backingInt(ui)].unit_frame_cie_first_target_reloc,
1782 };
1783 first_target_reloc.* = reloc.next;
1784 },
1785 else => |prev| prev.get(elf).next = reloc.next,
1786 }
1787 switch (reloc.next) {
1788 .none => {},
1789 else => |next| next.get(elf).prev = reloc.prev,
1790 }
1791 switch (reloc.result) {
1792 .ok => {},
1793 .overflowed => elf.overflowed_reloc_count -= 1,
1794 .misaligned => elf.misaligned_reloc_count -= 1,
1795 }
1796
1797 reloc.* = undefined;
1798 }
1799
1800 /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation.
1801 fn deleteOutputRel(reloc: *NodeReloc, elf: *Elf) void {
1802 const rela_index = reloc.rela_index.unwrap() orelse return;
1803 assert(elf.ehdrType() == .REL);
1804 elf.getNodeShndx(reloc.node).get(elf).rela.shndx.relaDeleteOne(elf, rela_index);
1805 reloc.rela_index = .none;
1806 }
1807};
1808
1809/// Identifies a single entry in the GOT.
1810const GotKey = union(enum) {
1811 /// The entry is a reserved word, initialized to zero. `initHeaders` will add as many of these
1812 /// as the target machine ABI requires.
1813 ///
1814 /// This `u32` value exists to allow reserving multiple words with distinct keys.
1815 reserved: u32,
1816
1817 /// Value is the address of the given symbol.
1818 symbol: Symbol.Id,
1819
1820 /// Value is the signed offset of the given symbol from the TLS pointer.
1821 tpoff: Symbol.Id,
1822
1823 /// Value is the TLS module ID of the DSO we are creating.
1824 ///
1825 /// Used for the first of the two GOT entries generated by a TLSLD relocation.
1826 tlsld0,
1827 /// Value is always 0.
1828 ///
1829 /// Used for the second of the two GOT entries generated by a TLSLD relocation.
1830 tlsld1,
1831
1832 /// Value is the TLS module ID for the given STT_TLS symbol.
1833 ///
1834 /// Used for the first of the two GOT entries generated by a TLSGD relocation.
1835 tlsgd0: Symbol.Id,
1836 /// Value is the offset of the given STT_TLS symbol from the base of the per-module TLS area.
1837 ///
1838 /// Used for the second of the two GOT entries generated by a TLSGD relocation.
1839 tlsgd1: Symbol.Id,
1840};
1841
1842/// A relocation targeting a particular GOT entry.
1843const GotReloc = struct {
1844 /// The node containing this relocation. Possible values are:
1845 /// * An input section
1846 /// * A section
1847 /// * A NAV, UAV, or lazy code/data
1848 /// * `.none`, if this relocation was deleted (in which case it should be ignored)
1849 node: MappedFile.Node.Index.Optional,
1850 /// The offset of the relocation inside of `node`.
1851 offset: u64,
1852 target: GotKey,
1853 addend: i64,
1854 type: GotReloc.Type,
1855 result: enum(u8) { ok, overflowed, misaligned },
1856
1857 /// `GotReloc.Type` has the same structure as `SymbolReloc.Type`, just with different `Target`
1858 /// and `Special` enums---consult doc comments on `SymbolReloc.Type` for an overview.
1859 const Type = packed struct(u16) {
1860 fn simple(target: Target, action: Simple) GotReloc.Type {
1861 assert(target != .special);
1862 return .{ .target = target, .action = .{ .simple = action } };
1863 }
1864
1865 fn special(s: Special) GotReloc.Type {
1866 return .{ .target = .special, .action = .{ .special = s } };
1867 }
1868
1869 target: Target,
1870 action: packed union {
1871 simple: Simple,
1872 special: Special,
1873 },
1874
1875 /// Like `SymbolReloc.Target`, but for GOT relocations. There are fewer tags because there
1876 /// are fewer different kinds of GOT relocation.
1877 const Target = enum(u3) {
1878 /// This is a "special" relocation whose specific type is in the `action.special` field.
1879 special,
1880
1881 /// Absolute address of the GOT entry.
1882 abs,
1883 /// Offset from the relocation itself to the GOT entry ("PC-relative").
1884 rel,
1885 /// Offset from the base of the GOT to the GOT entry.
1886 offset,
1887 };
1888
1889 const Simple = SymbolReloc.Type.Simple;
1890
1891 /// Like `SymbolReloc.Special`, but for GOT relocations.
1892 const Special = enum(u13) {
1893 larch_pcala_hi20,
1894 larch_pcala64_lo20,
1895 larch_pcala64_hi12,
1896
1897 sparc_op_lox10,
1898 sparc_op_hix22,
1899
1900 fn applyInner(
1901 s: Special,
1902 elf: *Elf,
1903 got_vaddr: u64,
1904 got_offset: u64,
1905 addend: u64,
1906 dest_vaddr: u64,
1907 dest_slice: []u8,
1908 ) error{ RelocationMisaligned, RelocationOverflow }!void {
1909 switch (s) {
1910 .larch_pcala_hi20 => {
1911 const val = got_vaddr +% got_offset +% addend;
1912 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1913 elf.targetStore(inst, .{
1914 .b0_4 = elf.targetLoad(inst).b0_4,
1915 .j20 = link.loongarch.pcalaHi20(val, dest_vaddr),
1916 .b25_31 = elf.targetLoad(inst).b25_31,
1917 });
1918 },
1919 .larch_pcala64_lo20 => {
1920 const val = got_vaddr +% got_offset +% addend;
1921 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1922 elf.targetStore(inst, .{
1923 .b0_4 = elf.targetLoad(inst).b0_4,
1924 .j20 = link.loongarch.pcala64Lo20(val, dest_vaddr),
1925 .b25_31 = elf.targetLoad(inst).b25_31,
1926 });
1927 },
1928 .larch_pcala64_hi12 => {
1929 const val = got_vaddr +% got_offset +% addend;
1930 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
1931 elf.targetStore(inst, .{
1932 .b0_9 = elf.targetLoad(inst).b0_9,
1933 .k12 = link.loongarch.pcala64Hi12(val, dest_vaddr),
1934 .b22_31 = elf.targetLoad(inst).b22_31,
1935 });
1936 },
1937 .sparc_op_lox10 => {
1938 const dest_ptr: *align(1) packed struct(u32) {
1939 imm13: u13,
1940 b13_31: u19,
1941 } = @ptrCast(dest_slice);
1942 elf.targetStore(dest_ptr, .{
1943 .imm13 = @as(u10, @truncate(got_offset)),
1944 .b13_31 = elf.targetLoad(dest_ptr).b13_31,
1945 });
1946 },
1947 .sparc_op_hix22 => {
1948 const dest_ptr: *align(1) packed struct(u32) {
1949 imm22: u22,
1950 b22_31: u10,
1951 } = @ptrCast(dest_slice);
1952 elf.targetStore(dest_ptr, .{
1953 .imm22 = @truncate(got_offset >> 10),
1954 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
1955 });
1956 },
1957 }
1958 }
1959 };
1960 };
1961
1962 const Index = enum(u32) {
1963 none = std.math.maxInt(u32),
1964 _,
1965
1966 fn get(index: GotReloc.Index, elf: *Elf) *GotReloc {
1967 return &elf.got_relocs.items[@backingInt(index)];
1968 }
1969 };
1970
1971 fn apply(reloc: *GotReloc, elf: *Elf) void {
1972 assert(elf.ehdrType() != .REL);
1973 const node = reloc.node.unwrap() orelse return; // deleted
1974 if (node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) {
1685 // There's no point applying the relocation now, because it will be re-applied by1975 // There's no point applying the relocation now, because it will be re-applied by
1686 // `flushMoved` at some point anyway.1976 // `flushMoved` at some point anyway.
1687 return;1977 return;
...@@ -1705,118 +1995,99 @@ const SymbolReloc = struct {...@@ -1705,118 +1995,99 @@ const SymbolReloc = struct {
1705 },1995 },
1706 }1996 }
1707 }1997 }
1708 fn applyInner(reloc: *const SymbolReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {1998 fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
1709 const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset;1999 const node = reloc.node.unwrap().?;
1710 const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..];2000 const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset;
2001 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
17112002
2003 const got_vaddr = elf.shndx.got.vaddr(elf);
2004 const got_index: u64 = elf.got.getIndex(reloc.target).?;
2005 const got_offset: u64 = switch (elf.identClass()) {
2006 .NONE, _ => unreachable,
2007 inline else => |class| @sizeOf(class.ElfN().Addr) * got_index,
2008 };
1712 const addend: u64 = @bitCast(reloc.addend);2009 const addend: u64 = @bitCast(reloc.addend);
1713 const target_val: u64 = type: switch (reloc.type.target) {2010
1714 .abs => reloc.target.value(elf) +% addend,2011 const target_val: u64 = switch (reloc.type.target) {
1715 .rel => reloc.target.value(elf) +% addend -% dest_vaddr,2012 .abs => got_vaddr +% got_offset +% addend,
1716 .pltabs => {2013 .rel => got_vaddr +% got_offset +% addend -% dest_vaddr,
1717 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .abs;2014 .offset => got_offset +% addend,
1718 break :type plt_entry_addr +% addend;
1719 },
1720 .pltrel => {
1721 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .rel;
1722 break :type plt_entry_addr +% addend -% dest_vaddr;
1723 },
1724 .dtpoff => reloc.target.value(elf) +% addend,
1725 .tpoff => switch (elf.targetTlsVariant()) {
1726 .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend,
1727 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend,
1728 .II => {
1729 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
1730 const tls_size: u64 = switch (elf.phdrSlice()) {
1731 inline else => |phdr| tls_size: {
1732 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
1733 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);
1734 },
1735 };
1736 break :type reloc.target.value(elf) +% addend -% tls_size;
1737 },
1738 },
1739 .size => switch (elf.symPtr(reloc.target.index(elf))) {
1740 inline else => |sym| elf.targetLoad(&sym.size),
1741 },
1742 .special => return reloc.type.action.special.applyInner(2015 .special => return reloc.type.action.special.applyInner(
1743 elf,2016 elf,
1744 reloc.target,2017 got_vaddr,
2018 got_offset,
1745 addend,2019 addend,
1746 dest_vaddr,2020 dest_vaddr,
1747 dest_slice,2021 dest_slice,
1748 ),2022 ),
1749 };2023 };
1750
1751 // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast
1752 // is required, meaning we can handle it now and return early.
1753 if (reloc.rela_index.unwrap()) |rela_index| switch (elf.classifySymbolValue(reloc.target)) {
1754 .static => unreachable,
1755 .dynamic => return, // the relocation happens at runtime
1756 .static_relative => {
1757 // We have emitted an R_*_RELATIVE relocation to help lower an absolute-address
1758 // relocation. The value computed above is valid, but instead of writing it to the
1759 // destination slice, we actually want to write it to the runtime relocation entry.
1760 switch (elf.identClass()) {
1761 .NONE, _ => unreachable,
1762 .@"32" => assert(reloc.type.action.simple.dest == .@"32"),
1763 .@"64" => assert(reloc.type.action.simple.dest == .@"64"),
1764 }
1765 assert(reloc.type.action.simple.cast == .unsigned);
1766 assert(reloc.type.action.simple.shift == .@"0");
1767 elf.shndx.rela_dyn.relaSetRelativeOffset(elf, rela_index, target_val);
1768 return;
1769 },
1770 };
1771
1772 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());2024 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
1773 }2025 }
17742026
1775 fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void {2027 fn delete(reloc: *GotReloc, elf: *Elf) void {
1776 assert(index.get(elf) == reloc);
1777
1778 reloc.deleteOutputRel(elf);
1779 if (reloc.type.dependsOnTlsSize(elf)) {
1780 assert(elf.tls_size_symbol_relocs.swapRemove(index));
1781 }
1782
1783 switch (reloc.prev) {
1784 .none => {
1785 const target_ptr = reloc.target.index(elf).ptr(elf);
1786 assert(target_ptr.first_target_reloc == index);
1787 target_ptr.first_target_reloc = reloc.next;
1788 },
1789 else => |prev| prev.get(elf).next = reloc.next,
1790 }
1791 switch (reloc.next) {
1792 .none => {},
1793 else => |next| next.get(elf).prev = reloc.prev,
1794 }
1795 switch (reloc.result) {2028 switch (reloc.result) {
1796 .ok => {},2029 .ok => {},
1797 .overflowed => elf.overflowed_reloc_count -= 1,2030 .overflowed => elf.overflowed_reloc_count -= 1,
1798 .misaligned => elf.misaligned_reloc_count -= 1,2031 .misaligned => elf.misaligned_reloc_count -= 1,
1799 }2032 }
2033 reloc.* = .{
2034 .node = .none,
2035 .offset = undefined,
2036 .target = undefined,
2037 .addend = undefined,
2038 .type = undefined,
2039 .result = undefined,
2040 };
2041 }
2042};
18002043
1801 reloc.* = undefined;2044fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) Error!void {
2045 const gpa = elf.base.comp.gpa;
2046
2047 try elf.symtab.ensureUnusedCapacity(gpa, len);
2048
2049 // If adding locals, we may need to move one global out of the way for each local. If adding
2050 // globals, they could all get demoted to STB_LOCAL, meaning we have to move N other globals
2051 // around to keep `.dynsym` compact. Either way, the maximum is N.
2052 try elf.changed_symtab_index.ensureUnusedCapacity(gpa, len);
2053
2054 {
2055 // Ensure the symtab section's node is big enough
2056 const need_node_size: u64 = switch (elf.shdrPtr(.symtab)) {
2057 inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym),
2058 };
2059 try Section.Index.symtab.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_node_size);
1802 }2060 }
18032061
1804 /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation, updating2062 switch (kind) {
1805 /// `elf.textrel_count` if necessary.2063 .all_local => {},
1806 fn deleteOutputRel(reloc: *SymbolReloc, elf: *Elf) void {2064 .maybe_global => {
1807 const rela_index = reloc.rela_index.unwrap() orelse return;2065 try elf.globals.strong_def.ensureUnusedCapacity(gpa, len);
1808 reloc.relaSection(elf).relaDeleteOne(elf, rela_index);2066 try elf.globals.weak_def.ensureUnusedCapacity(gpa, len);
1809 switch (elf.ehdrType()) {2067 try elf.globals.strong_undef.ensureUnusedCapacity(gpa, len);
1810 .REL => {},2068 try elf.globals.weak_undef.ensureUnusedCapacity(gpa, len);
1811 .EXEC, .DYN => switch (elf.nodeWantsDsoRelocation(reloc.node)) {2069
1812 .no => unreachable, // there *was* a dynamic relocation!2070 try elf.node_global_symbols.ensureUnusedCapacity(gpa, len);
1813 .yes => {},2071
1814 .yes_textrel => elf.textrel_count -= 1,2072 if (elf.shndx.dynsym != .UNDEF) {
1815 },2073 const dynsym_cur_size: u64, const dynsym_ent_size: u32 = switch (elf.shdrPtr(elf.shndx.dynsym)) {
1816 }2074 inline else => |shdr, class| .{
1817 reloc.rela_index = .none;2075 elf.targetLoad(&shdr.size),
2076 @sizeOf(class.ElfN().Sym),
2077 },
2078 };
2079 const dynsym_cur_len: u32 = @intCast(@divExact(dynsym_cur_size, dynsym_ent_size));
2080
2081 const dynsym_need_size: u64 = (dynsym_cur_len + len) * dynsym_ent_size;
2082 try elf.shndx.dynsym.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, dynsym_need_size);
2083
2084 try elf.ensureDynsymHashCapacity(dynsym_cur_len + len);
2085
2086 try elf.ensureUnusedPltCapacity(len);
2087 }
2088 },
1818 }2089 }
1819};2090}
18202091
1821fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {2092fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void {
1822 const gpa = elf.base.comp.gpa;2093 const gpa = elf.base.comp.gpa;
...@@ -1984,53 +2255,6 @@ fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {...@@ -1984,53 +2255,6 @@ fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void {
1984 }2255 }
1985}2256}
19862257
1987fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) Error!void {
1988 const gpa = elf.base.comp.gpa;
1989
1990 try elf.symtab.ensureUnusedCapacity(gpa, len);
1991
1992 // If adding locals, we may need to move one global out of the way for each local. If adding
1993 // globals, they could all get demoted to STB_LOCAL, meaning we have to move N other globals
1994 // around to keep `.dynsym` compact. Either way, the maximum is N.
1995 try elf.changed_symtab_index.ensureUnusedCapacity(gpa, len);
1996
1997 {
1998 // Ensure the symtab section's node is big enough
1999 const need_node_size: u64 = switch (elf.shdrPtr(.symtab)) {
2000 inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym),
2001 };
2002 try Section.Index.symtab.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_node_size);
2003 }
2004
2005 switch (kind) {
2006 .all_local => {},
2007 .maybe_global => {
2008 try elf.globals.strong_def.ensureUnusedCapacity(gpa, len);
2009 try elf.globals.weak_def.ensureUnusedCapacity(gpa, len);
2010 try elf.globals.strong_undef.ensureUnusedCapacity(gpa, len);
2011 try elf.globals.weak_undef.ensureUnusedCapacity(gpa, len);
2012
2013 try elf.node_global_symbols.ensureUnusedCapacity(gpa, len);
2014
2015 if (elf.shndx.dynsym != .UNDEF) {
2016 const dynsym_cur_size: u64, const dynsym_ent_size: u32 = switch (elf.shdrPtr(elf.shndx.dynsym)) {
2017 inline else => |shdr, class| .{
2018 elf.targetLoad(&shdr.size),
2019 @sizeOf(class.ElfN().Sym),
2020 },
2021 };
2022 const dynsym_cur_len: u32 = @intCast(@divExact(dynsym_cur_size, dynsym_ent_size));
2023
2024 const dynsym_need_size: u64 = (dynsym_cur_len + len) * dynsym_ent_size;
2025 try elf.shndx.dynsym.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, dynsym_need_size);
2026
2027 try elf.ensureDynsymHashCapacity(dynsym_cur_len + len);
2028
2029 try elf.ensureUnusedPltCapacity(len);
2030 }
2031 },
2032 }
2033}
2034fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {2258fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
2035 const gpa = elf.base.comp.gpa;2259 const gpa = elf.base.comp.gpa;
20362260
...@@ -2138,7 +2362,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L...@@ -2138,7 +2362,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L
2138 .other = .{ .visibility = .DEFAULT },2362 .other = .{ .visibility = .DEFAULT },
2139 .shndx = opts.shndx.toSection().?,2363 .shndx = opts.shndx.toSection().?,
2140 };2364 };
2141 if (elf.targetEndian() != native_endian) {2365 if (elf.targetEndian() != std.lang.Endian.native) {
2142 std.mem.byteSwapAllFields(class.ElfN().Sym, target_sym);2366 std.mem.byteSwapAllFields(class.ElfN().Sym, target_sym);
2143 }2367 }
21442368
...@@ -2323,7 +2547,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{...@@ -2323,7 +2547,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{
2323 .other = .{ .visibility = opts.visibility },2547 .other = .{ .visibility = opts.visibility },
2324 .shndx = opts.shndx.toSection().?,2548 .shndx = opts.shndx.toSection().?,
2325 };2549 };
2326 if (elf.targetEndian() != native_endian) {2550 if (elf.targetEndian() != std.lang.Endian.native) {
2327 std.mem.byteSwapAllFields(Sym, sym);2551 std.mem.byteSwapAllFields(Sym, sym);
2328 }2552 }
2329 },2553 },
...@@ -2359,7 +2583,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{...@@ -2359,7 +2583,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{
2359 .other = .{ .visibility = opts.visibility },2583 .other = .{ .visibility = opts.visibility },
2360 .shndx = opts.shndx.toSection().?,2584 .shndx = opts.shndx.toSection().?,
2361 };2585 };
2362 if (elf.targetEndian() != native_endian) {2586 if (elf.targetEndian() != std.lang.Endian.native) {
2363 std.mem.byteSwapAllFields(Sym, sym);2587 std.mem.byteSwapAllFields(Sym, sym);
2364 }2588 }
2365 elf.appendDynsymHashEntry(dynsym_index);2589 elf.appendDynsymHashEntry(dynsym_index);
...@@ -2991,10 +3215,18 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {...@@ -2991,10 +3215,18 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId {
2991 .shdr,3215 .shdr,
2992 .segment,3216 .segment,
2993 .section,3217 .section,
3218 .section_manual_size,
2994 .input_section,3219 .input_section,
2995 .copied_global,3220 .copied_global,
3221 .value_debug_info,
3222 .global_debug_info,
3223 .frame_padding,
3224 .unit_frame,
3225 .unit_frame_cie,
3226 .func_frame_fde,
3227 .func_debug_info,
3228 .func_debug_line,
2996 => unreachable,3229 => unreachable,
2997
2998 inline .nav,3230 inline .nav,
2999 .uav,3231 .uav,
3000 .lazy_code,3232 .lazy_code,
...@@ -3025,7 +3257,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol...@@ -3025,7 +3257,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol
3025 .const_data => .{ .rodata, .OBJECT },3257 .const_data => .{ .rodata, .OBJECT },
3026 };3258 };
3027 const node = try shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{});3259 const node = try shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{});
3028 var name_buf: [64]u8 = undefined;3260 var name_buf: [std.fmt.count("__lazy_const_data_{d}", .{std.math.maxInt(u32)})]u8 = undefined;
3029 const name = std.mem.print(3261 const name = std.mem.print(
3030 &name_buf,3262 &name_buf,
3031 "__lazy_{t}_{d}",3263 "__lazy_{t}_{d}",
...@@ -3114,6 +3346,24 @@ pub fn addReloc(...@@ -3114,6 +3346,24 @@ pub fn addReloc(
3114 else => |e| return e,3346 else => |e| return e,
3115 };3347 };
3116}3348}
3349pub fn addNodeReloc(
3350 elf: *Elf,
3351 node: MappedFile.Node.Index,
3352 offset: u64,
3353 target: MappedFile.Node.Index,
3354 addend: i64,
3355 @"type": NodeReloc.Type,
3356) link.Error!void {
3357 const diags = &elf.base.comp.link_diags;
3358 elf.ensureUnusedRelocCapacity(node, 1) catch |err| switch (err) {
3359 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3360 else => |e| return e,
3361 };
3362 elf.addNodeRelocAssumeCapacity(node, offset, target, addend, @"type") catch |err| switch (err) {
3363 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
3364 else => |e| return e,
3365 };
3366}
3117pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) link.Error!link.File.SymbolId {3367pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) link.Error!link.File.SymbolId {
3118 const diags = &elf.base.comp.link_diags;3368 const diags = &elf.base.comp.link_diags;
3119 const zcu = elf.base.comp.zcu.?;3369 const zcu = elf.base.comp.zcu.?;
...@@ -3393,6 +3643,7 @@ fn create(...@@ -3393,6 +3643,7 @@ fn create(
3393 .data = undefined,3643 .data = undefined,
3394 .data_rel_ro = undefined,3644 .data_rel_ro = undefined,
3395 .tls = .none,3645 .tls = .none,
3646 .gnu_eh_frame = .none,
3396 },3647 },
3397 .archive = null,3648 .archive = null,
3398 .nodes = .empty,3649 .nodes = .empty,
...@@ -3410,6 +3661,11 @@ fn create(...@@ -3410,6 +3661,11 @@ fn create(
3410 .tdata = .UNDEF,3661 .tdata = .UNDEF,
3411 .rela_dyn = .UNDEF,3662 .rela_dyn = .UNDEF,
3412 .rela_plt = .UNDEF,3663 .rela_plt = .UNDEF,
3664 .eh_frame_hdr = .UNDEF,
3665 .eh_frame = .UNDEF,
3666 .debug_frame = .UNDEF,
3667 .debug_info = .UNDEF,
3668 .debug_line = .UNDEF,
3413 .init_array = .UNDEF,3669 .init_array = .UNDEF,
3414 .fini_array = .UNDEF,3670 .fini_array = .UNDEF,
3415 .preinit_array = .UNDEF,3671 .preinit_array = .UNDEF,
...@@ -3437,6 +3693,7 @@ fn create(...@@ -3437,6 +3693,7 @@ fn create(
3437 .got = .empty,3693 .got = .empty,
3438 .plt = .empty,3694 .plt = .empty,
3439 .plt_first_symbol_reloc = .none,3695 .plt_first_symbol_reloc = .none,
3696 .eh_frame_hdr_first_symbol_reloc = .none,
3440 .needed = .empty,3697 .needed = .empty,
3441 .inputs = .empty,3698 .inputs = .empty,
3442 .input_pending_index = 0,3699 .input_pending_index = 0,
...@@ -3451,13 +3708,26 @@ fn create(...@@ -3451,13 +3708,26 @@ fn create(
3451 }),3708 }),
3452 .pending_uavs = .empty,3709 .pending_uavs = .empty,
3453 .symbol_relocs = .empty,3710 .symbol_relocs = .empty,
3454 .got_relocs = .empty,
3455 .tls_size_symbol_relocs = .empty,3711 .tls_size_symbol_relocs = .empty,
3712 .node_relocs = .empty,
3713 .got_relocs = .empty,
3456 .section_by_name = .empty,3714 .section_by_name = .empty,
3457 .changed_symtab_index = .empty,3715 .changed_symtab_index = .empty,
3458 .textrel_count = 0,3716 .textrel_count = 0,
3717
3718 .dwarf = .init(&elf.base, switch (comp.config.debug_format) {
3719 .strip => .@"32",
3720 .dwarf => |v| v,
3721 .code_view => unreachable,
3722 }),
3723 .dwarf_units = .empty,
3724 .dwarf_values = .empty,
3725 .dwarf_globals = .empty,
3726 .dwarf_funcs = .empty,
3727
3459 .overflowed_reloc_count = 0,3728 .overflowed_reloc_count = 0,
3460 .misaligned_reloc_count = 0,3729 .misaligned_reloc_count = 0,
3730
3461 .const_prog_node = .none,3731 .const_prog_node = .none,
3462 .synth_prog_node = .none,3732 .synth_prog_node = .none,
3463 .input_prog_node = .none,3733 .input_prog_node = .none,
...@@ -3498,10 +3768,18 @@ pub fn deinit(elf: *Elf) void {...@@ -3498,10 +3768,18 @@ pub fn deinit(elf: *Elf) void {
3498 for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa);3768 for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa);
3499 elf.pending_uavs.deinit(gpa);3769 elf.pending_uavs.deinit(gpa);
3500 elf.symbol_relocs.deinit(gpa);3770 elf.symbol_relocs.deinit(gpa);
3501 elf.got_relocs.deinit(gpa);
3502 elf.tls_size_symbol_relocs.deinit(gpa);3771 elf.tls_size_symbol_relocs.deinit(gpa);
3772 elf.node_relocs.deinit(gpa);
3773 elf.got_relocs.deinit(gpa);
3503 elf.section_by_name.deinit(gpa);3774 elf.section_by_name.deinit(gpa);
3504 elf.changed_symtab_index.deinit(gpa);3775 elf.changed_symtab_index.deinit(gpa);
3776
3777 elf.dwarf.deinit(gpa);
3778 elf.dwarf_units.deinit(gpa);
3779 elf.dwarf_values.deinit(gpa);
3780 elf.dwarf_globals.deinit(gpa);
3781 elf.dwarf_funcs.deinit(gpa);
3782
3505 elf.* = undefined;3783 elf.* = undefined;
3506}3784}
35073785
...@@ -3518,11 +3796,17 @@ fn initHeaders(...@@ -3518,11 +3796,17 @@ fn initHeaders(
3518 const gpa = comp.gpa;3796 const gpa = comp.gpa;
35193797
3520 const is_archive = comp.config.output_mode == .Lib and comp.config.link_mode == .static;3798 const is_archive = comp.config.output_mode == .Lib and comp.config.link_mode == .static;
3521 const have_dynamic_section = switch (@"type") {3799 const have_dynamic = switch (@"type") {
3522 .REL => false,3800 .REL => false,
3523 .EXEC => comp.config.link_mode == .dynamic,3801 .EXEC => comp.config.link_mode == .dynamic,
3524 .DYN => true,3802 .DYN => true,
3525 };3803 };
3804 const have_eh_frame = machine == .X86_64 and comp.config.any_unwind_tables;
3805 const have_debug_frame = machine == .X86_64 and switch (comp.config.debug_format) {
3806 .strip => false,
3807 .dwarf => !comp.config.any_unwind_tables,
3808 .code_view => unreachable,
3809 };
3526 const addr_align: Alignment = switch (class) {3810 const addr_align: Alignment = switch (class) {
3527 .NONE, _ => unreachable,3811 .NONE, _ => unreachable,
3528 .@"32" => .@"4",3812 .@"32" => .@"4",
...@@ -3537,7 +3821,7 @@ fn initHeaders(...@@ -3537,7 +3821,7 @@ fn initHeaders(
3537 //3821 //
3538 // It can be handy to temporarily set this to `.@"1"` when working on the linker, because it3822 // It can be handy to temporarily set this to `.@"1"` when working on the linker, because it
3539 // prevents alignment bugs from being hidden by your filesystem's block alignment.3823 // prevents alignment bugs from being hidden by your filesystem's block alignment.
3540 const node_block_align: Alignment = elf.mf.flags.block_size;3824 const node_block_align = elf.mf.flags.block_size;
35413825
3542 const plt: PltInfo = .fromMachine(machine);3826 const plt: PltInfo = .fromMachine(machine);
35433827
...@@ -3552,7 +3836,7 @@ fn initHeaders(...@@ -3552,7 +3836,7 @@ fn initHeaders(
3552 shnum += 1; // .data3836 shnum += 1; // .data
3553 shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata3837 shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata
3554 shnum += 1; // .data.rel.ro3838 shnum += 1; // .data.rel.ro
3555 if (have_dynamic_section) {3839 if (have_dynamic) {
3556 shnum += 1; // .dynamic3840 shnum += 1; // .dynamic
3557 shnum += 1; // .dynstr3841 shnum += 1; // .dynstr
3558 shnum += 1; // .dynsym3842 shnum += 1; // .dynsym
...@@ -3560,6 +3844,19 @@ fn initHeaders(...@@ -3560,6 +3844,19 @@ fn initHeaders(
3560 shnum += 1; // .rela.dyn3844 shnum += 1; // .rela.dyn
3561 shnum += 1; // .rela.plt3845 shnum += 1; // .rela.plt
3562 }3846 }
3847 if (have_eh_frame) {
3848 shnum += @intFromBool(@"type" != .REL); // .eh_frame_hdr
3849 shnum += 1; // .eh_frame
3850 }
3851 switch (comp.config.debug_format) {
3852 .strip => {},
3853 .dwarf => {
3854 shnum += @intFromBool(have_debug_frame); // .debug_frame
3855 shnum += 1; // .debug_info
3856 shnum += 1; // .debug_line
3857 },
3858 .code_view => unreachable,
3859 }
3563 if (@"type" != .REL) {3860 if (@"type" != .REL) {
3564 shnum += 1; // .got3861 shnum += 1; // .got
3565 shnum += @intFromBool(plt.got_plt != null); // .got.plt3862 shnum += @intFromBool(plt.got_plt != null); // .got.plt
...@@ -3574,14 +3871,15 @@ fn initHeaders(...@@ -3574,14 +3871,15 @@ fn initHeaders(
3574 interp: u32,3871 interp: u32,
3575 rodata: u32,3872 rodata: u32,
3576 text: u32,3873 text: u32,
3577 data: u32,
3578 /// On most targets this is `undefined`, but on machines where JUMP_SLOT relocations write3874 /// On most targets this is `undefined`, but on machines where JUMP_SLOT relocations write
3579 /// directly to the PLT, we place the PLT in its own segment in order to avoid making the3875 /// directly to the PLT, we place the PLT in its own segment in order to avoid making the
3580 /// general data segment RWX.3876 /// general data segment RWX.
3581 plt: u32,3877 plt: u32,
3878 data: u32,
3582 tls: u32,3879 tls: u32,
3583 dynamic: u32,3880 dynamic: u32,
3584 relro: u32,3881 relro: u32,
3882 gnu_eh_frame: u32,
3585 gnu_stack: u32,3883 gnu_stack: u32,
3586 }, const phnum: u32 = ph: {3884 }, const phnum: u32 = ph: {
3587 switch (@"type") {3885 switch (@"type") {
...@@ -3622,7 +3920,7 @@ fn initHeaders(...@@ -3622,7 +3920,7 @@ fn initHeaders(
3622 defer phnum += 1;3920 defer phnum += 1;
3623 break :phndx phnum;3921 break :phndx phnum;
3624 } else undefined,3922 } else undefined,
3625 .dynamic = if (have_dynamic_section) phndx: {3923 .dynamic = if (have_dynamic) phndx: {
3626 defer phnum += 1;3924 defer phnum += 1;
3627 break :phndx phnum;3925 break :phndx phnum;
3628 } else undefined,3926 } else undefined,
...@@ -3630,6 +3928,10 @@ fn initHeaders(...@@ -3630,6 +3928,10 @@ fn initHeaders(
3630 defer phnum += 1;3928 defer phnum += 1;
3631 break :phndx phnum;3929 break :phndx phnum;
3632 },3930 },
3931 .gnu_eh_frame = if (have_eh_frame) phndx: {
3932 defer phnum += 1;
3933 break :phndx phnum;
3934 } else undefined,
3633 .gnu_stack = phndx: {3935 .gnu_stack = phndx: {
3634 defer phnum += 1;3936 defer phnum += 1;
3635 break :phndx phnum;3937 break :phndx phnum;
...@@ -3872,7 +4174,7 @@ fn initHeaders(...@@ -3872,7 +4174,7 @@ fn initHeaders(
3872 ehdr.shentsize = @sizeOf(ElfN.Shdr);4174 ehdr.shentsize = @sizeOf(ElfN.Shdr);
3873 ehdr.shnum = 1; // Only the SHN_UNDEF shdr initially---will be incremented by `addSection`4175 ehdr.shnum = 1; // Only the SHN_UNDEF shdr initially---will be incremented by `addSection`
3874 ehdr.shstrndx = std.elf.SHN_UNDEF;4176 ehdr.shstrndx = std.elf.SHN_UNDEF;
3875 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);4177 if (elf.targetEndian() != std.lang.Endian.native) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
3876 },4178 },
3877 }4179 }
38784180
...@@ -3925,8 +4227,7 @@ fn initHeaders(...@@ -3925,8 +4227,7 @@ fn initHeaders(
3925 elf.ni.phdr.slice(&elf.mf)[0 .. phnum * @sizeOf(ElfN.Phdr)],4227 elf.ni.phdr.slice(&elf.mf)[0 .. phnum * @sizeOf(ElfN.Phdr)],
3926 ));4228 ));
39274229
3928 const ph_phdr = &phdr[phndx.phdr];4230 phdr[phndx.phdr] = .{
3929 ph_phdr.* = .{
3930 .type = .PHDR,4231 .type = .PHDR,
3931 .offset = 0,4232 .offset = 0,
3932 .vaddr = 0,4233 .vaddr = 0,
...@@ -3938,8 +4239,7 @@ fn initHeaders(...@@ -3938,8 +4239,7 @@ fn initHeaders(
3938 };4239 };
39394240
3940 if (maybe_interp) |_| {4241 if (maybe_interp) |_| {
3941 const ph_interp = &phdr[phndx.interp];4242 phdr[phndx.interp] = .{
3942 ph_interp.* = .{
3943 .type = .INTERP,4243 .type = .INTERP,
3944 .offset = 0,4244 .offset = 0,
3945 .vaddr = 0,4245 .vaddr = 0,
...@@ -3951,8 +4251,7 @@ fn initHeaders(...@@ -3951,8 +4251,7 @@ fn initHeaders(
3951 };4251 };
3952 }4252 }
39534253
3954 const ph_rodata = &phdr[phndx.rodata];4254 phdr[phndx.rodata] = .{
3955 ph_rodata.* = .{
3956 .type = .NULL,4255 .type = .NULL,
3957 .offset = 0,4256 .offset = 0,
3958 .vaddr = @intCast(base_vaddr),4257 .vaddr = @intCast(base_vaddr),
...@@ -3963,74 +4262,62 @@ fn initHeaders(...@@ -3963,74 +4262,62 @@ fn initHeaders(
3963 .@"align" = @intCast(page_align.toByteUnits()),4262 .@"align" = @intCast(page_align.toByteUnits()),
3964 };4263 };
39654264
3966 const ph_text = &phdr[phndx.text];4265 phdr[phndx.text] = .{
3967 ph_text.* = .{4266 .type = .NULL,
4267 .offset = 0,
4268 .vaddr = @intCast(base_vaddr),
4269 .paddr = @intCast(base_vaddr),
4270 .filesz = 0,
4271 .memsz = 0,
4272 .flags = .{ .R = true, .X = true },
4273 .@"align" = @intCast(page_align.toByteUnits()),
4274 };
4275
4276 phdr[phndx.data] = .{
3968 .type = .NULL,4277 .type = .NULL,
3969 .offset = 0,4278 .offset = 0,
3970 .vaddr = @intCast(base_vaddr),4279 .vaddr = @intCast(base_vaddr),
3971 .paddr = @intCast(base_vaddr),4280 .paddr = @intCast(base_vaddr),
3972 .filesz = 0,4281 .filesz = 0,
3973 .memsz = 0,4282 .memsz = 0,
3974 .flags = .{ .R = true, .X = true },4283 .flags = .{ .R = true, .W = true },
3975 .@"align" = @intCast(page_align.toByteUnits()),4284 .@"align" = @intCast(page_align.toByteUnits()),
3976 };4285 };
39774286
3978 const ph_data = &phdr[phndx.data];4287 if (plt.got_plt == null) phdr[phndx.plt] = .{
3979 ph_data.* = .{
3980 .type = .NULL,4288 .type = .NULL,
3981 .offset = 0,4289 .offset = 0,
3982 .vaddr = @intCast(base_vaddr),4290 .vaddr = @intCast(base_vaddr),
3983 .paddr = @intCast(base_vaddr),4291 .paddr = @intCast(base_vaddr),
3984 .filesz = 0,4292 .filesz = 0,
3985 .memsz = 0,4293 .memsz = 0,
3986 .flags = .{ .R = true, .W = true },4294 .flags = .{ .R = true, .W = true, .X = true },
3987 .@"align" = @intCast(page_align.toByteUnits()),4295 .@"align" = @intCast(page_align.toByteUnits()),
3988 };4296 };
39894297
3990 if (plt.got_plt == null) {4298 if (elf.ni.tls.unwrap()) |tls_segment_ni| phdr[phndx.tls] = .{
3991 const ph_plt = &phdr[phndx.plt];4299 .type = .TLS,
3992 ph_plt.* = .{4300 .offset = 0,
3993 .type = .NULL,4301 .vaddr = 0,
3994 .offset = 0,4302 .paddr = 0,
3995 .vaddr = @intCast(base_vaddr),4303 .filesz = 0,
3996 .paddr = @intCast(base_vaddr),4304 .memsz = 0,
3997 .filesz = 0,4305 .flags = .{ .R = true },
3998 .memsz = 0,4306 .@"align" = @intCast(tls_segment_ni.alignment(&elf.mf).toByteUnits()),
3999 .flags = .{ .R = true, .W = true, .X = true },4307 };
4000 .@"align" = @intCast(page_align.toByteUnits()),
4001 };
4002 }
4003
4004 if (elf.ni.tls.unwrap()) |tls_segment_ni| {
4005 const ph_tls = &phdr[phndx.tls];
4006 ph_tls.* = .{
4007 .type = .TLS,
4008 .offset = 0,
4009 .vaddr = 0,
4010 .paddr = 0,
4011 .filesz = 0,
4012 .memsz = 0,
4013 .flags = .{ .R = true },
4014 .@"align" = @intCast(tls_segment_ni.alignment(&elf.mf).toByteUnits()),
4015 };
4016 }
40174308
4018 if (have_dynamic_section) {4309 if (have_dynamic) phdr[phndx.dynamic] = .{
4019 const ph_dynamic = &phdr[phndx.dynamic];4310 .type = .DYNAMIC,
4020 ph_dynamic.* = .{4311 .offset = 0,
4021 .type = .DYNAMIC,4312 .vaddr = 0,
4022 .offset = 0,4313 .paddr = 0,
4023 .vaddr = 0,4314 .filesz = 0,
4024 .paddr = 0,4315 .memsz = 0,
4025 .filesz = 0,4316 .flags = .{ .R = true, .W = true },
4026 .memsz = 0,4317 .@"align" = @intCast(addr_align.toByteUnits()),
4027 .flags = .{ .R = true, .W = true },4318 };
4028 .@"align" = @intCast(addr_align.toByteUnits()),
4029 };
4030 }
40314319
4032 const ph_relro = &phdr[phndx.relro];4320 phdr[phndx.relro] = .{
4033 ph_relro.* = .{
4034 .type = .GNU_RELRO,4321 .type = .GNU_RELRO,
4035 .offset = 0,4322 .offset = 0,
4036 .vaddr = 0,4323 .vaddr = 0,
...@@ -4041,8 +4328,18 @@ fn initHeaders(...@@ -4041,8 +4328,18 @@ fn initHeaders(
4041 .@"align" = @intCast(elf.ni.data_rel_ro.alignment(&elf.mf).toByteUnits()),4328 .@"align" = @intCast(elf.ni.data_rel_ro.alignment(&elf.mf).toByteUnits()),
4042 };4329 };
40434330
4044 const ph_gnu_stack = &phdr[phndx.gnu_stack];4331 if (have_eh_frame) phdr[phndx.gnu_eh_frame] = .{
4045 ph_gnu_stack.* = .{4332 .type = .GNU_EH_FRAME,
4333 .offset = 0,
4334 .vaddr = 0,
4335 .paddr = 0,
4336 .filesz = @sizeOf(Dwarf.EhFrameHdr),
4337 .memsz = @sizeOf(Dwarf.EhFrameHdr),
4338 .flags = .{ .R = true },
4339 .@"align" = 4,
4340 };
4341
4342 phdr[phndx.gnu_stack] = .{
4046 .type = .GNU_STACK,4343 .type = .GNU_STACK,
4047 .offset = 0,4344 .offset = 0,
4048 .vaddr = 0,4345 .vaddr = 0,
...@@ -4071,7 +4368,7 @@ fn initHeaders(...@@ -4071,7 +4368,7 @@ fn initHeaders(
4071 .addralign = 0,4368 .addralign = 0,
4072 .entsize = 0,4369 .entsize = 0,
4073 };4370 };
4074 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);4371 if (target_endian != std.lang.Endian.native) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
40754372
4076 elf.symtab.addOneAssumeCapacity().* = .{4373 elf.symtab.addOneAssumeCapacity().* = .{
4077 .node = .none,4374 .node = .none,
...@@ -4084,6 +4381,7 @@ fn initHeaders(...@@ -4084,6 +4381,7 @@ fn initHeaders(
4084 .entsize = @sizeOf(ElfN.Sym),4381 .entsize = @sizeOf(ElfN.Sym),
4085 .node_align = node_block_align,4382 .node_align = node_block_align,
4086 .info = 1, // index of first non-local symbol4383 .info = 1, // index of first non-local symbol
4384 .manual_size = true,
4087 }));4385 }));
4088 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));4386 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
4089 symtab_null.* = .{4387 symtab_null.* = .{
...@@ -4094,7 +4392,7 @@ fn initHeaders(...@@ -4094,7 +4392,7 @@ fn initHeaders(
4094 .other = .{ .visibility = .DEFAULT },4392 .other = .{ .visibility = .DEFAULT },
4095 .shndx = std.elf.SHN_UNDEF,4393 .shndx = std.elf.SHN_UNDEF,
4096 };4394 };
4097 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);4395 if (target_endian != std.lang.Endian.native) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);
40984396
4099 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));4397 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
4100 ehdr.shstrndx = ehdr.shnum;4398 ehdr.shstrndx = ehdr.shnum;
...@@ -4105,6 +4403,7 @@ fn initHeaders(...@@ -4105,6 +4403,7 @@ fn initHeaders(
4105 .size = 1,4403 .size = 1,
4106 .entsize = 1,4404 .entsize = 1,
4107 .node_align = node_block_align,4405 .node_align = node_block_align,
4406 .manual_size = true,
4108 }));4407 }));
4109 Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0;4408 Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0;
41104409
...@@ -4117,6 +4416,7 @@ fn initHeaders(...@@ -4117,6 +4416,7 @@ fn initHeaders(
4117 .size = 1,4416 .size = 1,
4118 .entsize = 1,4417 .entsize = 1,
4119 .node_align = node_block_align,4418 .node_align = node_block_align,
4419 .manual_size = true,
4120 }));4420 }));
4121 Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0;4421 Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0;
4122 switch (elf.shdrPtr(.symtab)) {4422 switch (elf.shdrPtr(.symtab)) {
...@@ -4156,6 +4456,7 @@ fn initHeaders(...@@ -4156,6 +4456,7 @@ fn initHeaders(
4156 .flags = .{ .WRITE = true, .ALLOC = true },4456 .flags = .{ .WRITE = true, .ALLOC = true },
4157 .addralign = addr_align,4457 .addralign = addr_align,
4158 .entsize = @intCast(addr_align.toByteUnits()),4458 .entsize = @intCast(addr_align.toByteUnits()),
4459 .manual_size = true,
4159 });4460 });
4160 {4461 {
4161 const init_plt_size = plt.entry_size * plt.header_entries;4462 const init_plt_size = plt.entry_size * plt.header_entries;
...@@ -4168,6 +4469,7 @@ fn initHeaders(...@@ -4168,6 +4469,7 @@ fn initHeaders(
4168 .size = got_plt.header_entries * elf.targetPtrSize(),4469 .size = got_plt.header_entries * elf.targetPtrSize(),
4169 .addralign = addr_align,4470 .addralign = addr_align,
4170 .entsize = @intCast(addr_align.toByteUnits()),4471 .entsize = @intCast(addr_align.toByteUnits()),
4472 .manual_size = true,
4171 });4473 });
4172 elf.shndx.plt = try elf.addSection(elf.ni.text, .{4474 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
4173 .name = ".plt",4475 .name = ".plt",
...@@ -4176,6 +4478,7 @@ fn initHeaders(...@@ -4176,6 +4478,7 @@ fn initHeaders(
4176 .size = plt.@"align".forward(init_plt_size),4478 .size = plt.@"align".forward(init_plt_size),
4177 .addralign = plt.@"align",4479 .addralign = plt.@"align",
4178 .node_align = node_block_align,4480 .node_align = node_block_align,
4481 .manual_size = true,
4179 });4482 });
4180 } else {4483 } else {
4181 elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt].unwrap().?, .{4484 elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt].unwrap().?, .{
...@@ -4185,6 +4488,7 @@ fn initHeaders(...@@ -4185,6 +4488,7 @@ fn initHeaders(
4185 .size = plt.@"align".forward(init_plt_size),4488 .size = plt.@"align".forward(init_plt_size),
4186 .addralign = plt.@"align",4489 .addralign = plt.@"align",
4187 .node_align = node_block_align,4490 .node_align = node_block_align,
4491 .manual_size = true,
4188 });4492 });
4189 }4493 }
4190 // And the award for most annoying PLT requirement goes to SPARC, which decided that the4494 // And the award for most annoying PLT requirement goes to SPARC, which decided that the
...@@ -4222,7 +4526,7 @@ fn initHeaders(...@@ -4222,7 +4526,7 @@ fn initHeaders(
4222 @memcpy(sec_interp[0..interp.len], interp);4526 @memcpy(sec_interp[0..interp.len], interp);
4223 sec_interp[interp.len] = 0;4527 sec_interp[interp.len] = 0;
4224 }4528 }
4225 if (have_dynamic_section) {4529 if (have_dynamic) {
4226 assert(elf.ni.data_rel_ro.alignment(&elf.mf).compare(.gte, addr_align));4530 assert(elf.ni.data_rel_ro.alignment(&elf.mf).compare(.gte, addr_align));
4227 const dynamic_ni = try elf.ni.data_rel_ro.addFloatingChild(&elf.mf, gpa, .{4531 const dynamic_ni = try elf.ni.data_rel_ro.addFloatingChild(&elf.mf, gpa, .{
4228 .alignment = addr_align,4532 .alignment = addr_align,
...@@ -4239,6 +4543,7 @@ fn initHeaders(...@@ -4239,6 +4543,7 @@ fn initHeaders(
4239 .size = 1,4543 .size = 1,
4240 .entsize = 1,4544 .entsize = 1,
4241 .node_align = node_block_align,4545 .node_align = node_block_align,
4546 .manual_size = true,
4242 });4547 });
4243 dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0;4548 dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0;
4244 elf.shndx.dynstr = dynstr_shndx;4549 elf.shndx.dynstr = dynstr_shndx;
...@@ -4257,6 +4562,7 @@ fn initHeaders(...@@ -4257,6 +4562,7 @@ fn initHeaders(
4257 .addralign = addr_align,4562 .addralign = addr_align,
4258 .entsize = @sizeOf(Sym),4563 .entsize = @sizeOf(Sym),
4259 .node_align = node_block_align,4564 .node_align = node_block_align,
4565 .manual_size = true,
4260 });4566 });
4261 const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class));4567 const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class));
4262 dynsym_null.* = .{4568 dynsym_null.* = .{
...@@ -4267,7 +4573,7 @@ fn initHeaders(...@@ -4267,7 +4573,7 @@ fn initHeaders(
4267 .other = .{ .visibility = .DEFAULT },4573 .other = .{ .visibility = .DEFAULT },
4268 .shndx = std.elf.SHN_UNDEF,4574 .shndx = std.elf.SHN_UNDEF,
4269 };4575 };
4270 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(4576 if (elf.targetEndian() != std.lang.Endian.native) std.mem.byteSwapAllFields(
4271 Sym,4577 Sym,
4272 dynsym_null,4578 dynsym_null,
4273 );4579 );
...@@ -4285,6 +4591,7 @@ fn initHeaders(...@@ -4285,6 +4591,7 @@ fn initHeaders(
4285 .addralign = addr_align,4591 .addralign = addr_align,
4286 .entsize = rela_size,4592 .entsize = rela_size,
4287 .node_align = node_block_align,4593 .node_align = node_block_align,
4594 .manual_size = true,
4288 });4595 });
4289 elf.shndx.rela_plt = try elf.addSection(elf.ni.rodata, .{4596 elf.shndx.rela_plt = try elf.addSection(elf.ni.rodata, .{
4290 .name = ".rela.plt",4597 .name = ".rela.plt",
...@@ -4295,6 +4602,7 @@ fn initHeaders(...@@ -4295,6 +4602,7 @@ fn initHeaders(
4295 .addralign = addr_align,4602 .addralign = addr_align,
4296 .entsize = rela_size,4603 .entsize = rela_size,
4297 .node_align = node_block_align,4604 .node_align = node_block_align,
4605 .manual_size = true,
4298 });4606 });
4299 elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{4607 elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{
4300 .name = ".dynamic",4608 .name = ".dynamic",
...@@ -4303,6 +4611,7 @@ fn initHeaders(...@@ -4303,6 +4611,7 @@ fn initHeaders(
4303 .link = dynstr_shndx.toSection().?,4611 .link = dynstr_shndx.toSection().?,
4304 .entsize = @intCast(addr_align.toByteUnits() * 2),4612 .entsize = @intCast(addr_align.toByteUnits() * 2),
4305 .addralign = addr_align,4613 .addralign = addr_align,
4614 .manual_size = true,
4306 });4615 });
4307 switch (elf.targetDynsymHashInfo()) {4616 switch (elf.targetDynsymHashInfo()) {
4308 inline else => |info| {4617 inline else => |info| {
...@@ -4318,6 +4627,7 @@ fn initHeaders(...@@ -4318,6 +4627,7 @@ fn initHeaders(
4318 .addralign = .fromByteUnits(@sizeOf(info.Int())),4627 .addralign = .fromByteUnits(@sizeOf(info.Int())),
4319 // initially: nbucket = 8 + nchain = 14628 // initially: nbucket = 8 + nchain = 1
4320 .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1),4629 .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1),
4630 .manual_size = true,
4321 });4631 });
4322 const hash_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf));4632 const hash_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf));
4323 const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]);4633 const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]);
...@@ -4407,13 +4717,45 @@ fn initHeaders(...@@ -4407,13 +4717,45 @@ fn initHeaders(
4407 .SPARCV9 => {},4717 .SPARCV9 => {},
4408 }4718 }
4409 }4719 }
4720 if (have_eh_frame) {
4721 elf.ni.gnu_eh_frame = .wrap(try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{
4722 .size = @sizeOf(Dwarf.EhFrameHdr),
4723 .alignment = .@"4",
4724 .moved = true,
4725 .bubbles_moved = false,
4726 }));
4727 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.gnu_eh_frame });
4728 elf.phdrs.items[phndx.gnu_eh_frame] = elf.ni.gnu_eh_frame;
4729
4730 elf.shndx.eh_frame_hdr = try elf.addSection(elf.ni.gnu_eh_frame.unwrap().?, .{
4731 .name = ".eh_frame_hdr",
4732 .type = .PROGBITS,
4733 .flags = .{ .ALLOC = true },
4734 .size = @sizeOf(Dwarf.EhFrameHdr),
4735 .addralign = .@"4",
4736 });
4737 elf.shndx.eh_frame = try elf.addSection(elf.ni.rodata, .{
4738 .name = ".eh_frame",
4739 .flags = .{ .ALLOC = true },
4740 .addralign = addr_align,
4741 .node_align = elf.mf.flags.block_size,
4742 });
4743 const eh_frame_hdr_ni = elf.shndx.eh_frame_hdr.get(elf).ni;
4744 elf.eh_frame_hdr_first_symbol_reloc =
4745 @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
4746 try elf.dwarf.genEhFrameHdr(
4747 Node.toAtom(eh_frame_hdr_ni),
4748 @ptrCast(@alignCast(eh_frame_hdr_ni.slice(&elf.mf))),
4749 Symbol.Id.local(elf.shndx.eh_frame.get(elf).lsi).toTypeErased(),
4750 );
4751 }
44104752
4411 // Populate reserved GOT words.4753 // Populate reserved GOT words.
4412 switch (machine) {4754 switch (machine) {
4413 .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)),4755 .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)),
4414 .X86_64 => {4756 .X86_64 => {
4415 try elf.got.ensureUnusedCapacity(gpa, 3);4757 try elf.got.ensureUnusedCapacity(gpa, 3);
4416 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {4758 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic) {
4417 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },4759 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },
4418 false => .{ .reserved = 0 },4760 false => .{ .reserved = 0 },
4419 }, .none);4761 }, .none);
...@@ -4422,7 +4764,7 @@ fn initHeaders(...@@ -4422,7 +4764,7 @@ fn initHeaders(
4422 },4764 },
4423 .LOONGARCH, .SPARCV9 => {4765 .LOONGARCH, .SPARCV9 => {
4424 try elf.got.ensureUnusedCapacity(gpa, 1);4766 try elf.got.ensureUnusedCapacity(gpa, 1);
4425 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {4767 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic) {
4426 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },4768 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },
4427 false => .{ .reserved = 0 },4769 false => .{ .reserved = 0 },
4428 }, .none);4770 }, .none);
...@@ -4567,7 +4909,7 @@ fn initHeaders(...@@ -4567,7 +4909,7 @@ fn initHeaders(
4567 }) catch |err| switch (err) {4909 }) catch |err| switch (err) {
4568 error.MultipleDefinitions => unreachable, // no inputs are processed yet4910 error.MultipleDefinitions => unreachable, // no inputs are processed yet
4569 };4911 };
4570 if (have_dynamic_section) {4912 if (have_dynamic) {
4571 _ = elf.addGlobalSymbolAssumeCapacity(.{4913 _ = elf.addGlobalSymbolAssumeCapacity(.{
4572 .node = .wrap(elf.shndx.dynamic.get(elf).ni),4914 .node = .wrap(elf.shndx.dynamic.get(elf).ni),
4573 .name = try .string(elf, "_DYNAMIC"),4915 .name = try .string(elf, "_DYNAMIC"),
...@@ -4583,13 +4925,39 @@ fn initHeaders(...@@ -4583,13 +4925,39 @@ fn initHeaders(
4583 }4925 }
4584 } else {4926 } else {
4585 assert(maybe_interp == null);4927 assert(maybe_interp == null);
4586 assert(!have_dynamic_section);4928 assert(!have_dynamic);
4929 if (have_eh_frame) elf.shndx.eh_frame = try elf.addSection(elf.ni.rodata, .{
4930 .name = ".eh_frame",
4931 .type = if (machine == .X86_64) .X86_64_UNWIND else .NULL,
4932 .flags = .{ .ALLOC = true },
4933 .addralign = addr_align,
4934 .node_align = elf.mf.flags.block_size,
4935 });
4587 }4936 }
4588 if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{4937 if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{
4589 .name = ".tdata",4938 .name = ".tdata",
4590 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },4939 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
4591 .node_align = node_block_align,4940 .node_align = node_block_align,
4592 });4941 });
4942 switch (comp.config.debug_format) {
4943 .strip => {},
4944 .dwarf => {
4945 if (have_debug_frame) elf.shndx.debug_frame = try elf.addSection(elf.ni.elf, .{
4946 .name = ".debug_frame",
4947 .addralign = addr_align,
4948 .node_align = elf.mf.flags.block_size,
4949 });
4950 elf.shndx.debug_info = try elf.addSection(elf.ni.elf, .{
4951 .name = ".debug_info",
4952 .node_align = elf.mf.flags.block_size,
4953 });
4954 elf.shndx.debug_line = try elf.addSection(elf.ni.elf, .{
4955 .name = ".debug_line",
4956 .node_align = elf.mf.flags.block_size,
4957 });
4958 },
4959 .code_view => unreachable,
4960 }
45934961
4594 assert(elf.nodes.len == expected_nodes_len);4962 assert(elf.nodes.len == expected_nodes_len);
4595 assert(elf.shdrs.items.len == shnum - 1); // -1 to exclude SHN_UNDEF4963 assert(elf.shdrs.items.len == shnum - 1); // -1 to exclude SHN_UNDEF
...@@ -4599,7 +4967,7 @@ fn initHeaders(...@@ -4599,7 +4967,7 @@ fn initHeaders(
4599 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});4967 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});
4600 }4968 }
46014969
4602 if (have_dynamic_section) elf.dynamic = .{4970 if (have_dynamic) elf.dynamic = .{
4603 .flags = if (elf.options.z_now) std.elf.DF_BIND_NOW else 0,4971 .flags = if (elf.options.z_now) std.elf.DF_BIND_NOW else 0,
4604 .flags_1 = f: {4972 .flags_1 = f: {
4605 var f: u32 = 0;4973 var f: u32 = 0;
...@@ -4677,15 +5045,26 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {...@@ -4677,15 +5045,26 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index {
4677 .ehdr,5045 .ehdr,
4678 .shdr,5046 .shdr,
4679 .segment,5047 .segment,
5048 .value_debug_info,
5049 .global_debug_info,
5050 .frame_padding,
5051 .func_debug_info,
5052 .func_debug_line,
4680 => unreachable,5053 => unreachable,
4681 .section => |shndx| shndx,5054 .section, .section_manual_size => |shndx| shndx,
4682 .input_section,5055 .input_section,
4683 .copied_global,5056 .copied_global,
4684 .nav,5057 .nav,
4685 .uav,5058 .uav,
4686 .lazy_code,5059 .lazy_code,
4687 .lazy_const_data,5060 .lazy_const_data,
5061 .unit_frame,
4688 => elf.getNode(ni.parent(&elf.mf).unwrap().?).section,5062 => elf.getNode(ni.parent(&elf.mf).unwrap().?).section,
5063 .unit_frame_cie, .func_frame_fde => {
5064 const unit_frame_ni = ni.parent(&elf.mf).unwrap().?;
5065 assert(elf.getNode(unit_frame_ni) == .unit_frame);
5066 return elf.getNode(unit_frame_ni.parent(&elf.mf).unwrap().?).section;
5067 },
4689 };5068 };
4690}5069}
4691fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {5070fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
...@@ -4699,31 +5078,52 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {...@@ -4699,31 +5078,52 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4699 .shdr,5078 .shdr,
4700 .segment,5079 .segment,
4701 .copied_global,5080 .copied_global,
5081 .value_debug_info,
5082 .global_debug_info,
5083 .frame_padding,
5084 .func_debug_info,
5085 .func_debug_line,
4702 => unreachable,5086 => unreachable,
4703 .section => |shndx| shndx.vaddr(elf),5087 .section, .section_manual_size => |shndx| shndx.vaddr(elf),
4704 .input_section => |isi| isi.ptrConst(elf).vaddr,5088 .input_section => |isi| isi.ptrConst(elf).vaddr,
4705 inline .nav,5089 inline .nav,
4706 .uav,5090 .uav,
4707 .lazy_code,5091 .lazy_code,
4708 .lazy_const_data,5092 .lazy_const_data,
4709 => |i| Symbol.Id.local(i.symbol(elf)).value(elf),5093 => |i| Symbol.Id.local(i.symbol(elf)).value(elf),
5094 .unit_frame, .unit_frame_cie, .func_frame_fde => elf.computeNodeVAddr(ni),
4710 };5095 };
4711}5096}
4712fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {5097fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4713 const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) {5098 const parent_ni = ni.parent(&elf.mf).unwrap().?;
4714 .archive,5099 const parent_vaddr = parent_vaddr: switch (elf.getNode(parent_ni)) {
4715 .archive_header,5100 .archive, .archive_header, .archive_input_member, .archive_elf_member_header => unreachable,
4716 .archive_input_member,
4717 .archive_elf_member_header,
4718 => unreachable,
4719 .elf => return 0,5101 .elf => return 0,
4720 .ehdr, .shdr => unreachable,5102 .ehdr, .shdr => unreachable,
4721 .segment => |phndx| switch (elf.phdrSlice()) {5103 .segment => |phndx| switch (elf.phdrSlice()) {
4722 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),5104 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),
4723 },5105 },
4724 .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf),5106 .section, .section_manual_size => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf),
4725 .input_section, .copied_global => unreachable,5107 .input_section, .copied_global => unreachable,
4726 inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf),5108 inline .nav,
5109 .uav,
5110 .lazy_code,
5111 .lazy_const_data,
5112 => |i| Symbol.Id.local(i.symbol(elf)).value(elf),
5113 .value_debug_info,
5114 .global_debug_info,
5115 .frame_padding,
5116 => unreachable,
5117 .unit_frame => {
5118 const section_ni = parent_ni.parent(&elf.mf).unwrap().?;
5119 const section_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf);
5120 break :parent_vaddr elf.getNode(section_ni).section.vaddr(elf) + section_offset;
5121 },
5122 .unit_frame_cie,
5123 .func_frame_fde,
5124 .func_debug_info,
5125 .func_debug_line,
5126 => unreachable,
4727 };5127 };
4728 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);5128 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);
4729 return parent_vaddr + offset;5129 return parent_vaddr + offset;
...@@ -4736,9 +5136,9 @@ fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 {...@@ -4736,9 +5136,9 @@ fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 {
4736/// sequence of relocations, so that the caller may append the node's updated relocations.5136/// sequence of relocations, so that the caller may append the node's updated relocations.
4737///5137///
4738/// Asserts that `ni` must be a node which supports relocations (see `Elf.Node`). Does not support5138/// Asserts that `ni` must be a node which supports relocations (see `Elf.Node`). Does not support
4739/// the special-case sections '.plt' and '.dynamic'.5139/// the special-case sections '.plt', '.dynamic', and '.eh_frame_hdr'.
4740fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {5140fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
4741 const symbol_relocs: *SymbolReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) {5141 const symbol_relocs: *SymbolReloc.Index, const node_relocs: ?*NodeReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) {
4742 .archive,5142 .archive,
4743 .archive_header,5143 .archive_header,
4744 .archive_input_member,5144 .archive_input_member,
...@@ -4748,24 +5148,42 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -4748,24 +5148,42 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
4748 .shdr,5148 .shdr,
4749 .segment,5149 .segment,
4750 .copied_global,5150 .copied_global,
5151 .value_debug_info,
5152 .global_debug_info,
5153 .frame_padding,
5154 .unit_frame,
5155 .unit_frame_cie,
5156 .func_debug_info,
5157 .func_debug_line,
4751 => unreachable, // cannot contain relocs5158 => unreachable, // cannot contain relocs
4752 .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported)5159 .section,
5160 .section_manual_size,
5161 => unreachable, // cannot contain relocs (.plt, .dynamic, and .eh_frame_hdr unsupported)
4753 .input_section => |isi| .{5162 .input_section => |isi| .{
4754 &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc,5163 &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc,
5164 null,
4755 &elf.input_sections.items[@backingInt(isi)].first_got_reloc,5165 &elf.input_sections.items[@backingInt(isi)].first_got_reloc,
4756 },5166 },
4757 .nav => |nmi| .{5167 .nav => |nmi| .{
4758 &elf.navs.values()[@backingInt(nmi)].first_symbol_reloc,5168 &elf.navs.values()[@backingInt(nmi)].first_symbol_reloc,
5169 null,
4759 &elf.navs.values()[@backingInt(nmi)].first_got_reloc,5170 &elf.navs.values()[@backingInt(nmi)].first_got_reloc,
4760 },5171 },
4761 .uav => |umi| .{5172 .uav => |umi| .{
4762 &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc,5173 &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc,
4763 null,5174 null,
5175 null,
4764 },5176 },
4765 inline .lazy_code, .lazy_const_data => |lmi| .{5177 inline .lazy_code, .lazy_const_data => |lmi| .{
4766 &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_symbol_reloc,5178 &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_symbol_reloc,
5179 null,
4767 &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_got_reloc,5180 &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_got_reloc,
4768 },5181 },
5182 .func_frame_fde => |fi| .{
5183 &elf.dwarf_funcs.items[@backingInt(fi)].func_frame_fde_first_symbol_reloc,
5184 &elf.dwarf_funcs.items[@backingInt(fi)].func_frame_fde_first_node_reloc,
5185 null,
5186 },
4769 };5187 };
47705188
4771 if (symbol_relocs.* != .none) {5189 if (symbol_relocs.* != .none) {
...@@ -4779,6 +5197,16 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -4779,6 +5197,16 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
4779 }5197 }
4780 symbol_relocs.* = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));5198 symbol_relocs.* = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
47815199
5200 if (node_relocs) |ptr| {
5201 if (ptr.* != .none) {
5202 for (elf.node_relocs.items[@backingInt(ptr.*)..]) |*reloc| {
5203 if (reloc.node != ni) break;
5204 reloc.delete(elf);
5205 }
5206 }
5207 ptr.* = @fromBackingInt(@intCast(elf.node_relocs.items.len));
5208 }
5209
4782 if (got_relocs) |ptr| {5210 if (got_relocs) |ptr| {
4783 if (ptr.* != .none) {5211 if (ptr.* != .none) {
4784 for (elf.got_relocs.items[@backingInt(ptr.*)..]) |*reloc| {5212 for (elf.got_relocs.items[@backingInt(ptr.*)..]) |*reloc| {
...@@ -4797,6 +5225,7 @@ fn flushMovedNodeRelocs(...@@ -4797,6 +5225,7 @@ fn flushMovedNodeRelocs(
4797 node: MappedFile.Node.Index,5225 node: MappedFile.Node.Index,
4798 node_vaddr: u64,5226 node_vaddr: u64,
4799 first_symbol_reloc: SymbolReloc.Index,5227 first_symbol_reloc: SymbolReloc.Index,
5228 first_node_reloc: NodeReloc.Index,
4800 first_got_reloc: GotReloc.Index,5229 first_got_reloc: GotReloc.Index,
4801) void {5230) void {
4802 if (first_symbol_reloc != .none) {5231 if (first_symbol_reloc != .none) {
...@@ -4816,6 +5245,21 @@ fn flushMovedNodeRelocs(...@@ -4816,6 +5245,21 @@ fn flushMovedNodeRelocs(
4816 }5245 }
4817 }5246 }
48185247
5248 if (first_node_reloc != .none) {
5249 for (elf.node_relocs.items[@backingInt(first_node_reloc)..]) |*reloc| {
5250 if (reloc.node != node) break;
5251 if (reloc.rela_index.unwrap()) |rela_index| {
5252 assert(elf.ehdrType() == .REL);
5253 // The node has moved, so the offset of the relocation within the section might have
5254 // changed, so update the `offset` field of the `ElfN.Rela` entry.
5255 elf.getNodeShndx(reloc.node).get(elf).rela.shndx.relaSetOffset(elf, rela_index, node_vaddr + reloc.offset);
5256 } else {
5257 assert(elf.ehdrType() != .REL);
5258 reloc.apply(elf);
5259 }
5260 }
5261 }
5262
4819 if (first_got_reloc != .none) {5263 if (first_got_reloc != .none) {
4820 for (elf.got_relocs.items[@backingInt(first_got_reloc)..]) |*reloc| {5264 for (elf.got_relocs.items[@backingInt(first_got_reloc)..]) |*reloc| {
4821 if (reloc.node != node.toOptional()) break;5265 if (reloc.node != node.toOptional()) break;
...@@ -5226,7 +5670,7 @@ fn mapInputSection(elf: *Elf, opts: struct {...@@ -5226,7 +5670,7 @@ fn mapInputSection(elf: *Elf, opts: struct {
5226 }5670 }
52275671
5228 switch (elf.targetLoad(&shdr.type)) {5672 switch (elf.targetLoad(&shdr.type)) {
5229 .NULL, .PROGBITS => {},5673 .NULL, .PROGBITS, .X86_64_UNWIND => {},
5230 else => return error.SectionTypeConflict,5674 else => return error.SectionTypeConflict,
5231 }5675 }
52325676
...@@ -5360,7 +5804,7 @@ fn uavMapIndex(...@@ -5360,7 +5804,7 @@ fn uavMapIndex(
5360 .moved = true, // see assert at end of `genUav`5804 .moved = true, // see assert at end of `genUav`
5361 .alignment = resolved_align,5805 .alignment = resolved_align,
5362 });5806 });
5363 var name_buf: [32]u8 = undefined;5807 var name_buf: [std.fmt.count("__anon_{d}", .{std.math.maxInt(u32)})]u8 = undefined;
5364 const name = std.mem.print(5808 const name = std.mem.print(
5365 &name_buf,5809 &name_buf,
5366 "__anon_{d}",5810 "__anon_{d}",
...@@ -5520,7 +5964,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load...@@ -5520,7 +5964,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load
5520 }5964 }
5521 var strtab: std.Io.Writer.Allocating = .init(gpa);5965 var strtab: std.Io.Writer.Allocating = .init(gpa);
5522 defer strtab.deinit();5966 defer strtab.deinit();
5523 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {5967 while (r.takeStruct(std.elf.ar_hdr, .native)) |header| {
5524 if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG))5968 if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG))
5525 return diags.failParse(path, "bad file magic", .{});5969 return diags.failParse(path, "bad file magic", .{});
5526 const offset = fr.logicalPos();5970 const offset = fr.logicalPos();
...@@ -5717,13 +6161,13 @@ fn loadObject(...@@ -5717,13 +6161,13 @@ fn loadObject(
5717 for (sections[1..]) |*section| {6161 for (sections[1..]) |*section| {
5718 if (section.shdr.name >= shstrtab.len) continue;6162 if (section.shdr.name >= shstrtab.len) continue;
5719 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);6163 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
6164 if (!comp.config.any_unwind_tables and std.mem.eql(u8, name, ".eh_frame")) continue;
5720 const opts: struct {6165 const opts: struct {
5721 shndx: Section.Index,6166 shndx: Section.Index,
5722 has_file_bits: bool,
5723 node_fixed: bool,6167 node_fixed: bool,
5724 } = switch (section.shdr.type) {6168 } = switch (section.shdr.type) {
5725 else => continue,6169 else => continue,
5726 .PROGBITS, .NOBITS => opts: {6170 .PROGBITS, .NOBITS, .X86_64_UNWIND => opts: {
5727 const shndx = elf.mapInputSection(.{6171 const shndx = elf.mapInputSection(.{
5728 .name = name,6172 .name = name,
5729 .flags = section.shdr.flags.shf,6173 .flags = section.shdr.flags.shf,
...@@ -5776,7 +6220,6 @@ fn loadObject(...@@ -5776,7 +6220,6 @@ fn loadObject(
5776 }6220 }
5777 break :opts .{6221 break :opts .{
5778 .shndx = shndx,6222 .shndx = shndx,
5779 .has_file_bits = section.shdr.type == .PROGBITS,
5780 // For well-known sections, we know that it's fine to have e.g. random6223 // For well-known sections, we know that it's fine to have e.g. random
5781 // padding, so there's no need to make the sections fixed. For custom6224 // padding, so there's no need to make the sections fixed. For custom
5782 // sections, however, we do want fixed nodes to avoid padding.6225 // sections, however, we do want fixed nodes to avoid padding.
...@@ -5819,7 +6262,6 @@ fn loadObject(...@@ -5819,7 +6262,6 @@ fn loadObject(
5819 }6262 }
5820 break :shndx shndx.*;6263 break :shndx shndx.*;
5821 },6264 },
5822 .has_file_bits = true,
5823 // This node must be fixed to prevent padding from being added between different6265 // This node must be fixed to prevent padding from being added between different
5824 // INIT_ARRAY/FINI_ARRAY/PREINIT_ARRAY input sections.6266 // INIT_ARRAY/FINI_ARRAY/PREINIT_ARRAY input sections.
5825 .node_fixed = true,6267 .node_fixed = true,
...@@ -5855,7 +6297,7 @@ fn loadObject(...@@ -5855,7 +6297,7 @@ fn loadObject(
5855 .input = input_index,6297 .input = input_index,
5856 .file_location = .{6298 .file_location = .{
5857 .offset = fl.offset + section.shdr.offset,6299 .offset = fl.offset + section.shdr.offset,
5858 .size = if (opts.has_file_bits) section.shdr.size else 0,6300 .size = if (section.shdr.type == .NOBITS) 0 else section.shdr.size,
5859 },6301 },
5860 // The section vaddr is initially 0, because the symbol addresses are6302 // The section vaddr is initially 0, because the symbol addresses are
5861 // zero-based. This will eventually be updated by `flushMoved`.6303 // zero-based. This will eventually be updated by `flushMoved`.
...@@ -6407,6 +6849,7 @@ fn createInitFiniArraySection(...@@ -6407,6 +6849,7 @@ fn createInitFiniArraySection(
6407 .type = @"type",6849 .type = @"type",
6408 .flags = .{ .WRITE = true, .ALLOC = true },6850 .flags = .{ .WRITE = true, .ALLOC = true },
6409 .node_align = addr_align,6851 .node_align = addr_align,
6852 .manual_size = true,
6410 });6853 });
6411 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});6854 elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {});
6412 try elf.ensureUnusedSymbolCapacity(2, .maybe_global);6855 try elf.ensureUnusedSymbolCapacity(2, .maybe_global);
...@@ -6455,7 +6898,9 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -6455,7 +6898,9 @@ fn prelinkInner(elf: *Elf) Error!void {
6455 const comp = elf.base.comp;6898 const comp = elf.base.comp;
6456 const gpa = comp.gpa;6899 const gpa = comp.gpa;
64576900
6458 if (comp.zcu != null and !comp.config.use_llvm and elf.ni.elf == .root) {6901 if (comp.zcu) |zcu| self_hosted_codegen: {
6902 if (comp.config.use_llvm) break :self_hosted_codegen;
6903
6459 // We're using self-hosted codegen---add an input representing the Zig "object".6904 // We're using self-hosted codegen---add an input representing the Zig "object".
6460 try elf.ensureUnusedSymbolCapacity(1, .all_local);6905 try elf.ensureUnusedSymbolCapacity(1, .all_local);
6461 try elf.inputs.ensureUnusedCapacity(gpa, 1);6906 try elf.inputs.ensureUnusedCapacity(gpa, 1);
...@@ -6475,6 +6920,37 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -6475,6 +6920,37 @@ fn prelinkInner(elf: *Elf) Error!void {
6475 .extra = .{ .file_symbol = zcu_file_symbol },6920 .extra = .{ .file_symbol = zcu_file_symbol },
6476 };6921 };
6477 elf.input_pending_index += 1;6922 elf.input_pending_index += 1;
6923
6924 try elf.dwarf.initUnits(zcu);
6925 try elf.dwarf_units.appendNTimes(gpa, .{
6926 .unit_frame_cie_first_target_reloc = .none,
6927 }, elf.dwarf.units.count());
6928
6929 try elf.nodes.ensureUnusedCapacity(gpa, 2);
6930 for (
6931 [2]Dwarf.Frame.Format{ .eh_frame, .debug_frame },
6932 [2]Section.Index{ elf.shndx.eh_frame, elf.shndx.debug_frame },
6933 ) |format, frame_shndx| {
6934 if (frame_shndx == .UNDEF) continue;
6935 const frame_ni = frame_shndx.get(elf).ni;
6936 _ = frame_ni.last(&elf.mf).unwrap() orelse continue;
6937 const frame_padding_ni = try frame_ni.addFloatingChild(&elf.mf, gpa, .{
6938 .alignment = switch (elf.identClass()) {
6939 .NONE, _ => unreachable,
6940 .@"32" => .@"4",
6941 .@"64" => .@"8",
6942 },
6943 .next_moved = true,
6944 .enable_next_moved = true,
6945 });
6946 elf.nodes.appendAssumeCapacity(.frame_padding);
6947 var cie_writer: MappedFile.Node.Writer = undefined;
6948 frame_padding_ni.writer(&elf.mf, gpa, &cie_writer);
6949 defer cie_writer.deinit();
6950 elf.dwarf.genDebugFrameCie(&cie_writer.interface, null, format) catch |err| switch (err) {
6951 error.WriteFailed => return cie_writer.err.?,
6952 };
6953 }
6478 }6954 }
6479}6955}
64806956
...@@ -6610,7 +7086,7 @@ fn flushDynamic(elf: *Elf) void {...@@ -6610,7 +7086,7 @@ fn flushDynamic(elf: *Elf) void {
6610 dynamic_index += 9;7086 dynamic_index += 9;
66117087
6612 assert(dynamic_index == dynamic_entries.len);7088 assert(dynamic_index == dynamic_entries.len);
6613 if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry|7089 if (elf.targetEndian() != std.lang.Endian.native) for (dynamic_entries) |*dynamic_entry|
6614 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);7090 std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry);
6615 },7091 },
6616 }7092 }
...@@ -6626,6 +7102,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -6626,6 +7102,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
6626 addralign: Alignment = .@"1",7102 addralign: Alignment = .@"1",
6627 entsize: std.elf.Word = 0,7103 entsize: std.elf.Word = 0,
6628 node_align: Alignment = .@"1",7104 node_align: Alignment = .@"1",
7105 manual_size: bool = false,
6629}) Error!Section.Index {7106}) Error!Section.Index {
6630 switch (opts.type) {7107 switch (opts.type) {
6631 .NULL => assert(opts.size == 0),7108 .NULL => assert(opts.size == 0),
...@@ -6679,6 +7156,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -6679,6 +7156,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
6679 .size = opts.node_align.forward(opts.size),7156 .size = opts.node_align.forward(opts.size),
6680 .alignment = opts.addralign.max(opts.node_align),7157 .alignment = opts.addralign.max(opts.node_align),
6681 .resized = opts.size > 0,7158 .resized = opts.size > 0,
7159 .bubbles_moved = opts.flags.ALLOC,
6682 });7160 });
6683 const addr = elf.computeNodeVAddr(ni);7161 const addr = elf.computeNodeVAddr(ni);
6684 const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{7162 const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{
...@@ -6694,7 +7172,10 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -6694,7 +7172,10 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
6694 .RELA => .{ .free_head = .none },7172 .RELA => .{ .free_head = .none },
6695 else => .{ .shndx = .UNDEF },7173 else => .{ .shndx = .UNDEF },
6696 } });7174 } });
6697 elf.nodes.appendAssumeCapacity(.{ .section = shndx });7175 elf.nodes.appendAssumeCapacity(switch (opts.manual_size) {
7176 false => .{ .section = shndx },
7177 true => .{ .section_manual_size = shndx },
7178 });
6698 switch (elf.shdrPtr(shndx)) {7179 switch (elf.shdrPtr(shndx)) {
6699 inline else => |shdr, class| {7180 inline else => |shdr, class| {
6700 shdr.* = .{7181 shdr.* = .{
...@@ -6709,7 +7190,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -6709,7 +7190,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
6709 .addralign = @intCast(opts.addralign.toByteUnits()),7190 .addralign = @intCast(opts.addralign.toByteUnits()),
6710 .entsize = opts.entsize,7191 .entsize = opts.entsize,
6711 };7192 };
6712 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);7193 if (elf.targetEndian() != std.lang.Endian.native) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);
6713 },7194 },
6714 }7195 }
6715 return shndx;7196 return shndx;
...@@ -6719,6 +7200,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)...@@ -6719,6 +7200,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
6719 if (len == 0) return;7200 if (len == 0) return;
6720 const gpa = elf.base.comp.gpa;7201 const gpa = elf.base.comp.gpa;
6721 try elf.symbol_relocs.ensureUnusedCapacity(gpa, len);7202 try elf.symbol_relocs.ensureUnusedCapacity(gpa, len);
7203 try elf.node_relocs.ensureUnusedCapacity(gpa, len);
6722 try elf.got_relocs.ensureUnusedCapacity(gpa, len);7204 try elf.got_relocs.ensureUnusedCapacity(gpa, len);
6723 const class = elf.identClass();7205 const class = elf.identClass();
6724 switch (elf.ehdrType()) {7206 switch (elf.ehdrType()) {
...@@ -6749,6 +7231,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)...@@ -6749,6 +7231,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
6749 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),7231 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
6750 },7232 },
6751 .node_align = elf.mf.flags.block_size,7233 .node_align = elf.mf.flags.block_size,
7234 .manual_size = true,
6752 });7235 });
6753 elf.section_by_name.putAssumeCapacityNoClobber(rela_shndx.name(elf), {});7236 elf.section_by_name.putAssumeCapacityNoClobber(rela_shndx.name(elf), {});
6754 shndx.get(elf).rela.shndx = rela_shndx;7237 shndx.get(elf).rela.shndx = rela_shndx;
...@@ -6795,15 +7278,10 @@ fn addRelocAssumeCapacity(...@@ -6795,15 +7278,10 @@ fn addRelocAssumeCapacity(
6795 .addend = addend,7278 .addend = addend,
6796 });7279 });
6797 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));7280 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
6798 const next: SymbolReloc.Index = next: {7281 const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc;
6799 const target_ptr = target.index(elf).ptr(elf);7282 const next = first_target_reloc.*;
6800 const next = target_ptr.first_target_reloc;7283 first_target_reloc.* = ri;
6801 target_ptr.first_target_reloc = ri;7284 if (next != .none) next.get(elf).prev = ri;
6802 break :next next;
6803 };
6804 if (next != .none) {
6805 next.get(elf).prev = ri;
6806 }
6807 elf.symbol_relocs.appendAssumeCapacity(.{7285 elf.symbol_relocs.appendAssumeCapacity(.{
6808 .node = node,7286 .node = node,
6809 .offset = offset,7287 .offset = offset,
...@@ -6816,7 +7294,6 @@ fn addRelocAssumeCapacity(...@@ -6816,7 +7294,6 @@ fn addRelocAssumeCapacity(
6816 .result = .ok,7294 .result = .ok,
6817 });7295 });
6818 },7296 },
6819
6820 .DYN, .EXEC => switch (elf.ehdrMachine()) {7297 .DYN, .EXEC => switch (elf.ehdrMachine()) {
6821 .AARCH64 => switch (@"type".AARCH64) {7298 .AARCH64 => switch (@"type".AARCH64) {
6822 .NONE => {},7299 .NONE => {},
...@@ -7239,12 +7716,10 @@ fn addSymbolRelocAssumeCapacity(...@@ -7239,12 +7716,10 @@ fn addSymbolRelocAssumeCapacity(
7239 };7716 };
72407717
7241 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));7718 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
7242 const target_ptr = target.index(elf).ptr(elf);7719 const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc;
7243 const next = target_ptr.first_target_reloc;7720 const next = first_target_reloc.*;
7244 target_ptr.first_target_reloc = ri;7721 first_target_reloc.* = ri;
7245 if (next != .none) {7722 if (next != .none) next.get(elf).prev = ri;
7246 next.get(elf).prev = ri;
7247 }
7248 elf.symbol_relocs.appendAssumeCapacity(.{7723 elf.symbol_relocs.appendAssumeCapacity(.{
7249 .node = node,7724 .node = node,
7250 .offset = offset,7725 .offset = offset,
...@@ -7263,6 +7738,92 @@ fn addSymbolRelocAssumeCapacity(...@@ -7263,6 +7738,92 @@ fn addSymbolRelocAssumeCapacity(
7263 // Actually apply the new relocation!7738 // Actually apply the new relocation!
7264 ri.get(elf).apply(elf);7739 ri.get(elf).apply(elf);
7265}7740}
7741fn addNodeRelocAssumeCapacity(
7742 elf: *Elf,
7743 node: MappedFile.Node.Index,
7744 offset: u64,
7745 target: MappedFile.Node.Index,
7746 addend: i64,
7747 @"type": NodeReloc.Type,
7748) Error!void {
7749 const shndx = elf.getNodeShndx(target);
7750 assert(!shndx.flags(elf).ALLOC); // not yet needed so not implemented
7751 const first_target_reloc = switch (elf.getNode(target)) {
7752 else => unreachable,
7753 .unit_frame_cie => |ui| &elf.dwarf_units.items[@backingInt(ui)].unit_frame_cie_first_target_reloc,
7754 };
7755 const next = first_target_reloc.*;
7756 const ri: NodeReloc.Index = @fromBackingInt(@intCast(elf.node_relocs.items.len));
7757 first_target_reloc.* = ri;
7758 if (next != .none) next.get(elf).prev = ri;
7759 switch (elf.ehdrType()) {
7760 .REL => {
7761 const rela_shndx = elf.getNodeShndx(node).get(elf).rela.shndx;
7762 const rela_index = rela_shndx.relaAddOneAssumeCapacity(elf, .{
7763 .type = switch (elf.ehdrMachine()) {
7764 .AARCH64 => .{ .AARCH64 = switch (@"type") {
7765 .abs32 => .ABS32,
7766 .abs64 => .ABS64,
7767 } },
7768 .LOONGARCH => .{ .LARCH = switch (@"type") {
7769 .abs32 => .@"32",
7770 .abs64 => .@"64",
7771 } },
7772 .PPC64 => .{ .PPC64 = switch (@"type") {
7773 .abs32 => .ADDR32,
7774 .abs64 => .ADDR64,
7775 } },
7776 .RISCV => .{ .RISCV = switch (@"type") {
7777 .abs32 => .@"32",
7778 .abs64 => .@"64",
7779 } },
7780 .SPARCV9 => .{ .SPARC = switch (@"type") {
7781 .abs32 => .UA32,
7782 .abs64 => .UA64,
7783 } },
7784 .X86_64 => .{ .SPARC = switch (@"type") {
7785 .abs32 => .@"32",
7786 .abs64 => .@"64",
7787 } },
7788 },
7789 // This field needs to equal the offset into the section, which is *not* necessarily
7790 // the same thing as our `offset`, which is the offset into `node`. We could compute
7791 // the section offset now, but there's no point, because `flushMovedNodeRelocs` will
7792 // eventually do it for us anyway, so just init to 0.
7793 .offset = 0,
7794 .raw_sym_index = @backingInt(shndx.get(elf).lsi.index()),
7795 .addend = addend,
7796 });
7797 elf.node_relocs.appendAssumeCapacity(.{
7798 .node = node,
7799 .offset = offset,
7800 .type = undefined,
7801 .target = target,
7802 .addend = addend,
7803 .next = next,
7804 .prev = .none,
7805 .rela_index = rela_index.toOptional(),
7806 .result = .ok,
7807 });
7808 },
7809 .DYN, .EXEC => {
7810 elf.node_relocs.appendAssumeCapacity(.{
7811 .node = node,
7812 .offset = offset,
7813 .target = target,
7814 .addend = addend,
7815 .type = @"type",
7816 .next = next,
7817 .prev = .none,
7818 .rela_index = .none,
7819 .result = .ok,
7820 });
7821
7822 // Actually apply the new relocation!
7823 ri.get(elf).apply(elf);
7824 },
7825 }
7826}
7266fn addGotRelocAssumeCapacity(7827fn addGotRelocAssumeCapacity(
7267 elf: *Elf,7828 elf: *Elf,
7268 node: MappedFile.Node.Index,7829 node: MappedFile.Node.Index,
...@@ -7282,8 +7843,17 @@ fn addGotRelocAssumeCapacity(...@@ -7282,8 +7843,17 @@ fn addGotRelocAssumeCapacity(
7282 .shdr,7843 .shdr,
7283 .segment,7844 .segment,
7284 .copied_global,7845 .copied_global,
7846 .value_debug_info,
7847 .global_debug_info,
7848 .frame_padding,
7849 .unit_frame,
7850 .unit_frame_cie,
7851 .func_frame_fde,
7852 .func_debug_info,
7853 .func_debug_line,
7285 => unreachable, // cannot contain relocs,7854 => unreachable, // cannot contain relocs,
7286 .section,7855 .section,
7856 .section_manual_size,
7287 .uav,7857 .uav,
7288 => unreachable, // cannot contain GOT relocs7858 => unreachable, // cannot contain GOT relocs
7289 .input_section,7859 .input_section,
...@@ -7572,7 +8142,6 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -7572,7 +8142,6 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
75728142
7573 const nmi = try elf.navMapIndex(zcu, nav_index);8143 const nmi = try elf.navMapIndex(zcu, nav_index);
7574 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;8144 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;
7575 elf.resetNodeRelocs(ni);
75768145
7577 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be8146 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
7578 // called to apply the NAV's new relocations.8147 // called to apply the NAV's new relocations.
...@@ -7582,6 +8151,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -7582,6 +8151,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
7582 var nw: MappedFile.Node.Writer = undefined;8151 var nw: MappedFile.Node.Writer = undefined;
7583 ni.writer(&elf.mf, gpa, &nw);8152 ni.writer(&elf.mf, gpa, &nw);
7584 defer nw.deinit();8153 defer nw.deinit();
8154 elf.resetNodeRelocs(ni);
7585 codegen.generateSymbol(8155 codegen.generateSymbol(
7586 &elf.base,8156 &elf.base,
7587 pt,8157 pt,
...@@ -7628,7 +8198,6 @@ fn updateFuncInner(...@@ -7628,7 +8198,6 @@ fn updateFuncInner(
7628 const nmi = try elf.navMapIndex(zcu, func.owner_nav);8198 const nmi = try elf.navMapIndex(zcu, func.owner_nav);
7629 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });8199 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) });
7630 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;8200 const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?;
7631 elf.resetNodeRelocs(ni);
76328201
7633 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be8202 // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be
7634 // called to apply the NAV's new relocations.8203 // called to apply the NAV's new relocations.
...@@ -7638,6 +8207,132 @@ fn updateFuncInner(...@@ -7638,6 +8207,132 @@ fn updateFuncInner(
7638 var nw: MappedFile.Node.Writer = undefined;8207 var nw: MappedFile.Node.Writer = undefined;
7639 ni.writer(&elf.mf, gpa, &nw);8208 ni.writer(&elf.mf, gpa, &nw);
7640 defer nw.deinit();8209 defer nw.deinit();
8210 var debug: Dwarf.WipNav.Debug = undefined;
8211 const debug_output: link.File.DebugInfoOutput = debug_output: {
8212 if (elf.ehdrMachine() != .X86_64) break :debug_output .none;
8213 const dwarf = &elf.dwarf;
8214 const mod = zcu.navFileScope(func.owner_nav).mod.?;
8215 if (mod.strip and mod.unwind_tables == .none) break :debug_output .none;
8216
8217 try elf.nodes.ensureUnusedCapacity(gpa, 5);
8218 const dwarf_func_index = try dwarf.getFunc(func.owner_nav);
8219 try elf.dwarf_funcs.appendNTimes(gpa, .{
8220 .func_frame_fde_first_symbol_reloc = .none,
8221 .func_frame_fde_first_node_reloc = .none,
8222 }, @backingInt(dwarf_func_index) + 1 -| elf.dwarf_funcs.items.len);
8223
8224 debug.wip_nav = .{
8225 .dwarf = dwarf,
8226 .unit = dwarf.getUnit(mod),
8227 .func = dwarf_func_index,
8228 .func_si = Symbol.Id.local(nmi.symbol(elf)).toTypeErased(),
8229 .cfi = .{
8230 .loc = 0,
8231 .cfa = dwarf.frame.header.initial_instructions[0].def_cfa,
8232 },
8233 .frame_format = switch (mod.unwind_tables) {
8234 .none => .debug_frame,
8235 .sync, .async => .eh_frame,
8236 },
8237 .fde_writer = undefined,
8238 .frame_func_length_offset = std.math.maxInt(usize),
8239 };
8240 const unit = debug.wip_nav.unit.get(dwarf);
8241 const frame_align: Alignment = switch (elf.identClass()) {
8242 .NONE, _ => unreachable,
8243 .@"32" => .@"4",
8244 .@"64" => .@"8",
8245 };
8246 const frame_ni = unit.frame_ni.unwrap() orelse frame_ni: {
8247 const frame_ni = try switch (debug.wip_nav.frame_format) {
8248 .debug_frame => elf.shndx.debug_frame,
8249 .eh_frame => elf.shndx.eh_frame,
8250 }.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{
8251 .alignment = frame_align.max(elf.mf.flags.block_size),
8252 .next_moved = true,
8253 .enable_next_moved = true,
8254 });
8255 unit.frame_ni = .wrap(frame_ni);
8256 elf.nodes.appendAssumeCapacity(.{ .unit_frame = debug.wip_nav.unit });
8257 break :frame_ni frame_ni;
8258 };
8259 _ = unit.cie_ni.unwrap() orelse {
8260 const cie_ni = try frame_ni.addOnlyHeaderChild(&elf.mf, gpa, .{
8261 .alignment = frame_align,
8262 .next_moved = true,
8263 .enable_next_moved = true,
8264 });
8265 unit.cie_ni = .wrap(cie_ni);
8266 elf.nodes.appendAssumeCapacity(.{ .unit_frame_cie = debug.wip_nav.unit });
8267 var cie_writer: MappedFile.Node.Writer = undefined;
8268 cie_ni.writer(&elf.mf, gpa, &cie_writer);
8269 defer cie_writer.deinit();
8270 dwarf.genDebugFrameCie(&cie_writer.interface, switch (elf.ehdrMachine()) {
8271 else => unreachable,
8272 .X86_64 => .x86_64,
8273 }, debug.wip_nav.frame_format) catch |err| switch (err) {
8274 error.WriteFailed => return cie_writer.err.?,
8275 };
8276 @memset(cie_writer.interface.unusedCapacitySlice(), std.dwarf.CFA.nop);
8277 };
8278 const dwarf_func = dwarf_func_index.get(dwarf);
8279 const fde_ni = if (dwarf_func.fde_ni.unwrap()) |fde_ni| fde_ni: {
8280 try fde_ni.moved(gpa, &elf.mf);
8281 try fde_ni.nextMoved(gpa, &elf.mf);
8282 break :fde_ni fde_ni;
8283 } else fde_ni: {
8284 const fde_ni = try frame_ni.addFloatingChild(&elf.mf, gpa, .{
8285 .alignment = frame_align,
8286 .moved = true,
8287 .next_moved = true,
8288 .enable_next_moved = true,
8289 });
8290 dwarf_func.fde_ni = .wrap(fde_ni);
8291 break :fde_ni fde_ni;
8292 };
8293 fde_ni.writer(&elf.mf, gpa, &debug.wip_nav.fde_writer);
8294 if (mod.strip) break :debug_output .{ .eh_frame = &debug.wip_nav };
8295
8296 debug.pt = pt;
8297 debug.any_children = false;
8298 debug.blocks = .empty;
8299 const debug_info_ni = dwarf_func.debug_info_ni.unwrap() orelse debug_info_ni: {
8300 const debug_info_ni =
8301 try elf.shndx.debug_info.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{
8302 .next_moved = true,
8303 .enable_next_moved = true,
8304 });
8305 dwarf_func.debug_info_ni = .wrap(debug_info_ni);
8306 elf.nodes.appendAssumeCapacity(.{ .func_debug_info = dwarf_func_index });
8307 break :debug_info_ni debug_info_ni;
8308 };
8309 debug_info_ni.writer(&elf.mf, gpa, &debug.info_writer);
8310 const debug_line_ni = dwarf_func.debug_line_ni.unwrap() orelse debug_line_ni: {
8311 const debug_line_ni =
8312 try elf.shndx.debug_line.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{
8313 .next_moved = true,
8314 .enable_next_moved = true,
8315 });
8316 elf.nodes.appendAssumeCapacity(.{ .func_debug_line = dwarf_func_index });
8317 break :debug_line_ni debug_line_ni;
8318 };
8319 debug_line_ni.writer(&elf.mf, gpa, &debug.line_writer);
8320 break :debug_output .{ .dwarf2 = &debug };
8321 };
8322 defer switch (debug_output) {
8323 .dwarf => unreachable,
8324 inline .eh_frame, .dwarf2 => |dwarf| dwarf.deinit(gpa),
8325 .none => {},
8326 };
8327 switch (debug_output) {
8328 .dwarf => unreachable,
8329 inline .eh_frame, .dwarf2 => |dwarf| {
8330 elf.resetNodeRelocs(debug.wip_nav.func.?.get(&elf.dwarf).fde_ni.unwrap().?);
8331 try dwarf.genFuncHeaders();
8332 },
8333 .none => {},
8334 }
8335 elf.resetNodeRelocs(ni);
7641 codegen.emitFunction(8336 codegen.emitFunction(
7642 &elf.base,8337 &elf.base,
7643 pt,8338 pt,
...@@ -7645,13 +8340,35 @@ fn updateFuncInner(...@@ -7645,13 +8340,35 @@ fn updateFuncInner(
7645 Node.toAtom(ni),8340 Node.toAtom(ni),
7646 mir,8341 mir,
7647 &nw.interface,8342 &nw.interface,
7648 .none,8343 debug_output,
7649 ) catch |err| switch (err) {8344 ) catch |err| switch (err) {
7650 error.WriteFailed => return nw.err.?,8345 error.WriteFailed => return nw.err.?,
7651 else => |e| return e,8346 else => |e| return e,
7652 };8347 };
8348 const func_length = nw.interface.end;
8349 switch (debug_output) {
8350 .dwarf => unreachable,
8351 .eh_frame, .dwarf2 => {
8352 debug.wip_nav.finishDebugFrameFde(func_length);
8353 const frame_ni = switch (debug.wip_nav.frame_format) {
8354 .debug_frame => elf.shndx.debug_frame,
8355 .eh_frame => elf.shndx.eh_frame,
8356 }.get(elf).ni;
8357 try frame_ni.trimStart(&elf.mf, elf.base.comp.gpa);
8358 switch (debug.wip_nav.frame_format) {
8359 .debug_frame => {},
8360 .eh_frame => {
8361 const last_offset, const last_size =
8362 frame_ni.last(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf);
8363 const last_end = last_offset + last_size;
8364 try frame_ni.ensureMinimumSize(&elf.mf, elf.base.comp.gpa, last_end + 4);
8365 },
8366 }
8367 },
8368 .none => {},
8369 }
7653 switch (elf.symPtr(nmi.symbol(elf).index())) {8370 switch (elf.symPtr(nmi.symbol(elf).index())) {
7654 inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)),8371 inline else => |sym| elf.targetStore(&sym.size, @intCast(func_length)),
7655 }8372 }
7656 }8373 }
76578374
...@@ -7915,11 +8632,11 @@ fn idleProgNode(...@@ -7915,11 +8632,11 @@ fn idleProgNode(
7915 var name: [std.Progress.Node.max_name_len]u8 = undefined;8632 var name: [std.Progress.Node.max_name_len]u8 = undefined;
7916 return prog_node.start(name: switch (node) {8633 return prog_node.start(name: switch (node) {
7917 else => |tag| @tagName(tag),8634 else => |tag| @tagName(tag),
7918 .section => |shndx| shndx.name(elf).slice(elf),
7919 .archive_input_member => |ii| std.mem.print(&name, "{f}{f}", .{8635 .archive_input_member => |ii| std.mem.print(&name, "{f}{f}", .{
7920 ii.path(elf).fmtEscapeString(),8636 ii.path(elf).fmtEscapeString(),
7921 fmtMemberString(ii.member(elf)),8637 fmtMemberString(ii.member(elf)),
7922 }) catch &name,8638 }) catch &name,
8639 .section, .section_manual_size => |shndx| shndx.name(elf).slice(elf),
7923 .input_section => |isi| {8640 .input_section => |isi| {
7924 const ii = isi.input(elf);8641 const ii = isi.input(elf);
7925 break :name std.mem.print(&name, "{f}{f} {s}", .{8642 break :name std.mem.print(&name, "{f}{f} {s}", .{
...@@ -7935,6 +8652,31 @@ fn idleProgNode(...@@ -7935,6 +8652,31 @@ fn idleProgNode(
7935 .uav => |umi| std.mem.print(&name, "{f}", .{8652 .uav => |umi| std.mem.print(&name, "{f}", .{
7936 Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),8653 Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
7937 }) catch &name,8654 }) catch &name,
8655 .value_debug_info => |cpi| std.mem.print(&name, "debug info for {f}", .{
8656 Value.fromInterned(cpi.val(&elf.dwarf.const_pool))
8657 .fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
8658 }) catch &name,
8659 .global_debug_info => |gi| {
8660 const ip = &elf.base.comp.zcu.?.intern_pool;
8661 break :name std.mem.print(&name, "debug info for {f}", .{
8662 ip.getNav(gi.nav(&elf.dwarf)).fqn.fmt(ip),
8663 }) catch &name;
8664 },
8665 .unit_frame, .unit_frame_cie => |ui| std.mem.print(&name, "unwind info for {s}", .{
8666 ui.mod(&elf.dwarf).fully_qualified_name,
8667 }) catch &name,
8668 .func_frame_fde, .func_debug_info, .func_debug_line => |fi, tag| {
8669 const ip = &elf.base.comp.zcu.?.intern_pool;
8670 break :name std.mem.print(&name, "{s} info for {f}", .{
8671 switch (tag) {
8672 else => unreachable,
8673 .func_frame_fde => "unwind",
8674 .func_debug_info => "debug",
8675 .func_debug_line => "line",
8676 },
8677 ip.getNav(fi.nav(&elf.dwarf)).fqn.fmt(ip),
8678 }) catch &name;
8679 },
7938 }, 0);8680 }, 0);
7939}8681}
79408682
...@@ -7984,11 +8726,11 @@ fn genUav(...@@ -7984,11 +8726,11 @@ fn genUav(
79848726
7985 const uav_val = umi.uavValue(elf);8727 const uav_val = umi.uavValue(elf);
7986 const ni = umi.symbol(elf).index().ptr(elf).node.unwrap().?;8728 const ni = umi.symbol(elf).index().ptr(elf).node.unwrap().?;
7987 elf.resetNodeRelocs(ni);
79888729
7989 var nw: MappedFile.Node.Writer = undefined;8730 var nw: MappedFile.Node.Writer = undefined;
7990 ni.writer(&elf.mf, gpa, &nw);8731 ni.writer(&elf.mf, gpa, &nw);
7991 defer nw.deinit();8732 defer nw.deinit();
8733 elf.resetNodeRelocs(ni);
7992 codegen.generateSymbol(8734 codegen.generateSymbol(
7993 &elf.base,8735 &elf.base,
7994 pt,8736 pt,
...@@ -8013,7 +8755,6 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {...@@ -8013,7 +8755,6 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {
80138755
8014 const lazy = lmr.lazySymbol(elf);8756 const lazy = lmr.lazySymbol(elf);
8015 const ni = lmr.symbol(elf).index().ptr(elf).node.unwrap().?;8757 const ni = lmr.symbol(elf).index().ptr(elf).node.unwrap().?;
8016 elf.resetNodeRelocs(ni);
80178758
8018 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually8759 // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually
8019 // be called to apply the lazy node's new relocations.8760 // be called to apply the lazy node's new relocations.
...@@ -8023,6 +8764,7 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {...@@ -8023,6 +8764,7 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void {
8023 var nw: MappedFile.Node.Writer = undefined;8764 var nw: MappedFile.Node.Writer = undefined;
8024 ni.writer(&elf.mf, gpa, &nw);8765 ni.writer(&elf.mf, gpa, &nw);
8025 defer nw.deinit();8766 defer nw.deinit();
8767 elf.resetNodeRelocs(ni);
8026 codegen.generateLazySymbol(8768 codegen.generateLazySymbol(
8027 &elf.base,8769 &elf.base,
8028 pt,8770 pt,
...@@ -8155,7 +8897,7 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -8155,7 +8897,7 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void {
8155 elf.flushElfOffset(child_ni);8897 elf.flushElfOffset(child_ni);
8156 }8898 }
8157 },8899 },
8158 .section => |shndx| switch (elf.shdrPtr(shndx)) {8900 .section, .section_manual_size => |shndx| switch (elf.shdrPtr(shndx)) {
8159 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(elf_offset)),8901 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(elf_offset)),
8160 },8902 },
8161 }8903 }
...@@ -8194,6 +8936,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8194,6 +8936,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8194 .INTERP,8936 .INTERP,
8195 .PHDR,8937 .PHDR,
8196 .TLS,8938 .TLS,
8939 .GNU_EH_FRAME,
8197 .GNU_RELRO,8940 .GNU_RELRO,
8198 => {8941 => {
8199 const new_vaddr = elf.computeNodeVAddr(ni);8942 const new_vaddr = elf.computeNodeVAddr(ni);
...@@ -8204,14 +8947,11 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8204,14 +8947,11 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8204 },8947 },
8205 }8948 }
8206 },8949 },
8207 .section => |shndx| {8950 .section, .section_manual_size => |shndx| {
8208 elf.flushElfOffset(ni);8951 elf.flushElfOffset(ni);
8209 const addr = elf.computeNodeVAddr(ni);8952 const addr = elf.computeNodeVAddr(ni);
8210 const old_addr: u64, const flags: std.elf.SHF = switch (elf.shdrPtr(shndx)) {8953 const old_addr: u64, const flags: std.elf.SHF = switch (elf.shdrPtr(shndx)) {
8211 inline else => |shdr| .{8954 inline else => |shdr| .{ elf.targetLoad(&shdr.addr), elf.targetLoad(&shdr.flags).shf },
8212 elf.targetLoad(&shdr.addr),
8213 elf.targetLoad(&shdr.flags).shf,
8214 },
8215 };8955 };
82168956
8217 if (flags.ALLOC) {8957 if (flags.ALLOC) {
...@@ -8225,10 +8965,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8225,10 +8965,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8225 var name = first_name;8965 var name = first_name;
8226 while (name != .empty) {8966 while (name != .empty) {
8227 const old_sym_addr = Symbol.Id.global(name).value(elf);8967 const old_sym_addr = Symbol.Id.global(name).value(elf);
8228 Symbol.Id.global(name).flushMoved(8968 Symbol.Id.global(name).flushMoved(elf, old_sym_addr - old_addr + addr);
8229 elf,
8230 old_sym_addr - old_addr + addr,
8231 );
8232 name = elf.globalByName(name).?.next_in_node;8969 name = elf.globalByName(name).?.next_in_node;
8233 }8970 }
8234 }8971 }
...@@ -8246,12 +8983,14 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8246,12 +8983,14 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8246 reloc.apply(elf);8983 reloc.apply(elf);
8247 }8984 }
8248 } else if (shndx == elf.shndx.plt) {8985 } else if (shndx == elf.shndx.plt) {
8249 elf.flushMovedNodeRelocs(ni, addr, elf.plt_first_symbol_reloc, .none);8986 elf.flushMovedNodeRelocs(ni, addr, elf.plt_first_symbol_reloc, .none, .none);
8250 elf.flushMovedPltSection(.plt, old_addr, addr);8987 elf.flushMovedPltSection(.plt, old_addr, addr);
8251 } else if (shndx == elf.shndx.got_plt) {8988 } else if (shndx == elf.shndx.got_plt) {
8252 elf.flushMovedPltSection(.got_plt, old_addr, addr);8989 elf.flushMovedPltSection(.got_plt, old_addr, addr);
8253 } else if (shndx == elf.shndx.plt_sec) {8990 } else if (shndx == elf.shndx.plt_sec) {
8254 elf.flushMovedPltSection(.plt_sec, old_addr, addr);8991 elf.flushMovedPltSection(.plt_sec, old_addr, addr);
8992 } else if (shndx == elf.shndx.eh_frame_hdr) {
8993 elf.flushMovedNodeRelocs(ni, addr, elf.eh_frame_hdr_first_symbol_reloc, .none, .none);
8255 }8994 }
8256 },8995 },
8257 .input_section => |isi| {8996 .input_section => |isi| {
...@@ -8302,6 +9041,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8302,6 +9041,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8302 ni,9041 ni,
8303 new_section_addr,9042 new_section_addr,
8304 isi.ptrConst(elf).first_symbol_reloc,9043 isi.ptrConst(elf).first_symbol_reloc,
9044 .none,
8305 isi.ptrConst(elf).first_got_reloc,9045 isi.ptrConst(elf).first_got_reloc,
8306 );9046 );
8307 },9047 },
...@@ -8329,13 +9069,45 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -8329,13 +9069,45 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
8329 name = elf.globalByName(name).?.next_in_node;9069 name = elf.globalByName(name).?.next_in_node;
8330 }9070 }
8331 }9071 }
9072 elf.flushMovedNodeRelocs(ni, new_addr, mi.firstSymbolReloc(elf), .none, mi.firstGotReloc(elf));
9073 },
9074 .value_debug_info,
9075 .global_debug_info,
9076 .frame_padding,
9077 .unit_frame,
9078 => {},
9079 .unit_frame_cie => |ui| {
9080 const dwarf_unit = &elf.dwarf_units.items[@backingInt(ui)];
9081 var target_ri = dwarf_unit.unit_frame_cie_first_target_reloc;
9082 while (target_ri != .none) {
9083 const target_reloc = target_ri.get(elf);
9084 assert(target_reloc.target == ni);
9085 target_reloc.apply(elf);
9086 target_ri = target_reloc.next;
9087 }
9088 },
9089 .func_frame_fde => |fi| {
9090 const new_addr = elf.computeNodeVAddr(ni);
9091 const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)];
9092 const mod = elf.base.comp.zcu.?.navFileScope(fi.nav(&elf.dwarf)).mod.?;
9093 switch (mod.unwind_tables) {
9094 .none => {},
9095 .sync, .async => {
9096 const offset, _ = ni.location(&elf.mf).resolve(&elf.mf);
9097 elf.dwarf.updateEhFrameFde(ni.slice(&elf.mf), offset);
9098 },
9099 }
8332 elf.flushMovedNodeRelocs(9100 elf.flushMovedNodeRelocs(
8333 ni,9101 ni,
8334 new_addr,9102 new_addr,
8335 mi.firstSymbolReloc(elf),9103 dwarf_func.func_frame_fde_first_symbol_reloc,
8336 mi.firstGotReloc(elf),9104 dwarf_func.func_frame_fde_first_node_reloc,
9105 .none,
8337 );9106 );
8338 },9107 },
9108 .func_debug_info,
9109 .func_debug_line,
9110 => {},
8339 }9111 }
8340 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);9112 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
8341}9113}
...@@ -8523,7 +9295,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo...@@ -8523,7 +9295,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
8523 elf.targetStore(&ph.type, if (size > 0) .LOAD else .NULL);9295 elf.targetStore(&ph.type, if (size > 0) .LOAD else .NULL);
8524 try elf.allocateSegmentLoadAddress(phndx);9296 try elf.allocateSegmentLoadAddress(phndx);
8525 },9297 },
8526 .DYNAMIC, .INTERP, .PHDR, std.elf.PT.GNU_RELRO => {9298 .DYNAMIC, .INTERP, .PHDR, .GNU_EH_FRAME, .GNU_RELRO => {
8527 elf.targetStore(&ph.memsz, @intCast(size));9299 elf.targetStore(&ph.memsz, @intCast(size));
8528 },9300 },
8529 .TLS => {9301 .TLS => {
...@@ -8558,31 +9330,29 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo...@@ -8558,31 +9330,29 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
8558 inline else => |shdr| {9330 inline else => |shdr| {
8559 switch (elf.targetLoad(&shdr.type)) {9331 switch (elf.targetLoad(&shdr.type)) {
8560 else => unreachable,9332 else => unreachable,
8561
8562 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),9333 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
8563 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),9334 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
85649335 .X86_64_UNWIND => {},
8565 .INIT_ARRAY,
8566 .FINI_ARRAY,
8567 .PREINIT_ARRAY,
8568 .STRTAB,
8569 .SYMTAB,
8570 .DYNAMIC,
8571 .REL,
8572 .RELA,
8573 .DYNSYM,
8574 .HASH,
8575 => return,
8576 }
8577 if (shndx != elf.shndx.plt and
8578 shndx != elf.shndx.got and
8579 shndx != elf.shndx.got_plt)
8580 {
8581 elf.targetStore(&shdr.size, @intCast(size));
8582 }9336 }
9337 elf.targetStore(&shdr.size, @intCast(size));
8583 },9338 },
8584 },9339 },
8585 .input_section, .copied_global, .nav, .uav, .lazy_code, .lazy_const_data => {},9340 .section_manual_size,
9341 .input_section,
9342 .copied_global,
9343 .nav,
9344 .uav,
9345 .lazy_code,
9346 .lazy_const_data,
9347 .value_debug_info,
9348 .global_debug_info,
9349 .frame_padding,
9350 .unit_frame,
9351 .unit_frame_cie,
9352 .func_frame_fde,
9353 .func_debug_info,
9354 .func_debug_line,
9355 => {},
8586 }9356 }
8587}9357}
85889358
...@@ -8599,6 +9369,7 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!...@@ -8599,6 +9369,7 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!
8599 .shdr,9369 .shdr,
8600 .segment,9370 .segment,
8601 .section,9371 .section,
9372 .section_manual_size,
8602 .input_section,9373 .input_section,
8603 .copied_global,9374 .copied_global,
8604 .nav,9375 .nav,
...@@ -8633,6 +9404,66 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!...@@ -8633,6 +9404,66 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!
8633 error.NoSpaceLeft => archive.strtab_member_too_big = true,9404 error.NoSpaceLeft => archive.strtab_member_too_big = true,
8634 }9405 }
8635 },9406 },
9407 .value_debug_info,
9408 .global_debug_info,
9409 => {},
9410 .frame_padding, .unit_frame_cie, .func_frame_fde => |_, tag| {
9411 const offset, const size = ni.location(&elf.mf).resolve(&elf.mf);
9412 const slice = slice: {
9413 const parent_ni = ni.parent(&elf.mf).unwrap().?;
9414 if (ni.next(&elf.mf).unwrap()) |next_ni| {
9415 const parent_slice = parent_ni.slicePadding(&elf.mf);
9416 const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf);
9417 break :slice parent_slice[@intCast(offset)..@intCast(next_offset)];
9418 } else switch (tag) {
9419 else => unreachable,
9420 .frame_padding => {
9421 const frame_slice = parent_ni.slicePadding(&elf.mf);
9422 switch (elf.getNode(parent_ni).section.debugFrameFormat(elf).?) {
9423 .eh_frame => {
9424 const end = frame_slice.len - 4;
9425 std.mem.writeInt(u32, frame_slice[end..][0..4], 0, elf.dwarf.endian);
9426 break :slice frame_slice[@intCast(offset)..end];
9427 },
9428 .debug_frame => break :slice frame_slice[@intCast(offset)..],
9429 }
9430 },
9431 .unit_frame_cie, .func_frame_fde => {
9432 const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf);
9433 const frame_ni = parent_ni.parent(&elf.mf).unwrap().?;
9434 const frame_slice = frame_ni.slicePadding(&elf.mf);
9435 const format = elf.getNode(frame_ni).section.debugFrameFormat(elf).?;
9436 const slice = frame_slice[@intCast(parent_offset + offset)..if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| frame_end: {
9437 const parent_next_offset, _ = parent_next_ni.location(&elf.mf).resolve(&elf.mf);
9438 break :frame_end @intCast(parent_next_offset);
9439 } else frame_end: switch (format) {
9440 .eh_frame => {
9441 const frame_end = frame_slice.len - 4;
9442 std.mem.writeInt(u32, frame_slice[frame_end..][0..4], 0, elf.dwarf.endian);
9443 break :frame_end frame_end;
9444 },
9445 .debug_frame => frame_slice.len,
9446 }];
9447 var fw: std.Io.Writer = .fixed(slice[@intCast(size)..]);
9448 elf.dwarf.genDebugFrameCie(&fw, null, format) catch |err| switch (err) {
9449 error.WriteFailed => break :slice slice,
9450 };
9451 elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len);
9452 break :slice slice[0..@intCast(size)];
9453 },
9454 }
9455 };
9456 elf.dwarf.updateUnitLength(slice, slice.len);
9457 switch (tag) {
9458 else => unreachable,
9459 .frame_padding => {},
9460 .unit_frame_cie, .func_frame_fde => @memset(slice[@intCast(size)..], std.dwarf.CFA.nop),
9461 }
9462 },
9463 .unit_frame,
9464 .func_debug_info,
9465 .func_debug_line,
9466 => {},
8636 }9467 }
8637}9468}
86389469
...@@ -9118,7 +9949,7 @@ pub fn printNode(...@@ -9118,7 +9949,7 @@ pub fn printNode(
9118 try w.writeByte(')');9949 try w.writeByte(')');
9119 },9950 },
9120 },9951 },
9121 .section => |shndx| try w.print("({s})", .{shndx.name(elf).slice(elf)}),9952 .section, .section_manual_size => |shndx| try w.print("({s})", .{shndx.name(elf).slice(elf)}),
9122 .input_section => |isi| {9953 .input_section => |isi| {
9123 const ii = isi.input(elf);9954 const ii = isi.input(elf);
9124 try w.print("({f}{f}, {s})", .{9955 try w.print("({f}{f}, {s})", .{
...@@ -9151,6 +9982,31 @@ pub fn printNode(...@@ -9151,6 +9982,31 @@ pub fn printNode(
9151 .tid = tid,9982 .tid = tid,
9152 }),9983 }),
9153 }),9984 }),
9985 .value_debug_info => |cpi| try w.print("({f})", .{
9986 Value.fromInterned(cpi.val(&elf.dwarf.const_pool))
9987 .fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
9988 }),
9989 .global_debug_info => |gi| {
9990 const zcu = elf.base.comp.zcu.?;
9991 const ip = &zcu.intern_pool;
9992 const nav = ip.getNav(gi.nav(&elf.dwarf));
9993 try w.print("({f}, {f})", .{
9994 Type.fromInterned(ip.typeOf(nav.resolved.?.value)).fmt(.{ .zcu = zcu, .tid = tid }),
9995 nav.fqn.fmt(ip),
9996 });
9997 },
9998 .unit_frame, .unit_frame_cie => |ui| try w.print("({s})", .{
9999 ui.mod(&elf.dwarf).fully_qualified_name,
10000 }),
10001 .func_frame_fde, .func_debug_info, .func_debug_line => |fi| {
10002 const zcu = elf.base.comp.zcu.?;
10003 const ip = &zcu.intern_pool;
10004 const nav = ip.getNav(fi.nav(&elf.dwarf));
10005 try w.print("({f}, {f})", .{
10006 Type.fromInterned(ip.typeOf(nav.resolved.?.value)).fmt(.{ .zcu = zcu, .tid = tid }),
10007 nav.fqn.fmt(ip),
10008 });
10009 },
9154 }10010 }
9155 {10011 {
9156 const mf_node = &elf.mf.nodes.items[@backingInt(ni)];10012 const mf_node = &elf.mf.nodes.items[@backingInt(ni)];
src/link/MachO/ZigObject.zig+11-16
...@@ -647,14 +647,11 @@ pub fn getNavVAddr(...@@ -647,14 +647,11 @@ pub fn getNavVAddr(
647 },647 },
648 });648 });
649 },649 },
650 .debug_output => |debug_output| switch (debug_output) {650 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
651 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{651 .source_off = @intCast(reloc_info.offset),
652 .source_off = @intCast(reloc_info.offset),652 .target_sym = @fromBackingInt(@intCast(sym_index)),
653 .target_sym = @fromBackingInt(@intCast(sym_index)),653 .target_off = reloc_info.addend,
654 .target_off = reloc_info.addend,654 }),
655 }),
656 .none => unreachable,
657 },
658 }655 }
659 return vaddr;656 return vaddr;
660}657}
...@@ -686,14 +683,11 @@ pub fn getUavVAddr(...@@ -686,14 +683,11 @@ pub fn getUavVAddr(
686 },683 },
687 });684 });
688 },685 },
689 .debug_output => |debug_output| switch (debug_output) {686 .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{
690 .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{687 .source_off = @intCast(reloc_info.offset),
691 .source_off = @intCast(reloc_info.offset),688 .target_sym = @fromBackingInt(@intCast(sym_index)),
692 .target_sym = @fromBackingInt(@intCast(sym_index)),689 .target_off = reloc_info.addend,
693 .target_off = reloc_info.addend,690 }),
694 }),
695 .none => unreachable,
696 },
697 }691 }
698 return vaddr;692 return vaddr;
699}693}
...@@ -796,6 +790,7 @@ pub fn updateFunc(...@@ -796,6 +790,7 @@ pub fn updateFunc(
796 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,790 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
797 ) catch |err| switch (err) {791 ) catch |err| switch (err) {
798 error.WriteFailed => return error.OutOfMemory,792 error.WriteFailed => return error.OutOfMemory,
793 error.MappedFileIo => unreachable, // MappedFile is not being used
799 else => |e| return e,794 else => |e| return e,
800 };795 };
801 const code = aw.written();796 const code = aw.written();
src/link/MappedFile.zig+22
...@@ -636,11 +636,33 @@ pub const Node = extern struct {...@@ -636,11 +636,33 @@ pub const Node = extern struct {
636 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];636 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
637 }637 }
638638
639 pub fn slicePadding(ni: Node.Index, mf: *const MappedFile) []u8 {
640 const file_loc = ni.fileLocation(mf, false);
641 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
642 }
643
639 pub fn sliceConst(ni: Node.Index, mf: *const MappedFile) []const u8 {644 pub fn sliceConst(ni: Node.Index, mf: *const MappedFile) []const u8 {
640 const file_loc = ni.fileLocation(mf, false);645 const file_loc = ni.fileLocation(mf, false);
641 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];646 return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
642 }647 }
643648
649 pub fn trimStart(ni: Node.Index, mf: *MappedFile, gpa: Allocator) Allocator.Error!void {
650 mf.nodes_lock.assertUnlocked();
651 const node = ni.get(mf);
652 const first_ni = node.first.unwrap() orelse return;
653 const shift, _ = first_ni.location(mf).resolve(mf);
654 if (shift == 0) return;
655 const offset, const size = node.location().resolve(mf);
656 try ni.setLocation(mf, gpa, offset + shift, size - shift);
657 var child_oni = node.first;
658 while (child_oni.unwrap()) |child_ni| {
659 const child_node = child_ni.get(mf);
660 const child_offset, const child_size = child_node.location().resolve(mf);
661 try child_ni.setLocation(mf, gpa, child_offset - shift, child_size);
662 child_oni = child_node.next;
663 }
664 }
665
644 /// Ensures that the size of `ni` is at least `min_size`. Valid for any node.666 /// Ensures that the size of `ni` is at least `min_size`. Valid for any node.
645 ///667 ///
646 /// Applies `growth_factor` if necessary (so the caller should *not* apply `growth_factor`).668 /// Applies `growth_factor` if necessary (so the caller should *not* apply `growth_factor`).
tools/incr-check.zig+7
...@@ -17,6 +17,7 @@ const usage =...@@ -17,6 +17,7 @@ const usage =
17 \\Debug Options:17 \\Debug Options:
18 \\ --preserve-tmp18 \\ --preserve-tmp
19 \\ --debug-log foo19 \\ --debug-log foo
20 \\ --debug-link-snapshot
20;21;
2122
22pub const std_options: std.Options = .{23pub const std_options: std.Options = .{
...@@ -60,6 +61,7 @@ pub fn main(init: std.process.Init) !void {...@@ -60,6 +61,7 @@ pub fn main(init: std.process.Init) !void {
60 var quiet: bool = false;61 var quiet: bool = false;
6162
62 var debug_log_args: std.ArrayList([]const u8) = .empty;63 var debug_log_args: std.ArrayList([]const u8) = .empty;
64 var debug_link_snapshot = false;
6365
64 var arg_it = try init.minimal.args.iterateAllocator(arena);66 var arg_it = try init.minimal.args.iterateAllocator(arena);
65 _ = arg_it.skip();67 _ = arg_it.skip();
...@@ -77,6 +79,8 @@ pub fn main(init: std.process.Init) !void {...@@ -77,6 +79,8 @@ pub fn main(init: std.process.Init) !void {
77 arena,79 arena,
78 arg_it.next() orelse badUsage("expected arg after --debug-log", .{}),80 arg_it.next() orelse badUsage("expected arg after --debug-log", .{}),
79 );81 );
82 } else if (std.mem.eql(u8, arg, "--debug-link-snapshot")) {
83 debug_link_snapshot = true;
80 } else if (std.mem.eql(u8, arg, "--preserve-tmp")) {84 } else if (std.mem.eql(u8, arg, "--preserve-tmp")) {
81 preserve_tmp = true;85 preserve_tmp = true;
82 } else if (std.mem.eql(u8, arg, "-fqemu")) {86 } else if (std.mem.eql(u8, arg, "-fqemu")) {
...@@ -173,6 +177,9 @@ pub fn main(init: std.process.Init) !void {...@@ -173,6 +177,9 @@ pub fn main(init: std.process.Init) !void {
173 for (debug_log_args.items) |arg| {177 for (debug_log_args.items) |arg| {
174 try child_args.appendSlice(arena, &.{ "--debug-log", arg });178 try child_args.appendSlice(arena, &.{ "--debug-log", arg });
175 }179 }
180 if (debug_link_snapshot) {
181 try child_args.append(arena, "--debug-link-snapshot");
182 }
176 for (case.modules) |mod| {183 for (case.modules) |mod| {
177 try child_args.appendSlice(arena, &.{ "--dep", mod.name });184 try child_args.appendSlice(arena, &.{ "--dep", mod.name });
178 }185 }