Commit a6a10d9c2b
Changed files (11)
src
arch
aarch64
arm
riscv64
sparc64
src/arch/aarch64/CodeGen.zig
@@ -4012,7 +4012,6 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
.got => .load_memory_ptr_got,
.direct => .load_memory_ptr_direct,
.import => unreachable,
- .extern_got => unreachable,
};
const atom_index = switch (self.bin_file.tag) {
.macho => blk: {
@@ -5532,7 +5531,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
.got => .load_memory_ptr_got,
.direct => .load_memory_ptr_direct,
.import => unreachable,
- .extern_got => unreachable,
};
const atom_index = switch (self.bin_file.tag) {
.macho => blk: {
@@ -5654,7 +5652,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.got => .load_memory_got,
.direct => .load_memory_direct,
.import => .load_memory_import,
- .extern_got => unreachable,
};
const atom_index = switch (self.bin_file.tag) {
.macho => blk: {
@@ -5852,7 +5849,6 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
.got => .load_memory_ptr_got,
.direct => .load_memory_ptr_direct,
.import => unreachable,
- .extern_got => unreachable,
};
const atom_index = switch (self.bin_file.tag) {
.macho => blk: {
@@ -6180,7 +6176,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
.memory => |addr| .{ .memory = addr },
.load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },
.load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },
- .load_extern_got, .load_tlv => unreachable, // TODO
+ .load_memory, .lea_memory, .load_tlv => unreachable, // TODO
},
.fail => |msg| {
self.err_msg = msg;
src/arch/arm/CodeGen.zig
@@ -6135,7 +6135,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
.mcv => |mcv| switch (mcv) {
.none => .none,
.undef => .undef,
- .load_got, .load_extern_got, .load_direct, .load_tlv => unreachable, // TODO
+ .load_got, .load_memory, .lea_memory, .load_direct, .load_tlv => unreachable, // TODO
.immediate => |imm| .{ .immediate = @as(u32, @truncate(imm)) },
.memory => |addr| .{ .memory = addr },
},
src/arch/riscv64/CodeGen.zig
@@ -2591,7 +2591,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
.mcv => |mcv| switch (mcv) {
.none => .none,
.undef => .undef,
- .load_got, .load_extern_got, .load_direct, .load_tlv => unreachable, // TODO
+ .load_got, .load_memory, .lea_memory, .load_direct, .load_tlv => unreachable, // TODO
.immediate => |imm| .{ .immediate = imm },
.memory => |addr| .{ .memory = addr },
},
src/arch/sparc64/CodeGen.zig
@@ -4137,7 +4137,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
.mcv => |mcv| switch (mcv) {
.none => .none,
.undef => .undef,
- .load_got, .load_extern_got, .load_direct, .load_tlv => unreachable, // TODO
+ .load_got, .load_memory, .lea_memory, .load_direct, .load_tlv => unreachable, // TODO
.immediate => |imm| .{ .immediate = imm },
.memory => |addr| .{ .memory = addr },
},
src/arch/x86_64/CodeGen.zig
@@ -193,6 +193,11 @@ pub const MCValue = union(enum) {
/// The value is in memory at a hard-coded address.
/// If the type is a pointer, it means the pointer address is stored at this memory location.
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_memory: u32,
+ /// The address of the memory location not-yet-allocated by the linker.
+ lea_memory: u32,
/// The value is in memory at a constant offset from the address in a register.
indirect: RegisterOffset,
/// The value is in memory.
@@ -207,12 +212,6 @@ pub const MCValue = union(enum) {
/// The value is a pointer to a value referenced indirectly via GOT.
/// Payload is a symbol index.
lea_got: u32,
- /// The value is an extern variable referenced via GOT.
- /// Payload is a symbol index.
- load_extern_got: u32,
- /// The value is a pointer to an extern variable referenced via GOT.
- /// Payload is a symbol index.
- lea_extern_got: u32,
/// The value is a threadlocal variable.
/// Payload is a symbol index.
load_tlv: u32,
@@ -299,9 +298,9 @@ pub const MCValue = union(enum) {
.register_pair,
.register_offset,
.register_overflow,
+ .lea_memory,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
.reserved_frame,
@@ -315,8 +314,8 @@ pub const MCValue = union(enum) {
.load_direct => |sym_index| .{ .lea_direct = sym_index },
.load_got => |sym_index| .{ .lea_got = sym_index },
.load_tlv => |sym_index| .{ .lea_tlv = sym_index },
- .load_extern_got => |sym_index| .{ .lea_extern_got = sym_index },
.load_frame => |frame_addr| .{ .lea_frame = frame_addr },
+ .load_memory => |sym_index| .{ .lea_memory = sym_index },
};
}
@@ -333,9 +332,9 @@ pub const MCValue = union(enum) {
.indirect,
.load_direct,
.load_got,
- .load_extern_got,
.load_tlv,
.load_frame,
+ .load_memory,
.reserved_frame,
.air_ref,
=> unreachable, // not dereferenceable
@@ -344,9 +343,9 @@ pub const MCValue = union(enum) {
.register_offset => |reg_off| .{ .indirect = reg_off },
.lea_direct => |sym_index| .{ .load_direct = sym_index },
.lea_got => |sym_index| .{ .load_got = sym_index },
- .lea_extern_got => |sym_index| .{ .load_extern_got = sym_index },
.lea_tlv => |sym_index| .{ .load_tlv = sym_index },
.lea_frame => |frame_addr| .{ .load_frame = frame_addr },
+ .lea_memory => |sym_index| .{ .load_memory = sym_index },
};
}
@@ -368,11 +367,11 @@ pub const MCValue = union(enum) {
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.load_frame,
+ .load_memory,
+ .lea_memory,
=> switch (off) {
0 => mcv,
else => unreachable, // not offsettable
@@ -404,13 +403,13 @@ pub const MCValue = union(enum) {
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.lea_frame,
.reserved_frame,
.air_ref,
+ .load_memory,
+ .lea_memory,
=> unreachable,
.memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
Memory.sib(ptr_size, .{ .base = .{ .reg = .ds }, .disp = small_addr })
@@ -448,14 +447,14 @@ pub const MCValue = union(enum) {
.lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
.load_got => |pl| try writer.print("[got:{d}]", .{pl}),
.lea_got => |pl| try writer.print("got:{d}", .{pl}),
- .load_extern_got => |pl| try writer.print("[extern_got:{d}]", .{pl}),
- .lea_extern_got => |pl| try writer.print("extern_got:{d}", .{pl}),
.load_tlv => |pl| try writer.print("[tlv:{d}]", .{pl}),
.lea_tlv => |pl| try writer.print("tlv:{d}", .{pl}),
.load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }),
.lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }),
.reserved_frame => |pl| try writer.print("(dead:{})", .{pl}),
.air_ref => |pl| try writer.print("(air:0x{x})", .{@intFromEnum(pl)}),
+ .load_memory => |pl| try writer.print("[mem:{d}]", .{pl}),
+ .lea_memory => |pl| try writer.print("mem:{d}", .{pl}),
}
}
};
@@ -477,12 +476,12 @@ const InstTracking = struct {
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.load_frame,
.lea_frame,
+ .load_memory,
+ .lea_memory,
=> result,
.dead,
.reserved_frame,
@@ -538,12 +537,12 @@ const InstTracking = struct {
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.load_frame,
.lea_frame,
+ .load_memory,
+ .lea_memory,
=> self.long,
.dead,
.eflags,
@@ -575,11 +574,11 @@ const InstTracking = struct {
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.lea_frame,
+ .load_memory,
+ .lea_memory,
=> assert(std.meta.eql(self.long, target.long)),
.load_frame,
.reserved_frame,
@@ -883,6 +882,7 @@ pub fn generate(
var emit = Emit{
.lower = .{
+ .bin_file = bin_file,
.allocator = bin_file.allocator,
.mir = mir,
.cc = cc,
@@ -970,6 +970,7 @@ pub fn generateLazy(
var emit = Emit{
.lower = .{
+ .bin_file = bin_file,
.allocator = bin_file.allocator,
.mir = mir,
.cc = abi.resolveCallingConvention(.Unspecified, function.target.*),
@@ -1060,6 +1061,7 @@ fn formatWipMir(
writer: anytype,
) @TypeOf(writer).Error!void {
var lower = Lower{
+ .bin_file = data.self.bin_file,
.allocator = data.self.gpa,
.mir = .{
.instructions = data.self.mir_instructions.slice(),
@@ -4729,12 +4731,12 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
Memory.sib(.qword, .{ .base = .{ .frame = frame_addr.index }, .disp = frame_addr.off }),
),
.memory,
+ .load_memory,
.load_direct,
.load_got,
- .load_extern_got,
.load_tlv,
=> try self.genSetReg(addr_reg, Type.usize, array.address()),
- .lea_direct, .lea_tlv => unreachable,
+ .lea_memory, .lea_direct, .lea_tlv => unreachable,
else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
}
@@ -6327,17 +6329,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro
.immediate,
.register,
.register_offset,
+ .lea_memory,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
=> try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref()),
.memory,
.indirect,
+ .load_memory,
.load_direct,
.load_got,
- .load_extern_got,
.load_tlv,
.load_frame,
=> {
@@ -6476,17 +6478,17 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
.immediate,
.register,
.register_offset,
+ .lea_memory,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
=> try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv),
.memory,
.indirect,
+ .load_memory,
.load_direct,
.load_got,
- .load_extern_got,
.load_tlv,
.load_frame,
=> {
@@ -6913,15 +6915,15 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC
.register_overflow,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
.reserved_frame,
.air_ref,
+ .lea_memory,
=> unreachable, // unmodifiable destination
.register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
.register_pair => unreachable, // unimplemented
- .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => {
+ .memory, .load_memory, .load_got, .load_direct, .load_tlv => {
const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
defer self.register_manager.unlockReg(addr_reg_lock);
@@ -7973,12 +7975,12 @@ fn genBinOp(
.immediate,
.eflags,
.register_offset,
+ .load_memory,
+ .lea_memory,
.load_direct,
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.lea_frame,
@@ -8031,12 +8033,12 @@ fn genBinOp(
.register_pair,
.register_offset,
.register_overflow,
+ .load_memory,
+ .lea_memory,
.load_direct,
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.lea_frame,
@@ -9164,9 +9166,9 @@ fn genBinOpMir(
.register_overflow,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
+ .lea_memory,
.reserved_frame,
.air_ref,
=> unreachable, // unmodifiable destination
@@ -9249,12 +9251,12 @@ fn genBinOpMir(
.register_offset,
.memory,
.indirect,
+ .load_memory,
+ .lea_memory,
.load_direct,
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.load_frame,
@@ -9285,9 +9287,9 @@ fn genBinOpMir(
switch (src_mcv) {
.eflags,
.register_offset,
+ .lea_memory,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
=> {
@@ -9301,9 +9303,9 @@ fn genBinOpMir(
);
},
.memory,
+ .load_memory,
.load_direct,
.load_got,
- .load_extern_got,
.load_tlv,
=> {
const ptr_ty = try mod.singleConstPtrType(ty);
@@ -9324,13 +9326,13 @@ fn genBinOpMir(
}
}
},
- .memory, .indirect, .load_got, .load_extern_got, .load_direct, .load_tlv, .load_frame => {
+ .memory, .indirect, .load_memory, .load_got, .load_direct, .load_tlv, .load_frame => {
const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
const limb_abi_size: u32 = @min(abi_size, 8);
const dst_info: OpInfo = switch (dst_mcv) {
else => unreachable,
- .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => dst: {
+ .memory, .load_memory, .load_got, .load_direct, .load_tlv => dst: {
const dst_addr_reg =
(try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);
@@ -9364,17 +9366,17 @@ fn genBinOpMir(
.indirect,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.load_frame,
.lea_frame,
+ .lea_memory,
=> null,
- .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => src: {
+ .memory, .load_memory, .load_got, .load_direct, .load_tlv => src: {
switch (resolved_src_mcv) {
.memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr))) != null and
math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
break :src null,
- .load_got, .load_extern_got, .load_direct, .load_tlv => {},
+ .load_memory, .load_got, .load_direct, .load_tlv => {},
else => unreachable,
}
@@ -9416,8 +9418,8 @@ fn genBinOpMir(
Memory.PtrSize.fromSize(limb_abi_size),
switch (dst_mcv) {
.memory,
+ .load_memory,
.load_got,
- .load_extern_got,
.load_direct,
.load_tlv,
=> .{ .base = .{ .reg = dst_info.?.addr_reg }, .disp = off },
@@ -9498,12 +9500,12 @@ fn genBinOpMir(
.eflags,
.memory,
.indirect,
+ .load_memory,
+ .lea_memory,
.load_direct,
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.load_frame,
@@ -9517,9 +9519,9 @@ fn genBinOpMir(
},
.eflags,
.register_offset,
+ .lea_memory,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
=> switch (limb_i) {
@@ -9568,9 +9570,9 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
.eflags,
.register_offset,
.register_overflow,
+ .lea_memory,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
.reserved_frame,
@@ -9615,12 +9617,12 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
},
.register_offset,
.eflags,
+ .load_memory,
+ .lea_memory,
.load_direct,
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.lea_frame,
@@ -9659,7 +9661,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M
}
},
.register_pair => unreachable, // unimplemented
- .memory, .indirect, .load_direct, .load_got, .load_extern_got, .load_tlv, .load_frame => {
+ .memory, .indirect, .load_memory, .load_direct, .load_got, .load_tlv, .load_frame => {
const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
const tmp_mcv = MCValue{ .register = tmp_reg };
const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
@@ -9759,8 +9761,8 @@ fn genVarDbgInfo(
// .offset = -off,
//} },
.memory => |address| .{ .memory = address },
+ .load_memory => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } }, // TODO
.load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },
- .load_extern_got => |sym_index| .{ .linker_load = .{ .type = .extern_got, .sym_index = sym_index } },
.load_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },
.immediate => |x| .{ .immediate = x },
.undef => .undef,
@@ -10011,12 +10013,12 @@ fn genCall(self: *Self, info: union(enum) {
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
if (self.bin_file.options.pic) {
- try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym.esym_index });
+ try self.genSetReg(.rax, Type.usize, .{ .lea_memory = sym.esym_index });
try self.asmRegister(.{ ._, .call }, .rax);
} else {
_ = try self.addInst(.{
.tag = .call,
- .ops = .direct_got_reloc,
+ .ops = .linker_reloc,
.data = .{ .reloc = .{
.atom_index = try self.owner.getSymbolIndex(self),
.sym_index = sym.esym_index,
@@ -10241,14 +10243,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
.indirect,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
+ .lea_memory,
.reserved_frame,
.air_ref,
=> unreachable,
.register_pair, .load_frame => null,
- .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => dst: {
+ .memory, .load_memory, .load_got, .load_direct, .load_tlv => dst: {
switch (resolved_dst_mcv) {
.memory => |addr| if (math.cast(
i32,
@@ -10257,7 +10259,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
i32,
@as(i64, @bitCast(addr)) + abi_size - 8,
) != null) break :dst null,
- .load_got, .load_extern_got, .load_direct, .load_tlv => {},
+ .load_memory, .load_got, .load_direct, .load_tlv => {},
else => unreachable,
}
@@ -10298,16 +10300,16 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
.register_offset,
.register_overflow,
.indirect,
+ .lea_memory,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
.reserved_frame,
.air_ref,
=> unreachable,
.register_pair, .load_frame => null,
- .memory, .load_got, .load_extern_got, .load_direct, .load_tlv => src: {
+ .memory, .load_memory, .load_got, .load_direct, .load_tlv => src: {
switch (resolved_src_mcv) {
.memory => |addr| if (math.cast(
i32,
@@ -10316,7 +10318,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
i32,
@as(i64, @bitCast(addr)) + abi_size - 8,
) != null) break :src null,
- .load_got, .load_extern_got, .load_direct, .load_tlv => {},
+ .load_memory, .load_got, .load_direct, .load_tlv => {},
else => unreachable,
}
@@ -10739,9 +10741,9 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
.register_overflow,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
+ .lea_memory,
.reserved_frame,
.air_ref,
=> unreachable,
@@ -10765,8 +10767,8 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
},
.memory,
+ .load_memory,
.load_got,
- .load_extern_got,
.load_direct,
.load_tlv,
=> {
@@ -11363,7 +11365,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
.memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|
break :arg input_mcv,
.indirect, .load_frame => break :arg input_mcv,
- .load_direct, .load_got, .load_extern_got, .load_tlv => {},
+ .load_memory, .load_direct, .load_got, .load_tlv => {},
else => {
const temp_mcv = try self.allocTempRegOrMem(ty, false);
try self.genCopy(ty, temp_mcv, input_mcv);
@@ -11625,6 +11627,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
.{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_got = sym_index }) }
else
return self.fail("invalid modifier: '{s}'", .{modifier}),
+ .lea_memory => |sym_index| if (mem.eql(u8, modifier, "P"))
+ .{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_memory = sym_index }) }
+ else
+ return self.fail("invalid modifier: '{s}'", .{modifier}),
else => return self.fail("invalid constraint: '{s}'", .{op_str}),
};
} else if (mem.startsWith(u8, op_str, "$")) {
@@ -12178,9 +12184,9 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
.register_overflow,
.lea_direct,
.lea_got,
- .lea_extern_got,
.lea_tlv,
.lea_frame,
+ .lea_memory,
.reserved_frame,
.air_ref,
=> unreachable, // unmodifiable destination
@@ -12236,6 +12242,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
class_ty,
.{ .register = src_regs[dst_reg_i] },
),
+ .load_memory => {
+ const addr_reg = try self.copyToTmpRegister(Type.usize, src_mcv.address());
+ const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
+ defer self.register_manager.unlockReg(addr_lock);
+ try self.genCopy(ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } });
+ },
.memory, .indirect, .load_frame => try self.genSetReg(
dst_reg,
class_ty,
@@ -12251,11 +12263,11 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError
}
},
.indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv),
- .memory, .load_direct, .load_got, .load_extern_got, .load_tlv => {
+ .memory, .load_memory, .load_direct, .load_got, .load_tlv => {
switch (dst_mcv) {
.memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv),
- .load_direct, .load_got, .load_extern_got, .load_tlv => {},
+ .load_memory, .load_direct, .load_got, .load_tlv => {},
else => unreachable,
}
@@ -12431,7 +12443,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
else => unreachable,
},
)),
- .memory, .load_direct, .load_got, .load_extern_got, .load_tlv => {
+ .memory, .load_memory, .load_direct, .load_got, .load_tlv => {
switch (src_mcv) {
.memory => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
return (try self.moveStrategy(
@@ -12461,7 +12473,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
.segment, .mmx => unreachable,
.x87, .sse => {},
},
- .load_got, .load_extern_got, .load_tlv => {},
+ .load_memory, .load_got, .load_tlv => {},
else => unreachable,
}
@@ -12475,28 +12487,42 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .{ .reg = addr_reg } }),
);
},
- .lea_direct, .lea_got, .lea_extern_got => |sym_index| {
+ .lea_memory, .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, .lea_extern_got => .mov,
- else => unreachable,
- },
- .ops = switch (src_mcv) {
- .lea_direct => .direct_reloc,
- .lea_got => .got_reloc,
- .lea_extern_got => .extern_got_reloc,
- else => unreachable,
- },
- .data = .{ .rx = .{
- .r1 = dst_reg.to64(),
- .payload = try self.addExtra(Mir.Reloc{
- .atom_index = atom_index,
- .sym_index = sym_index,
- }),
- } },
- });
+ if (self.bin_file.cast(link.File.Elf)) |elf_file| {
+ const sym = elf_file.symbol(elf_file.zigModulePtr().symbol(sym_index));
+ _ = try self.addInst(.{
+ .tag = if (sym.flags.has_zig_got) .mov else .lea,
+ .ops = .linker_reloc,
+ .data = .{ .rx = .{
+ .r1 = dst_reg.to64(),
+ .payload = try self.addExtra(Mir.Reloc{
+ .atom_index = atom_index,
+ .sym_index = sym_index,
+ }),
+ } },
+ });
+ } else {
+ _ = 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(Mir.Reloc{
+ .atom_index = atom_index,
+ .sym_index = sym_index,
+ }),
+ } },
+ });
+ }
},
.lea_tlv => |sym_index| {
const atom_index = try self.owner.getSymbolIndex(self);
@@ -12645,12 +12671,12 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
.lea_direct,
.load_got,
.lea_got,
- .load_extern_got,
- .lea_extern_got,
.load_tlv,
.lea_tlv,
.load_frame,
.lea_frame,
+ .load_memory,
+ .lea_memory,
=> switch (abi_size) {
0 => {},
1, 2, 4, 8 => {
@@ -12741,8 +12767,8 @@ fn genLazySymbolRef(
if (self.bin_file.options.pic) {
switch (tag) {
- .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym.esym_index }),
- .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym.esym_index }),
+ .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_memory = sym.esym_index }),
+ .mov => try self.genSetReg(reg, Type.usize, .{ .load_memory = sym.esym_index }),
else => unreachable,
}
switch (tag) {
@@ -12758,7 +12784,7 @@ fn genLazySymbolRef(
switch (tag) {
.lea, .mov => _ = try self.addInst(.{
.tag = .mov,
- .ops = .direct_got_reloc,
+ .ops = .linker_reloc,
.data = .{ .rx = .{
.r1 = reg.to64(),
.payload = try self.addExtra(reloc),
@@ -12766,7 +12792,7 @@ fn genLazySymbolRef(
}),
.call => _ = try self.addInst(.{
.tag = .call,
- .ops = .direct_got_reloc,
+ .ops = .linker_reloc,
.data = .{ .reloc = reloc },
}),
else => unreachable,
@@ -14716,9 +14742,10 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
.undef => .undef,
.immediate => |imm| .{ .immediate = imm },
.memory => |addr| .{ .memory = addr },
+ .load_memory => |sym_index| .{ .load_memory = sym_index },
+ .lea_memory => |sym_index| .{ .lea_memory = sym_index },
.load_direct => |sym_index| .{ .load_direct = sym_index },
.load_got => |sym_index| .{ .lea_got = sym_index },
- .load_extern_got => |sym_index| .{ .lea_extern_got = sym_index },
.load_tlv => |sym_index| .{ .lea_tlv = sym_index },
},
.fail => |msg| {
src/arch/x86_64/Emit.zig
@@ -78,31 +78,41 @@ pub fn emitMir(emit: *Emit) Error!void {
} else return emit.fail("TODO implement extern reloc for {s}", .{
@tagName(emit.bin_file.tag),
}),
+ .linker_reloc => |data| if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
+ const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
+ const sym = elf_file.symbol(elf_file.zigModulePtr().symbol(data.sym_index));
+ if (emit.bin_file.options.pic) {
+ const r_type: u32 = if (sym.flags.has_zig_got)
+ link.File.Elf.R_X86_64_ZIG_GOTPCREL
+ else if (sym.flags.has_got)
+ std.elf.R_X86_64_GOTPCREL
+ else
+ 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,
+ });
+ } else {
+ const r_type: u32 = if (sym.flags.has_zig_got)
+ link.File.Elf.R_X86_64_ZIG_GOT32
+ else if (sym.flags.has_got)
+ std.elf.R_X86_64_GOT32
+ else
+ 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,
+ });
+ }
+ } else unreachable,
.linker_got,
- .linker_extern_got,
.linker_direct,
- .linker_direct_got,
.linker_import,
.linker_tlv,
- => |symbol| if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
- const r_type: u32 = switch (lowered_relocs[0].target) {
- .linker_direct_got => link.File.Elf.R_X86_64_ZIG_GOT32,
- .linker_got => link.File.Elf.R_X86_64_ZIG_GOTPCREL,
- .linker_extern_got => std.elf.R_X86_64_GOTPCREL,
- .linker_direct => std.elf.R_X86_64_PC32,
- else => unreachable,
- };
- const r_addend: i64 = switch (lowered_relocs[0].target) {
- .linker_direct_got => 0,
- .linker_got, .linker_extern_got, .linker_direct => -4,
- else => unreachable,
- };
- const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
- try atom_ptr.addReloc(elf_file, .{
- .r_offset = end_offset - 4,
- .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
- .r_addend = r_addend,
- });
+ => |symbol| if (emit.bin_file.cast(link.File.Elf)) |_| {
+ unreachable;
} else if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
src/arch/x86_64/Lower.zig
@@ -1,5 +1,6 @@
//! This file contains the functionality for lowering x86_64 MIR to Instructions
+bin_file: *link.File,
allocator: Allocator,
mir: Mir,
cc: std.builtin.CallingConvention,
@@ -49,11 +50,10 @@ pub const Reloc = struct {
const Target = union(enum) {
inst: Mir.Inst.Index,
+ linker_reloc: Mir.Reloc,
linker_extern_fn: Mir.Reloc,
linker_got: Mir.Reloc,
- linker_extern_got: Mir.Reloc,
linker_direct: Mir.Reloc,
- linker_direct_got: Mir.Reloc,
linker_import: Mir.Reloc,
linker_tlv: Mir.Reloc,
};
@@ -407,10 +407,9 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
.mi_sib_u, .mi_rip_u, .mi_sib_s, .mi_rip_s => inst.data.x.fixes,
.m_sib, .m_rip, .rax_moffs, .moffs_rax => inst.data.x.fixes,
.extern_fn_reloc,
+ .linker_reloc,
.got_reloc,
- .extern_got_reloc,
.direct_reloc,
- .direct_got_reloc,
.import_reloc,
.tlv_reloc,
=> ._,
@@ -545,32 +544,50 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
.extern_fn_reloc => &.{
.{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
},
- .direct_got_reloc => ops: {
- switch (inst.tag) {
- .call => {
- _ = lower.reloc(.{ .linker_direct_got = inst.data.reloc });
- break :ops &.{
- .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
- };
- },
- .mov => {
- const reg = inst.data.rx.r1;
- const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
- _ = lower.reloc(.{ .linker_direct_got = extra });
- break :ops &.{
- .{ .reg = reg },
- .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
- };
- },
- else => unreachable,
+ .linker_reloc => ops: {
+ if (lower.bin_file.options.pic) {
+ const reg = inst.data.rx.r1;
+ const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
+ _ = lower.reloc(.{ .linker_reloc = extra });
+ break :ops &.{
+ .{ .reg = reg },
+ .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
+ };
+ } else {
+ switch (inst.tag) {
+ .call => {
+ _ = lower.reloc(.{ .linker_reloc = inst.data.reloc });
+ break :ops &.{
+ .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
+ };
+ },
+ .mov => {
+ const reg = inst.data.rx.r1;
+ const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
+ _ = lower.reloc(.{ .linker_reloc = extra });
+ break :ops &.{
+ .{ .reg = reg },
+ .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
+ };
+ },
+ .lea => {
+ const reg = inst.data.rx.r1;
+ const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
+ _ = lower.reloc(.{ .linker_reloc = extra });
+ break :ops &.{
+ .{ .reg = reg },
+ .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
+ };
+ },
+ else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
+ }
}
},
- .got_reloc, .extern_got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ops: {
+ .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ops: {
const reg = inst.data.rx.r1;
const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
_ = lower.reloc(switch (inst.ops) {
.got_reloc => .{ .linker_got = extra },
- .extern_got_reloc => .{ .linker_extern_got = extra },
.direct_reloc => .{ .linker_direct = extra },
.import_reloc => .{ .linker_import = extra },
.tlv_reloc => .{ .linker_tlv = extra },
@@ -601,6 +618,7 @@ const abi = @import("abi.zig");
const assert = std.debug.assert;
const bits = @import("bits.zig");
const encoder = @import("encoder.zig");
+const link = @import("../../link.zig");
const std = @import("std");
const Air = @import("../../Air.zig");
src/arch/x86_64/Mir.zig
@@ -854,9 +854,6 @@ pub const Inst = struct {
/// Linker relocation - GOT indirection.
/// Uses `rx` payload with extra data of type `Reloc`.
got_reloc,
- /// Linker relocation - reference to an extern variable via GOT.
- /// Uses `rx` payload with extra data of type `Reloc`.
- extern_got_reloc,
/// Linker relocation - direct reference.
/// Uses `rx` payload with extra data of type `Reloc`.
direct_reloc,
@@ -866,9 +863,9 @@ pub const Inst = struct {
/// Linker relocation - threadlocal variable via GOT indirection.
/// Uses `rx` payload with extra data of type `Reloc`.
tlv_reloc,
- /// Linker relocation - non-PIC direct reference to GOT cell.
- /// Uses `reloc` payload if tag is `call`, `rx` otherwise.
- direct_got_reloc,
+ /// Linker relocation.
+ /// Uses `rx` payload with extra data of type `Reloc`.
+ linker_reloc,
// Pseudo instructions:
src/link/Elf/Atom.zig
@@ -370,6 +370,7 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
try self.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
},
+ elf.R_X86_64_GOT32,
elf.R_X86_64_GOTPC32,
elf.R_X86_64_GOTPC64,
elf.R_X86_64_GOTPCREL,
@@ -879,6 +880,8 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
}
},
+ elf.R_X86_64_GOT32 => try cwriter.writeIntLittle(i32, @as(i32, @intCast(G + GOT + A))),
+
// Zig custom relocations
Elf.R_X86_64_ZIG_GOT32 => try cwriter.writeIntLittle(u32, @as(u32, @intCast(ZIG_GOT + A))),
Elf.R_X86_64_ZIG_GOTPCREL => try cwriter.writeIntLittle(i32, @as(i32, @intCast(ZIG_GOT + A - P))),
src/link/Elf.zig
@@ -5955,6 +5955,12 @@ pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32
return lookup_gop.value_ptr.*;
}
+pub fn zigModulePtr(self: *Elf) *ZigModule {
+ assert(self.zig_module_index != null);
+ const file_ptr = self.file(self.zig_module_index.?).?;
+ return file_ptr.zig_module;
+}
+
const GetOrCreateComdatGroupOwnerResult = struct {
found_existing: bool,
index: ComdatGroupOwner.Index,
src/codegen.zig
@@ -791,13 +791,11 @@ fn lowerDeclRef(
/// Helper struct to denote that the value is in memory but requires a linker relocation fixup:
/// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
-/// * extern_got - pointer to extern variable referenced via GOT
/// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
/// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
pub const LinkerLoad = struct {
type: enum {
got,
- extern_got,
direct,
import,
},
@@ -827,8 +825,10 @@ pub const GenResult = union(enum) {
load_got: u32,
/// Direct by-address reference to memory location.
memory: u64,
- /// Pointer to extern variable via GOT.
- load_extern_got: u32,
+ /// Reference to memory location but deferred until linker allocated the Decl in memory.
+ /// Traditionally, this corresponds to emitting a relocation in a relocatable object file.
+ load_memory: u32,
+ lea_memory: u32,
};
fn mcv(val: MCValue) GenResult {
@@ -903,16 +903,13 @@ fn genDeclRef(
mod.intern_pool.stringToSliceUnwrap(ov.lib_name)
else
null;
- return GenResult.mcv(.{ .load_extern_got = try elf_file.getGlobalSymbol(name, lib_name) });
+ const sym_index = try elf_file.getGlobalSymbol(name, lib_name);
+ return GenResult.mcv(.{ .lea_memory = sym_index });
}
const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
- if (bin_file.options.pic) {
- return GenResult.mcv(.{ .load_got = sym.esym_index });
- } else {
- return GenResult.mcv(.{ .memory = sym.zigGotAddress(elf_file) });
- }
+ return GenResult.mcv(.{ .lea_memory = sym.esym_index });
} else if (bin_file.cast(link.File.MachO)) |macho_file| {
const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
@@ -948,11 +945,7 @@ fn genUnnamedConst(
};
if (bin_file.cast(link.File.Elf)) |elf_file| {
const local = elf_file.symbol(local_sym_index);
- if (bin_file.options.pic) {
- return GenResult.mcv(.{ .load_direct = local.esym_index });
- } else {
- return GenResult.mcv(.{ .memory = local.value });
- }
+ return GenResult.mcv(.{ .load_memory = local.esym_index });
} else if (bin_file.cast(link.File.MachO)) |_| {
return GenResult.mcv(.{ .load_direct = local_sym_index });
} else if (bin_file.cast(link.File.Coff)) |_| {