Skip to content

Commit f289b82

Browse files
committed
Dwarf: implement .eh_frame
1 parent 26d4fd5 commit f289b82

17 files changed

+1202
-274
lines changed

lib/std/leb128.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub const readILEB128 = readIleb128;
125125
pub 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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 112 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,6 +1491,46 @@ fn asmPseudo(self: *Self, ops: Mir.Inst.Ops) !void {
14911491
});
14921492
}
14931493

1494+
fn 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+
1504+
fn 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+
1514+
fn 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+
1524+
fn 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+
14941534
fn 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

19213-
fn 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-
1922119320
fn parseRegName(name: []const u8) ?Register {
1922219321
if (@hasDecl(Register, "parseRegName")) {
1922319322
return Register.parseRegName(name);

src/arch/x86_64/Emit.zig

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,21 @@ pub fn format(
220220
}
221221

222222
pub 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

0 commit comments

Comments
 (0)