mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
x86_64: support more dwarf locations
This commit is contained in:
parent
eaa227449c
commit
55864e98e0
@ -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,
|
||||
} },
|
||||
},
|
||||
);
|
||||
.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,
|
||||
} },
|
||||
},
|
||||
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,
|
||||
},
|
||||
.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 },
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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) },
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -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(" + ");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user