authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-08-26 15:38:35-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-08-27 03:55:56-04:00
logf289b82d0efda77b72ccf9c826023e904f9ffcab
treeeb0bbade490e385b46942628016d34dd32515c86
parent26d4fd5276eaaa939cf21a516265101c551b62f2

Dwarf: implement .eh_frame


17 files changed, 1202 insertions(+), 274 deletions(-)

lib/std/leb128.zig+1-1
......@@ -125,7 +125,7 @@ pub const readILEB128 = readIleb128;
125125pub fn writeIleb128(writer: anytype, arg: anytype) !void {
126126 const Arg = @TypeOf(arg);
127127 const Int = switch (Arg) {
128 comptime_int => std.math.IntFittingRange(-arg - 1, arg),
128 comptime_int => std.math.IntFittingRange(-@abs(arg), @abs(arg)),
129129 else => Arg,
130130 };
131131 const Signed = if (@typeInfo(Int).Int.bits < 8) i8 else Int;
lib/std/os/linux/x86_64.zig+3-2
......@@ -114,14 +114,15 @@ pub fn clone() callconv(.Naked) usize {
114114 \\ movq %%rcx,(%%rsi)
115115 \\ syscall
116116 \\ testq %%rax,%%rax
117 \\ jnz 1f
117 \\ jz 1f
118 \\ retq
119 \\1: .cfi_undefined %%rip
118120 \\ xorl %%ebp,%%ebp
119121 \\ popq %%rdi
120122 \\ callq *%%r9
121123 \\ movl %%eax,%%edi
122124 \\ movl $60,%%eax // SYS_exit
123125 \\ syscall
124 \\1: ret
125126 \\
126127 );
127128}
lib/std/start.zig+1
......@@ -249,6 +249,7 @@ fn _start() callconv(.Naked) noreturn {
249249 // linker explicitly.
250250 asm volatile (switch (native_arch) {
251251 .x86_64 =>
252 \\ .cfi_undefined %%rip
252253 \\ xorl %%ebp, %%ebp
253254 \\ movq %%rsp, %%rdi
254255 \\ andq $-16, %%rsp
src/arch/x86_64/CodeGen.zig+112-13
......@@ -1491,6 +1491,46 @@ fn asmPseudo(self: *Self, ops: Mir.Inst.Ops) !void {
14911491 });
14921492}
14931493
1494fn asmPseudoRegister(self: *Self, ops: Mir.Inst.Ops, reg: Register) !void {
1495 assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
1496 std.mem.endsWith(u8, @tagName(ops), "_r"));
1497 _ = try self.addInst(.{
1498 .tag = .pseudo,
1499 .ops = ops,
1500 .data = .{ .r = .{ .r1 = reg } },
1501 });
1502}
1503
1504fn asmPseudoImmediate(self: *Self, ops: Mir.Inst.Ops, imm: Immediate) !void {
1505 assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
1506 std.mem.endsWith(u8, @tagName(ops), "_i_s"));
1507 _ = try self.addInst(.{
1508 .tag = .pseudo,
1509 .ops = ops,
1510 .data = .{ .i = .{ .i = @bitCast(imm.signed) } },
1511 });
1512}
1513
1514fn asmPseudoRegisterRegister(self: *Self, ops: Mir.Inst.Ops, reg1: Register, reg2: Register) !void {
1515 assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
1516 std.mem.endsWith(u8, @tagName(ops), "_rr"));
1517 _ = try self.addInst(.{
1518 .tag = .pseudo,
1519 .ops = ops,
1520 .data = .{ .rr = .{ .r1 = reg1, .r2 = reg2 } },
1521 });
1522}
1523
1524fn asmPseudoRegisterImmediate(self: *Self, ops: Mir.Inst.Ops, reg: Register, imm: Immediate) !void {
1525 assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
1526 std.mem.endsWith(u8, @tagName(ops), "_ri_s"));
1527 _ = try self.addInst(.{
1528 .tag = .pseudo,
1529 .ops = ops,
1530 .data = .{ .ri = .{ .r1 = reg, .i = @bitCast(imm.signed) } },
1531 });
1532}
1533
14941534fn asmRegister(self: *Self, tag: Mir.Inst.FixedTag, reg: Register) !void {
14951535 _ = try self.addInst(.{
14961536 .tag = tag[1],
......@@ -1877,7 +1917,10 @@ fn gen(self: *Self) InnerError!void {
18771917 const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);
18781918 if (cc != .Naked) {
18791919 try self.asmRegister(.{ ._, .push }, .rbp);
1920 try self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, Immediate.s(8));
1921 try self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, .rbp, Immediate.s(0));
18801922 try self.asmRegisterRegister(.{ ._, .mov }, .rbp, .rsp);
1923 try self.asmPseudoRegister(.pseudo_cfi_def_cfa_register_r, .rbp);
18811924 const backpatch_push_callee_preserved_regs = try self.asmPlaceholder();
18821925 const backpatch_frame_align = try self.asmPlaceholder();
18831926 const backpatch_frame_align_extra = try self.asmPlaceholder();
......@@ -1962,6 +2005,7 @@ fn gen(self: *Self) InnerError!void {
19622005 const backpatch_stack_dealloc = try self.asmPlaceholder();
19632006 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
19642007 try self.asmRegister(.{ ._, .pop }, .rbp);
2008 try self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, .rsp, Immediate.s(8));
19652009 try self.asmOpOnly(.{ ._, .ret });
19662010
19672011 const frame_layout = try self.computeFrameLayout(cc);
......@@ -14038,7 +14082,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
1403814082 var mnem_it = mem.tokenizeAny(u8, line, " \t");
1403914083 var prefix: Instruction.Prefix = .none;
1404014084 const mnem_str = while (mnem_it.next()) |mnem_str| {
14041 if (mem.startsWith(u8, mnem_str, "#")) continue :next_line;
14085 if (mnem_str[0] == '#') continue :next_line;
1404214086 if (mem.startsWith(u8, mnem_str, "//")) continue :next_line;
1404314087 if (std.meta.stringToEnum(Instruction.Prefix, mnem_str)) |pre| {
1404414088 if (prefix != .none) return self.fail("extra prefix: '{s}'", .{mnem_str});
......@@ -14063,8 +14107,14 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
1406314107 }
1406414108 label_gop.value_ptr.target = @intCast(self.mir_instructions.len);
1406514109 } else continue;
14110 if (mnem_str[0] == '.') {
14111 if (prefix != .none) return self.fail("prefixed directive: '{s} {s}'", .{ @tagName(prefix), mnem_str });
14112 prefix = .directive;
14113 }
1406614114
14067 var mnem_size: ?Memory.Size = if (mem.endsWith(u8, mnem_str, "b"))
14115 var mnem_size: ?Memory.Size = if (prefix == .directive)
14116 null
14117 else if (mem.endsWith(u8, mnem_str, "b"))
1406814118 .byte
1406914119 else if (mem.endsWith(u8, mnem_str, "w"))
1407014120 .word
......@@ -14095,7 +14145,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
1409514145 mnem_size = fixed_mnem_size;
1409614146 }
1409714147 const mnem_name = @tagName(mnem_tag);
14098 const mnem_fixed_tag: Mir.Inst.FixedTag = for (std.enums.values(Mir.Inst.Fixes)) |fixes| {
14148 const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
14149 .{ ._, .pseudo }
14150 else for (std.enums.values(Mir.Inst.Fixes)) |fixes| {
1409914151 const fixes_name = @tagName(fixes);
1410014152 const space_i = mem.indexOfScalar(u8, fixes_name, ' ');
1410114153 const fixes_prefix = if (space_i) |i|
......@@ -14116,7 +14168,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
1411614168 } else {
1411714169 assert(prefix != .none); // no combination of fixes produced a known mnemonic
1411814170 return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{
14119 @tagName(prefix), mnem_str,
14171 @tagName(prefix), mnem_name,
1412014172 });
1412114173 };
1412214174
......@@ -14324,7 +14376,62 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
1432414376 } else return self.fail("invalid operand: '{s}'", .{op_str});
1432514377 } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str});
1432614378
14327 (switch (ops[0]) {
14379 (if (prefix == .directive) switch (mnem_tag) {
14380 .@".cfi_def_cfa" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
14381 self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, ops[0].reg, ops[1].imm)
14382 else
14383 error.InvalidInstruction,
14384 .@".cfi_def_cfa_register" => if (ops[0] == .reg and ops[1] == .none)
14385 self.asmPseudoRegister(.pseudo_cfi_def_cfa_register_r, ops[0].reg)
14386 else
14387 error.InvalidInstruction,
14388 .@".cfi_def_cfa_offset" => if (ops[0] == .imm and ops[1] == .none)
14389 self.asmPseudoImmediate(.pseudo_cfi_def_cfa_offset_i_s, ops[0].imm)
14390 else
14391 error.InvalidInstruction,
14392 .@".cfi_adjust_cfa_offset" => if (ops[0] == .imm and ops[1] == .none)
14393 self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, ops[0].imm)
14394 else
14395 error.InvalidInstruction,
14396 .@".cfi_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
14397 self.asmPseudoRegisterImmediate(.pseudo_cfi_offset_ri_s, ops[0].reg, ops[1].imm)
14398 else
14399 error.InvalidInstruction,
14400 .@".cfi_val_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
14401 self.asmPseudoRegisterImmediate(.pseudo_cfi_val_offset_ri_s, ops[0].reg, ops[1].imm)
14402 else
14403 error.InvalidInstruction,
14404 .@".cfi_rel_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
14405 self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, ops[0].reg, ops[1].imm)
14406 else
14407 error.InvalidInstruction,
14408 .@".cfi_register" => if (ops[0] == .reg and ops[1] == .reg and ops[2] == .none)
14409 self.asmPseudoRegisterRegister(.pseudo_cfi_register_rr, ops[0].reg, ops[1].reg)
14410 else
14411 error.InvalidInstruction,
14412 .@".cfi_restore" => if (ops[0] == .reg and ops[1] == .none)
14413 self.asmPseudoRegister(.pseudo_cfi_restore_r, ops[0].reg)
14414 else
14415 error.InvalidInstruction,
14416 .@".cfi_undefined" => if (ops[0] == .reg and ops[1] == .none)
14417 self.asmPseudoRegister(.pseudo_cfi_undefined_r, ops[0].reg)
14418 else
14419 error.InvalidInstruction,
14420 .@".cfi_same_value" => if (ops[0] == .reg and ops[1] == .none)
14421 self.asmPseudoRegister(.pseudo_cfi_same_value_r, ops[0].reg)
14422 else
14423 error.InvalidInstruction,
14424 .@".cfi_remember_state" => if (ops[0] == .none)
14425 self.asmPseudo(.pseudo_cfi_remember_state_none)
14426 else
14427 error.InvalidInstruction,
14428 .@".cfi_restore_state" => if (ops[0] == .none)
14429 self.asmPseudo(.pseudo_cfi_restore_state_none)
14430 else
14431 error.InvalidInstruction,
14432 .@".cfi_escape" => error.InvalidInstruction,
14433 else => unreachable,
14434 } else switch (ops[0]) {
1432814435 .none => self.asmOpOnly(mnem_fixed_tag),
1432914436 .reg => |reg0| switch (ops[1]) {
1433014437 .none => self.asmRegister(mnem_fixed_tag, reg0),
......@@ -19210,14 +19317,6 @@ fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError {
1921019317 return error.CodegenFail;
1921119318}
1921219319
19213fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerError {
19214 @branchHint(.cold);
19215 assert(self.err_msg == null);
19216 const gpa = self.gpa;
19217 self.err_msg = try ErrorMsg.create(gpa, self.src_loc, format, args);
19218 return error.CodegenFail;
19219}
19220
1922119320fn parseRegName(name: []const u8) ?Register {
1922219321 if (@hasDecl(Register, "parseRegName")) {
1922319322 return Register.parseRegName(name);
src/arch/x86_64/Emit.zig+53
......@@ -30,6 +30,59 @@ pub fn emitMir(emit: *Emit) Error!void {
3030 var lowered_relocs = lowered.relocs;
3131 for (lowered.insts, 0..) |lowered_inst, lowered_index| {
3232 const start_offset: u32 = @intCast(emit.code.items.len);
33 if (lowered_inst.prefix == .directive) {
34 switch (emit.debug_output) {
35 .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) {
36 .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{
37 .reg = lowered_inst.ops[0].reg.dwarfNum(),
38 .off = lowered_inst.ops[1].imm.signed,
39 } }),
40 .@".cfi_def_cfa_register" => try dwarf.genDebugFrame(start_offset, .{
41 .def_cfa_register = lowered_inst.ops[0].reg.dwarfNum(),
42 }),
43 .@".cfi_def_cfa_offset" => try dwarf.genDebugFrame(start_offset, .{
44 .def_cfa_offset = lowered_inst.ops[0].imm.signed,
45 }),
46 .@".cfi_adjust_cfa_offset" => try dwarf.genDebugFrame(start_offset, .{
47 .adjust_cfa_offset = lowered_inst.ops[0].imm.signed,
48 }),
49 .@".cfi_offset" => try dwarf.genDebugFrame(start_offset, .{ .offset = .{
50 .reg = lowered_inst.ops[0].reg.dwarfNum(),
51 .off = lowered_inst.ops[1].imm.signed,
52 } }),
53 .@".cfi_val_offset" => try dwarf.genDebugFrame(start_offset, .{ .val_offset = .{
54 .reg = lowered_inst.ops[0].reg.dwarfNum(),
55 .off = lowered_inst.ops[1].imm.signed,
56 } }),
57 .@".cfi_rel_offset" => try dwarf.genDebugFrame(start_offset, .{ .rel_offset = .{
58 .reg = lowered_inst.ops[0].reg.dwarfNum(),
59 .off = lowered_inst.ops[1].imm.signed,
60 } }),
61 .@".cfi_register" => try dwarf.genDebugFrame(start_offset, .{ .register = .{
62 lowered_inst.ops[0].reg.dwarfNum(),
63 lowered_inst.ops[1].reg.dwarfNum(),
64 } }),
65 .@".cfi_restore" => try dwarf.genDebugFrame(start_offset, .{
66 .restore = lowered_inst.ops[0].reg.dwarfNum(),
67 }),
68 .@".cfi_undefined" => try dwarf.genDebugFrame(start_offset, .{
69 .undefined = lowered_inst.ops[0].reg.dwarfNum(),
70 }),
71 .@".cfi_same_value" => try dwarf.genDebugFrame(start_offset, .{
72 .same_value = lowered_inst.ops[0].reg.dwarfNum(),
73 }),
74 .@".cfi_remember_state" => try dwarf.genDebugFrame(start_offset, .remember_state),
75 .@".cfi_restore_state" => try dwarf.genDebugFrame(start_offset, .restore_state),
76 .@".cfi_escape" => try dwarf.genDebugFrame(start_offset, .{
77 .escape = lowered_inst.ops[0].bytes,
78 }),
79 else => unreachable,
80 },
81 .plan9 => {},
82 .none => {},
83 }
84 continue;
85 }
3386 try lowered_inst.encode(emit.code.writer(), .{});
3487 const end_offset: u32 = @intCast(emit.code.items.len);
3588 while (lowered_relocs.len > 0 and
src/arch/x86_64/Encoding.zig+32-7
......@@ -220,6 +220,21 @@ pub fn format(
220220}
221221
222222pub const Mnemonic = enum {
223 // Directives
224 @".cfi_def_cfa",
225 @".cfi_def_cfa_register",
226 @".cfi_def_cfa_offset",
227 @".cfi_adjust_cfa_offset",
228 @".cfi_offset",
229 @".cfi_val_offset",
230 @".cfi_rel_offset",
231 @".cfi_register",
232 @".cfi_restore",
233 @".cfi_undefined",
234 @".cfi_same_value",
235 @".cfi_remember_state",
236 @".cfi_restore_state",
237 @".cfi_escape",
223238 // zig fmt: off
224239 // General-purpose
225240 adc, add, @"and",
......@@ -442,6 +457,7 @@ pub const Op = enum {
442457 imm8s, imm16s, imm32s,
443458 al, ax, eax, rax,
444459 cl,
460 rip, eip, ip,
445461 r8, r16, r32, r64,
446462 rm8, rm16, rm32, rm64,
447463 r32_m8, r32_m16, r64_m16,
......@@ -487,7 +503,12 @@ pub const Op = enum {
487503 256 => .ymm,
488504 else => unreachable,
489505 },
490 .ip => unreachable,
506 .ip => switch (reg) {
507 .rip => .rip,
508 .eip => .eip,
509 .ip => .ip,
510 else => unreachable,
511 },
491512 },
492513
493514 .mem => |mem| switch (mem) {
......@@ -531,13 +552,15 @@ pub const Op = enum {
531552 else
532553 .imm64,
533554 },
555
556 .bytes => unreachable,
534557 };
535558 }
536559
537560 pub fn immBitSize(op: Op) u64 {
538561 return switch (op) {
539562 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
540 .al, .cl, .r8, .rm8, .r32_m8 => unreachable,
563 .al, .cl, .rip, .eip, .ip, .r8, .rm8, .r32_m8 => unreachable,
541564 .ax, .r16, .rm16 => unreachable,
542565 .eax, .r32, .rm32, .r32_m16 => unreachable,
543566 .rax, .r64, .rm64, .r64_m16 => unreachable,
......@@ -560,9 +583,9 @@ pub const Op = enum {
560583 .rel8, .rel16, .rel32 => unreachable,
561584 .m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
562585 .al, .cl, .r8, .rm8 => 8,
563 .ax, .r16, .rm16 => 16,
564 .eax, .r32, .rm32, .r32_m8, .r32_m16 => 32,
565 .rax, .r64, .rm64, .r64_m16, .mm, .mm_m64 => 64,
586 .ax, .ip, .r16, .rm16 => 16,
587 .eax, .eip, .r32, .rm32, .r32_m8, .r32_m16 => 32,
588 .rax, .rip, .r64, .rm64, .r64_m16, .mm, .mm_m64 => 64,
566589 .st => 80,
567590 .xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
568591 .ymm, .ymm_m256 => 256,
......@@ -574,7 +597,7 @@ pub const Op = enum {
574597 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
575598 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
576599 .rel8, .rel16, .rel32 => unreachable,
577 .al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64 => unreachable,
600 .al, .cl, .r8, .ax, .ip, .r16, .eax, .eip, .r32, .rax, .rip, .r64 => unreachable,
578601 .st, .mm, .xmm0, .xmm, .ymm => unreachable,
579602 .m8, .rm8, .r32_m8, .xmm_m8 => 8,
580603 .m16, .rm16, .r32_m16, .r64_m16, .xmm_m16 => 16,
......@@ -602,8 +625,9 @@ pub const Op = enum {
602625 pub fn isRegister(op: Op) bool {
603626 // zig fmt: off
604627 return switch (op) {
605 .cl,
606628 .al, .ax, .eax, .rax,
629 .cl,
630 .ip, .eip, .rip,
607631 .r8, .r16, .r32, .r64,
608632 .rm8, .rm16, .rm32, .rm64,
609633 .r32_m8, .r32_m16, .r64_m16,
......@@ -664,6 +688,7 @@ pub const Op = enum {
664688 .mm, .mm_m64 => .mmx,
665689 .xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => .sse,
666690 .ymm, .ymm_m256 => .sse,
691 .rip, .eip, .ip => .ip,
667692 };
668693 }
669694
src/arch/x86_64/Lower.zig+87-11
......@@ -12,7 +12,7 @@ src_loc: Zcu.LazySrcLoc,
1212result_insts_len: u8 = undefined,
1313result_relocs_len: u8 = undefined,
1414result_insts: [
15 std.mem.max(usize, &.{
15 @max(
1616 1, // non-pseudo instructions
1717 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode
1818 2, // cmovcc: cmovcc \ cmovcc
......@@ -22,18 +22,18 @@ result_insts: [
2222 pseudo_probe_adjust_unrolled_max_insts,
2323 pseudo_probe_adjust_setup_insts,
2424 pseudo_probe_adjust_loop_insts,
25 abi.Win64.callee_preserved_regs.len, // push_regs/pop_regs
26 abi.SysV.callee_preserved_regs.len, // push_regs/pop_regs
27 })
25 abi.Win64.callee_preserved_regs.len * 2, // push_regs/pop_regs
26 abi.SysV.callee_preserved_regs.len * 2, // push_regs/pop_regs
27 )
2828]Instruction = undefined,
2929result_relocs: [
30 std.mem.max(usize, &.{
30 @max(
3131 1, // jmp/jcc/call/mov/lea: jmp/jcc/call/mov/lea
3232 2, // jcc: jcc \ jcc
3333 2, // test \ jcc \ probe \ sub \ jmp
3434 1, // probe \ sub \ jcc
3535 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode
36 })
36 )
3737]Reloc = undefined,
3838
3939pub const pseudo_probe_align_insts = 5; // test \ jcc \ probe \ sub \ jmp
......@@ -265,6 +265,50 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
265265 .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst),
266266 .pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst),
267267
268 .pseudo_cfi_def_cfa_ri_s => try lower.emit(.directive, .@".cfi_def_cfa", &.{
269 .{ .reg = inst.data.ri.r1 },
270 .{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
271 }),
272 .pseudo_cfi_def_cfa_register_r => try lower.emit(.directive, .@".cfi_def_cfa_register", &.{
273 .{ .reg = inst.data.r.r1 },
274 }),
275 .pseudo_cfi_def_cfa_offset_i_s => try lower.emit(.directive, .@".cfi_def_cfa_offset", &.{
276 .{ .imm = lower.imm(.i_s, inst.data.i.i) },
277 }),
278 .pseudo_cfi_adjust_cfa_offset_i_s => try lower.emit(.directive, .@".cfi_adjust_cfa_offset", &.{
279 .{ .imm = lower.imm(.i_s, inst.data.i.i) },
280 }),
281 .pseudo_cfi_offset_ri_s => try lower.emit(.directive, .@".cfi_offset", &.{
282 .{ .reg = inst.data.ri.r1 },
283 .{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
284 }),
285 .pseudo_cfi_val_offset_ri_s => try lower.emit(.directive, .@".cfi_val_offset", &.{
286 .{ .reg = inst.data.ri.r1 },
287 .{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
288 }),
289 .pseudo_cfi_rel_offset_ri_s => try lower.emit(.directive, .@".cfi_rel_offset", &.{
290 .{ .reg = inst.data.ri.r1 },
291 .{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
292 }),
293 .pseudo_cfi_register_rr => try lower.emit(.directive, .@".cfi_register", &.{
294 .{ .reg = inst.data.rr.r1 },
295 .{ .reg = inst.data.rr.r2 },
296 }),
297 .pseudo_cfi_restore_r => try lower.emit(.directive, .@".cfi_restore", &.{
298 .{ .reg = inst.data.r.r1 },
299 }),
300 .pseudo_cfi_undefined_r => try lower.emit(.directive, .@".cfi_undefined", &.{
301 .{ .reg = inst.data.r.r1 },
302 }),
303 .pseudo_cfi_same_value_r => try lower.emit(.directive, .@".cfi_same_value", &.{
304 .{ .reg = inst.data.r.r1 },
305 }),
306 .pseudo_cfi_remember_state_none => try lower.emit(.directive, .@".cfi_remember_state", &.{}),
307 .pseudo_cfi_restore_state_none => try lower.emit(.directive, .@".cfi_restore_state", &.{}),
308 .pseudo_cfi_escape_bytes => try lower.emit(.directive, .@".cfi_escape", &.{
309 .{ .bytes = inst.data.bytes.get(lower.mir) },
310 }),
311
268312 .pseudo_dbg_prologue_end_none,
269313 .pseudo_dbg_line_line_column,
270314 .pseudo_dbg_epilogue_begin_none,
......@@ -280,6 +324,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
280324 .pseudo_dbg_local_af,
281325 .pseudo_dbg_local_am,
282326 .pseudo_dbg_var_args_none,
327
283328 .pseudo_dead_none,
284329 => {},
285330 else => unreachable,
......@@ -665,12 +710,43 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
665710
666711fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
667712 const callee_preserved_regs = abi.getCalleePreservedRegs(lower.cc);
668 var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) {
669 .push => .reverse,
670 .pop => .forward,
713 var off: i32 = switch (mnemonic) {
714 .push => 0,
715 .pop => undefined,
671716 else => unreachable,
672 } });
673 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i] }});
717 };
718 {
719 var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) {
720 .push => .reverse,
721 .pop => .forward,
722 else => unreachable,
723 } });
724 while (it.next()) |i| {
725 try lower.emit(.none, mnemonic, &.{.{
726 .reg = callee_preserved_regs[i],
727 }});
728 switch (mnemonic) {
729 .push => off -= 8,
730 .pop => {},
731 else => unreachable,
732 }
733 }
734 }
735 switch (mnemonic) {
736 .push => {
737 var it = inst.data.reg_list.iterator(.{});
738 while (it.next()) |i| {
739 try lower.emit(.directive, .@".cfi_rel_offset", &.{
740 .{ .reg = callee_preserved_regs[i] },
741 .{ .imm = Immediate.s(off) },
742 });
743 off += 8;
744 }
745 assert(off == 0);
746 },
747 .pop => {},
748 else => unreachable,
749 }
674750}
675751
676752const page_size: i32 = 1 << 12;
src/arch/x86_64/Mir.zig+48-1
......@@ -879,6 +879,7 @@ pub const Inst = struct {
879879 /// Probe adjust loop
880880 /// Uses `rr` payload.
881881 pseudo_probe_adjust_loop_rr,
882
882883 /// Push registers
883884 /// Uses `reg_list` payload.
884885 pseudo_push_reg_list,
......@@ -886,6 +887,47 @@ pub const Inst = struct {
886887 /// Uses `reg_list` payload.
887888 pseudo_pop_reg_list,
888889
890 /// Define cfa rule as offset from register.
891 /// Uses `ri` payload.
892 pseudo_cfi_def_cfa_ri_s,
893 /// Modify cfa rule register.
894 /// Uses `r` payload.
895 pseudo_cfi_def_cfa_register_r,
896 /// Modify cfa rule offset.
897 /// Uses `i` payload.
898 pseudo_cfi_def_cfa_offset_i_s,
899 /// Offset cfa rule offset.
900 /// Uses `i` payload.
901 pseudo_cfi_adjust_cfa_offset_i_s,
902 /// Define register rule as stored at offset from cfa.
903 /// Uses `ri` payload.
904 pseudo_cfi_offset_ri_s,
905 /// Define register rule as offset from cfa.
906 /// Uses `ri` payload.
907 pseudo_cfi_val_offset_ri_s,
908 /// Define register rule as stored at offset from cfa rule register.
909 /// Uses `ri` payload.
910 pseudo_cfi_rel_offset_ri_s,
911 /// Define register rule as register.
912 /// Uses `rr` payload.
913 pseudo_cfi_register_rr,
914 /// Define register rule from initial.
915 /// Uses `r` payload.
916 pseudo_cfi_restore_r,
917 /// Define register rule as undefined.
918 /// Uses `r` payload.
919 pseudo_cfi_undefined_r,
920 /// Define register rule as itself.
921 /// Uses `r` payload.
922 pseudo_cfi_same_value_r,
923 /// Push cfi state.
924 pseudo_cfi_remember_state_none,
925 /// Pop cfi state.
926 pseudo_cfi_restore_state_none,
927 /// Raw cfi bytes.
928 /// Uses `bytes` payload.
929 pseudo_cfi_escape_bytes,
930
889931 /// End of prologue
890932 pseudo_dbg_prologue_end_none,
891933 /// Update debug line
......@@ -1028,8 +1070,13 @@ pub const Inst = struct {
10281070 fixes: Fixes = ._,
10291071 payload: u32,
10301072 },
1031 ix: struct {
1073 bytes: struct {
10321074 payload: u32,
1075 len: u32,
1076
1077 pub fn get(bytes: @This(), mir: Mir) []const u8 {
1078 return std.mem.sliceAsBytes(mir.extra[bytes.payload..])[0..bytes.len];
1079 }
10331080 },
10341081 a: struct {
10351082 air_inst: Air.Inst.Index,
src/arch/x86_64/bits.zig+1-1
......@@ -371,7 +371,7 @@ pub const Register = enum(u7) {
371371 .x87 => 33 + @as(u6, reg.enc()),
372372 .mmx => 41 + @as(u6, reg.enc()),
373373 .segment => 50 + @as(u6, reg.enc()),
374 .ip => unreachable,
374 .ip => 16,
375375 };
376376 }
377377};
src/arch/x86_64/encoder.zig+43-12
......@@ -25,6 +25,7 @@ pub const Instruction = struct {
2525 repz,
2626 repne,
2727 repnz,
28 directive,
2829 };
2930
3031 pub const Immediate = union(enum) {
......@@ -180,6 +181,7 @@ pub const Instruction = struct {
180181 reg: Register,
181182 mem: Memory,
182183 imm: Immediate,
184 bytes: []const u8,
183185
184186 /// Returns the bitsize of the operand.
185187 pub fn bitSize(op: Operand) u64 {
......@@ -188,6 +190,7 @@ pub const Instruction = struct {
188190 .reg => |reg| reg.bitSize(),
189191 .mem => |mem| mem.bitSize(),
190192 .imm => unreachable,
193 .bytes => unreachable,
191194 };
192195 }
193196
......@@ -199,6 +202,7 @@ pub const Instruction = struct {
199202 .reg => |reg| reg.class() == .segment,
200203 .mem => |mem| mem.isSegmentRegister(),
201204 .imm => unreachable,
205 .bytes => unreachable,
202206 };
203207 }
204208
......@@ -207,6 +211,7 @@ pub const Instruction = struct {
207211 .none, .imm => false,
208212 .reg => |reg| reg.isExtended(),
209213 .mem => |mem| mem.base().isExtended(),
214 .bytes => unreachable,
210215 };
211216 }
212217
......@@ -214,6 +219,7 @@ pub const Instruction = struct {
214219 return switch (op) {
215220 .none, .reg, .imm => false,
216221 .mem => |mem| if (mem.scaleIndex()) |si| si.index.isExtended() else false,
222 .bytes => unreachable,
217223 };
218224 }
219225
......@@ -299,6 +305,7 @@ pub const Instruction = struct {
299305 if (imms < 0) try writer.writeByte('-');
300306 try writer.print("0x{x}", .{@abs(imms)});
301307 } else try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}),
308 .bytes => unreachable,
302309 }
303310 }
304311
......@@ -308,20 +315,39 @@ pub const Instruction = struct {
308315 };
309316
310317 pub fn new(prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) !Instruction {
311 const encoding = (try Encoding.findByMnemonic(prefix, mnemonic, ops)) orelse {
312 log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
313 @tagName(prefix),
314 @tagName(mnemonic),
315 @tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none),
316 @tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none),
317 @tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none),
318 @tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none),
319 });
320 return error.InvalidInstruction;
318 const encoding: Encoding = switch (prefix) {
319 else => (try Encoding.findByMnemonic(prefix, mnemonic, ops)) orelse {
320 log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
321 @tagName(prefix),
322 @tagName(mnemonic),
323 @tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none),
324 @tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none),
325 @tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none),
326 @tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none),
327 });
328 return error.InvalidInstruction;
329 },
330 .directive => .{
331 .mnemonic = mnemonic,
332 .data = .{
333 .op_en = .zo,
334 .ops = .{
335 if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none,
336 if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none,
337 if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none,
338 if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none,
339 },
340 .opc_len = 0,
341 .opc = undefined,
342 .modrm_ext = 0,
343 .mode = .none,
344 .feature = .none,
345 },
346 },
321347 };
322348 log.debug("selected encoding: {}", .{encoding});
323349
324 var inst = Instruction{
350 var inst: Instruction = .{
325351 .prefix = prefix,
326352 .encoding = encoding,
327353 .ops = [1]Operand{.none} ** 4,
......@@ -338,7 +364,10 @@ pub const Instruction = struct {
338364 ) @TypeOf(writer).Error!void {
339365 _ = unused_format_string;
340366 _ = options;
341 if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)});
367 switch (inst.prefix) {
368 .none, .directive => {},
369 else => try writer.print("{s} ", .{@tagName(inst.prefix)}),
370 }
342371 try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});
343372 for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| {
344373 if (op == .none) break;
......@@ -349,6 +378,7 @@ pub const Instruction = struct {
349378 }
350379
351380 pub fn encode(inst: Instruction, writer: anytype, comptime opts: Options) !void {
381 assert(inst.prefix != .directive);
352382 const encoder = Encoder(@TypeOf(writer), opts){ .writer = writer };
353383 const enc = inst.encoding;
354384 const data = enc.data;
......@@ -435,6 +465,7 @@ pub const Instruction = struct {
435465 .lock => legacy.prefix_f0 = true,
436466 .repne, .repnz => legacy.prefix_f2 = true,
437467 .rep, .repe, .repz => legacy.prefix_f3 = true,
468 .directive => unreachable,
438469 }
439470
440471 switch (data.mode) {
src/link/Dwarf.zig+646-130
......@@ -10,6 +10,7 @@ navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index),
1010
1111debug_abbrev: DebugAbbrev,
1212debug_aranges: DebugAranges,
13debug_frame: DebugFrame,
1314debug_info: DebugInfo,
1415debug_line: DebugLine,
1516debug_line_str: StringSection,
......@@ -73,11 +74,7 @@ const DebugAranges = struct {
7374 section: Section,
7475
7576 fn headerBytes(dwarf: *Dwarf) u32 {
76 return std.mem.alignForwardAnyAlign(
77 u32,
78 dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1,
79 @intFromEnum(dwarf.address_size) * 2,
80 );
77 return dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1;
8178 }
8279
8380 fn trailerBytes(dwarf: *Dwarf) u32 {
......@@ -85,6 +82,47 @@ const DebugAranges = struct {
8582 }
8683};
8784
85const DebugFrame = struct {
86 header: Header,
87 section: Section,
88
89 const Format = enum { none, debug_frame, eh_frame };
90 const Header = struct {
91 format: Format,
92 code_alignment_factor: u32,
93 data_alignment_factor: i32,
94 return_address_register: u32,
95 initial_instructions: []const Cfa,
96 };
97
98 fn headerBytes(dwarf: *Dwarf) u32 {
99 const target = dwarf.bin_file.comp.root_mod.resolved_target.result;
100 return @intCast(switch (dwarf.debug_frame.header.format) {
101 .none => return 0,
102 .debug_frame => dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 1 + "\x00".len + 1 + 1,
103 .eh_frame => dwarf.unitLengthBytes() + 4 + 1 + "zR\x00".len +
104 uleb128Bytes(1) + 1,
105 } + switch (target.cpu.arch) {
106 .x86_64 => len: {
107 dev.check(.x86_64_backend);
108 const Register = @import("../arch/x86_64/bits.zig").Register;
109 break :len uleb128Bytes(1) + sleb128Bytes(-8) + uleb128Bytes(Register.rip.dwarfNum()) +
110 1 + uleb128Bytes(Register.rsp.dwarfNum()) + sleb128Bytes(-1) +
111 1 + uleb128Bytes(1);
112 },
113 else => unreachable,
114 });
115 }
116
117 fn trailerBytes(dwarf: *Dwarf) u32 {
118 return @intCast(switch (dwarf.debug_frame.header.format) {
119 .none => 0,
120 .debug_frame => dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 1 + "\x00".len + 1 + 1 + uleb128Bytes(1) + sleb128Bytes(1) + uleb128Bytes(0),
121 .eh_frame => dwarf.unitLengthBytes() + 4 + 1 + "\x00".len + uleb128Bytes(1) + sleb128Bytes(1) + uleb128Bytes(0),
122 });
123 }
124};
125
88126const DebugInfo = struct {
89127 section: Section,
90128
......@@ -227,8 +265,10 @@ pub const Section = struct {
227265 len: u64,
228266 units: std.ArrayListUnmanaged(Unit),
229267
230 const Index = enum {
268 pub const Index = enum {
231269 debug_abbrev,
270 debug_aranges,
271 debug_frame,
232272 debug_info,
233273 debug_line,
234274 debug_line_str,
......@@ -259,15 +299,17 @@ pub const Section = struct {
259299 const unit: Unit.Index = @enumFromInt(sec.units.items.len);
260300 const unit_ptr = try sec.units.addOne(dwarf.gpa);
261301 errdefer sec.popUnit(dwarf.gpa);
302 const aligned_header_len: u32 = @intCast(sec.alignment.forward(header_len));
303 const aligned_trailer_len: u32 = @intCast(sec.alignment.forward(trailer_len));
262304 unit_ptr.* = .{
263305 .prev = sec.last,
264306 .next = .none,
265307 .first = .none,
266308 .last = .none,
267309 .off = 0,
268 .header_len = header_len,
269 .trailer_len = trailer_len,
270 .len = header_len + trailer_len,
310 .header_len = aligned_header_len,
311 .trailer_len = aligned_trailer_len,
312 .len = aligned_header_len + aligned_trailer_len,
271313 .entries = .{},
272314 .cross_unit_relocs = .{},
273315 .cross_section_relocs = .{},
......@@ -288,8 +330,8 @@ pub const Section = struct {
288330 const unit_ptr = sec.getUnit(unit);
289331 if (unit_ptr.prev.unwrap()) |prev_unit| sec.getUnit(prev_unit).next = unit_ptr.next;
290332 if (unit_ptr.next.unwrap()) |next_unit| sec.getUnit(next_unit).prev = unit_ptr.prev;
291 if (sec.first.unwrap().? == unit) sec.first = unit_ptr.next;
292 if (sec.last.unwrap().? == unit) sec.last = unit_ptr.prev;
333 if (sec.first == unit.toOptional()) sec.first = unit_ptr.next;
334 if (sec.last == unit.toOptional()) sec.last = unit_ptr.prev;
293335 }
294336
295337 fn popUnit(sec: *Section, gpa: std.mem.Allocator) void {
......@@ -303,10 +345,10 @@ pub const Section = struct {
303345 return &sec.units.items[@intFromEnum(unit)];
304346 }
305347
306 fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
348 fn resizeEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, len: u32) UpdateError!void {
307349 const unit_ptr = sec.getUnit(unit);
308350 const entry_ptr = unit_ptr.getEntry(entry);
309 if (contents.len > 0) {
351 if (len > 0) {
310352 if (entry_ptr.len == 0) {
311353 assert(entry_ptr.prev == .none and entry_ptr.next == .none);
312354 entry_ptr.off = if (unit_ptr.last.unwrap()) |last_entry| off: {
......@@ -316,15 +358,27 @@ pub const Section = struct {
316358 } else 0;
317359 entry_ptr.prev = unit_ptr.last;
318360 unit_ptr.last = entry.toOptional();
361 if (unit_ptr.first == .none) unit_ptr.first = unit_ptr.last;
362 if (entry_ptr.prev.unwrap()) |prev_entry| try unit_ptr.getEntry(prev_entry).pad(unit_ptr, sec, dwarf);
319363 }
320 try entry_ptr.replace(unit_ptr, sec, dwarf, contents);
364 try entry_ptr.resize(unit_ptr, sec, dwarf, len);
321365 }
322 assert(entry_ptr.len == contents.len);
366 assert(entry_ptr.len == len);
367 }
368
369 fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
370 try sec.resizeEntry(unit, entry, dwarf, @intCast(contents.len));
371 const unit_ptr = sec.getUnit(unit);
372 try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents);
323373 }
324374
325375 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
376 if (len <= sec.len) return;
326377 if (dwarf.bin_file.cast(.elf)) |elf_file| {
327 try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true);
378 if (sec == &dwarf.debug_frame.section)
379 try elf_file.growAllocSection(sec.index, len)
380 else
381 try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true);
328382 const shdr = &elf_file.sections.items(.shdr)[sec.index];
329383 sec.off = shdr.sh_offset;
330384 sec.len = shdr.sh_size;
......@@ -366,7 +420,7 @@ pub const Section = struct {
366420 }
367421
368422 fn padToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) {
369 return if (sec.pad_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size;
423 return @intCast(sec.alignment.forward(if (sec.pad_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size));
370424 }
371425};
372426
......@@ -562,6 +616,43 @@ const Unit = struct {
562616 } else if (sec == &dwarf.debug_aranges.section) fill: {
563617 trailer.appendNTimesAssumeCapacity(0, @intFromEnum(dwarf.address_size) * 2);
564618 break :fill 0;
619 } else if (sec == &dwarf.debug_frame.section) fill: {
620 switch (dwarf.debug_frame.header.format) {
621 .none => {},
622 .debug_frame, .eh_frame => |format| {
623 const unit_len = len - dwarf.unitLengthBytes();
624 switch (dwarf.format) {
625 .@"32" => std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
626 .@"64" => {
627 std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
628 std.mem.writeInt(u64, trailer.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
629 },
630 }
631 switch (format) {
632 .none => unreachable,
633 .debug_frame => {
634 switch (dwarf.format) {
635 .@"32" => std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian),
636 .@"64" => std.mem.writeInt(u64, trailer.addManyAsArrayAssumeCapacity(8), std.math.maxInt(u64), dwarf.endian),
637 }
638 trailer.appendAssumeCapacity(4);
639 trailer.appendSliceAssumeCapacity("\x00");
640 trailer.appendAssumeCapacity(@intFromEnum(dwarf.address_size));
641 trailer.appendAssumeCapacity(0);
642 },
643 .eh_frame => {
644 std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), 0, dwarf.endian);
645 trailer.appendAssumeCapacity(1);
646 trailer.appendSliceAssumeCapacity("\x00");
647 },
648 }
649 uleb128(trailer.fixedWriter(), 1) catch unreachable;
650 sleb128(trailer.fixedWriter(), 1) catch unreachable;
651 uleb128(trailer.fixedWriter(), 0) catch unreachable;
652 },
653 }
654 trailer.appendNTimesAssumeCapacity(DW.CFA.nop, unit.trailer_len - trailer.items.len);
655 break :fill DW.CFA.nop;
565656 } else if (sec == &dwarf.debug_info.section) fill: {
566657 assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
567658 trailer.appendNTimesAssumeCapacity(@intFromEnum(AbbrevCode.null), 2);
......@@ -571,7 +662,7 @@ const Unit = struct {
571662 break :fill DW.RLE.end_of_list;
572663 } else unreachable;
573664 assert(trailer.items.len == unit.trailer_len);
574 trailer.appendNTimesAssumeCapacity(fill_byte, len - trailer.items.len);
665 trailer.appendNTimesAssumeCapacity(fill_byte, len - unit.trailer_len);
575666 assert(trailer.items.len == len);
576667 try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start);
577668 }
......@@ -655,6 +746,23 @@ const Entry = struct {
655746 fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
656747 assert(entry.len > 0);
657748 const start = entry.off + entry.len;
749 if (sec == &dwarf.debug_frame.section) {
750 const len = if (entry.next.unwrap()) |next_entry|
751 unit.getEntry(next_entry).off - entry.off
752 else
753 entry.len;
754 var unit_len: [8]u8 = undefined;
755 dwarf.writeInt(unit_len[0..dwarf.sectionOffsetBytes()], len - dwarf.unitLengthBytes());
756 try dwarf.getFile().?.pwriteAll(
757 unit_len[0..dwarf.sectionOffsetBytes()],
758 sec.off + unit.off + unit.header_len + entry.off,
759 );
760 const buf = try dwarf.gpa.alloc(u8, len - entry.len);
761 defer dwarf.gpa.free(buf);
762 @memset(buf, DW.CFA.nop);
763 try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start);
764 return;
765 }
658766 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
659767 var buf: [
660768 @max(
......@@ -711,18 +819,20 @@ const Entry = struct {
711819 try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);
712820 }
713821
714 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
822 fn resize(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {
823 assert(len > 0);
824 assert(sec.alignment.check(len));
825 if (entry_ptr.len == len) return;
715826 const end = if (entry_ptr.next.unwrap()) |next_entry|
716827 unit.getEntry(next_entry).off
717828 else
718829 unit.len -| (unit.header_len + unit.trailer_len);
719 if (entry_ptr.off + contents.len > end) {
830 if (entry_ptr.off + len > end) {
720831 if (entry_ptr.next.unwrap()) |next_entry| {
721 if (entry_ptr.prev.unwrap()) |prev_entry| {
722 const prev_entry_ptr = unit.getEntry(prev_entry);
723 prev_entry_ptr.next = entry_ptr.next;
724 try prev_entry_ptr.pad(unit, sec, dwarf);
725 } else unit.first = entry_ptr.next;
832 if (entry_ptr.prev.unwrap()) |prev_entry|
833 unit.getEntry(prev_entry).next = entry_ptr.next
834 else
835 unit.first = entry_ptr.next;
726836 const next_entry_ptr = unit.getEntry(next_entry);
727837 const entry = next_entry_ptr.prev;
728838 next_entry_ptr.prev = entry_ptr.prev;
......@@ -733,12 +843,15 @@ const Entry = struct {
733843 entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
734844 unit.last = entry;
735845 }
736 try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padToIdeal(contents.len) + unit.trailer_len));
846 try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padToIdeal(len) + unit.trailer_len));
737847 }
738 entry_ptr.len = @intCast(contents.len);
739 if (entry_ptr.prev.unwrap()) |prev_entry| try unit.getEntry(prev_entry).pad(unit, sec, dwarf);
740 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off);
848 entry_ptr.len = len;
741849 try entry_ptr.pad(unit, sec, dwarf);
850 }
851
852 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
853 assert(contents.len == entry_ptr.len);
854 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off);
742855 if (false) {
743856 const buf = try dwarf.gpa.alloc(u8, sec.len);
744857 defer dwarf.gpa.free(buf);
......@@ -844,6 +957,22 @@ const Entry = struct {
844957 dwarf.sectionOffsetBytes(),
845958 );
846959 }
960 if (sec == &dwarf.debug_frame.section) switch (DebugFrame.format(dwarf)) {
961 .none, .debug_frame => {},
962 .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| {
963 const zo = elf_file.zigObjectPtr().?;
964 const entry_addr: i64 = @intCast(entry_off - sec.off + elf_file.shdrs.items[sec.index].sh_addr);
965 for (entry.external_relocs.items) |reloc| {
966 const symbol = zo.symbol(reloc.target_sym);
967 try dwarf.resolveReloc(
968 entry_off + reloc.source_off,
969 @bitCast((symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off))) -
970 (entry_addr + reloc.source_off + 4)),
971 4,
972 );
973 }
974 } else unreachable,
975 };
847976 if (dwarf.bin_file.cast(.elf)) |elf_file| {
848977 const zo = elf_file.zigObjectPtr().?;
849978 for (entry.external_relocs.items) |reloc| {
......@@ -871,7 +1000,7 @@ const Entry = struct {
8711000
8721001const CrossEntryReloc = struct {
8731002 source_off: u32 = 0,
874 target_entry: Entry.Index,
1003 target_entry: Entry.Index.Optional = .none,
8751004 target_off: u32 = 0,
8761005};
8771006const CrossUnitReloc = struct {
......@@ -937,14 +1066,14 @@ pub const Loc = union(enum) {
9371066 }
9381067 }
9391068
940 fn write(loc: Loc, wip: anytype) UpdateError!void {
941 const writer = wip.infoWriter();
1069 fn write(loc: Loc, adapter: anytype) UpdateError!void {
1070 const writer = adapter.writer();
9421071 switch (loc) {
943 .empty => unreachable,
1072 .empty => {},
9441073 .addr => |addr| {
9451074 try writer.writeByte(DW.OP.addr);
9461075 switch (addr) {
947 .sym => |sym_index| try wip.addrSym(sym_index),
1076 .sym => |sym_index| try adapter.addrSym(sym_index),
9481077 }
9491078 },
9501079 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
......@@ -953,45 +1082,45 @@ pub const Loc = union(enum) {
9531082 try writer.writeAll(&.{ DW.OP.const1u, const1u });
9541083 } else if (std.math.cast(u16, constu)) |const2u| {
9551084 try writer.writeByte(DW.OP.const2u);
956 try writer.writeInt(u16, const2u, wip.dwarf.endian);
1085 try writer.writeInt(u16, const2u, adapter.endian());
9571086 } else if (std.math.cast(u21, constu)) |const3u| {
9581087 try writer.writeByte(DW.OP.constu);
9591088 try uleb128(writer, const3u);
9601089 } else if (std.math.cast(u32, constu)) |const4u| {
9611090 try writer.writeByte(DW.OP.const4u);
962 try writer.writeInt(u32, const4u, wip.dwarf.endian);
1091 try writer.writeInt(u32, const4u, adapter.endian());
9631092 } else if (std.math.cast(u49, constu)) |const7u| {
9641093 try writer.writeByte(DW.OP.constu);
9651094 try uleb128(writer, const7u);
9661095 } else {
9671096 try writer.writeByte(DW.OP.const8u);
968 try writer.writeInt(u64, constu, wip.dwarf.endian);
1097 try writer.writeInt(u64, constu, adapter.endian());
9691098 },
9701099 .consts => |consts| if (std.math.cast(i8, consts)) |const1s| {
9711100 try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) });
9721101 } else if (std.math.cast(i16, consts)) |const2s| {
9731102 try writer.writeByte(DW.OP.const2s);
974 try writer.writeInt(i16, const2s, wip.dwarf.endian);
1103 try writer.writeInt(i16, const2s, adapter.endian());
9751104 } else if (std.math.cast(i21, consts)) |const3s| {
9761105 try writer.writeByte(DW.OP.consts);
9771106 try sleb128(writer, const3s);
9781107 } else if (std.math.cast(i32, consts)) |const4s| {
9791108 try writer.writeByte(DW.OP.const4s);
980 try writer.writeInt(i32, const4s, wip.dwarf.endian);
1109 try writer.writeInt(i32, const4s, adapter.endian());
9811110 } else if (std.math.cast(i49, consts)) |const7s| {
9821111 try writer.writeByte(DW.OP.consts);
9831112 try sleb128(writer, const7s);
9841113 } else {
9851114 try writer.writeByte(DW.OP.const8s);
986 try writer.writeInt(i64, consts, wip.dwarf.endian);
1115 try writer.writeInt(i64, consts, adapter.endian());
9871116 },
9881117 .plus => |plus| done: {
9891118 if (plus[0].getConst(u0)) |_| {
990 try plus[1].write(wip);
1119 try plus[1].write(adapter);
9911120 break :done;
9921121 }
9931122 if (plus[1].getConst(u0)) |_| {
994 try plus[0].write(wip);
1123 try plus[0].write(adapter);
9951124 break :done;
9961125 }
9971126 if (plus[0].getBaseReg()) |breg| {
......@@ -1009,19 +1138,19 @@ pub const Loc = union(enum) {
10091138 }
10101139 }
10111140 if (plus[0].getConst(u64)) |uconst| {
1012 try plus[1].write(wip);
1141 try plus[1].write(adapter);
10131142 try writer.writeByte(DW.OP.plus_uconst);
10141143 try uleb128(writer, uconst);
10151144 break :done;
10161145 }
10171146 if (plus[1].getConst(u64)) |uconst| {
1018 try plus[0].write(wip);
1147 try plus[0].write(adapter);
10191148 try writer.writeByte(DW.OP.plus_uconst);
10201149 try uleb128(writer, uconst);
10211150 break :done;
10221151 }
1023 try plus[0].write(wip);
1024 try plus[1].write(wip);
1152 try plus[0].write(adapter);
1153 try plus[1].write(adapter);
10251154 try writer.writeByte(DW.OP.plus);
10261155 },
10271156 .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer),
......@@ -1031,7 +1160,7 @@ pub const Loc = union(enum) {
10311160 },
10321161 .push_object_address => try writer.writeByte(DW.OP.push_object_address),
10331162 .form_tls_address => |addr| {
1034 try addr.write(wip);
1163 try addr.write(adapter);
10351164 try writer.writeByte(DW.OP.form_tls_address);
10361165 },
10371166 .implicit_value => |value| {
......@@ -1040,7 +1169,7 @@ pub const Loc = union(enum) {
10401169 try writer.writeAll(value);
10411170 },
10421171 .stack_value => |value| {
1043 try value.write(wip);
1172 try value.write(adapter);
10441173 try writer.writeByte(DW.OP.stack_value);
10451174 },
10461175 .wasm_ext => |wasm_ext| {
......@@ -1055,7 +1184,7 @@ pub const Loc = union(enum) {
10551184 try uleb128(writer, global_u21);
10561185 } else {
10571186 try writer.writeByte(DW.OP.WASM_global_u32);
1058 try writer.writeInt(u32, global, wip.dwarf.endian);
1187 try writer.writeInt(u32, global, adapter.endian());
10591188 },
10601189 .operand_stack => |operand_stack| {
10611190 try writer.writeByte(DW.OP.WASM_operand_stack);
......@@ -1067,6 +1196,153 @@ pub const Loc = union(enum) {
10671196 }
10681197};
10691198
1199pub const Cfa = union(enum) {
1200 nop,
1201 advance_loc: u32,
1202 offset: RegOff,
1203 rel_offset: RegOff,
1204 restore: u32,
1205 undefined: u32,
1206 same_value: u32,
1207 register: [2]u32,
1208 remember_state,
1209 restore_state,
1210 def_cfa: RegOff,
1211 def_cfa_register: u32,
1212 def_cfa_offset: i64,
1213 adjust_cfa_offset: i64,
1214 def_cfa_expression: Loc,
1215 expression: RegExpr,
1216 val_offset: RegOff,
1217 val_expression: RegExpr,
1218 escape: []const u8,
1219
1220 const RegOff = struct { reg: u32, off: i64 };
1221 const RegExpr = struct { reg: u32, expr: Loc };
1222
1223 fn write(cfa: Cfa, wip_nav: *WipNav) UpdateError!void {
1224 const writer = wip_nav.debug_frame.writer(wip_nav.dwarf.gpa);
1225 switch (cfa) {
1226 .nop => try writer.writeByte(DW.CFA.nop),
1227 .advance_loc => |loc| {
1228 const delta = @divExact(loc - wip_nav.cfi.loc, wip_nav.dwarf.debug_frame.header.code_alignment_factor);
1229 if (delta == 0) {} else if (std.math.cast(u6, delta)) |small_delta|
1230 try writer.writeByte(@as(u8, DW.CFA.advance_loc) + small_delta)
1231 else if (std.math.cast(u8, delta)) |ubyte_delta|
1232 try writer.writeAll(&.{ DW.CFA.advance_loc1, ubyte_delta })
1233 else if (std.math.cast(u16, delta)) |uhalf_delta| {
1234 try writer.writeByte(DW.CFA.advance_loc2);
1235 try writer.writeInt(u16, uhalf_delta, wip_nav.dwarf.endian);
1236 } else if (std.math.cast(u32, delta)) |uword_delta| {
1237 try writer.writeByte(DW.CFA.advance_loc4);
1238 try writer.writeInt(u32, uword_delta, wip_nav.dwarf.endian);
1239 }
1240 wip_nav.cfi.loc = loc;
1241 },
1242 .offset, .rel_offset => |reg_off| {
1243 const factored_off = @divExact(reg_off.off - switch (cfa) {
1244 else => unreachable,
1245 .offset => 0,
1246 .rel_offset => wip_nav.cfi.cfa.off,
1247 }, wip_nav.dwarf.debug_frame.header.data_alignment_factor);
1248 if (std.math.cast(u63, factored_off)) |unsigned_off| {
1249 if (std.math.cast(u6, reg_off.reg)) |small_reg| {
1250 try writer.writeByte(@as(u8, DW.CFA.offset) + small_reg);
1251 } else {
1252 try writer.writeByte(DW.CFA.offset_extended);
1253 try uleb128(writer, reg_off.reg);
1254 }
1255 try uleb128(writer, unsigned_off);
1256 } else {
1257 try writer.writeByte(DW.CFA.offset_extended_sf);
1258 try uleb128(writer, reg_off.reg);
1259 try sleb128(writer, factored_off);
1260 }
1261 },
1262 .restore => |reg| if (std.math.cast(u6, reg)) |small_reg|
1263 try writer.writeByte(@as(u8, DW.CFA.restore) + small_reg)
1264 else {
1265 try writer.writeByte(DW.CFA.restore_extended);
1266 try uleb128(writer, reg);
1267 },
1268 .undefined => |reg| {
1269 try writer.writeByte(DW.CFA.undefined);
1270 try uleb128(writer, reg);
1271 },
1272 .same_value => |reg| {
1273 try writer.writeByte(DW.CFA.same_value);
1274 try uleb128(writer, reg);
1275 },
1276 .register => |regs| if (regs[0] != regs[1]) {
1277 try writer.writeByte(DW.CFA.register);
1278 for (regs) |reg| try uleb128(writer, reg);
1279 } else {
1280 try writer.writeByte(DW.CFA.same_value);
1281 try uleb128(writer, regs[0]);
1282 },
1283 .remember_state => try writer.writeByte(DW.CFA.remember_state),
1284 .restore_state => try writer.writeByte(DW.CFA.restore_state),
1285 .def_cfa, .def_cfa_register, .def_cfa_offset, .adjust_cfa_offset => {
1286 const reg_off: RegOff = switch (cfa) {
1287 else => unreachable,
1288 .def_cfa => |reg_off| reg_off,
1289 .def_cfa_register => |reg| .{ .reg = reg, .off = wip_nav.cfi.cfa.off },
1290 .def_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = off },
1291 .adjust_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = wip_nav.cfi.cfa.off + off },
1292 };
1293 const changed_reg = reg_off.reg != wip_nav.cfi.cfa.reg;
1294 const unsigned_off = std.math.cast(u63, reg_off.off);
1295 if (reg_off.off == wip_nav.cfi.cfa.off) {
1296 if (changed_reg) {
1297 try writer.writeByte(DW.CFA.def_cfa_register);
1298 try uleb128(writer, reg_off.reg);
1299 }
1300 } else if (switch (wip_nav.dwarf.debug_frame.header.data_alignment_factor) {
1301 0 => unreachable,
1302 1 => unsigned_off != null,
1303 else => |data_alignment_factor| @rem(reg_off.off, data_alignment_factor) != 0,
1304 }) {
1305 try writer.writeByte(if (changed_reg) DW.CFA.def_cfa else DW.CFA.def_cfa_offset);
1306 if (changed_reg) try uleb128(writer, reg_off.reg);
1307 try uleb128(writer, unsigned_off.?);
1308 } else {
1309 try writer.writeByte(if (changed_reg) DW.CFA.def_cfa_sf else DW.CFA.def_cfa_offset_sf);
1310 if (changed_reg) try uleb128(writer, reg_off.reg);
1311 try sleb128(writer, @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor));
1312 }
1313 wip_nav.cfi.cfa = reg_off;
1314 },
1315 .def_cfa_expression => |expr| {
1316 try writer.writeByte(DW.CFA.def_cfa_expression);
1317 try wip_nav.frameExprloc(expr);
1318 },
1319 .expression => |reg_expr| {
1320 try writer.writeByte(DW.CFA.expression);
1321 try uleb128(writer, reg_expr.reg);
1322 try wip_nav.frameExprloc(reg_expr.expr);
1323 },
1324 .val_offset => |reg_off| {
1325 const factored_off = @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor);
1326 if (std.math.cast(u63, factored_off)) |unsigned_off| {
1327 try writer.writeByte(DW.CFA.val_offset);
1328 try uleb128(writer, reg_off.reg);
1329 try uleb128(writer, unsigned_off);
1330 } else {
1331 try writer.writeByte(DW.CFA.val_offset_sf);
1332 try uleb128(writer, reg_off.reg);
1333 try sleb128(writer, factored_off);
1334 }
1335 },
1336 .val_expression => |reg_expr| {
1337 try writer.writeByte(DW.CFA.val_expression);
1338 try uleb128(writer, reg_expr.reg);
1339 try wip_nav.frameExprloc(reg_expr.expr);
1340 },
1341 .escape => |bytes| try writer.writeAll(bytes),
1342 }
1343 }
1344};
1345
10701346pub const WipNav = struct {
10711347 dwarf: *Dwarf,
10721348 pt: Zcu.PerThread,
......@@ -1080,6 +1356,11 @@ pub const WipNav = struct {
10801356 abbrev_code: u32,
10811357 high_reloc: u32,
10821358 }),
1359 cfi: struct {
1360 loc: u32,
1361 cfa: Cfa.RegOff,
1362 },
1363 debug_frame: std.ArrayListUnmanaged(u8),
10831364 debug_info: std.ArrayListUnmanaged(u8),
10841365 debug_line: std.ArrayListUnmanaged(u8),
10851366 debug_loclists: std.ArrayListUnmanaged(u8),
......@@ -1088,14 +1369,19 @@ pub const WipNav = struct {
10881369 pub fn deinit(wip_nav: *WipNav) void {
10891370 const gpa = wip_nav.dwarf.gpa;
10901371 if (wip_nav.func != .none) wip_nav.inlined_funcs.deinit(gpa);
1372 wip_nav.debug_frame.deinit(gpa);
10911373 wip_nav.debug_info.deinit(gpa);
10921374 wip_nav.debug_line.deinit(gpa);
10931375 wip_nav.debug_loclists.deinit(gpa);
10941376 wip_nav.pending_types.deinit(gpa);
10951377 }
10961378
1097 pub fn infoWriter(wip_nav: *WipNav) std.ArrayListUnmanaged(u8).Writer {
1098 return wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
1379 pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) UpdateError!void {
1380 assert(wip_nav.func != .none);
1381 if (wip_nav.dwarf.debug_frame.header.format == .none) return;
1382 const loc_cfa: Cfa = .{ .advance_loc = loc };
1383 try loc_cfa.write(wip_nav);
1384 try cfa.write(wip_nav);
10991385 }
11001386
11011387 pub const LocalTag = enum { local_arg, local_var };
......@@ -1301,7 +1587,7 @@ pub const WipNav = struct {
13011587 } else {
13021588 try entry_ptr.cross_entry_relocs.append(gpa, .{
13031589 .source_off = @intCast(wip_nav.debug_info.items.len),
1304 .target_entry = entry,
1590 .target_entry = entry.toOptional(),
13051591 .target_off = off,
13061592 });
13071593 }
......@@ -1312,7 +1598,45 @@ pub const WipNav = struct {
13121598 try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);
13131599 }
13141600
1315 fn addrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
1601 const ExprLocCounter = struct {
1602 const Stream = std.io.CountingWriter(std.io.NullWriter);
1603 stream: Stream,
1604 address_size: AddressSize,
1605 fn writer(counter: *ExprLocCounter) Stream.Writer {
1606 return counter.stream.writer();
1607 }
1608 fn endian(_: ExprLocCounter) std.builtin.Endian {
1609 return @import("builtin").cpu.arch.endian();
1610 }
1611 fn addrSym(counter: *ExprLocCounter, _: u32) error{}!void {
1612 counter.stream.bytes_written += @intFromEnum(counter.address_size);
1613 }
1614 };
1615
1616 fn exprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1617 var counter: ExprLocCounter = .{
1618 .stream = std.io.countingWriter(std.io.null_writer),
1619 .address_size = wip_nav.dwarf.address_size,
1620 };
1621 try loc.write(&counter);
1622
1623 const adapter: struct {
1624 wip_nav: *WipNav,
1625 fn writer(ctx: @This()) std.ArrayListUnmanaged(u8).Writer {
1626 return ctx.wip_nav.debug_info.writer(ctx.wip_nav.dwarf.gpa);
1627 }
1628 fn endian(ctx: @This()) std.builtin.Endian {
1629 return ctx.wip_nav.dwarf.endian;
1630 }
1631 fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void {
1632 try ctx.wip_nav.infoAddrSym(sym_index);
1633 }
1634 } = .{ .wip_nav = wip_nav };
1635 try uleb128(adapter.writer(), counter.stream.bytes_written);
1636 try loc.write(adapter);
1637 }
1638
1639 fn infoAddrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
13161640 const dwarf = wip_nav.dwarf;
13171641 try dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
13181642 .source_off = @intCast(wip_nav.debug_info.items.len),
......@@ -1321,25 +1645,36 @@ pub const WipNav = struct {
13211645 try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size));
13221646 }
13231647
1324 fn exprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1325 if (loc == .empty) return;
1326 var wip: struct {
1327 const Info = std.io.CountingWriter(std.io.NullWriter);
1328 dwarf: *Dwarf,
1329 debug_info: Info,
1330 fn infoWriter(wip: *@This()) Info.Writer {
1331 return wip.debug_info.writer();
1648 fn frameExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1649 var counter: ExprLocCounter = .{
1650 .stream = std.io.countingWriter(std.io.null_writer),
1651 .address_size = wip_nav.dwarf.address_size,
1652 };
1653 try loc.write(&counter);
1654
1655 const adapter: struct {
1656 wip_nav: *WipNav,
1657 fn writer(ctx: @This()) std.ArrayListUnmanaged(u8).Writer {
1658 return ctx.wip_nav.debug_frame.writer(ctx.wip_nav.dwarf.gpa);
13321659 }
1333 fn addrSym(wip: *@This(), _: u32) error{}!void {
1334 wip.debug_info.bytes_written += @intFromEnum(wip.dwarf.address_size);
1660 fn endian(ctx: @This()) std.builtin.Endian {
1661 return ctx.wip_nav.dwarf.endian;
13351662 }
1336 } = .{
1337 .dwarf = wip_nav.dwarf,
1338 .debug_info = std.io.countingWriter(std.io.null_writer),
1339 };
1340 try loc.write(&wip);
1341 try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), wip.debug_info.bytes_written);
1342 try loc.write(wip_nav);
1663 fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void {
1664 try ctx.wip_nav.frameAddrSym(sym_index);
1665 }
1666 } = .{ .wip_nav = wip_nav };
1667 try uleb128(adapter.writer(), counter.stream.bytes_written);
1668 try loc.write(adapter);
1669 }
1670
1671 fn frameAddrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
1672 const dwarf = wip_nav.dwarf;
1673 try dwarf.debug_frame.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
1674 .source_off = @intCast(wip_nav.debug_frame.items.len),
1675 .target_sym = sym_index,
1676 });
1677 try wip_nav.debug_frame.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size));
13431678 }
13441679
13451680 fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } {
......@@ -1387,7 +1722,7 @@ pub const WipNav = struct {
13871722
13881723 fn finishForward(wip_nav: *WipNav, reloc_index: u32) void {
13891724 const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index];
1390 reloc.target_entry = wip_nav.entry;
1725 reloc.target_entry = wip_nav.entry.toOptional();
13911726 reloc.target_off = @intCast(wip_nav.debug_info.items.len);
13921727 }
13931728
......@@ -1490,6 +1825,28 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf {
14901825
14911826 .debug_abbrev = .{ .section = Section.init },
14921827 .debug_aranges = .{ .section = Section.init },
1828 .debug_frame = .{
1829 .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: {
1830 const Register = @import("../arch/x86_64/bits.zig").Register;
1831 break :header comptime .{
1832 .format = .eh_frame,
1833 .code_alignment_factor = 1,
1834 .data_alignment_factor = -8,
1835 .return_address_register = Register.rip.dwarfNum(),
1836 .initial_instructions = &.{
1837 .{ .def_cfa = .{ .reg = Register.rsp.dwarfNum(), .off = 8 } },
1838 .{ .offset = .{ .reg = Register.rip.dwarfNum(), .off = -8 } },
1839 },
1840 };
1841 } else .{
1842 .format = .none,
1843 .code_alignment_factor = undefined,
1844 .data_alignment_factor = undefined,
1845 .return_address_register = undefined,
1846 .initial_instructions = &.{},
1847 },
1848 .section = Section.init,
1849 },
14931850 .debug_info = .{ .section = Section.init },
14941851 .debug_line = .{
14951852 .header = switch (target.cpu.arch) {
......@@ -1524,6 +1881,7 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
15241881 for ([_]*Section{
15251882 &dwarf.debug_abbrev.section,
15261883 &dwarf.debug_aranges.section,
1884 &dwarf.debug_frame.section,
15271885 &dwarf.debug_info.section,
15281886 &dwarf.debug_line.section,
15291887 &dwarf.debug_line_str.section,
......@@ -1533,6 +1891,7 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
15331891 }, [_]u32{
15341892 elf_file.debug_abbrev_section_index.?,
15351893 elf_file.debug_aranges_section_index.?,
1894 elf_file.eh_frame_section_index.?,
15361895 elf_file.debug_info_section_index.?,
15371896 elf_file.debug_line_section_index.?,
15381897 elf_file.debug_line_str_section_index.?,
......@@ -1612,6 +1971,12 @@ pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
16121971 dwarf.debug_aranges.section.pad_to_ideal = false;
16131972 dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size) * 2);
16141973
1974 dwarf.debug_frame.section.alignment = switch (dwarf.debug_frame.header.format) {
1975 .none => .@"1",
1976 .debug_frame => InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size)),
1977 .eh_frame => .@"4",
1978 };
1979
16151980 dwarf.debug_line_str.section.pad_to_ideal = false;
16161981 assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
16171982 errdefer dwarf.debug_line_str.section.popUnit(dwarf.gpa);
......@@ -1633,6 +1998,7 @@ pub fn deinit(dwarf: *Dwarf) void {
16331998 dwarf.navs.deinit(gpa);
16341999 dwarf.debug_abbrev.section.deinit(gpa);
16352000 dwarf.debug_aranges.section.deinit(gpa);
2001 dwarf.debug_frame.section.deinit(gpa);
16362002 dwarf.debug_info.section.deinit(gpa);
16372003 dwarf.debug_line.section.deinit(gpa);
16382004 dwarf.debug_line_str.deinit(gpa);
......@@ -1660,6 +2026,12 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index {
16602026 dwarf,
16612027 ) == unit);
16622028 errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);
2029 assert(try dwarf.debug_frame.section.addUnit(
2030 DebugFrame.headerBytes(dwarf),
2031 DebugFrame.trailerBytes(dwarf),
2032 dwarf,
2033 ) == unit);
2034 errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa);
16632035 assert(try dwarf.debug_info.section.addUnit(
16642036 DebugInfo.headerBytes(dwarf),
16652037 DebugInfo.trailer_bytes,
......@@ -1729,6 +2101,8 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
17292101 .func_sym_index = undefined,
17302102 .func_high_reloc = undefined,
17312103 .inlined_funcs = undefined,
2104 .cfi = undefined,
2105 .debug_frame = .{},
17322106 .debug_info = .{},
17332107 .debug_line = .{},
17342108 .debug_loclists = .{},
......@@ -1870,6 +2244,50 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
18702244 wip_nav.func = nav_val.toIntern();
18712245 wip_nav.func_sym_index = sym_index;
18722246 wip_nav.inlined_funcs = .{};
2247 if (dwarf.debug_frame.header.format != .none) wip_nav.cfi = .{
2248 .loc = 0,
2249 .cfa = dwarf.debug_frame.header.initial_instructions[0].def_cfa,
2250 };
2251
2252 switch (dwarf.debug_frame.header.format) {
2253 .none => {},
2254 .debug_frame, .eh_frame => |format| {
2255 const entry = dwarf.debug_frame.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry);
2256 const dfw = wip_nav.debug_frame.writer(dwarf.gpa);
2257 switch (dwarf.format) {
2258 .@"32" => try dfw.writeInt(u32, undefined, dwarf.endian),
2259 .@"64" => {
2260 try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian);
2261 try dfw.writeInt(u64, undefined, dwarf.endian);
2262 },
2263 }
2264 switch (format) {
2265 .none => unreachable,
2266 .debug_frame => {
2267 try entry.cross_entry_relocs.append(dwarf.gpa, .{
2268 .source_off = @intCast(wip_nav.debug_frame.items.len),
2269 });
2270 try dfw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
2271 try entry.external_relocs.append(dwarf.gpa, .{
2272 .source_off = @intCast(wip_nav.debug_frame.items.len),
2273 .target_sym = sym_index,
2274 });
2275 try dfw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
2276 try dfw.writeByteNTimes(undefined, @intFromEnum(dwarf.address_size));
2277 },
2278 .eh_frame => {
2279 try dfw.writeInt(u32, undefined, dwarf.endian);
2280 try entry.external_relocs.append(dwarf.gpa, .{
2281 .source_off = @intCast(wip_nav.debug_frame.items.len),
2282 .target_sym = sym_index,
2283 });
2284 try dfw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
2285 try dfw.writeInt(u32, undefined, dwarf.endian);
2286 try uleb128(dfw, 0);
2287 },
2288 }
2289 },
2290 }
18732291
18742292 const diw = wip_nav.debug_info.writer(dwarf.gpa);
18752293 try wip_nav.abbrevCode(.decl_func);
......@@ -1953,49 +2371,84 @@ pub fn finishWipNav(
19532371 log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)});
19542372
19552373 if (wip_nav.func != .none) {
1956 const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
1957 external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;
1958 if (wip_nav.any_children) {
1959 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1960 try uleb128(diw, @intFromEnum(AbbrevCode.null));
1961 } else std.leb.writeUnsignedFixed(
1962 AbbrevCode.decl_bytes,
1963 wip_nav.debug_info.items[0..AbbrevCode.decl_bytes],
1964 try dwarf.refAbbrevCode(.decl_empty_func),
1965 );
1966
1967 var aranges_entry = [1]u8{0} ** (8 + 8);
1968 try dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
1969 .target_sym = sym.index,
1970 });
1971 dwarf.writeInt(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);
1972 dwarf.writeInt(aranges_entry[@intFromEnum(dwarf.address_size)..][0..@intFromEnum(dwarf.address_size)], sym.size);
1973
1974 @memset(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);
1975 try dwarf.debug_aranges.section.replaceEntry(
1976 wip_nav.unit,
1977 wip_nav.entry,
1978 dwarf,
1979 aranges_entry[0 .. @intFromEnum(dwarf.address_size) * 2],
1980 );
1981
1982 try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{
1983 .{
1984 .source_off = 1,
1985 .target_sym = sym.index,
1986 },
1987 .{
1988 .source_off = 1 + @intFromEnum(dwarf.address_size),
1989 .target_sym = sym.index,
1990 .target_off = sym.size,
2374 {
2375 const external_relocs = &dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
2376 try external_relocs.append(dwarf.gpa, .{ .target_sym = sym.index });
2377 var entry: [8 + 8]u8 = undefined;
2378 @memset(entry[0..@intFromEnum(dwarf.address_size)], 0);
2379 dwarf.writeInt(entry[@intFromEnum(dwarf.address_size)..][0..@intFromEnum(dwarf.address_size)], sym.size);
2380 try dwarf.debug_aranges.section.replaceEntry(
2381 wip_nav.unit,
2382 wip_nav.entry,
2383 dwarf,
2384 entry[0 .. @intFromEnum(dwarf.address_size) * 2],
2385 );
2386 }
2387 switch (dwarf.debug_frame.header.format) {
2388 .none => {},
2389 .debug_frame, .eh_frame => |format| {
2390 try wip_nav.debug_frame.appendNTimes(
2391 dwarf.gpa,
2392 DW.CFA.nop,
2393 @intCast(dwarf.debug_frame.section.alignment.forward(wip_nav.debug_frame.items.len) - wip_nav.debug_frame.items.len),
2394 );
2395 const contents = wip_nav.debug_frame.items;
2396 try dwarf.debug_frame.section.resizeEntry(wip_nav.unit, wip_nav.entry, dwarf, @intCast(contents.len));
2397 const unit = dwarf.debug_frame.section.getUnit(wip_nav.unit);
2398 const entry = unit.getEntry(wip_nav.entry);
2399 const unit_len = (if (entry.next.unwrap()) |next_entry|
2400 unit.getEntry(next_entry).off - entry.off
2401 else
2402 entry.len) - dwarf.unitLengthBytes();
2403 dwarf.writeInt(contents[dwarf.unitLengthBytes() - dwarf.sectionOffsetBytes() ..][0..dwarf.sectionOffsetBytes()], unit_len);
2404 switch (format) {
2405 .none => unreachable,
2406 .debug_frame => dwarf.writeInt(contents[dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() +
2407 @intFromEnum(dwarf.address_size) ..][0..@intFromEnum(dwarf.address_size)], sym.size),
2408 .eh_frame => {
2409 std.mem.writeInt(
2410 u32,
2411 contents[dwarf.unitLengthBytes()..][0..4],
2412 unit.header_len + entry.off + dwarf.unitLengthBytes(),
2413 dwarf.endian,
2414 );
2415 std.mem.writeInt(u32, contents[dwarf.unitLengthBytes() + 4 + 4 ..][0..4], @intCast(sym.size), dwarf.endian);
2416 },
2417 }
2418 try entry.replace(unit, &dwarf.debug_frame.section, dwarf, contents);
19912419 },
1992 });
1993 try dwarf.debug_rnglists.section.replaceEntry(
1994 wip_nav.unit,
1995 wip_nav.entry,
1996 dwarf,
1997 ([1]u8{DW.RLE.start_end} ++ [1]u8{0} ** (8 + 8))[0 .. 1 + @intFromEnum(dwarf.address_size) + @intFromEnum(dwarf.address_size)],
1998 );
2420 }
2421 {
2422 const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
2423 external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;
2424 if (wip_nav.any_children) {
2425 const diw = wip_nav.debug_info.writer(dwarf.gpa);
2426 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2427 } else std.leb.writeUnsignedFixed(
2428 AbbrevCode.decl_bytes,
2429 wip_nav.debug_info.items[0..AbbrevCode.decl_bytes],
2430 try dwarf.refAbbrevCode(.decl_empty_func),
2431 );
2432 }
2433 {
2434 try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{
2435 .{
2436 .source_off = 1,
2437 .target_sym = sym.index,
2438 },
2439 .{
2440 .source_off = 1 + @intFromEnum(dwarf.address_size),
2441 .target_sym = sym.index,
2442 .target_off = sym.size,
2443 },
2444 });
2445 try dwarf.debug_rnglists.section.replaceEntry(
2446 wip_nav.unit,
2447 wip_nav.entry,
2448 dwarf,
2449 ([1]u8{DW.RLE.start_end} ++ [1]u8{0} ** (8 + 8))[0 .. 1 + @intFromEnum(dwarf.address_size) + @intFromEnum(dwarf.address_size)],
2450 );
2451 }
19992452 }
20002453
20012454 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
......@@ -2038,6 +2491,8 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
20382491 .func_sym_index = undefined,
20392492 .func_high_reloc = undefined,
20402493 .inlined_funcs = undefined,
2494 .cfi = undefined,
2495 .debug_frame = .{},
20412496 .debug_info = .{},
20422497 .debug_line = .{},
20432498 .debug_loclists = .{},
......@@ -2546,6 +3001,8 @@ fn updateType(
25463001 .func_sym_index = undefined,
25473002 .func_high_reloc = undefined,
25483003 .inlined_funcs = undefined,
3004 .cfi = undefined,
3005 .debug_frame = .{},
25493006 .debug_info = .{},
25503007 .debug_line = .{},
25513008 .debug_loclists = .{},
......@@ -2999,6 +3456,8 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
29993456 .func_sym_index = undefined,
30003457 .func_high_reloc = undefined,
30013458 .inlined_funcs = undefined,
3459 .cfi = undefined,
3460 .debug_frame = .{},
30023461 .debug_info = .{},
30033462 .debug_line = .{},
30043463 .debug_loclists = .{},
......@@ -3062,6 +3521,8 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
30623521 .func_sym_index = undefined,
30633522 .func_high_reloc = undefined,
30643523 .inlined_funcs = undefined,
3524 .cfi = undefined,
3525 .debug_frame = .{},
30653526 .debug_info = .{},
30663527 .debug_line = .{},
30673528 .debug_loclists = .{},
......@@ -3255,6 +3716,8 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
32553716 .func_sym_index = undefined,
32563717 .func_high_reloc = undefined,
32573718 .inlined_funcs = undefined,
3719 .cfi = undefined,
3720 .debug_frame = .{},
32583721 .debug_info = .{},
32593722 .debug_line = .{},
32603723 .debug_loclists = .{},
......@@ -3306,13 +3769,13 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
33063769 else
33073770 dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
33083771 switch (dwarf.format) {
3309 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3772 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
33103773 .@"64" => {
3311 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3312 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3774 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
3775 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
33133776 },
33143777 }
3315 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 2, dwarf.endian);
3778 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 2, dwarf.endian);
33163779 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
33173780 .source_off = @intCast(header.items.len),
33183781 .target_sec = .debug_info,
......@@ -3326,6 +3789,49 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
33263789 }
33273790 dwarf.debug_aranges.section.dirty = false;
33283791 }
3792 if (dwarf.debug_frame.section.dirty) {
3793 const target = dwarf.bin_file.comp.root_mod.resolved_target.result;
3794 switch (dwarf.debug_frame.header.format) {
3795 .none => {},
3796 .debug_frame => unreachable,
3797 .eh_frame => switch (target.cpu.arch) {
3798 .x86_64 => {
3799 dev.check(.x86_64_backend);
3800 const Register = @import("../arch/x86_64/bits.zig").Register;
3801 for (dwarf.debug_frame.section.units.items) |*unit| {
3802 header.clearRetainingCapacity();
3803 try header.ensureTotalCapacity(unit.header_len);
3804 const unit_len = unit.header_len - dwarf.unitLengthBytes();
3805 switch (dwarf.format) {
3806 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
3807 .@"64" => {
3808 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
3809 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
3810 },
3811 }
3812 header.appendNTimesAssumeCapacity(0, 4);
3813 header.appendAssumeCapacity(1);
3814 header.appendSliceAssumeCapacity("zR\x00");
3815 uleb128(header.fixedWriter(), dwarf.debug_frame.header.code_alignment_factor) catch unreachable;
3816 sleb128(header.fixedWriter(), dwarf.debug_frame.header.data_alignment_factor) catch unreachable;
3817 uleb128(header.fixedWriter(), dwarf.debug_frame.header.return_address_register) catch unreachable;
3818 uleb128(header.fixedWriter(), 1) catch unreachable;
3819 header.appendAssumeCapacity(0x10 | 0x08 | 0x03);
3820 header.appendAssumeCapacity(DW.CFA.def_cfa_sf);
3821 uleb128(header.fixedWriter(), Register.rsp.dwarfNum()) catch unreachable;
3822 sleb128(header.fixedWriter(), -1) catch unreachable;
3823 header.appendAssumeCapacity(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum());
3824 uleb128(header.fixedWriter(), 1) catch unreachable;
3825 header.appendNTimesAssumeCapacity(DW.CFA.nop, unit.header_len - header.items.len);
3826 try unit.replaceHeader(&dwarf.debug_frame.section, dwarf, header.items);
3827 try unit.writeTrailer(&dwarf.debug_frame.section, dwarf);
3828 }
3829 },
3830 else => unreachable,
3831 },
3832 }
3833 dwarf.debug_frame.section.dirty = false;
3834 }
33293835 if (dwarf.debug_info.section.dirty) {
33303836 for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| {
33313837 const unit: Unit.Index = @enumFromInt(unit_index);
......@@ -3339,13 +3845,13 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
33393845 else
33403846 dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
33413847 switch (dwarf.format) {
3342 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3848 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
33433849 .@"64" => {
3344 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3345 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3850 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
3851 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
33463852 },
33473853 }
3348 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3854 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 5, dwarf.endian);
33493855 header.appendSliceAssumeCapacity(&.{ DW.UT.compile, @intFromEnum(dwarf.address_size) });
33503856 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
33513857 .source_off = @intCast(header.items.len),
......@@ -3438,13 +3944,13 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
34383944 else
34393945 dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes();
34403946 switch (dwarf.format) {
3441 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
3947 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
34423948 .@"64" => {
3443 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3444 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
3949 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
3950 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
34453951 },
34463952 }
3447 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
3953 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 5, dwarf.endian);
34483954 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
34493955 dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), unit.header_len - header.items.len);
34503956 const StandardOpcode = DeclValEnum(DW.LNS);
......@@ -3540,15 +4046,15 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
35404046 else
35414047 dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes();
35424048 switch (dwarf.format) {
3543 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),
4049 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
35444050 .@"64" => {
3545 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);
3546 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);
4051 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
4052 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
35474053 },
35484054 }
3549 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
4055 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 5, dwarf.endian);
35504056 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3551 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), 1, dwarf.endian);
4057 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), 1, dwarf.endian);
35524058 dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), dwarf.sectionOffsetBytes() * 1);
35534059 try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header.items);
35544060 try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);
......@@ -3557,6 +4063,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
35574063 }
35584064 assert(!dwarf.debug_abbrev.section.dirty);
35594065 assert(!dwarf.debug_aranges.section.dirty);
4066 assert(!dwarf.debug_frame.section.dirty);
35604067 assert(!dwarf.debug_info.section.dirty);
35614068 assert(!dwarf.debug_line.section.dirty);
35624069 assert(!dwarf.debug_line_str.section.dirty);
......@@ -3569,6 +4076,7 @@ pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
35694076 for ([_]*Section{
35704077 &dwarf.debug_abbrev.section,
35714078 &dwarf.debug_aranges.section,
4079 &dwarf.debug_frame.section,
35724080 &dwarf.debug_info.section,
35734081 &dwarf.debug_line.section,
35744082 &dwarf.debug_line_str.section,
......@@ -4147,6 +4655,7 @@ fn getFile(dwarf: *Dwarf) ?std.fs.File {
41474655
41484656fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
41494657 const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);
4658 assert(try dwarf.debug_frame.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
41504659 assert(try dwarf.debug_info.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
41514660 assert(try dwarf.debug_line.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
41524661 assert(try dwarf.debug_loclists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
......@@ -4190,6 +4699,12 @@ fn uleb128Bytes(value: anytype) u32 {
41904699 return @intCast(cw.bytes_written);
41914700}
41924701
4702fn sleb128Bytes(value: anytype) u32 {
4703 var cw = std.io.countingWriter(std.io.null_writer);
4704 try sleb128(cw.writer(), value);
4705 return @intCast(cw.bytes_written);
4706}
4707
41934708/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
41944709const force_incremental = false;
41954710inline fn incremental(dwarf: Dwarf) bool {
......@@ -4206,6 +4721,7 @@ const Zcu = @import("../Zcu.zig");
42064721const Zir = std.zig.Zir;
42074722const assert = std.debug.assert;
42084723const codegen = @import("../codegen.zig");
4724const dev = @import("../dev.zig");
42094725const link = @import("../link.zig");
42104726const log = std.log.scoped(.dwarf);
42114727const sleb128 = std.leb.writeIleb128;
src/link/Elf.zig+80-53
......@@ -569,9 +569,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
569569
570570 if (shdr.sh_type != elf.SHT_NOBITS) {
571571 const allocated_size = self.allocatedSize(shdr.sh_offset);
572 if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
573 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
574 } else if (needed_size > allocated_size) {
572 if (needed_size > allocated_size) {
575573 const existing_size = shdr.sh_size;
576574 shdr.sh_size = 0;
577575 // Must move the entire section.
......@@ -590,6 +588,8 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
590588
591589 shdr.sh_offset = new_offset;
592590 if (maybe_phdr) |phdr| phdr.p_offset = new_offset;
591 } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
592 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
593593 }
594594 if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;
595595 }
......@@ -621,9 +621,7 @@ pub fn growNonAllocSection(
621621 assert(shdr.sh_flags & elf.SHF_ALLOC == 0);
622622
623623 const allocated_size = self.allocatedSize(shdr.sh_offset);
624 if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
625 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
626 } else if (needed_size > allocated_size) {
624 if (needed_size > allocated_size) {
627625 const existing_size = shdr.sh_size;
628626 shdr.sh_size = 0;
629627 // Move all the symbols to a new file location.
......@@ -646,6 +644,8 @@ pub fn growNonAllocSection(
646644 }
647645
648646 shdr.sh_offset = new_offset;
647 } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
648 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
649649 }
650650 shdr.sh_size = needed_size;
651651
......@@ -699,7 +699,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
699699 const sub_prog_node = prog_node.start("ELF Flush", 0);
700700 defer sub_prog_node.end();
701701
702 const target = comp.root_mod.resolved_target.result;
702 const target = self.getTarget();
703703 const link_mode = comp.config.link_mode;
704704 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
705705 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
......@@ -1053,7 +1053,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
10531053 defer arena_allocator.deinit();
10541054 const arena = arena_allocator.allocator();
10551055
1056 const target = self.base.comp.root_mod.resolved_target.result;
1056 const target = self.getTarget();
10571057 const link_mode = self.base.comp.config.link_mode;
10581058 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
10591059 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
......@@ -1498,15 +1498,13 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
14981498}
14991499
15001500pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Word) !void {
1501 const target = self.base.comp.root_mod.resolved_target.result;
1502
15031501 if (self.first_eflags == null) {
15041502 self.first_eflags = e_flags;
15051503 return; // there isn't anything to conflict with yet
15061504 }
15071505 const self_eflags: *elf.Elf64_Word = &self.first_eflags.?;
15081506
1509 switch (target.cpu.arch) {
1507 switch (self.getTarget().cpu.arch) {
15101508 .riscv64 => {
15111509 if (e_flags != self_eflags.*) {
15121510 const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags);
......@@ -1549,7 +1547,7 @@ fn accessLibPath(
15491547 link_mode: ?std.builtin.LinkMode,
15501548) !bool {
15511549 const sep = fs.path.sep_str;
1552 const target = self.base.comp.root_mod.resolved_target.result;
1550 const target = self.getTarget();
15531551 test_path.clearRetainingCapacity();
15541552 const prefix = if (link_mode != null) "lib" else "";
15551553 const suffix = if (link_mode) |mode| switch (mode) {
......@@ -1779,7 +1777,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
17791777 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;
17801778 const have_dynamic_linker = comp.config.link_libc and
17811779 link_mode == .dynamic and is_exe_or_dyn_lib;
1782 const target = comp.root_mod.resolved_target.result;
1780 const target = self.getTarget();
17831781 const compiler_rt_path: ?[]const u8 = blk: {
17841782 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
17851783 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
......@@ -2353,8 +2351,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
23532351
23542352pub fn writeShdrTable(self: *Elf) !void {
23552353 const gpa = self.base.comp.gpa;
2356 const target = self.base.comp.root_mod.resolved_target.result;
2357 const target_endian = target.cpu.arch.endian();
2354 const target_endian = self.getTarget().cpu.arch.endian();
23582355 const foreign_endian = target_endian != builtin.cpu.arch.endian();
23592356 const shsize: u64 = switch (self.ptr_width) {
23602357 .p32 => @sizeOf(elf.Elf32_Shdr),
......@@ -2410,8 +2407,7 @@ pub fn writeShdrTable(self: *Elf) !void {
24102407
24112408fn writePhdrTable(self: *Elf) !void {
24122409 const gpa = self.base.comp.gpa;
2413 const target = self.base.comp.root_mod.resolved_target.result;
2414 const target_endian = target.cpu.arch.endian();
2410 const target_endian = self.getTarget().cpu.arch.endian();
24152411 const foreign_endian = target_endian != builtin.cpu.arch.endian();
24162412 const phdr_table = &self.phdrs.items[self.phdr_table_index.?];
24172413
......@@ -2464,7 +2460,7 @@ pub fn writeElfHeader(self: *Elf) !void {
24642460 };
24652461 index += 1;
24662462
2467 const target = comp.root_mod.resolved_target.result;
2463 const target = self.getTarget();
24682464 const endian = target.cpu.arch.endian();
24692465 hdr_buf[index] = switch (endian) {
24702466 .little => elf.ELFDATA2LSB,
......@@ -2772,21 +2768,25 @@ fn initOutputSections(self: *Elf) !void {
27722768
27732769fn initSyntheticSections(self: *Elf) !void {
27742770 const comp = self.base.comp;
2775 const target = comp.root_mod.resolved_target.result;
2771 const target = self.getTarget();
27762772 const ptr_size = self.ptrWidthBytes();
27772773
27782774 const needs_eh_frame = for (self.objects.items) |index| {
27792775 if (self.file(index).?.object.cies.items.len > 0) break true;
27802776 } else false;
27812777 if (needs_eh_frame) {
2782 self.eh_frame_section_index = try self.addSection(.{
2783 .name = try self.insertShString(".eh_frame"),
2784 .type = elf.SHT_PROGBITS,
2785 .flags = elf.SHF_ALLOC,
2786 .addralign = ptr_size,
2787 .offset = std.math.maxInt(u64),
2788 });
2789
2778 if (self.eh_frame_section_index == null) {
2779 self.eh_frame_section_index = try self.addSection(.{
2780 .name = try self.insertShString(".eh_frame"),
2781 .type = if (target.cpu.arch == .x86_64)
2782 elf.SHT_X86_64_UNWIND
2783 else
2784 elf.SHT_PROGBITS,
2785 .flags = elf.SHF_ALLOC,
2786 .addralign = ptr_size,
2787 .offset = std.math.maxInt(u64),
2788 });
2789 }
27902790 if (comp.link_eh_frame_hdr) {
27912791 self.eh_frame_hdr_section_index = try self.addSection(.{
27922792 .name = try self.insertShString(".eh_frame_hdr"),
......@@ -3446,7 +3446,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
34463446}
34473447
34483448fn updateSectionSizes(self: *Elf) !void {
3449 const target = self.base.comp.root_mod.resolved_target.result;
34503449 const slice = self.sections.slice();
34513450 for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| {
34523451 if (atom_list.items.len == 0) continue;
......@@ -3474,7 +3473,11 @@ fn updateSectionSizes(self: *Elf) !void {
34743473
34753474 const shdrs = slice.items(.shdr);
34763475 if (self.eh_frame_section_index) |index| {
3477 shdrs[index].sh_size = try eh_frame.calcEhFrameSize(self);
3476 shdrs[index].sh_size = existing_size: {
3477 const zo = self.zigObjectPtr() orelse break :existing_size 0;
3478 const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
3479 break :existing_size sym.atom(self).?.size;
3480 } + try eh_frame.calcEhFrameSize(self);
34783481 }
34793482
34803483 if (self.eh_frame_hdr_section_index) |index| {
......@@ -3517,7 +3520,7 @@ fn updateSectionSizes(self: *Elf) !void {
35173520 }
35183521
35193522 if (self.interp_section_index) |index| {
3520 shdrs[index].sh_size = target.dynamic_linker.get().?.len + 1;
3523 shdrs[index].sh_size = self.getTarget().dynamic_linker.get().?.len + 1;
35213524 }
35223525
35233526 if (self.hash_section_index) |index| {
......@@ -3759,10 +3762,10 @@ pub fn allocateAllocSections(self: *Elf) !void {
37593762 }
37603763
37613764 const first = slice.items(.shdr)[cover.items[0]];
3762 var off = try self.findFreeSpace(filesz, @"align");
3765 var new_offset = try self.findFreeSpace(filesz, @"align");
37633766 const phndx = try self.addPhdr(.{
37643767 .type = elf.PT_LOAD,
3765 .offset = off,
3768 .offset = new_offset,
37663769 .addr = first.sh_addr,
37673770 .memsz = memsz,
37683771 .filesz = filesz,
......@@ -3777,9 +3780,28 @@ pub fn allocateAllocSections(self: *Elf) !void {
37773780 shdr.sh_offset = 0;
37783781 continue;
37793782 }
3780 off = alignment.@"align"(shndx, shdr.sh_addralign, off);
3781 shdr.sh_offset = off;
3782 off += shdr.sh_size;
3783 new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset);
3784
3785 if (shndx == self.eh_frame_section_index) eh_frame: {
3786 const zo = self.zigObjectPtr() orelse break :eh_frame;
3787 const sym = zo.symbol(zo.eh_frame_index orelse break :eh_frame);
3788 const existing_size = sym.atom(self).?.size;
3789 log.debug("moving {s} from 0x{x} to 0x{x}", .{
3790 self.getShString(shdr.sh_name),
3791 shdr.sh_offset,
3792 new_offset,
3793 });
3794 const amt = try self.base.file.?.copyRangeAll(
3795 shdr.sh_offset,
3796 self.base.file.?,
3797 new_offset,
3798 existing_size,
3799 );
3800 if (amt != existing_size) return error.InputOutput;
3801 }
3802
3803 shdr.sh_offset = new_offset;
3804 new_offset += shdr.sh_size;
37833805 }
37843806
37853807 addr = mem.alignForward(u64, addr, self.page_size);
......@@ -3910,9 +3932,9 @@ fn writeAtoms(self: *Elf) !void {
39103932 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
39113933
39123934 // TODO really, really handle debug section separately
3913 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
3935 const base_offset = if (self.isDebugSection(@intCast(shndx))) base_offset: {
39143936 const zo = self.zigObjectPtr().?;
3915 break :blk for ([_]Symbol.Index{
3937 for ([_]Symbol.Index{
39163938 zo.debug_info_index.?,
39173939 zo.debug_abbrev_index.?,
39183940 zo.debug_aranges_index.?,
......@@ -3924,8 +3946,13 @@ fn writeAtoms(self: *Elf) !void {
39243946 }) |sym_index| {
39253947 const sym = zo.symbol(sym_index);
39263948 const atom_ptr = sym.atom(self).?;
3927 if (atom_ptr.output_section_index == shndx) break atom_ptr.size;
3928 } else 0;
3949 if (atom_ptr.output_section_index == shndx) break :base_offset atom_ptr.size;
3950 }
3951 break :base_offset 0;
3952 } else if (@as(u32, @intCast(shndx)) == self.eh_frame_section_index) base_offset: {
3953 const zo = self.zigObjectPtr() orelse break :base_offset 0;
3954 const sym = zo.symbol(zo.eh_frame_index orelse break :base_offset 0);
3955 break :base_offset sym.atom(self).?.size;
39293956 } else 0;
39303957 const sh_offset = shdr.sh_offset + base_offset;
39313958 const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
......@@ -4082,12 +4109,11 @@ pub fn updateSymtabSize(self: *Elf) !void {
40824109
40834110fn writeSyntheticSections(self: *Elf) !void {
40844111 const gpa = self.base.comp.gpa;
4085 const target = self.getTarget();
40864112 const slice = self.sections.slice();
40874113
40884114 if (self.interp_section_index) |shndx| {
40894115 var buffer: [256]u8 = undefined;
4090 const interp = target.dynamic_linker.get().?;
4116 const interp = self.getTarget().dynamic_linker.get().?;
40914117 @memcpy(buffer[0..interp.len], interp);
40924118 buffer[interp.len] = 0;
40934119 const contents = buffer[0 .. interp.len + 1];
......@@ -4144,12 +4170,18 @@ fn writeSyntheticSections(self: *Elf) !void {
41444170 }
41454171
41464172 if (self.eh_frame_section_index) |shndx| {
4173 const existing_size = existing_size: {
4174 const zo = self.zigObjectPtr() orelse break :existing_size 0;
4175 const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
4176 break :existing_size sym.atom(self).?.size;
4177 };
41474178 const shdr = slice.items(.shdr)[shndx];
41484179 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
4149 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
4180 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
41504181 defer buffer.deinit();
41514182 try eh_frame.writeEhFrame(self, buffer.writer());
4152 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
4183 assert(buffer.items.len == sh_size - existing_size);
4184 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset + existing_size);
41534185 }
41544186
41554187 if (self.eh_frame_hdr_section_index) |shndx| {
......@@ -4222,7 +4254,6 @@ pub fn writeShStrtab(self: *Elf) !void {
42224254
42234255pub fn writeSymtab(self: *Elf) !void {
42244256 const gpa = self.base.comp.gpa;
4225 const target = self.getTarget();
42264257 const slice = self.sections.slice();
42274258 const symtab_shdr = slice.items(.shdr)[self.symtab_section_index.?];
42284259 const strtab_shdr = slice.items(.shdr)[self.strtab_section_index.?];
......@@ -4292,7 +4323,7 @@ pub fn writeSymtab(self: *Elf) !void {
42924323 self.plt_got.writeSymtab(self);
42934324 }
42944325
4295 const foreign_endian = target.cpu.arch.endian() != builtin.cpu.arch.endian();
4326 const foreign_endian = self.getTarget().cpu.arch.endian() != builtin.cpu.arch.endian();
42964327 switch (self.ptr_width) {
42974328 .p32 => {
42984329 const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);
......@@ -4630,10 +4661,8 @@ pub fn isZigSection(self: Elf, shndx: u32) bool {
46304661 self.zig_data_rel_ro_section_index,
46314662 self.zig_data_section_index,
46324663 self.zig_bss_section_index,
4633 }) |maybe_index| {
4634 if (maybe_index) |index| {
4635 if (index == shndx) return true;
4636 }
4664 }) |index| {
4665 if (index == shndx) return true;
46374666 }
46384667 return false;
46394668}
......@@ -4648,10 +4677,8 @@ pub fn isDebugSection(self: Elf, shndx: u32) bool {
46484677 self.debug_line_str_section_index,
46494678 self.debug_loclists_section_index,
46504679 self.debug_rnglists_section_index,
4651 }) |maybe_index| {
4652 if (maybe_index) |index| {
4653 if (index == shndx) return true;
4654 }
4680 }) |index| {
4681 if (index == shndx) return true;
46554682 }
46564683 return false;
46574684}
src/link/Elf/ZigObject.zig+42-9
......@@ -49,6 +49,7 @@ debug_line_section_dirty: bool = false,
4949debug_line_str_section_dirty: bool = false,
5050debug_loclists_section_dirty: bool = false,
5151debug_rnglists_section_dirty: bool = false,
52eh_frame_section_dirty: bool = false,
5253
5354debug_info_index: ?Symbol.Index = null,
5455debug_abbrev_index: ?Symbol.Index = null,
......@@ -58,6 +59,7 @@ debug_line_index: ?Symbol.Index = null,
5859debug_line_str_index: ?Symbol.Index = null,
5960debug_loclists_index: ?Symbol.Index = null,
6061debug_rnglists_index: ?Symbol.Index = null,
62eh_frame_index: ?Symbol.Index = null,
6163
6264pub const global_symbol_bit: u32 = 0x80000000;
6365pub const symbol_mask: u32 = 0x7fffffff;
......@@ -72,8 +74,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
7274 const comp = elf_file.base.comp;
7375 const gpa = comp.gpa;
7476 const ptr_size = elf_file.ptrWidthBytes();
75 const target = elf_file.getTarget();
76 const ptr_bit_width = target.ptrBitWidth();
7777
7878 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section
7979 try self.relocs.append(gpa, .{}); // null relocs section
......@@ -113,7 +113,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
113113 .type = elf.PT_LOAD,
114114 .offset = off,
115115 .filesz = filesz,
116 .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000,
116 .addr = if (ptr_size >= 4) 0x4000000 else 0x4000,
117117 .memsz = filesz,
118118 .@"align" = elf_file.page_size,
119119 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
......@@ -128,7 +128,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
128128 .type = elf.PT_LOAD,
129129 .offset = off,
130130 .filesz = filesz,
131 .addr = if (ptr_bit_width >= 32) 0xc000000 else 0xa000,
131 .addr = if (ptr_size >= 4) 0xc000000 else 0xa000,
132132 .memsz = filesz,
133133 .@"align" = alignment,
134134 .flags = elf.PF_R | elf.PF_W,
......@@ -143,7 +143,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
143143 .type = elf.PT_LOAD,
144144 .offset = off,
145145 .filesz = filesz,
146 .addr = if (ptr_bit_width >= 32) 0x10000000 else 0xc000,
146 .addr = if (ptr_size >= 4) 0x10000000 else 0xc000,
147147 .memsz = filesz,
148148 .@"align" = alignment,
149149 .flags = elf.PF_R | elf.PF_W,
......@@ -154,7 +154,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
154154 const alignment = elf_file.page_size;
155155 elf_file.phdr_zig_load_zerofill_index = try elf_file.addPhdr(.{
156156 .type = elf.PT_LOAD,
157 .addr = if (ptr_bit_width >= 32) 0x14000000 else 0xf000,
157 .addr = if (ptr_size >= 4) 0x14000000 else 0xf000,
158158 .memsz = 1024,
159159 .@"align" = alignment,
160160 .flags = elf.PF_R | elf.PF_W,
......@@ -354,6 +354,20 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
354354 self.debug_rnglists_index = try addSectionSymbol(self, gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?);
355355 }
356356
357 if (elf_file.eh_frame_section_index == null) {
358 elf_file.eh_frame_section_index = try elf_file.addSection(.{
359 .name = try elf_file.insertShString(".eh_frame"),
360 .type = if (elf_file.getTarget().cpu.arch == .x86_64)
361 elf.SHT_X86_64_UNWIND
362 else
363 elf.SHT_PROGBITS,
364 .flags = elf.SHF_ALLOC,
365 .addralign = ptr_size,
366 });
367 self.eh_frame_section_dirty = true;
368 self.eh_frame_index = try addSectionSymbol(self, gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), elf_file.eh_frame_section_index.?);
369 }
370
357371 try dwarf.initMetadata();
358372 self.dwarf = dwarf;
359373 },
......@@ -460,6 +474,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
460474 self.debug_line_str_index.?,
461475 self.debug_loclists_index.?,
462476 self.debug_rnglists_index.?,
477 self.eh_frame_index.?,
463478 }, [_]*Dwarf.Section{
464479 &dwarf.debug_info.section,
465480 &dwarf.debug_abbrev.section,
......@@ -469,7 +484,18 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
469484 &dwarf.debug_line_str.section,
470485 &dwarf.debug_loclists.section,
471486 &dwarf.debug_rnglists.section,
472 }) |sym_index, sect| {
487 &dwarf.debug_frame.section,
488 }, [_]Dwarf.Section.Index{
489 .debug_info,
490 .debug_abbrev,
491 .debug_str,
492 .debug_aranges,
493 .debug_line,
494 .debug_line_str,
495 .debug_loclists,
496 .debug_rnglists,
497 .debug_frame,
498 }) |sym_index, sect, sect_index| {
473499 const sym = self.symbol(sym_index);
474500 const atom_ptr = self.atom(sym.ref.index).?;
475501 if (!atom_ptr.alive) continue;
......@@ -509,6 +535,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
509535 for (unit.cross_section_relocs.items) |reloc| {
510536 const target_sym_index = switch (reloc.target_sec) {
511537 .debug_abbrev => self.debug_abbrev_index.?,
538 .debug_aranges => self.debug_aranges_index.?,
539 .debug_frame => self.eh_frame_index.?,
512540 .debug_info => self.debug_info_index.?,
513541 .debug_line => self.debug_line_index.?,
514542 .debug_line_str => self.debug_line_str_index.?,
......@@ -547,7 +575,10 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
547575 entry.external_relocs.items.len);
548576 for (entry.cross_entry_relocs.items) |reloc| {
549577 const r_offset = entry_off + reloc.source_off;
550 const r_addend: i64 = @intCast(unit.off + reloc.target_off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sect, dwarf).off);
578 const r_addend: i64 = @intCast(unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
579 unit.header_len + unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
580 else
581 0));
551582 const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
552583 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
553584 self.symbol(sym_index).name(elf_file),
......@@ -584,6 +615,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
584615 for (entry.cross_section_relocs.items) |reloc| {
585616 const target_sym_index = switch (reloc.target_sec) {
586617 .debug_abbrev => self.debug_abbrev_index.?,
618 .debug_aranges => self.debug_aranges_index.?,
619 .debug_frame => self.eh_frame_index.?,
587620 .debug_info => self.debug_info_index.?,
588621 .debug_line => self.debug_line_index.?,
589622 .debug_line_str => self.debug_line_str_index.?,
......@@ -617,7 +650,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
617650 const target_sym = self.symbol(reloc.target_sym);
618651 const r_offset = entry_off + reloc.source_off;
619652 const r_addend: i64 = @intCast(reloc.target_off);
620 const r_type = relocation.dwarf.externalRelocType(target_sym.*, dwarf.address_size, cpu_arch);
653 const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch);
621654 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
622655 target_sym.name(elf_file),
623656 r_offset,
src/link/Elf/relocatable.zig+27-15
......@@ -289,8 +289,6 @@ fn claimUnresolved(elf_file: *Elf) void {
289289}
290290
291291fn initSections(elf_file: *Elf) !void {
292 const ptr_size = elf_file.ptrWidthBytes();
293
294292 for (elf_file.objects.items) |index| {
295293 const object = elf_file.file(index).?.object;
296294 try object.initOutputSections(elf_file);
......@@ -306,13 +304,18 @@ fn initSections(elf_file: *Elf) !void {
306304 if (elf_file.file(index).?.object.cies.items.len > 0) break true;
307305 } else false;
308306 if (needs_eh_frame) {
309 elf_file.eh_frame_section_index = try elf_file.addSection(.{
310 .name = try elf_file.insertShString(".eh_frame"),
311 .type = elf.SHT_PROGBITS,
312 .flags = elf.SHF_ALLOC,
313 .addralign = ptr_size,
314 .offset = std.math.maxInt(u64),
315 });
307 if (elf_file.eh_frame_section_index == null) {
308 elf_file.eh_frame_section_index = try elf_file.addSection(.{
309 .name = try elf_file.insertShString(".eh_frame"),
310 .type = if (elf_file.getTarget().cpu.arch == .x86_64)
311 elf.SHT_X86_64_UNWIND
312 else
313 elf.SHT_PROGBITS,
314 .flags = elf.SHF_ALLOC,
315 .addralign = elf_file.ptrWidthBytes(),
316 .offset = std.math.maxInt(u64),
317 });
318 }
316319 elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr(
317320 try elf_file.insertShString(".rela.eh_frame"),
318321 elf_file.eh_frame_section_index.?,
......@@ -373,7 +376,11 @@ fn updateSectionSizes(elf_file: *Elf) !void {
373376 }
374377
375378 if (elf_file.eh_frame_section_index) |index| {
376 slice.items(.shdr)[index].sh_size = try eh_frame.calcEhFrameSize(elf_file);
379 slice.items(.shdr)[index].sh_size = existing_size: {
380 const zo = elf_file.zigObjectPtr() orelse break :existing_size 0;
381 const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
382 break :existing_size sym.atom(elf_file).?.size;
383 } + try eh_frame.calcEhFrameSize(elf_file);
377384 }
378385 if (elf_file.eh_frame_rela_section_index) |index| {
379386 const shdr = &slice.items(.shdr)[index];
......@@ -526,17 +533,22 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
526533 }
527534
528535 if (elf_file.eh_frame_section_index) |shndx| {
536 const existing_size = existing_size: {
537 const zo = elf_file.zigObjectPtr() orelse break :existing_size 0;
538 const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
539 break :existing_size sym.atom(elf_file).?.size;
540 };
529541 const shdr = slice.items(.shdr)[shndx];
530542 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
531 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
543 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
532544 defer buffer.deinit();
533545 try eh_frame.writeEhFrameObject(elf_file, buffer.writer());
534546 log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{
535 shdr.sh_offset,
536 shdr.sh_offset + shdr.sh_size,
547 shdr.sh_offset + existing_size,
548 shdr.sh_offset + sh_size,
537549 });
538 assert(buffer.items.len == sh_size);
539 try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
550 assert(buffer.items.len == sh_size - existing_size);
551 try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset + existing_size);
540552 }
541553 if (elf_file.eh_frame_rela_section_index) |shndx| {
542554 const shdr = slice.items(.shdr)[shndx];
src/link/Elf/relocation.zig+17-10
......@@ -108,20 +108,27 @@ pub const dwarf = struct {
108108
109109 pub fn externalRelocType(
110110 target: Symbol,
111 source_section: Dwarf.Section.Index,
111112 address_size: Dwarf.AddressSize,
112113 cpu_arch: std.Target.Cpu.Arch,
113114 ) u32 {
114115 return switch (cpu_arch) {
115 .x86_64 => @intFromEnum(switch (address_size) {
116 .@"32" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF32 else .@"32",
117 .@"64" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF64 else .@"64",
118 else => unreachable,
119 }),
120 .riscv64 => @intFromEnum(switch (address_size) {
121 .@"32" => elf.R_RISCV.@"32",
122 .@"64" => elf.R_RISCV.@"64",
123 else => unreachable,
124 }),
116 .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (source_section) {
117 else => switch (address_size) {
118 .@"32" => if (target.flags.is_tls) .DTPOFF32 else .@"32",
119 .@"64" => if (target.flags.is_tls) .DTPOFF64 else .@"64",
120 else => unreachable,
121 },
122 .debug_frame => .PC32,
123 })),
124 .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) {
125 else => switch (address_size) {
126 .@"32" => .@"32",
127 .@"64" => .@"64",
128 else => unreachable,
129 },
130 .debug_frame => unreachable,
131 })),
125132 else => @panic("TODO unhandled cpu arch"),
126133 };
127134 }
src/link/MachO.zig+6-6
......@@ -3411,9 +3411,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
34113411
34123412 if (!sect.isZerofill()) {
34133413 const allocated_size = self.allocatedSize(sect.offset);
3414 if (sect.offset + allocated_size == std.math.maxInt(u64)) {
3415 try self.base.file.?.setEndPos(sect.offset + needed_size);
3416 } else if (needed_size > allocated_size) {
3414 if (needed_size > allocated_size) {
34173415 const existing_size = sect.size;
34183416 sect.size = 0;
34193417
......@@ -3431,6 +3429,8 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
34313429 try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);
34323430
34333431 sect.offset = @intCast(new_offset);
3432 } else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
3433 try self.base.file.?.setEndPos(sect.offset + needed_size);
34343434 }
34353435 seg.filesize = needed_size;
34363436 }
......@@ -3456,9 +3456,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
34563456
34573457 if (!sect.isZerofill()) {
34583458 const allocated_size = self.allocatedSize(sect.offset);
3459 if (sect.offset + allocated_size == std.math.maxInt(u64)) {
3460 try self.base.file.?.setEndPos(sect.offset + needed_size);
3461 } else if (needed_size > allocated_size) {
3459 if (needed_size > allocated_size) {
34623460 const existing_size = sect.size;
34633461 sect.size = 0;
34643462
......@@ -3480,6 +3478,8 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
34803478
34813479 sect.offset = @intCast(new_offset);
34823480 sect.addr = new_addr;
3481 } else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
3482 try self.base.file.?.setEndPos(sect.offset + needed_size);
34833483 }
34843484 }
34853485 sect.size = needed_size;
src/link/MachO/DebugSymbols.zig+3-3
......@@ -105,9 +105,7 @@ pub fn growSection(
105105 const sect = self.getSectionPtr(sect_index);
106106
107107 const allocated_size = self.allocatedSize(sect.offset);
108 if (sect.offset + allocated_size == std.math.maxInt(u64)) {
109 try self.file.setEndPos(sect.offset + needed_size);
110 } else if (needed_size > allocated_size) {
108 if (needed_size > allocated_size) {
111109 const existing_size = sect.size;
112110 sect.size = 0; // free the space
113111 const new_offset = try self.findFreeSpace(needed_size, 1);
......@@ -130,6 +128,8 @@ pub fn growSection(
130128 }
131129
132130 sect.offset = @intCast(new_offset);
131 } else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
132 try self.file.setEndPos(sect.offset + needed_size);
133133 }
134134
135135 sect.size = needed_size;