diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2024-08-20 15:07:47 -0400 |
|---|---|---|
| committer | Jacob Young <jacobly0@users.noreply.github.com> | 2024-08-20 15:08:23 -0400 |
| commit | 55864e98e08c9d44ee2ea6fc1f3a3c2a98042310 (patch) | |
| tree | 78344089f8c4cc2bdc07ea74f0a47b8f500d2fcb /src | |
| parent | eaa227449c894a9205d63c2e963b967d13446591 (diff) | |
| download | zig-55864e98e08c9d44ee2ea6fc1f3a3c2a98042310.tar.gz zig-55864e98e08c9d44ee2ea6fc1f3a3c2a98042310.zip | |
x86_64: support more dwarf locations
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 312 | ||||
| -rw-r--r-- | src/arch/x86_64/Emit.zig | 157 | ||||
| -rw-r--r-- | src/arch/x86_64/Lower.zig | 75 | ||||
| -rw-r--r-- | src/arch/x86_64/Mir.zig | 49 | ||||
| -rw-r--r-- | src/arch/x86_64/bits.zig | 39 | ||||
| -rw-r--r-- | src/arch/x86_64/encoder.zig | 15 |
6 files changed, 374 insertions, 273 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 3f64d77aba..1fd231460e 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -64,8 +64,8 @@ va_info: union { sysv: struct { gp_count: u32, fp_count: u32, - overflow_arg_area: FrameAddr, - reg_save_area: FrameAddr, + overflow_arg_area: bits.FrameAddr, + reg_save_area: bits.FrameAddr, }, win64: struct {}, }, @@ -110,10 +110,6 @@ air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, const air_bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; -const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; -const RegisterOffset = struct { reg: Register, off: i32 = 0 }; -const SymbolOffset = struct { sym: u32, off: i32 = 0 }; - const Owner = union(enum) { nav_index: InternPool.Nav.Index, lazy_sym: link.File.LazySymbol, @@ -171,7 +167,7 @@ pub const MCValue = union(enum) { /// The value is split across two registers. register_pair: [2]Register, /// The value is a constant offset from the value in a register. - register_offset: RegisterOffset, + register_offset: bits.RegisterOffset, /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register. register_overflow: struct { reg: Register, eflags: Condition }, /// The value is in memory at a hard-coded address. @@ -179,11 +175,11 @@ pub const MCValue = union(enum) { memory: u64, /// The value is in memory at an address not-yet-allocated by the linker. /// This traditionally corresponds to a relocation emitted in a relocatable object file. - load_symbol: SymbolOffset, + load_symbol: bits.SymbolOffset, /// The address of the memory location not-yet-allocated by the linker. - lea_symbol: SymbolOffset, + lea_symbol: bits.SymbolOffset, /// The value is in memory at a constant offset from the address in a register. - indirect: RegisterOffset, + indirect: bits.RegisterOffset, /// The value is in memory. /// Payload is a symbol index. load_direct: u32, @@ -204,10 +200,10 @@ pub const MCValue = union(enum) { lea_tlv: u32, /// The value stored at an offset from a frame index /// Payload is a frame address. - load_frame: FrameAddr, + load_frame: bits.FrameAddr, /// The address of an offset from a frame index /// Payload is a frame address. - lea_frame: FrameAddr, + lea_frame: bits.FrameAddr, /// Supports integer_per_element abi elementwise_regs_then_frame: packed struct { regs: u3 = 0, frame_off: i29 = 0, frame_index: FrameIndex }, /// This indicates that we have already allocated a frame index for this instruction, @@ -423,10 +419,7 @@ pub const MCValue = union(enum) { .load_symbol => |sym_off| { assert(sym_off.off == 0); return .{ - .base = .{ .reloc = .{ - .atom_index = try function.owner.getSymbolIndex(function), - .sym_index = sym_off.sym, - } }, + .base = .{ .reloc = sym_off.sym_index }, .mod = .{ .rm = .{ .size = size, .disp = sym_off.off, @@ -453,8 +446,8 @@ pub const MCValue = union(enum) { .register_overflow => |pl| try writer.print("{s}:{s}", .{ @tagName(pl.eflags), @tagName(pl.reg), }), - .load_symbol => |pl| try writer.print("[{} + 0x{x}]", .{ pl.sym, pl.off }), - .lea_symbol => |pl| try writer.print("{} + 0x{x}", .{ pl.sym, pl.off }), + .load_symbol => |pl| try writer.print("[{} + 0x{x}]", .{ pl.sym_index, pl.off }), + .lea_symbol => |pl| try writer.print("{} + 0x{x}", .{ pl.sym_index, pl.off }), .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}), .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), @@ -921,6 +914,13 @@ pub fn generate( .link_mode = comp.config.link_mode, .pic = mod.pic, }, + .atom_index = function.owner.getSymbolIndex(&function) catch |err| switch (err) { + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ + .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), + }, + else => |e| return e, + }, .debug_output = debug_output, .code = code, .prev_di_pc = 0, @@ -1019,6 +1019,13 @@ pub fn generateLazy( .link_mode = comp.config.link_mode, .pic = mod.pic, }, + .atom_index = function.owner.getSymbolIndex(&function) catch |err| switch (err) { + error.CodegenFail => return Result{ .fail = function.err_msg.? }, + error.OutOfRegisters => return Result{ + .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), + }, + else => |e| return e, + }, .debug_output = debug_output, .code = code, .prev_di_pc = undefined, // no debug info yet @@ -1192,6 +1199,7 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { self.mir_extra.appendAssumeCapacity(switch (field.type) { u32 => @field(extra, field.name), i32, Mir.Memory.Info => @bitCast(@field(extra, field.name)), + bits.FrameIndex => @intFromEnum(@field(extra, field.name)), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), }); } @@ -1358,26 +1366,94 @@ fn asmAir(self: *Self, tag: MirTagAir, inst: Air.Inst.Index) !void { } fn asmAirImmediate(self: *Self, tag: MirTagAir, inst: Air.Inst.Index, imm: Immediate) !void { - const ops: Mir.Inst.Ops, const i: u32 = switch (imm) { - .signed => |s| .{ switch (tag) { - .dbg_local => .pseudo_dbg_local_ai_s, - }, @bitCast(s) }, - .unsigned => |u| if (math.cast(u32, u)) |small| - .{ switch (tag) { + switch (imm) { + .signed => |s| _ = try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_ai_s, + }, + .data = .{ .ai = .{ + .air_inst = inst, + .i = @bitCast(s), + } }, + }), + .unsigned => |u| _ = if (math.cast(u32, u)) |small| try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { .dbg_local => .pseudo_dbg_local_ai_u, - }, small } - else - .{ switch (tag) { + }, + .data = .{ .ai = .{ + .air_inst = inst, + .i = small, + } }, + }) else try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { .dbg_local => .pseudo_dbg_local_ai_64, - }, try self.addExtra(Mir.Imm64.encode(u)) }, - .reloc => unreachable, - }; + }, + .data = .{ .ai = .{ + .air_inst = inst, + .i = try self.addExtra(Mir.Imm64.encode(u)), + } }, + }), + .reloc => |sym_off| _ = if (sym_off.off == 0) try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_as, + }, + .data = .{ .as = .{ + .air_inst = inst, + .sym_index = sym_off.sym_index, + } }, + }) else try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_aso, + }, + .data = .{ .ax = .{ + .air_inst = inst, + .payload = try self.addExtra(sym_off), + } }, + }), + } +} + +fn asmAirRegisterImmediate( + self: *Self, + tag: MirTagAir, + inst: Air.Inst.Index, + reg: Register, + imm: Immediate, +) !void { _ = try self.addInst(.{ .tag = .pseudo, - .ops = ops, - .data = .{ .ai = .{ + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_aro, + }, + .data = .{ .rx = .{ + .r1 = reg, + .payload = try self.addExtra(Mir.AirOffset{ + .air_inst = inst, + .off = imm.signed, + }), + } }, + }); +} + +fn asmAirFrameAddress( + self: *Self, + tag: MirTagAir, + inst: Air.Inst.Index, + frame_addr: bits.FrameAddr, +) !void { + _ = try self.addInst(.{ + .tag = .pseudo, + .ops = switch (tag) { + .dbg_local => .pseudo_dbg_local_af, + }, + .data = .{ .ax = .{ .air_inst = inst, - .i = i, + .payload = try self.addExtra(frame_addr), } }, }); } @@ -1433,9 +1509,9 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void { .reloc => .rel, }, .data = switch (imm) { - .reloc => |x| reloc: { + .reloc => |sym_off| reloc: { assert(tag[0] == ._); - break :reloc .{ .reloc = x }; + break :reloc .{ .reloc = sym_off }; }, .signed, .unsigned => .{ .i = .{ .fixes = tag[0], @@ -2515,12 +2591,12 @@ fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayo }; } -fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) Alignment { +fn getFrameAddrAlignment(self: *Self, frame_addr: bits.FrameAddr) Alignment { const alloc_align = self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align; return @enumFromInt(@min(@intFromEnum(alloc_align), @ctz(frame_addr.off))); } -fn getFrameAddrSize(self: *Self, frame_addr: FrameAddr) u32 { +fn getFrameAddrSize(self: *Self, frame_addr: bits.FrameAddr) u32 { return self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_size - @as(u31, @intCast(frame_addr.off)); } @@ -11999,6 +12075,8 @@ fn genLocalDebugInfo( .none => try self.asmAir(.dbg_local, inst), .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable, .immediate => |imm| try self.asmAirImmediate(.dbg_local, inst, Immediate.u(imm)), + .lea_frame => |frame_addr| try self.asmAirFrameAddress(.dbg_local, inst, frame_addr), + .lea_symbol => |sym_off| try self.asmAirImmediate(.dbg_local, inst, Immediate.rel(sym_off)), else => { const ty = switch (tag) { else => unreachable, @@ -12027,14 +12105,14 @@ fn genLocalDebugInfo( } }, }), .lea_symbol => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{ - .base = .{ .reloc = .{ .atom_index = undefined, .sym_index = sym_off.sym } }, + .base = .{ .reloc = sym_off.sym_index }, .mod = .{ .rm = .{ .size = .qword, .disp = sym_off.off, } }, }), - .lea_direct, .lea_got, .lea_tlv => |sym| try self.asmAirMemory(.dbg_local, inst, .{ - .base = .{ .reloc = .{ .atom_index = undefined, .sym_index = sym } }, + .lea_direct, .lea_got, .lea_tlv => |sym_index| try self.asmAirMemory(.dbg_local, inst, .{ + .base = .{ .reloc = sym_index }, .mod = .{ .rm = .{ .size = .qword } }, }), }, @@ -12357,10 +12435,7 @@ fn genCall(self: *Self, info: union(enum) { if (self.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav); - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym_index, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym_index })); } else if (self.bin_file.cast(.coff)) |coff_file| { const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; @@ -12370,10 +12445,7 @@ fn genCall(self: *Self, info: union(enum) { const zo = macho_file.getZigObject().?; const sym_index = try zo.getOrCreateMetadataForNav(macho_file, func.owner_nav); const sym = zo.symbols.items[sym_index]; - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym.nlist_idx, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym.nlist_idx })); } else if (self.bin_file.cast(.plan9)) |p9| { const atom_index = try p9.seeNav(pt, func.owner_nav); const atom = p9.getAtom(atom_index); @@ -12391,19 +12463,13 @@ fn genCall(self: *Self, info: union(enum) { @"extern".name.toSlice(ip), @"extern".lib_name.toSlice(ip), ); - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = target_sym_index, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); } else if (self.bin_file.cast(.macho)) |macho_file| { const target_sym_index = try macho_file.getGlobalSymbol( @"extern".name.toSlice(ip), @"extern".lib_name.toSlice(ip), ); - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = target_sym_index, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); } else try self.genExternSymbolRef( .call, @"extern".lib_name.toSlice(ip), @@ -12418,16 +12484,10 @@ fn genCall(self: *Self, info: union(enum) { }, .lib => |lib| if (self.bin_file.cast(.elf)) |elf_file| { const target_sym_index = try elf_file.getGlobalSymbol(lib.callee, lib.lib); - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = target_sym_index, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); } else if (self.bin_file.cast(.macho)) |macho_file| { const target_sym_index = try macho_file.getGlobalSymbol(lib.callee, lib.lib); - try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = target_sym_index, - })); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = target_sym_index })); } else try self.genExternSymbolRef(.call, lib.lib, lib.callee), } return call_info.return_value.short; @@ -14968,10 +15028,7 @@ fn genSetReg( .general_purpose => { assert(sym_off.off == 0); try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(dst_reg, abi_size), .{ - .base = .{ .reloc = .{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym_off.sym, - } }, + .base = .{ .reloc = sym_off.sym_index }, .mod = .{ .rm = .{ .size = self.memSize(ty), .disp = sym_off.off, @@ -14989,10 +15046,7 @@ fn genSetReg( .ops = .direct_reloc, .data = .{ .rx = .{ .r1 = registerAlias(dst_reg, abi_size), - .payload = try self.addExtra(bits.Symbol{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym_index, - }), + .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }), } }, }); return; @@ -15017,52 +15071,38 @@ fn genSetReg( }, ); }, - .lea_symbol => |sym_index| { - const atom_index = try self.owner.getSymbolIndex(self); - switch (self.bin_file.tag) { - .elf, .macho => { - try self.asmRegisterMemory( - .{ ._, .lea }, - dst_reg.to64(), - .{ - .base = .{ .reloc = .{ - .atom_index = atom_index, - .sym_index = sym_index.sym, - } }, - .mod = .{ .rm = .{ - .size = .qword, - .disp = sym_index.off, - } }, - }, - ); - }, - else => return self.fail("TODO emit symbol sequence on {s}", .{ - @tagName(self.bin_file.tag), - }), - } - }, - .lea_direct, .lea_got => |sym_index| { - const atom_index = try self.owner.getSymbolIndex(self); - _ = try self.addInst(.{ - .tag = switch (src_mcv) { - .lea_direct => .lea, - .lea_got => .mov, - else => unreachable, - }, - .ops = switch (src_mcv) { - .lea_direct => .direct_reloc, - .lea_got => .got_reloc, - else => unreachable, + .lea_symbol => |sym_off| switch (self.bin_file.tag) { + .elf, .macho => try self.asmRegisterMemory( + .{ ._, .lea }, + dst_reg.to64(), + .{ + .base = .{ .reloc = sym_off.sym_index }, + .mod = .{ .rm = .{ + .size = .qword, + .disp = sym_off.off, + } }, }, - .data = .{ .rx = .{ - .r1 = dst_reg.to64(), - .payload = try self.addExtra(bits.Symbol{ - .atom_index = atom_index, - .sym_index = sym_index, - }), - } }, - }); + ), + else => return self.fail("TODO emit symbol sequence on {s}", .{ + @tagName(self.bin_file.tag), + }), }, + .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{ + .tag = switch (src_mcv) { + .lea_direct => .lea, + .lea_got => .mov, + else => unreachable, + }, + .ops = switch (src_mcv) { + .lea_direct => .direct_reloc, + .lea_got => .got_reloc, + else => unreachable, + }, + .data = .{ .rx = .{ + .r1 = dst_reg.to64(), + .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }), + } }, + }), .lea_tlv => unreachable, // TODO: remove this .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref), opts), } @@ -15083,7 +15123,7 @@ fn genSetMem( .none => .{ .immediate = @bitCast(@as(i64, disp)) }, .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } }, .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } }, - .reloc => |base_symbol| .{ .lea_symbol = .{ .sym = base_symbol.sym_index, .off = disp } }, + .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } }, }; switch (src_mcv) { .none, @@ -15326,7 +15366,6 @@ fn genExternSymbolRef( lib: ?[]const u8, callee: []const u8, ) InnerError!void { - const atom_index = try self.owner.getSymbolIndex(self); if (self.bin_file.cast(.coff)) |coff_file| { const global_index = try coff_file.getGlobalSymbol(callee, lib); _ = try self.addInst(.{ @@ -15334,8 +15373,7 @@ fn genExternSymbolRef( .ops = .import_reloc, .data = .{ .rx = .{ .r1 = .rax, - .payload = try self.addExtra(bits.Symbol{ - .atom_index = atom_index, + .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = link.File.Coff.global_symbol_bit | global_index, }), } }, @@ -15362,10 +15400,10 @@ fn genLazySymbolRef( if (self.mod.pic) { switch (tag) { .lea, .call => try self.genSetReg(reg, Type.usize, .{ - .lea_symbol = .{ .sym = sym_index }, + .lea_symbol = .{ .sym_index = sym_index }, }, .{}), .mov => try self.genSetReg(reg, Type.usize, .{ - .load_symbol = .{ .sym = sym_index }, + .load_symbol = .{ .sym_index = sym_index }, }, .{}), else => unreachable, } @@ -15374,19 +15412,13 @@ fn genLazySymbolRef( .call => try self.asmRegister(.{ ._, .call }, reg), else => unreachable, } - } else { - const reloc = bits.Symbol{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym_index, - }; - switch (tag) { - .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{ - .base = .{ .reloc = reloc }, - .mod = .{ .rm = .{ .size = .qword } }, - }), - .call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(reloc)), - else => unreachable, - } + } else switch (tag) { + .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{ + .base = .{ .reloc = sym_index }, + .mod = .{ .rm = .{ .size = .qword } }, + }), + .call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ .sym_index = sym_index })), + else => unreachable, } } else if (self.bin_file.cast(.plan9)) |p9_file| { const atom_index = p9_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| @@ -15436,10 +15468,10 @@ fn genLazySymbolRef( const sym = zo.symbols.items[sym_index]; switch (tag) { .lea, .call => try self.genSetReg(reg, Type.usize, .{ - .lea_symbol = .{ .sym = sym.nlist_idx }, + .lea_symbol = .{ .sym_index = sym.nlist_idx }, }, .{}), .mov => try self.genSetReg(reg, Type.usize, .{ - .load_symbol = .{ .sym = sym.nlist_idx }, + .load_symbol = .{ .sym_index = sym.nlist_idx }, }, .{}), else => unreachable, } @@ -18784,7 +18816,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { .{ .frame = frame_index }, 0, Type.usize, - .{ .lea_symbol = .{ .sym = tlv_sym } }, + .{ .lea_symbol = .{ .sym_index = tlv_sym } }, .{}, ); break :init .{ .load_frame = .{ .index = frame_index } }; @@ -18840,8 +18872,8 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue { .undef => .undef, .immediate => |imm| .{ .immediate = imm }, .memory => |addr| .{ .memory = addr }, - .load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } }, - .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } }, + .load_symbol => |sym_index| .{ .load_symbol = .{ .sym_index = sym_index } }, + .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index } }, .load_direct => |sym_index| .{ .load_direct = sym_index }, .lea_direct => |sym_index| .{ .lea_direct = sym_index }, .load_got => |sym_index| .{ .lea_got = sym_index }, diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index afbc4912bc..579fd00d9d 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -2,6 +2,7 @@ air: Air, lower: Lower, +atom_index: u32, debug_output: DebugInfoOutput, code: *std.ArrayList(u8), @@ -37,83 +38,84 @@ pub fn emitMir(emit: *Emit) Error!void { }) switch (lowered_relocs[0].target) { .inst => |target| try emit.relocs.append(emit.lower.allocator, .{ .source = start_offset, + .source_offset = end_offset - 4, .target = target, - .offset = end_offset - 4, + .target_offset = lowered_relocs[0].off, .length = @intCast(end_offset - start_offset), }), - .linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(.elf)) |elf_file| { + .linker_extern_fn => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| { // Add relocation to the decl. const zo = elf_file.zigObjectPtr().?; - const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?; + const atom_ptr = zo.symbol(emit.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.PLT32); try atom_ptr.addReloc(elf_file, .{ .r_offset = end_offset - 4, - .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type, - .r_addend = -4, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, + .r_addend = lowered_relocs[0].off - 4, }); } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { // Add relocation to the decl. const zo = macho_file.getZigObject().?; - const atom = zo.symbols.items[symbol.atom_index].getAtom(macho_file).?; + const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; try atom.addReloc(macho_file, .{ .tag = .@"extern", .offset = end_offset - 4, - .target = symbol.sym_index, - .addend = 0, + .target = sym_index, + .addend = lowered_relocs[0].off, .type = .branch, .meta = .{ .pcrel = true, .has_subtractor = false, .length = 2, - .symbolnum = @intCast(symbol.sym_index), + .symbolnum = @intCast(sym_index), }, }); } else if (emit.lower.bin_file.cast(.coff)) |coff_file| { // Add relocation to the decl. const atom_index = coff_file.getAtomIndexForSymbol( - .{ .sym_index = symbol.atom_index, .file = null }, + .{ .sym_index = emit.atom_index, .file = null }, ).?; - const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0) - coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index) + const target = if (link.File.Coff.global_symbol_bit & sym_index != 0) + coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index) else - link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null }; + link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null }; try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ .type = .direct, .target = target, .offset = end_offset - 4, - .addend = 0, + .addend = @intCast(lowered_relocs[0].off), .pcrel = true, .length = 2, }); } else return emit.fail("TODO implement extern reloc for {s}", .{ @tagName(emit.lower.bin_file.tag), }), - .linker_tlsld => |data| { + .linker_tlsld => |sym_index| { const elf_file = emit.lower.bin_file.cast(.elf).?; const zo = elf_file.zigObjectPtr().?; - const atom = zo.symbol(data.atom_index).atom(elf_file).?; + const atom = zo.symbol(emit.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD); try atom.addReloc(elf_file, .{ .r_offset = end_offset - 4, - .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, - .r_addend = -4, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, + .r_addend = lowered_relocs[0].off - 4, }); }, - .linker_dtpoff => |data| { + .linker_dtpoff => |sym_index| { const elf_file = emit.lower.bin_file.cast(.elf).?; const zo = elf_file.zigObjectPtr().?; - const atom = zo.symbol(data.atom_index).atom(elf_file).?; + const atom = zo.symbol(emit.atom_index).atom(elf_file).?; const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32); try atom.addReloc(elf_file, .{ .r_offset = end_offset - 4, - .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, - .r_addend = 0, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, + .r_addend = lowered_relocs[0].off, }); }, - .linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| { + .linker_reloc => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; - const atom = zo.symbol(data.atom_index).atom(elf_file).?; - const sym = zo.symbol(data.sym_index); + const atom = zo.symbol(emit.atom_index).atom(elf_file).?; + const sym = zo.symbol(sym_index); if (emit.lower.pic) { const r_type: u32 = if (sym.flags.is_extern_ptr) @intFromEnum(std.elf.R_X86_64.GOTPCREL) @@ -121,8 +123,8 @@ pub fn emitMir(emit: *Emit) Error!void { @intFromEnum(std.elf.R_X86_64.PC32); try atom.addReloc(elf_file, .{ .r_offset = end_offset - 4, - .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, - .r_addend = -4, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, + .r_addend = lowered_relocs[0].off - 4, }); } else { const r_type: u32 = if (sym.flags.is_tls) @@ -131,14 +133,14 @@ pub fn emitMir(emit: *Emit) Error!void { @intFromEnum(std.elf.R_X86_64.@"32"); try atom.addReloc(elf_file, .{ .r_offset = end_offset - 4, - .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type, - .r_addend = 0, + .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type, + .r_addend = lowered_relocs[0].off, }); } } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { const zo = macho_file.getZigObject().?; - const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?; - const sym = &zo.symbols.items[data.sym_index]; + const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; + const sym = &zo.symbols.items[sym_index]; const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr) .got_load else if (sym.flags.tlv) @@ -148,33 +150,33 @@ pub fn emitMir(emit: *Emit) Error!void { try atom.addReloc(macho_file, .{ .tag = .@"extern", .offset = @intCast(end_offset - 4), - .target = data.sym_index, - .addend = 0, + .target = sym_index, + .addend = lowered_relocs[0].off, .type = @"type", .meta = .{ .pcrel = true, .has_subtractor = false, .length = 2, - .symbolnum = @intCast(data.sym_index), + .symbolnum = @intCast(sym_index), }, }); } else unreachable, .linker_got, .linker_direct, .linker_import, - => |symbol| if (emit.lower.bin_file.cast(.elf)) |_| { + => |sym_index| if (emit.lower.bin_file.cast(.elf)) |_| { unreachable; } else if (emit.lower.bin_file.cast(.macho)) |_| { unreachable; } else if (emit.lower.bin_file.cast(.coff)) |coff_file| { const atom_index = coff_file.getAtomIndexForSymbol(.{ - .sym_index = symbol.atom_index, + .sym_index = emit.atom_index, .file = null, }).?; - const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0) - coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index) + const target = if (link.File.Coff.global_symbol_bit & sym_index != 0) + coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index) else - link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null }; + link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null }; try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ .type = switch (lowered_relocs[0].target) { .linker_got => .got, @@ -184,16 +186,15 @@ pub fn emitMir(emit: *Emit) Error!void { }, .target = target, .offset = @intCast(end_offset - 4), - .addend = 0, + .addend = @intCast(lowered_relocs[0].off), .pcrel = true, .length = 2, }); } else if (emit.lower.bin_file.cast(.plan9)) |p9_file| { - const atom_index = symbol.atom_index; - try p9_file.addReloc(atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct - .target = symbol.sym_index, // we set sym_index to just be the atom index + try p9_file.addReloc(emit.atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct + .target = sym_index, // we set sym_index to just be the atom index .offset = @intCast(end_offset - 4), - .addend = 0, + .addend = @intCast(lowered_relocs[0].off), .type = .pcrel, }); } else return emit.fail("TODO implement linker reloc for {s}", .{ @@ -261,6 +262,10 @@ pub fn emitMir(emit: *Emit) Error!void { .pseudo_dbg_local_ai_s, .pseudo_dbg_local_ai_u, .pseudo_dbg_local_ai_64, + .pseudo_dbg_local_as, + .pseudo_dbg_local_aso, + .pseudo_dbg_local_aro, + .pseudo_dbg_local_af, .pseudo_dbg_local_am, => { switch (emit.debug_output) { @@ -279,6 +284,57 @@ pub fn emitMir(emit: *Emit) Error!void { }; break :stack_value &loc_buf[0]; } } }, + .pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{ .addr = .{ + .sym = mir_inst.data.as.sym_index, + } } }, + .pseudo_dbg_local_aso => loc: { + const sym_off = emit.lower.mir.extraData( + bits.SymbolOffset, + mir_inst.data.ax.payload, + ).data; + break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ + sym: { + loc_buf[0] = .{ .addr = .{ .sym = sym_off.sym_index } }; + break :sym &loc_buf[0]; + }, + off: { + loc_buf[1] = .{ .consts = sym_off.off }; + break :off &loc_buf[1]; + }, + } } }; + }, + .pseudo_dbg_local_aro => loc: { + const air_off = emit.lower.mir.extraData( + Mir.AirOffset, + mir_inst.data.rx.payload, + ).data; + break :loc .{ air_off.air_inst, .{ .plus = .{ + reg: { + loc_buf[0] = .{ .breg = mir_inst.data.rx.r1.dwarfNum() }; + break :reg &loc_buf[0]; + }, + off: { + loc_buf[1] = .{ .consts = air_off.off }; + break :off &loc_buf[1]; + }, + } } }; + }, + .pseudo_dbg_local_af => loc: { + const reg_off = emit.lower.mir.resolveFrameAddr(emit.lower.mir.extraData( + bits.FrameAddr, + mir_inst.data.ax.payload, + ).data); + break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ + reg: { + loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() }; + break :reg &loc_buf[0]; + }, + off: { + loc_buf[1] = .{ .consts = reg_off.off }; + break :off &loc_buf[1]; + }, + } } }; + }, .pseudo_dbg_local_am => loc: { const mem = emit.lower.mem(mir_inst.data.ax.payload); break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ @@ -287,7 +343,7 @@ pub fn emitMir(emit: *Emit) Error!void { .none => .{ .constu = 0 }, .reg => |reg| .{ .breg = reg.dwarfNum() }, .frame => unreachable, - .reloc => |reloc| .{ .addr = .{ .sym = reloc.sym_index } }, + .reloc => |sym_index| .{ .addr = .{ .sym = sym_index } }, }; break :base &loc_buf[0]; }, @@ -352,10 +408,12 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error { const Reloc = struct { /// Offset of the instruction. source: usize, + /// Offset of the relocation within the instruction. + source_offset: u32, /// Target of the relocation. target: Mir.Inst.Index, - /// Offset of the relocation within the instruction. - offset: u32, + /// Offset from the target instruction. + target_offset: i32, /// Length of the instruction. length: u5, }; @@ -368,8 +426,8 @@ fn fixupRelocs(emit: *Emit) Error!void { for (emit.relocs.items) |reloc| { const target = emit.code_offset_mapping.get(reloc.target) orelse return emit.fail("JMP/CALL relocation target not found!", .{}); - const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length)); - std.mem.writeInt(i32, emit.code.items[reloc.offset..][0..4], @intCast(disp), .little); + const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.source + reloc.length)) + reloc.target_offset; + std.mem.writeInt(i32, emit.code.items[reloc.source_offset..][0..4], @intCast(disp), .little); } } @@ -422,6 +480,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { } } +const bits = @import("bits.zig"); const link = @import("../../link.zig"); const log = std.log.scoped(.emit); const std = @import("std"); diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index 860f42d566..e46160c319 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -52,16 +52,17 @@ pub const Error = error{ pub const Reloc = struct { lowered_inst_index: u8, target: Target, + off: i32, const Target = union(enum) { inst: Mir.Inst.Index, - linker_reloc: bits.Symbol, - linker_tlsld: bits.Symbol, - linker_dtpoff: bits.Symbol, - linker_extern_fn: bits.Symbol, - linker_got: bits.Symbol, - linker_direct: bits.Symbol, - linker_import: bits.Symbol, + linker_reloc: u32, + linker_tlsld: u32, + linker_dtpoff: u32, + linker_extern_fn: u32, + linker_got: u32, + linker_direct: u32, + linker_import: u32, }; }; @@ -173,19 +174,19 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo_j_z_and_np_inst => { assert(inst.data.inst.fixes == ._); try lower.emit(.none, .jnz, &.{ - .{ .imm = lower.reloc(.{ .inst = index + 1 }) }, + .{ .imm = lower.reloc(.{ .inst = index + 1 }, 0) }, }); try lower.emit(.none, .jnp, &.{ - .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) }, + .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) }, }); }, .pseudo_j_nz_or_p_inst => { assert(inst.data.inst.fixes == ._); try lower.emit(.none, .jnz, &.{ - .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) }, + .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) }, }); try lower.emit(.none, .jp, &.{ - .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) }, + .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) }, }); }, @@ -195,7 +196,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .{ .imm = Immediate.s(@bitCast(inst.data.ri.i)) }, }); try lower.emit(.none, .jz, &.{ - .{ .imm = lower.reloc(.{ .inst = index + 1 }) }, + .{ .imm = lower.reloc(.{ .inst = index + 1 }, 0) }, }); try lower.emit(.none, .lea, &.{ .{ .reg = inst.data.ri.r1 }, @@ -211,7 +212,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .{ .reg = inst.data.ri.r1.to32() }, }); try lower.emit(.none, .jmp, &.{ - .{ .imm = lower.reloc(.{ .inst = index }) }, + .{ .imm = lower.reloc(.{ .inst = index }, 0) }, }); assert(lower.result_insts_len == pseudo_probe_align_insts); }, @@ -257,7 +258,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .{ .imm = Immediate.s(page_size) }, }); try lower.emit(.none, .jae, &.{ - .{ .imm = lower.reloc(.{ .inst = index }) }, + .{ .imm = lower.reloc(.{ .inst = index }, 0) }, }); assert(lower.result_insts_len == pseudo_probe_adjust_loop_insts); }, @@ -273,6 +274,10 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo_dbg_local_ai_s, .pseudo_dbg_local_ai_u, .pseudo_dbg_local_ai_64, + .pseudo_dbg_local_as, + .pseudo_dbg_local_aso, + .pseudo_dbg_local_aro, + .pseudo_dbg_local_af, .pseudo_dbg_local_am, .pseudo_dead_none, => {}, @@ -328,10 +333,11 @@ pub fn mem(lower: Lower, payload: u32) Memory { return lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode(); } -fn reloc(lower: *Lower, target: Reloc.Target) Immediate { +fn reloc(lower: *Lower, target: Reloc.Target, off: i32) Immediate { lower.result_relocs[lower.result_relocs_len] = .{ .lowered_inst_index = lower.result_insts_len, .target = target, + .off = off, }; lower.result_relocs_len += 1; return Immediate.s(0); @@ -347,37 +353,36 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) else => op, .mem => |mem_op| switch (mem_op.base()) { else => op, - .reloc => |sym| op: { + .reloc => |sym_index| op: { assert(prefix == .none); assert(mem_op.sib.disp == 0); assert(mem_op.sib.scale_index.scale == 0); if (lower.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; - const elf_sym = zo.symbol(sym.sym_index); + const elf_sym = zo.symbol(sym_index); if (elf_sym.flags.is_tls) { // TODO handle extern TLS vars, i.e., emit GD model if (lower.pic) { // Here, we currently assume local dynamic TLS vars, and so // we emit LD model. - _ = lower.reloc(.{ .linker_tlsld = sym }); + _ = lower.reloc(.{ .linker_tlsld = sym_index }, 0); lower.result_insts[lower.result_insts_len] = try Instruction.new(.none, .lea, &[_]Operand{ .{ .reg = .rdi }, .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }, }); lower.result_insts_len += 1; - _ = lower.reloc(.{ .linker_extern_fn = .{ - .atom_index = sym.atom_index, - .sym_index = try elf_file.getGlobalSymbol("__tls_get_addr", null), - } }); + _ = lower.reloc(.{ + .linker_extern_fn = try elf_file.getGlobalSymbol("__tls_get_addr", null), + }, 0); lower.result_insts[lower.result_insts_len] = try Instruction.new(.none, .call, &[_]Operand{ .{ .imm = Immediate.s(0) }, }); lower.result_insts_len += 1; - _ = lower.reloc(.{ .linker_dtpoff = sym }); + _ = lower.reloc(.{ .linker_dtpoff = sym_index }, 0); emit_mnemonic = .lea; break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ .reg = .rax }, @@ -391,7 +396,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) }, }); lower.result_insts_len += 1; - _ = lower.reloc(.{ .linker_reloc = sym }); + _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); emit_mnemonic = .lea; break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ .reg = .rax }, @@ -400,7 +405,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) } } - _ = lower.reloc(.{ .linker_reloc = sym }); + _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); if (lower.pic) switch (mnemonic) { .lea => { if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov; @@ -437,10 +442,10 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) } } else if (lower.bin_file.cast(.macho)) |macho_file| { const zo = macho_file.getZigObject().?; - const macho_sym = zo.symbols.items[sym.sym_index]; + const macho_sym = zo.symbols.items[sym_index]; if (macho_sym.flags.tlv) { - _ = lower.reloc(.{ .linker_reloc = sym }); + _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); lower.result_insts[lower.result_insts_len] = try Instruction.new(.none, .mov, &[_]Operand{ .{ .reg = .rdi }, @@ -456,7 +461,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) break :op .{ .reg = .rax }; } - _ = lower.reloc(.{ .linker_reloc = sym }); + _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); break :op switch (mnemonic) { .lea => { if (macho_sym.flags.is_extern_ptr) emit_mnemonic = .mov; @@ -535,7 +540,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { }, switch (inst.ops) { .none => &.{}, .inst => &.{ - .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) }, + .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }, 0) }, }, .i_s, .i_u => &.{ .{ .imm = lower.imm(inst.ops, inst.data.i.i) }, @@ -637,17 +642,17 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) }, }, .extern_fn_reloc, .rel => &.{ - .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) }, + .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc.sym_index }, inst.data.reloc.off) }, }, .got_reloc, .direct_reloc, .import_reloc => ops: { const reg = inst.data.rx.r1; - const extra = lower.mir.extraData(bits.Symbol, inst.data.rx.payload).data; + const extra = lower.mir.extraData(bits.SymbolOffset, inst.data.rx.payload).data; _ = lower.reloc(switch (inst.ops) { - .got_reloc => .{ .linker_got = extra }, - .direct_reloc => .{ .linker_direct = extra }, - .import_reloc => .{ .linker_import = extra }, + .got_reloc => .{ .linker_got = extra.sym_index }, + .direct_reloc => .{ .linker_direct = extra.sym_index }, + .import_reloc => .{ .linker_import = extra.sym_index }, else => unreachable, - }); + }, extra.off); break :ops &.{ .{ .reg = reg }, .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) }, diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 534c9c31f6..3992594b1b 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -820,16 +820,16 @@ pub const Inst = struct { /// Uses `reloc` payload. extern_fn_reloc, /// Linker relocation - GOT indirection. - /// Uses `rx` payload with extra data of type `bits.Symbol`. + /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. got_reloc, /// Linker relocation - direct reference. - /// Uses `rx` payload with extra data of type `bits.Symbol`. + /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. direct_reloc, /// Linker relocation - imports table indirection (binding). - /// Uses `rx` payload with extra data of type `bits.Symbol`. + /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. import_reloc, /// Linker relocation - threadlocal variable via GOT indirection. - /// Uses `rx` payload with extra data of type `bits.Symbol`. + /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. tlv_reloc, // Pseudo instructions: @@ -907,9 +907,21 @@ pub const Inst = struct { /// Uses `ai` payload. pseudo_dbg_local_ai_u, /// Local argument or variable. - /// Uses `ax` payload with extra data of type `Imm64`. + /// Uses `ai` payload with extra data of type `Imm64`. pseudo_dbg_local_ai_64, /// Local argument or variable. + /// Uses `as` payload. + pseudo_dbg_local_as, + /// Local argument or variable. + /// Uses `ax` payload with extra data of type `bits.SymbolOffset`. + pseudo_dbg_local_aso, + /// Local argument or variable. + /// Uses `rx` payload with extra data of type `AirOffset`. + pseudo_dbg_local_aro, + /// Local argument or variable. + /// Uses `ax` payload with extra data of type `bits.FrameAddr`. + pseudo_dbg_local_af, + /// Local argument or variable. /// Uses `ax` payload with extra data of type `Memory`. pseudo_dbg_local_am, @@ -1014,6 +1026,9 @@ pub const Inst = struct { fixes: Fixes = ._, payload: u32, }, + ix: struct { + payload: u32, + }, a: struct { air_inst: Air.Inst.Index, }, @@ -1021,14 +1036,18 @@ pub const Inst = struct { air_inst: Air.Inst.Index, i: u32, }, + as: struct { + air_inst: Air.Inst.Index, + sym_index: u32, + }, ax: struct { air_inst: Air.Inst.Index, payload: u32, }, /// Relocation for the linker where: - /// * `atom_index` is the index of the source /// * `sym_index` is the index of the target - reloc: bits.Symbol, + /// * `off` is the offset from the target + reloc: bits.SymbolOffset, /// Debug line and column position line_column: struct { line: u32, @@ -1048,6 +1067,8 @@ pub const Inst = struct { } }; +pub const AirOffset = struct { air_inst: Air.Inst.Index, off: i32 }; + /// Used in conjunction with payload to transfer a list of used registers in a compact manner. pub const RegisterList = struct { bitset: BitSet = BitSet.initEmpty(), @@ -1146,15 +1167,13 @@ pub const Memory = struct { .none => undefined, .reg => |reg| @intFromEnum(reg), .frame => |frame_index| @intFromEnum(frame_index), - .reloc => |symbol| symbol.sym_index, + .reloc => |sym_index| sym_index, }, .off = switch (mem.mod) { .rm => |rm| @bitCast(rm.disp), .off => |off| @truncate(off), }, - .extra = if (mem.base == .reloc) - mem.base.reloc.atom_index - else if (mem.mod == .off) + .extra = if (mem.mod == .off) @intCast(mem.mod.off >> 32) else undefined, @@ -1174,7 +1193,7 @@ pub const Memory = struct { .none => .none, .reg => .{ .reg = @enumFromInt(mem.base) }, .frame => .{ .frame = @enumFromInt(mem.base) }, - .reloc => .{ .reloc = .{ .atom_index = mem.extra, .sym_index = mem.base } }, + .reloc => .{ .reloc = mem.base }, }, .scale_index = switch (mem.info.index) { .none => null, @@ -1214,6 +1233,7 @@ pub fn extraData(mir: Mir, comptime T: type, index: u32) struct { data: T, end: @field(result, field.name) = switch (field.type) { u32 => mir.extra[i], i32, Memory.Info => @bitCast(mir.extra[i]), + bits.FrameIndex, Air.Inst.Index => @enumFromInt(mir.extra[i]), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), }; i += 1; @@ -1229,6 +1249,11 @@ pub const FrameLoc = struct { disp: i32, }; +pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffset { + const frame_loc = mir.frame_locs.get(@intFromEnum(frame_addr.index)); + return .{ .reg = frame_loc.base, .off = frame_loc.disp + frame_addr.off }; +} + pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory { return switch (mem.info.base) { .none, .reg, .reloc => mem, diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index 56b5fcc5d4..839084456a 100644 --- a/src/arch/x86_64/bits.zig +++ b/src/arch/x86_64/bits.zig @@ -447,26 +447,11 @@ pub const FrameIndex = enum(u32) { } }; -/// A linker symbol not yet allocated in VM. -pub const Symbol = struct { - /// Index of the containing atom. - atom_index: u32, - /// Index into the linker's symbol table. - sym_index: u32, +pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; - pub fn format( - sym: Symbol, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try writer.writeAll("Symbol("); - try std.fmt.formatType(sym.atom_index, fmt, options, writer, 0); - try writer.writeAll(", "); - try std.fmt.formatType(sym.sym_index, fmt, options, writer, 0); - try writer.writeByte(')'); - } -}; +pub const RegisterOffset = struct { reg: Register, off: i32 = 0 }; + +pub const SymbolOffset = struct { sym_index: u32, off: i32 = 0 }; pub const Memory = struct { base: Base, @@ -476,7 +461,7 @@ pub const Memory = struct { none, reg: Register, frame: FrameIndex, - reloc: Symbol, + reloc: u32, pub const Tag = @typeInfo(Base).Union.tag_type.?; @@ -568,7 +553,7 @@ pub const Memory = struct { pub const Immediate = union(enum) { signed: i32, unsigned: u64, - reloc: Symbol, + reloc: SymbolOffset, pub fn u(x: u64) Immediate { return .{ .unsigned = x }; @@ -578,19 +563,19 @@ pub const Immediate = union(enum) { return .{ .signed = x }; } - pub fn rel(symbol: Symbol) Immediate { - return .{ .reloc = symbol }; + pub fn rel(sym_off: SymbolOffset) Immediate { + return .{ .reloc = sym_off }; } pub fn format( imm: Immediate, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, + comptime _: []const u8, + _: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { switch (imm) { - .reloc => |x| try std.fmt.formatType(x, fmt, options, writer, 0), - inline else => |x| try writer.print("{d}", .{x}), + inline else => |int| try writer.print("{d}", .{int}), + .reloc => |sym_off| try writer.print("Symbol({[sym_index]d}) + {[off]d}", sym_off), } } }; diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index b58a191473..ce5b9c4d0f 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -266,17 +266,12 @@ pub const Instruction = struct { try writer.writeByte('['); - var any = false; + var any = true; switch (sib.base) { - .none => {}, - .reg => |reg| { - try writer.print("{s}", .{@tagName(reg)}); - any = true; - }, - inline .frame, .reloc => |payload| { - try writer.print("{}", .{payload}); - any = true; - }, + .none => any = false, + .reg => |reg| try writer.print("{s}", .{@tagName(reg)}), + .frame => |frame_index| try writer.print("{}", .{frame_index}), + .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}), } if (mem.scaleIndex()) |si| { if (any) try writer.writeAll(" + "); |
