mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Merge pull request #21065 from ziglang/elf-zig-got
elf: replace .got.zig with a zig jump table
This commit is contained in:
commit
90989be0e3
@ -218,7 +218,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
|
|||||||
|
|
||||||
if (opts.is_test) {
|
if (opts.is_test) {
|
||||||
try buffer.appendSlice(
|
try buffer.appendSlice(
|
||||||
\\pub var test_functions: []const std.builtin.TestFn = undefined; // overwritten later
|
\\pub var test_functions: []const std.builtin.TestFn = &.{}; // overwritten later
|
||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3092,6 +3092,10 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
|
|||||||
if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) {
|
if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) {
|
||||||
total += 1;
|
total += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (zcu.failed_codegen.keys()) |_| {
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The "no entry point found" error only counts if there are no semantic analysis errors.
|
// The "no entry point found" error only counts if there are no semantic analysis errors.
|
||||||
@ -3237,6 +3241,9 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (zcu.failed_codegen.values()) |error_msg| {
|
||||||
|
try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
|
||||||
|
}
|
||||||
for (zcu.failed_exports.values()) |value| {
|
for (zcu.failed_exports.values()) |value| {
|
||||||
try addModuleErrorMsg(zcu, &bundle, value.*, &all_references);
|
try addModuleErrorMsg(zcu, &bundle, value.*, &all_references);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4352,24 +4352,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
|
|||||||
// on linking.
|
// on linking.
|
||||||
if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
|
if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
|
||||||
.func => |func| {
|
.func => |func| {
|
||||||
if (self.bin_file.cast(.elf)) |elf_file| {
|
if (self.bin_file.cast(.elf)) |_| {
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
return self.fail("TODO implement calling functions for Elf", .{});
|
||||||
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
|
} else if (self.bin_file.cast(.macho)) |_| {
|
||||||
const sym = zo.symbol(sym_index);
|
return self.fail("TODO implement calling functions for MachO", .{});
|
||||||
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
|
|
||||||
const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));
|
|
||||||
try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr });
|
|
||||||
} else if (self.bin_file.cast(.macho)) |macho_file| {
|
|
||||||
_ = macho_file;
|
|
||||||
@panic("TODO airCall");
|
|
||||||
// const atom = try macho_file.getOrCreateAtomForNav(func.owner_nav);
|
|
||||||
// const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
|
|
||||||
// try self.genSetReg(Type.u64, .x30, .{
|
|
||||||
// .linker_load = .{
|
|
||||||
// .type = .got,
|
|
||||||
// .sym_index = sym_index,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
} else if (self.bin_file.cast(.coff)) |coff_file| {
|
} else if (self.bin_file.cast(.coff)) |coff_file| {
|
||||||
const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);
|
const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);
|
||||||
const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
|
const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
|
||||||
@ -4393,21 +4379,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
|
|||||||
.@"extern" => |@"extern"| {
|
.@"extern" => |@"extern"| {
|
||||||
const nav_name = ip.getNav(@"extern".owner_nav).name.toSlice(ip);
|
const nav_name = ip.getNav(@"extern".owner_nav).name.toSlice(ip);
|
||||||
const lib_name = @"extern".lib_name.toSlice(ip);
|
const lib_name = @"extern".lib_name.toSlice(ip);
|
||||||
if (self.bin_file.cast(.macho)) |macho_file| {
|
if (self.bin_file.cast(.macho)) |_| {
|
||||||
_ = macho_file;
|
return self.fail("TODO implement calling extern functions for MachO", .{});
|
||||||
@panic("TODO airCall");
|
|
||||||
// const sym_index = try macho_file.getGlobalSymbol(nav_name, lib_name);
|
|
||||||
// const atom = try macho_file.getOrCreateAtomForNav(self.owner_nav);
|
|
||||||
// const atom_index = macho_file.getAtom(atom).getSymbolIndex().?;
|
|
||||||
// _ = try self.addInst(.{
|
|
||||||
// .tag = .call_extern,
|
|
||||||
// .data = .{
|
|
||||||
// .relocation = .{
|
|
||||||
// .atom_index = atom_index,
|
|
||||||
// .sym_index = sym_index,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
} else if (self.bin_file.cast(.coff)) |coff_file| {
|
} else if (self.bin_file.cast(.coff)) |coff_file| {
|
||||||
const sym_index = try coff_file.getGlobalSymbol(nav_name, lib_name);
|
const sym_index = try coff_file.getGlobalSymbol(nav_name, lib_name);
|
||||||
try self.genSetReg(Type.u64, .x30, .{
|
try self.genSetReg(Type.u64, .x30, .{
|
||||||
@ -6234,7 +6207,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
|
|||||||
.memory => |addr| .{ .memory = addr },
|
.memory => |addr| .{ .memory = addr },
|
||||||
.load_got => |sym_index| .{ .linker_load = .{ .type = .got, .sym_index = sym_index } },
|
.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_direct => |sym_index| .{ .linker_load = .{ .type = .direct, .sym_index = sym_index } },
|
||||||
.load_symbol, .load_tlv => unreachable, // TODO
|
.load_symbol, .load_tlv, .lea_symbol => unreachable, // TODO
|
||||||
},
|
},
|
||||||
.fail => |msg| {
|
.fail => |msg| {
|
||||||
self.err_msg = msg;
|
self.err_msg = msg;
|
||||||
|
|||||||
@ -4333,22 +4333,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
|
|||||||
// Due to incremental compilation, how function calls are generated depends
|
// Due to incremental compilation, how function calls are generated depends
|
||||||
// on linking.
|
// on linking.
|
||||||
if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
|
if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
|
||||||
.func => |func| {
|
.func => {
|
||||||
if (self.bin_file.cast(.elf)) |elf_file| {
|
return self.fail("TODO implement calling functions", .{});
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
|
||||||
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
|
|
||||||
const sym = zo.symbol(sym_index);
|
|
||||||
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
|
|
||||||
const got_addr: u32 = @intCast(sym.zigGotAddress(elf_file));
|
|
||||||
try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr });
|
|
||||||
} else if (self.bin_file.cast(.macho)) |_| {
|
|
||||||
unreachable; // unsupported architecture for MachO
|
|
||||||
} else {
|
|
||||||
return self.fail("TODO implement call on {s} for {s}", .{
|
|
||||||
@tagName(self.bin_file.tag),
|
|
||||||
@tagName(self.target.cpu.arch),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.@"extern" => {
|
.@"extern" => {
|
||||||
return self.fail("TODO implement calling extern functions", .{});
|
return self.fail("TODO implement calling extern functions", .{});
|
||||||
@ -6184,7 +6170,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
|
|||||||
.mcv => |mcv| switch (mcv) {
|
.mcv => |mcv| switch (mcv) {
|
||||||
.none => .none,
|
.none => .none,
|
||||||
.undef => .undef,
|
.undef => .undef,
|
||||||
.load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO
|
.load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO
|
||||||
.immediate => |imm| .{ .immediate = @truncate(imm) },
|
.immediate => |imm| .{ .immediate = @truncate(imm) },
|
||||||
.memory => |addr| .{ .memory = addr },
|
.memory => |addr| .{ .memory = addr },
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4937,7 +4937,7 @@ fn genCall(
|
|||||||
if (func.mod.pic) {
|
if (func.mod.pic) {
|
||||||
return func.fail("TODO: genCall pic", .{});
|
return func.fail("TODO: genCall pic", .{});
|
||||||
} else {
|
} else {
|
||||||
try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym_index } });
|
try func.genSetReg(Type.u64, .ra, .{ .lea_symbol = .{ .sym = sym_index } });
|
||||||
_ = try func.addInst(.{
|
_ = try func.addInst(.{
|
||||||
.tag = .jalr,
|
.tag = .jalr,
|
||||||
.data = .{ .i_type = .{
|
.data = .{ .i_type = .{
|
||||||
@ -6120,7 +6120,7 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
|
|||||||
arg_map.get(op_str["%[".len .. mod_index orelse op_str.len - "]".len]) orelse
|
arg_map.get(op_str["%[".len .. mod_index orelse op_str.len - "]".len]) orelse
|
||||||
return func.fail("no matching constraint: '{s}'", .{op_str})
|
return func.fail("no matching constraint: '{s}'", .{op_str})
|
||||||
]) {
|
]) {
|
||||||
.load_symbol => |sym_off| if (mem.eql(u8, modifier, "plt")) blk: {
|
.lea_symbol => |sym_off| if (mem.eql(u8, modifier, "plt")) blk: {
|
||||||
assert(sym_off.off == 0);
|
assert(sym_off.off == 0);
|
||||||
break :blk .{ .sym = sym_off };
|
break :blk .{ .sym = sym_off };
|
||||||
} else return func.fail("invalid modifier: '{s}'", .{modifier}),
|
} else return func.fail("invalid modifier: '{s}'", .{modifier}),
|
||||||
@ -6388,7 +6388,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
|
|||||||
ty,
|
ty,
|
||||||
src_mcv,
|
src_mcv,
|
||||||
),
|
),
|
||||||
.load_tlv => {
|
.load_symbol, .load_tlv => {
|
||||||
const addr_reg, const addr_lock = try func.allocReg(.int);
|
const addr_reg, const addr_lock = try func.allocReg(.int);
|
||||||
defer func.register_manager.unlockReg(addr_lock);
|
defer func.register_manager.unlockReg(addr_lock);
|
||||||
|
|
||||||
@ -6433,7 +6433,7 @@ fn genCopy(func: *Func, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void {
|
|||||||
part_disp += @intCast(dst_ty.abiSize(func.pt));
|
part_disp += @intCast(dst_ty.abiSize(func.pt));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => return func.fail("TODO: genCopy to {s} from {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }),
|
else => return std.debug.panic("TODO: genCopy to {s} from {s}", .{ @tagName(dst_mcv), @tagName(src_mcv) }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6594,7 +6594,7 @@ fn genInlineMemset(
|
|||||||
.tag = .beq,
|
.tag = .beq,
|
||||||
.data = .{
|
.data = .{
|
||||||
.b_type = .{
|
.b_type = .{
|
||||||
.inst = @intCast(func.mir_instructions.len + 4), // points after the last inst
|
.inst = @intCast(func.mir_instructions.len + 3), // points after the last inst
|
||||||
.rs1 = count,
|
.rs1 = count,
|
||||||
.rs2 = .zero,
|
.rs2 = .zero,
|
||||||
},
|
},
|
||||||
@ -8026,6 +8026,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
|
|||||||
.mcv => |mcv| switch (mcv) {
|
.mcv => |mcv| switch (mcv) {
|
||||||
.none => .none,
|
.none => .none,
|
||||||
.undef => unreachable,
|
.undef => unreachable,
|
||||||
|
.lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },
|
||||||
.load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
|
.load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
|
||||||
.load_tlv => |sym_index| .{ .lea_tlv = sym_index },
|
.load_tlv => |sym_index| .{ .lea_tlv = sym_index },
|
||||||
.immediate => |imm| .{ .immediate = imm },
|
.immediate => |imm| .{ .immediate = imm },
|
||||||
|
|||||||
@ -43,31 +43,19 @@ pub fn emitMir(emit: *Emit) Error!void {
|
|||||||
.fmt = std.meta.activeTag(lowered_inst),
|
.fmt = std.meta.activeTag(lowered_inst),
|
||||||
}),
|
}),
|
||||||
.load_symbol_reloc => |symbol| {
|
.load_symbol_reloc => |symbol| {
|
||||||
const is_obj_or_static_lib = switch (emit.lower.output_mode) {
|
|
||||||
.Exe => false,
|
|
||||||
.Obj => true,
|
|
||||||
.Lib => emit.lower.link_mode == .static,
|
|
||||||
};
|
|
||||||
|
|
||||||
const elf_file = emit.bin_file.cast(.elf).?;
|
const elf_file = emit.bin_file.cast(.elf).?;
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
const zo = elf_file.zigObjectPtr().?;
|
||||||
|
|
||||||
const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
|
const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
|
||||||
const sym = zo.symbol(symbol.sym_index);
|
const sym = zo.symbol(symbol.sym_index);
|
||||||
|
|
||||||
var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);
|
if (sym.flags.is_extern_ptr and emit.lower.pic) {
|
||||||
var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);
|
return emit.fail("emit GOT relocation for symbol '{s}'", .{sym.name(elf_file)});
|
||||||
|
|
||||||
if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
|
|
||||||
_ = try sym.getOrCreateZigGotEntry(symbol.sym_index, elf_file);
|
|
||||||
|
|
||||||
hi_r_type = Elf.R_ZIG_GOT_HI20;
|
|
||||||
lo_r_type = Elf.R_ZIG_GOT_LO12;
|
|
||||||
} else if (sym.flags.needs_got) {
|
|
||||||
hi_r_type = Elf.R_GOT_HI20_STATIC; // TODO: rework this #20887
|
|
||||||
lo_r_type = Elf.R_GOT_LO12_I_STATIC; // TODO: rework this #20887
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);
|
||||||
|
const lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);
|
||||||
|
|
||||||
try atom_ptr.addReloc(elf_file, .{
|
try atom_ptr.addReloc(elf_file, .{
|
||||||
.r_offset = start_offset,
|
.r_offset = start_offset,
|
||||||
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type,
|
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type,
|
||||||
|
|||||||
@ -1349,34 +1349,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
|
|||||||
// Due to incremental compilation, how function calls are generated depends
|
// Due to incremental compilation, how function calls are generated depends
|
||||||
// on linking.
|
// on linking.
|
||||||
if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
|
if (try self.air.value(callee, pt)) |func_value| switch (ip.indexToKey(func_value.toIntern())) {
|
||||||
.func => |func| {
|
.func => {
|
||||||
const got_addr = if (self.bin_file.cast(.elf)) |elf_file| blk: {
|
return self.fail("TODO implement calling functions", .{});
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
|
||||||
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
|
|
||||||
const sym = zo.symbol(sym_index);
|
|
||||||
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
|
|
||||||
break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));
|
|
||||||
} else @panic("TODO SPARCv9 currently does not support non-ELF binaries");
|
|
||||||
|
|
||||||
try self.genSetReg(Type.usize, .o7, .{ .memory = got_addr });
|
|
||||||
|
|
||||||
_ = try self.addInst(.{
|
|
||||||
.tag = .jmpl,
|
|
||||||
.data = .{
|
|
||||||
.arithmetic_3op = .{
|
|
||||||
.is_imm = false,
|
|
||||||
.rd = .o7,
|
|
||||||
.rs1 = .o7,
|
|
||||||
.rs2_or_imm = .{ .rs2 = .g0 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO Find a way to fill this delay slot
|
|
||||||
_ = try self.addInst(.{
|
|
||||||
.tag = .nop,
|
|
||||||
.data = .{ .nop = {} },
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
.@"extern" => {
|
.@"extern" => {
|
||||||
return self.fail("TODO implement calling extern functions", .{});
|
return self.fail("TODO implement calling extern functions", .{});
|
||||||
@ -4153,7 +4127,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
|
|||||||
.mcv => |mcv| switch (mcv) {
|
.mcv => |mcv| switch (mcv) {
|
||||||
.none => .none,
|
.none => .none,
|
||||||
.undef => .undef,
|
.undef => .undef,
|
||||||
.load_got, .load_symbol, .load_direct, .load_tlv => unreachable, // TODO
|
.load_got, .load_symbol, .load_direct, .load_tlv, .lea_symbol => unreachable, // TODO
|
||||||
.immediate => |imm| .{ .immediate = imm },
|
.immediate => |imm| .{ .immediate = imm },
|
||||||
.memory => |addr| .{ .memory = addr },
|
.memory => |addr| .{ .memory = addr },
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1379,14 +1379,22 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void {
|
|||||||
.ops = switch (imm) {
|
.ops = switch (imm) {
|
||||||
.signed => .i_s,
|
.signed => .i_s,
|
||||||
.unsigned => .i_u,
|
.unsigned => .i_u,
|
||||||
|
.reloc => .rel,
|
||||||
},
|
},
|
||||||
.data = .{ .i = .{
|
.data = switch (imm) {
|
||||||
.fixes = tag[0],
|
.reloc => |x| reloc: {
|
||||||
.i = switch (imm) {
|
assert(tag[0] == ._);
|
||||||
.signed => |s| @bitCast(s),
|
break :reloc .{ .reloc = x };
|
||||||
.unsigned => |u| @intCast(u),
|
|
||||||
},
|
},
|
||||||
} },
|
.signed, .unsigned => .{ .i = .{
|
||||||
|
.fixes = tag[0],
|
||||||
|
.i = switch (imm) {
|
||||||
|
.signed => |s| @bitCast(s),
|
||||||
|
.unsigned => |u| @intCast(u),
|
||||||
|
.reloc => unreachable,
|
||||||
|
},
|
||||||
|
} },
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1406,6 +1414,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm:
|
|||||||
const ops: Mir.Inst.Ops = switch (imm) {
|
const ops: Mir.Inst.Ops = switch (imm) {
|
||||||
.signed => .ri_s,
|
.signed => .ri_s,
|
||||||
.unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
|
.unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
|
||||||
|
.reloc => unreachable,
|
||||||
};
|
};
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
.tag = tag[1],
|
.tag = tag[1],
|
||||||
@ -1417,6 +1426,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm:
|
|||||||
.i = switch (imm) {
|
.i = switch (imm) {
|
||||||
.signed => |s| @bitCast(s),
|
.signed => |s| @bitCast(s),
|
||||||
.unsigned => |u| @intCast(u),
|
.unsigned => |u| @intCast(u),
|
||||||
|
.reloc => unreachable,
|
||||||
},
|
},
|
||||||
} },
|
} },
|
||||||
.ri64 => .{ .rx = .{
|
.ri64 => .{ .rx = .{
|
||||||
@ -1488,6 +1498,7 @@ fn asmRegisterRegisterRegisterImmediate(
|
|||||||
.i = switch (imm) {
|
.i = switch (imm) {
|
||||||
.signed => |s| @bitCast(@as(i8, @intCast(s))),
|
.signed => |s| @bitCast(@as(i8, @intCast(s))),
|
||||||
.unsigned => |u| @intCast(u),
|
.unsigned => |u| @intCast(u),
|
||||||
|
.reloc => unreachable,
|
||||||
},
|
},
|
||||||
} },
|
} },
|
||||||
});
|
});
|
||||||
@ -1505,6 +1516,7 @@ fn asmRegisterRegisterImmediate(
|
|||||||
.ops = switch (imm) {
|
.ops = switch (imm) {
|
||||||
.signed => .rri_s,
|
.signed => .rri_s,
|
||||||
.unsigned => .rri_u,
|
.unsigned => .rri_u,
|
||||||
|
.reloc => unreachable,
|
||||||
},
|
},
|
||||||
.data = .{ .rri = .{
|
.data = .{ .rri = .{
|
||||||
.fixes = tag[0],
|
.fixes = tag[0],
|
||||||
@ -1513,6 +1525,7 @@ fn asmRegisterRegisterImmediate(
|
|||||||
.i = switch (imm) {
|
.i = switch (imm) {
|
||||||
.signed => |s| @bitCast(s),
|
.signed => |s| @bitCast(s),
|
||||||
.unsigned => |u| @intCast(u),
|
.unsigned => |u| @intCast(u),
|
||||||
|
.reloc => unreachable,
|
||||||
},
|
},
|
||||||
} },
|
} },
|
||||||
});
|
});
|
||||||
@ -1610,6 +1623,7 @@ fn asmRegisterMemoryImmediate(
|
|||||||
if (switch (imm) {
|
if (switch (imm) {
|
||||||
.signed => |s| if (math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null,
|
.signed => |s| if (math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null,
|
||||||
.unsigned => |u| math.cast(u16, u),
|
.unsigned => |u| math.cast(u16, u),
|
||||||
|
.reloc => unreachable,
|
||||||
}) |small_imm| {
|
}) |small_imm| {
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
.tag = tag[1],
|
.tag = tag[1],
|
||||||
@ -1625,6 +1639,7 @@ fn asmRegisterMemoryImmediate(
|
|||||||
const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
|
const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
|
||||||
.signed => |s| @bitCast(s),
|
.signed => |s| @bitCast(s),
|
||||||
.unsigned => unreachable,
|
.unsigned => unreachable,
|
||||||
|
.reloc => unreachable,
|
||||||
} });
|
} });
|
||||||
assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));
|
assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
@ -1632,6 +1647,7 @@ fn asmRegisterMemoryImmediate(
|
|||||||
.ops = switch (imm) {
|
.ops = switch (imm) {
|
||||||
.signed => .rmi_s,
|
.signed => .rmi_s,
|
||||||
.unsigned => .rmi_u,
|
.unsigned => .rmi_u,
|
||||||
|
.reloc => unreachable,
|
||||||
},
|
},
|
||||||
.data = .{ .rx = .{
|
.data = .{ .rx = .{
|
||||||
.fixes = tag[0],
|
.fixes = tag[0],
|
||||||
@ -1679,6 +1695,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed
|
|||||||
const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
|
const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
|
||||||
.signed => |s| @bitCast(s),
|
.signed => |s| @bitCast(s),
|
||||||
.unsigned => |u| @intCast(u),
|
.unsigned => |u| @intCast(u),
|
||||||
|
.reloc => unreachable,
|
||||||
} });
|
} });
|
||||||
assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));
|
assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
@ -1686,6 +1703,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed
|
|||||||
.ops = switch (imm) {
|
.ops = switch (imm) {
|
||||||
.signed => .mi_s,
|
.signed => .mi_s,
|
||||||
.unsigned => .mi_u,
|
.unsigned => .mi_u,
|
||||||
|
.reloc => unreachable,
|
||||||
},
|
},
|
||||||
.data = .{ .x = .{
|
.data = .{ .x = .{
|
||||||
.fixes = tag[0],
|
.fixes = tag[0],
|
||||||
@ -12310,33 +12328,10 @@ fn genCall(self: *Self, info: union(enum) {
|
|||||||
if (self.bin_file.cast(.elf)) |elf_file| {
|
if (self.bin_file.cast(.elf)) |elf_file| {
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
const zo = elf_file.zigObjectPtr().?;
|
||||||
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
|
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
|
||||||
if (self.mod.pic) {
|
try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
|
||||||
const callee_reg: Register = switch (resolved_cc) {
|
.atom_index = try self.owner.getSymbolIndex(self),
|
||||||
.SysV => callee: {
|
.sym_index = sym_index,
|
||||||
if (!fn_info.is_var_args) break :callee .rax;
|
}));
|
||||||
const param_regs = abi.getCAbiIntParamRegs(resolved_cc);
|
|
||||||
break :callee if (call_info.gp_count < param_regs.len)
|
|
||||||
param_regs[call_info.gp_count]
|
|
||||||
else
|
|
||||||
.r10;
|
|
||||||
},
|
|
||||||
.Win64 => .rax,
|
|
||||||
else => unreachable,
|
|
||||||
};
|
|
||||||
try self.genSetReg(
|
|
||||||
callee_reg,
|
|
||||||
Type.usize,
|
|
||||||
.{ .load_symbol = .{ .sym = sym_index } },
|
|
||||||
.{},
|
|
||||||
);
|
|
||||||
try self.asmRegister(.{ ._, .call }, callee_reg);
|
|
||||||
} else try self.asmMemory(.{ ._, .call }, .{
|
|
||||||
.base = .{ .reloc = .{
|
|
||||||
.atom_index = try self.owner.getSymbolIndex(self),
|
|
||||||
.sym_index = sym_index,
|
|
||||||
} },
|
|
||||||
.mod = .{ .rm = .{ .size = .qword } },
|
|
||||||
});
|
|
||||||
} else if (self.bin_file.cast(.coff)) |coff_file| {
|
} else if (self.bin_file.cast(.coff)) |coff_file| {
|
||||||
const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);
|
const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);
|
||||||
const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
|
const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
|
||||||
@ -12365,7 +12360,16 @@ fn genCall(self: *Self, info: union(enum) {
|
|||||||
});
|
});
|
||||||
} else unreachable;
|
} else unreachable;
|
||||||
},
|
},
|
||||||
.@"extern" => |@"extern"| try self.genExternSymbolRef(
|
.@"extern" => |@"extern"| if (self.bin_file.cast(.elf)) |elf_file| {
|
||||||
|
const target_sym_index = try elf_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,
|
||||||
|
}));
|
||||||
|
} else try self.genExternSymbolRef(
|
||||||
.call,
|
.call,
|
||||||
@"extern".lib_name.toSlice(ip),
|
@"extern".lib_name.toSlice(ip),
|
||||||
@"extern".name.toSlice(ip),
|
@"extern".name.toSlice(ip),
|
||||||
@ -12377,7 +12381,13 @@ fn genCall(self: *Self, info: union(enum) {
|
|||||||
try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee }, .{});
|
try self.genSetReg(.rax, Type.usize, .{ .air_ref = callee }, .{});
|
||||||
try self.asmRegister(.{ ._, .call }, .rax);
|
try self.asmRegister(.{ ._, .call }, .rax);
|
||||||
},
|
},
|
||||||
.lib => |lib| try self.genExternSymbolRef(.call, lib.lib, lib.callee),
|
.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,
|
||||||
|
}));
|
||||||
|
} else try self.genExternSymbolRef(.call, lib.lib, lib.callee),
|
||||||
}
|
}
|
||||||
return call_info.return_value.short;
|
return call_info.return_value.short;
|
||||||
}
|
}
|
||||||
@ -14096,8 +14106,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
|
|||||||
.{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_got = sym_index }) }
|
.{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_got = sym_index }) }
|
||||||
else
|
else
|
||||||
return self.fail("invalid modifier: '{s}'", .{modifier}),
|
return self.fail("invalid modifier: '{s}'", .{modifier}),
|
||||||
.load_symbol => |sym_off| if (mem.eql(u8, modifier, "P"))
|
.lea_symbol => |sym_off| if (mem.eql(u8, modifier, "P"))
|
||||||
.{ .reg = try self.copyToTmpRegister(Type.usize, .{ .load_symbol = sym_off }) }
|
.{ .reg = try self.copyToTmpRegister(Type.usize, .{ .lea_symbol = sym_off }) }
|
||||||
else
|
else
|
||||||
return self.fail("invalid modifier: '{s}'", .{modifier}),
|
return self.fail("invalid modifier: '{s}'", .{modifier}),
|
||||||
else => return self.fail("invalid constraint: '{s}'", .{op_str}),
|
else => return self.fail("invalid constraint: '{s}'", .{op_str}),
|
||||||
@ -15253,16 +15263,7 @@ fn genExternSymbolRef(
|
|||||||
callee: []const u8,
|
callee: []const u8,
|
||||||
) InnerError!void {
|
) InnerError!void {
|
||||||
const atom_index = try self.owner.getSymbolIndex(self);
|
const atom_index = try self.owner.getSymbolIndex(self);
|
||||||
if (self.bin_file.cast(.elf)) |elf_file| {
|
if (self.bin_file.cast(.coff)) |coff_file| {
|
||||||
_ = try self.addInst(.{
|
|
||||||
.tag = tag,
|
|
||||||
.ops = .extern_fn_reloc,
|
|
||||||
.data = .{ .reloc = .{
|
|
||||||
.atom_index = atom_index,
|
|
||||||
.sym_index = try elf_file.getGlobalSymbol(callee, lib),
|
|
||||||
} },
|
|
||||||
});
|
|
||||||
} else if (self.bin_file.cast(.coff)) |coff_file| {
|
|
||||||
const global_index = try coff_file.getGlobalSymbol(callee, lib);
|
const global_index = try coff_file.getGlobalSymbol(callee, lib);
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
.tag = .mov,
|
.tag = .mov,
|
||||||
@ -15306,7 +15307,7 @@ fn genLazySymbolRef(
|
|||||||
if (self.mod.pic) {
|
if (self.mod.pic) {
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
.lea, .call => try self.genSetReg(reg, Type.usize, .{
|
.lea, .call => try self.genSetReg(reg, Type.usize, .{
|
||||||
.load_symbol = .{ .sym = sym_index },
|
.lea_symbol = .{ .sym = sym_index },
|
||||||
}, .{}),
|
}, .{}),
|
||||||
.mov => try self.genSetReg(reg, Type.usize, .{
|
.mov => try self.genSetReg(reg, Type.usize, .{
|
||||||
.load_symbol = .{ .sym = sym_index },
|
.load_symbol = .{ .sym = sym_index },
|
||||||
@ -15324,14 +15325,11 @@ fn genLazySymbolRef(
|
|||||||
.sym_index = sym_index,
|
.sym_index = sym_index,
|
||||||
};
|
};
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
.lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), .{
|
.lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{
|
||||||
.base = .{ .reloc = reloc },
|
|
||||||
.mod = .{ .rm = .{ .size = .qword } },
|
|
||||||
}),
|
|
||||||
.call => try self.asmMemory(.{ ._, .call }, .{
|
|
||||||
.base = .{ .reloc = reloc },
|
.base = .{ .reloc = reloc },
|
||||||
.mod = .{ .rm = .{ .size = .qword } },
|
.mod = .{ .rm = .{ .size = .qword } },
|
||||||
}),
|
}),
|
||||||
|
.call => try self.asmImmediate(.{ ._, .call }, Immediate.rel(reloc)),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -18790,6 +18788,7 @@ fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
|
|||||||
.immediate => |imm| .{ .immediate = imm },
|
.immediate => |imm| .{ .immediate = imm },
|
||||||
.memory => |addr| .{ .memory = addr },
|
.memory => |addr| .{ .memory = addr },
|
||||||
.load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
|
.load_symbol => |sym_index| .{ .load_symbol = .{ .sym = sym_index } },
|
||||||
|
.lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym = sym_index } },
|
||||||
.load_direct => |sym_index| .{ .load_direct = sym_index },
|
.load_direct => |sym_index| .{ .load_direct = sym_index },
|
||||||
.load_got => |sym_index| .{ .lea_got = sym_index },
|
.load_got => |sym_index| .{ .lea_got = sym_index },
|
||||||
.load_tlv => |sym_index| .{ .lea_tlv = sym_index },
|
.load_tlv => |sym_index| .{ .lea_tlv = sym_index },
|
||||||
|
|||||||
@ -8,7 +8,7 @@ const bits = @import("bits.zig");
|
|||||||
const encoder = @import("encoder.zig");
|
const encoder = @import("encoder.zig");
|
||||||
|
|
||||||
const Encoding = @import("Encoding.zig");
|
const Encoding = @import("Encoding.zig");
|
||||||
const Immediate = bits.Immediate;
|
const Immediate = Instruction.Immediate;
|
||||||
const Instruction = encoder.Instruction;
|
const Instruction = encoder.Instruction;
|
||||||
const LegacyPrefixes = encoder.LegacyPrefixes;
|
const LegacyPrefixes = encoder.LegacyPrefixes;
|
||||||
const Memory = Instruction.Memory;
|
const Memory = Instruction.Memory;
|
||||||
|
|||||||
@ -110,21 +110,11 @@ pub fn emitMir(emit: *Emit) Error!void {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
.linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
|
.linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
|
||||||
const is_obj_or_static_lib = switch (emit.lower.output_mode) {
|
|
||||||
.Exe => false,
|
|
||||||
.Obj => true,
|
|
||||||
.Lib => emit.lower.link_mode == .static,
|
|
||||||
};
|
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
const zo = elf_file.zigObjectPtr().?;
|
||||||
const atom = zo.symbol(data.atom_index).atom(elf_file).?;
|
const atom = zo.symbol(data.atom_index).atom(elf_file).?;
|
||||||
const sym = zo.symbol(data.sym_index);
|
const sym = zo.symbol(data.sym_index);
|
||||||
if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
|
|
||||||
_ = try sym.getOrCreateZigGotEntry(data.sym_index, elf_file);
|
|
||||||
}
|
|
||||||
if (emit.lower.pic) {
|
if (emit.lower.pic) {
|
||||||
const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
|
const r_type: u32 = if (sym.flags.is_extern_ptr)
|
||||||
link.File.Elf.R_ZIG_GOTPCREL
|
|
||||||
else if (sym.flags.needs_got)
|
|
||||||
@intFromEnum(std.elf.R_X86_64.GOTPCREL)
|
@intFromEnum(std.elf.R_X86_64.GOTPCREL)
|
||||||
else
|
else
|
||||||
@intFromEnum(std.elf.R_X86_64.PC32);
|
@intFromEnum(std.elf.R_X86_64.PC32);
|
||||||
@ -134,28 +124,15 @@ pub fn emitMir(emit: *Emit) Error!void {
|
|||||||
.r_addend = -4,
|
.r_addend = -4,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (lowered_inst.encoding.mnemonic == .call and sym.flags.needs_zig_got and is_obj_or_static_lib) {
|
const r_type: u32 = if (sym.flags.is_tls)
|
||||||
const r_type = @intFromEnum(std.elf.R_X86_64.PC32);
|
@intFromEnum(std.elf.R_X86_64.TPOFF32)
|
||||||
try atom.addReloc(elf_file, .{
|
else
|
||||||
.r_offset = end_offset - 4,
|
@intFromEnum(std.elf.R_X86_64.@"32");
|
||||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
|
try atom.addReloc(elf_file, .{
|
||||||
.r_addend = -4,
|
.r_offset = end_offset - 4,
|
||||||
});
|
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
|
||||||
} else {
|
.r_addend = 0,
|
||||||
const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
|
});
|
||||||
link.File.Elf.R_ZIG_GOT32
|
|
||||||
else if (sym.flags.needs_got)
|
|
||||||
@intFromEnum(std.elf.R_X86_64.GOT32)
|
|
||||||
else if (sym.flags.is_tls)
|
|
||||||
@intFromEnum(std.elf.R_X86_64.TPOFF32)
|
|
||||||
else
|
|
||||||
@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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (emit.lower.bin_file.cast(.macho)) |macho_file| {
|
} else if (emit.lower.bin_file.cast(.macho)) |macho_file| {
|
||||||
const is_obj_or_static_lib = switch (emit.lower.output_mode) {
|
const is_obj_or_static_lib = switch (emit.lower.output_mode) {
|
||||||
|
|||||||
@ -397,33 +397,40 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ = lower.reloc(.{ .linker_reloc = sym });
|
_ = lower.reloc(.{ .linker_reloc = sym });
|
||||||
break :op if (lower.pic) switch (mnemonic) {
|
if (lower.pic) switch (mnemonic) {
|
||||||
.lea => {
|
.lea => {
|
||||||
|
if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov;
|
||||||
break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
|
break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
|
||||||
},
|
},
|
||||||
.mov => {
|
.mov => {
|
||||||
if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea;
|
if (elf_sym.flags.is_extern_ptr) {
|
||||||
|
const reg = ops[0].reg;
|
||||||
|
lower.result_insts[lower.result_insts_len] =
|
||||||
|
try Instruction.new(.none, .mov, &[_]Operand{
|
||||||
|
.{ .reg = reg.to64() },
|
||||||
|
.{ .mem = Memory.rip(.qword, 0) },
|
||||||
|
});
|
||||||
|
lower.result_insts_len += 1;
|
||||||
|
break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{
|
||||||
|
.reg = reg.to64(),
|
||||||
|
} }) };
|
||||||
|
}
|
||||||
break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
|
break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
} else switch (mnemonic) {
|
} else switch (mnemonic) {
|
||||||
.call => break :op if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) .{
|
.call => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
|
||||||
.imm = Immediate.s(0),
|
|
||||||
} else .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
|
|
||||||
.base = .{ .reg = .ds },
|
.base = .{ .reg = .ds },
|
||||||
}) },
|
}) },
|
||||||
.lea => {
|
.lea => {
|
||||||
emit_mnemonic = .mov;
|
emit_mnemonic = .mov;
|
||||||
break :op .{ .imm = Immediate.s(0) };
|
break :op .{ .imm = Immediate.s(0) };
|
||||||
},
|
},
|
||||||
.mov => {
|
.mov => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
|
||||||
if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea;
|
.base = .{ .reg = .ds },
|
||||||
break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
|
}) },
|
||||||
.base = .{ .reg = .ds },
|
|
||||||
}) };
|
|
||||||
},
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
}
|
||||||
} else if (lower.bin_file.cast(.macho)) |macho_file| {
|
} else if (lower.bin_file.cast(.macho)) |macho_file| {
|
||||||
const zo = macho_file.getZigObject().?;
|
const zo = macho_file.getZigObject().?;
|
||||||
const macho_sym = zo.symbols.items[sym.sym_index];
|
const macho_sym = zo.symbols.items[sym.sym_index];
|
||||||
@ -485,7 +492,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
|
|||||||
.rrmi => inst.data.rrix.fixes,
|
.rrmi => inst.data.rrix.fixes,
|
||||||
.mi_u, .mi_s => inst.data.x.fixes,
|
.mi_u, .mi_s => inst.data.x.fixes,
|
||||||
.m => inst.data.x.fixes,
|
.m => inst.data.x.fixes,
|
||||||
.extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ._,
|
.extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc, .rel => ._,
|
||||||
else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}),
|
else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}),
|
||||||
};
|
};
|
||||||
try lower.emit(switch (fixes) {
|
try lower.emit(switch (fixes) {
|
||||||
@ -617,7 +624,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
|
|||||||
.{ .mem = lower.mem(inst.data.rrix.payload) },
|
.{ .mem = lower.mem(inst.data.rrix.payload) },
|
||||||
.{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },
|
.{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },
|
||||||
},
|
},
|
||||||
.extern_fn_reloc => &.{
|
.extern_fn_reloc, .rel => &.{
|
||||||
.{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
|
.{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
|
||||||
},
|
},
|
||||||
.got_reloc, .direct_reloc, .import_reloc => ops: {
|
.got_reloc, .direct_reloc, .import_reloc => ops: {
|
||||||
@ -660,7 +667,7 @@ const std = @import("std");
|
|||||||
const Air = @import("../../Air.zig");
|
const Air = @import("../../Air.zig");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const ErrorMsg = Zcu.ErrorMsg;
|
const ErrorMsg = Zcu.ErrorMsg;
|
||||||
const Immediate = bits.Immediate;
|
const Immediate = Instruction.Immediate;
|
||||||
const Instruction = encoder.Instruction;
|
const Instruction = encoder.Instruction;
|
||||||
const Lower = @This();
|
const Lower = @This();
|
||||||
const Memory = Instruction.Memory;
|
const Memory = Instruction.Memory;
|
||||||
|
|||||||
@ -769,7 +769,7 @@ pub const Inst = struct {
|
|||||||
/// Uses `imm` payload.
|
/// Uses `imm` payload.
|
||||||
i_u,
|
i_u,
|
||||||
/// Relative displacement operand.
|
/// Relative displacement operand.
|
||||||
/// Uses `imm` payload.
|
/// Uses `reloc` payload.
|
||||||
rel,
|
rel,
|
||||||
/// Register, memory operands.
|
/// Register, memory operands.
|
||||||
/// Uses `rx` payload with extra data of type `Memory`.
|
/// Uses `rx` payload with extra data of type `Memory`.
|
||||||
|
|||||||
@ -569,6 +569,7 @@ pub const Memory = struct {
|
|||||||
pub const Immediate = union(enum) {
|
pub const Immediate = union(enum) {
|
||||||
signed: i32,
|
signed: i32,
|
||||||
unsigned: u64,
|
unsigned: u64,
|
||||||
|
reloc: Symbol,
|
||||||
|
|
||||||
pub fn u(x: u64) Immediate {
|
pub fn u(x: u64) Immediate {
|
||||||
return .{ .unsigned = x };
|
return .{ .unsigned = x };
|
||||||
@ -578,39 +579,19 @@ pub const Immediate = union(enum) {
|
|||||||
return .{ .signed = x };
|
return .{ .signed = x };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asSigned(imm: Immediate, bit_size: u64) i64 {
|
pub fn rel(symbol: Symbol) Immediate {
|
||||||
return switch (imm) {
|
return .{ .reloc = symbol };
|
||||||
.signed => |x| switch (bit_size) {
|
|
||||||
1, 8 => @as(i8, @intCast(x)),
|
|
||||||
16 => @as(i16, @intCast(x)),
|
|
||||||
32, 64 => x,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.unsigned => |x| switch (bit_size) {
|
|
||||||
1, 8 => @as(i8, @bitCast(@as(u8, @intCast(x)))),
|
|
||||||
16 => @as(i16, @bitCast(@as(u16, @intCast(x)))),
|
|
||||||
32 => @as(i32, @bitCast(@as(u32, @intCast(x)))),
|
|
||||||
64 => @bitCast(x),
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 {
|
pub fn format(
|
||||||
return switch (imm) {
|
imm: Immediate,
|
||||||
.signed => |x| switch (bit_size) {
|
comptime fmt: []const u8,
|
||||||
1, 8 => @as(u8, @bitCast(@as(i8, @intCast(x)))),
|
options: std.fmt.FormatOptions,
|
||||||
16 => @as(u16, @bitCast(@as(i16, @intCast(x)))),
|
writer: anytype,
|
||||||
32, 64 => @as(u32, @bitCast(x)),
|
) @TypeOf(writer).Error!void {
|
||||||
else => unreachable,
|
switch (imm) {
|
||||||
},
|
.reloc => |x| try std.fmt.formatType(x, fmt, options, writer, 0),
|
||||||
.unsigned => |x| switch (bit_size) {
|
inline else => |x| try writer.print("{d}", .{x}),
|
||||||
1, 8 => @as(u8, @intCast(x)),
|
}
|
||||||
16 => @as(u16, @intCast(x)),
|
|
||||||
32 => @as(u32, @intCast(x)),
|
|
||||||
64 => x,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,7 +7,6 @@ const testing = std.testing;
|
|||||||
const bits = @import("bits.zig");
|
const bits = @import("bits.zig");
|
||||||
const Encoding = @import("Encoding.zig");
|
const Encoding = @import("Encoding.zig");
|
||||||
const FrameIndex = bits.FrameIndex;
|
const FrameIndex = bits.FrameIndex;
|
||||||
const Immediate = bits.Immediate;
|
|
||||||
const Register = bits.Register;
|
const Register = bits.Register;
|
||||||
const Symbol = bits.Symbol;
|
const Symbol = bits.Symbol;
|
||||||
|
|
||||||
@ -28,6 +27,55 @@ pub const Instruction = struct {
|
|||||||
repnz,
|
repnz,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Immediate = union(enum) {
|
||||||
|
signed: i32,
|
||||||
|
unsigned: u64,
|
||||||
|
|
||||||
|
pub fn u(x: u64) Immediate {
|
||||||
|
return .{ .unsigned = x };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn s(x: i32) Immediate {
|
||||||
|
return .{ .signed = x };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asSigned(imm: Immediate, bit_size: u64) i64 {
|
||||||
|
return switch (imm) {
|
||||||
|
.signed => |x| switch (bit_size) {
|
||||||
|
1, 8 => @as(i8, @intCast(x)),
|
||||||
|
16 => @as(i16, @intCast(x)),
|
||||||
|
32, 64 => x,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.unsigned => |x| switch (bit_size) {
|
||||||
|
1, 8 => @as(i8, @bitCast(@as(u8, @intCast(x)))),
|
||||||
|
16 => @as(i16, @bitCast(@as(u16, @intCast(x)))),
|
||||||
|
32 => @as(i32, @bitCast(@as(u32, @intCast(x)))),
|
||||||
|
64 => @bitCast(x),
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 {
|
||||||
|
return switch (imm) {
|
||||||
|
.signed => |x| switch (bit_size) {
|
||||||
|
1, 8 => @as(u8, @bitCast(@as(i8, @intCast(x)))),
|
||||||
|
16 => @as(u16, @bitCast(@as(i16, @intCast(x)))),
|
||||||
|
32, 64 => @as(u32, @bitCast(x)),
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.unsigned => |x| switch (bit_size) {
|
||||||
|
1, 8 => @as(u8, @intCast(x)),
|
||||||
|
16 => @as(u16, @intCast(x)),
|
||||||
|
32 => @as(u32, @intCast(x)),
|
||||||
|
64 => x,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const Memory = union(enum) {
|
pub const Memory = union(enum) {
|
||||||
sib: Sib,
|
sib: Sib,
|
||||||
rip: Rip,
|
rip: Rip,
|
||||||
@ -1119,7 +1167,7 @@ test "encode" {
|
|||||||
|
|
||||||
const inst = try Instruction.new(.none, .mov, &.{
|
const inst = try Instruction.new(.none, .mov, &.{
|
||||||
.{ .reg = .rbx },
|
.{ .reg = .rbx },
|
||||||
.{ .imm = Immediate.u(4) },
|
.{ .imm = Instruction.Immediate.u(4) },
|
||||||
});
|
});
|
||||||
try inst.encode(buf.writer(), .{});
|
try inst.encode(buf.writer(), .{});
|
||||||
try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);
|
try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);
|
||||||
@ -1129,47 +1177,47 @@ test "lower I encoding" {
|
|||||||
var enc = TestEncode{};
|
var enc = TestEncode{};
|
||||||
|
|
||||||
try enc.encode(.push, &.{
|
try enc.encode(.push, &.{
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10");
|
try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10");
|
||||||
|
|
||||||
try enc.encode(.push, &.{
|
try enc.encode(.push, &.{
|
||||||
.{ .imm = Immediate.u(0x1000) },
|
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000");
|
try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000");
|
||||||
|
|
||||||
try enc.encode(.push, &.{
|
try enc.encode(.push, &.{
|
||||||
.{ .imm = Immediate.u(0x10000000) },
|
.{ .imm = Instruction.Immediate.u(0x10000000) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000");
|
try expectEqualHexStrings("\x68\x00\x00\x00\x10", enc.code(), "push 0x10000000");
|
||||||
|
|
||||||
try enc.encode(.adc, &.{
|
try enc.encode(.adc, &.{
|
||||||
.{ .reg = .rax },
|
.{ .reg = .rax },
|
||||||
.{ .imm = Immediate.u(0x10000000) },
|
.{ .imm = Instruction.Immediate.u(0x10000000) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000");
|
try expectEqualHexStrings("\x48\x15\x00\x00\x00\x10", enc.code(), "adc rax, 0x10000000");
|
||||||
|
|
||||||
try enc.encode(.add, &.{
|
try enc.encode(.add, &.{
|
||||||
.{ .reg = .al },
|
.{ .reg = .al },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10");
|
try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10");
|
||||||
|
|
||||||
try enc.encode(.add, &.{
|
try enc.encode(.add, &.{
|
||||||
.{ .reg = .rax },
|
.{ .reg = .rax },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
|
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
|
||||||
|
|
||||||
try enc.encode(.sbb, &.{
|
try enc.encode(.sbb, &.{
|
||||||
.{ .reg = .ax },
|
.{ .reg = .ax },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10");
|
try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10");
|
||||||
|
|
||||||
try enc.encode(.xor, &.{
|
try enc.encode(.xor, &.{
|
||||||
.{ .reg = .al },
|
.{ .reg = .al },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10");
|
try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10");
|
||||||
}
|
}
|
||||||
@ -1179,43 +1227,43 @@ test "lower MI encoding" {
|
|||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .reg = .r12 },
|
.{ .reg = .r12 },
|
||||||
.{ .imm = Immediate.u(0x1000) },
|
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
|
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
|
||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) },
|
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
|
try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
|
||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .reg = .r12 },
|
.{ .reg = .r12 },
|
||||||
.{ .imm = Immediate.u(0x1000) },
|
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
|
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
|
||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .reg = .r12 },
|
.{ .reg = .r12 },
|
||||||
.{ .imm = Immediate.u(0x1000) },
|
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
|
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
|
||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .reg = .rax },
|
.{ .reg = .rax },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
|
try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
|
||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) },
|
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
|
try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
|
||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .mem = Instruction.Memory.rip(.qword, 0x10) },
|
.{ .mem = Instruction.Memory.rip(.qword, 0x10) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
|
"\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
|
||||||
@ -1225,19 +1273,19 @@ test "lower MI encoding" {
|
|||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) },
|
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");
|
try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10");
|
||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) },
|
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) },
|
||||||
.{ .imm = Immediate.s(-16) },
|
.{ .imm = Instruction.Immediate.s(-16) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");
|
try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16");
|
||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) },
|
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
|
try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
|
||||||
|
|
||||||
@ -1247,7 +1295,7 @@ test "lower MI encoding" {
|
|||||||
.disp = 0x10000000,
|
.disp = 0x10000000,
|
||||||
.scale_index = .{ .scale = 2, .index = .rcx },
|
.scale_index = .{ .scale = 2, .index = .rcx },
|
||||||
}) },
|
}) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
|
"\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
|
||||||
@ -1257,43 +1305,43 @@ test "lower MI encoding" {
|
|||||||
|
|
||||||
try enc.encode(.adc, &.{
|
try enc.encode(.adc, &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
|
.{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
|
try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
|
||||||
|
|
||||||
try enc.encode(.adc, &.{
|
try enc.encode(.adc, &.{
|
||||||
.{ .mem = Instruction.Memory.rip(.qword, 0) },
|
.{ .mem = Instruction.Memory.rip(.qword, 0) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");
|
try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10");
|
||||||
|
|
||||||
try enc.encode(.adc, &.{
|
try enc.encode(.adc, &.{
|
||||||
.{ .reg = .rax },
|
.{ .reg = .rax },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
|
try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
|
||||||
|
|
||||||
try enc.encode(.add, &.{
|
try enc.encode(.add, &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) },
|
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
|
try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
|
||||||
|
|
||||||
try enc.encode(.add, &.{
|
try enc.encode(.add, &.{
|
||||||
.{ .reg = .rax },
|
.{ .reg = .rax },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
|
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
|
||||||
|
|
||||||
try enc.encode(.add, &.{
|
try enc.encode(.add, &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
|
.{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
|
||||||
.{ .imm = Immediate.s(-0x10) },
|
.{ .imm = Instruction.Immediate.s(-0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");
|
try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10");
|
||||||
|
|
||||||
try enc.encode(.@"and", &.{
|
try enc.encode(.@"and", &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
|
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x83\x24\x25\x00\x00\x00\x10\x10",
|
"\x83\x24\x25\x00\x00\x00\x10\x10",
|
||||||
@ -1303,7 +1351,7 @@ test "lower MI encoding" {
|
|||||||
|
|
||||||
try enc.encode(.@"and", &.{
|
try enc.encode(.@"and", &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) },
|
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x26\x83\x24\x25\x00\x00\x00\x10\x10",
|
"\x26\x83\x24\x25\x00\x00\x00\x10\x10",
|
||||||
@ -1313,7 +1361,7 @@ test "lower MI encoding" {
|
|||||||
|
|
||||||
try enc.encode(.@"and", &.{
|
try enc.encode(.@"and", &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
|
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x41\x83\xA4\x24\x00\x00\x00\x10\x10",
|
"\x41\x83\xA4\x24\x00\x00\x00\x10\x10",
|
||||||
@ -1323,7 +1371,7 @@ test "lower MI encoding" {
|
|||||||
|
|
||||||
try enc.encode(.sub, &.{
|
try enc.encode(.sub, &.{
|
||||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
|
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x41\x83\xAB\x00\x00\x00\x10\x10",
|
"\x41\x83\xAB\x00\x00\x00\x10\x10",
|
||||||
@ -1542,14 +1590,14 @@ test "lower RMI encoding" {
|
|||||||
try enc.encode(.imul, &.{
|
try enc.encode(.imul, &.{
|
||||||
.{ .reg = .r11 },
|
.{ .reg = .r11 },
|
||||||
.{ .reg = .r12 },
|
.{ .reg = .r12 },
|
||||||
.{ .imm = Immediate.s(-2) },
|
.{ .imm = Instruction.Immediate.s(-2) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2");
|
try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2");
|
||||||
|
|
||||||
try enc.encode(.imul, &.{
|
try enc.encode(.imul, &.{
|
||||||
.{ .reg = .r11 },
|
.{ .reg = .r11 },
|
||||||
.{ .mem = Instruction.Memory.rip(.qword, -16) },
|
.{ .mem = Instruction.Memory.rip(.qword, -16) },
|
||||||
.{ .imm = Immediate.s(-1024) },
|
.{ .imm = Instruction.Immediate.s(-1024) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF",
|
"\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF",
|
||||||
@ -1560,7 +1608,7 @@ test "lower RMI encoding" {
|
|||||||
try enc.encode(.imul, &.{
|
try enc.encode(.imul, &.{
|
||||||
.{ .reg = .bx },
|
.{ .reg = .bx },
|
||||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
|
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
|
||||||
.{ .imm = Immediate.s(-1024) },
|
.{ .imm = Instruction.Immediate.s(-1024) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x66\x69\x5D\xF0\x00\xFC",
|
"\x66\x69\x5D\xF0\x00\xFC",
|
||||||
@ -1571,7 +1619,7 @@ test "lower RMI encoding" {
|
|||||||
try enc.encode(.imul, &.{
|
try enc.encode(.imul, &.{
|
||||||
.{ .reg = .bx },
|
.{ .reg = .bx },
|
||||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
|
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
|
||||||
.{ .imm = Immediate.u(1024) },
|
.{ .imm = Instruction.Immediate.u(1024) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x66\x69\x5D\xF0\x00\x04",
|
"\x66\x69\x5D\xF0\x00\x04",
|
||||||
@ -1687,7 +1735,7 @@ test "lower M encoding" {
|
|||||||
try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
|
try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
|
||||||
|
|
||||||
try enc.encode(.call, &.{
|
try enc.encode(.call, &.{
|
||||||
.{ .imm = Immediate.s(0) },
|
.{ .imm = Instruction.Immediate.s(0) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
|
try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
|
||||||
|
|
||||||
@ -1746,7 +1794,7 @@ test "lower OI encoding" {
|
|||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .reg = .rax },
|
.{ .reg = .rax },
|
||||||
.{ .imm = Immediate.u(0x1000000000000000) },
|
.{ .imm = Instruction.Immediate.u(0x1000000000000000) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
|
"\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
|
||||||
@ -1756,7 +1804,7 @@ test "lower OI encoding" {
|
|||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .reg = .r11 },
|
.{ .reg = .r11 },
|
||||||
.{ .imm = Immediate.u(0x1000000000000000) },
|
.{ .imm = Instruction.Immediate.u(0x1000000000000000) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings(
|
try expectEqualHexStrings(
|
||||||
"\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
|
"\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
|
||||||
@ -1766,19 +1814,19 @@ test "lower OI encoding" {
|
|||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .reg = .r11d },
|
.{ .reg = .r11d },
|
||||||
.{ .imm = Immediate.u(0x10000000) },
|
.{ .imm = Instruction.Immediate.u(0x10000000) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000");
|
try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", enc.code(), "mov r11d, 0x10000000");
|
||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .reg = .r11w },
|
.{ .reg = .r11w },
|
||||||
.{ .imm = Immediate.u(0x1000) },
|
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000");
|
try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000");
|
||||||
|
|
||||||
try enc.encode(.mov, &.{
|
try enc.encode(.mov, &.{
|
||||||
.{ .reg = .r11b },
|
.{ .reg = .r11b },
|
||||||
.{ .imm = Immediate.u(0x10) },
|
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||||
});
|
});
|
||||||
try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10");
|
try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10");
|
||||||
}
|
}
|
||||||
@ -1900,7 +1948,7 @@ test "invalid instruction" {
|
|||||||
.{ .reg = .r12d },
|
.{ .reg = .r12d },
|
||||||
});
|
});
|
||||||
try invalidInstruction(.push, &.{
|
try invalidInstruction(.push, &.{
|
||||||
.{ .imm = Immediate.u(0x1000000000000000) },
|
.{ .imm = Instruction.Immediate.u(0x1000000000000000) },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2213,7 +2261,7 @@ const Assembler = struct {
|
|||||||
.immediate => {
|
.immediate => {
|
||||||
const is_neg = if (as.expect(.minus)) |_| true else |_| false;
|
const is_neg = if (as.expect(.minus)) |_| true else |_| false;
|
||||||
const imm_tok = try as.expect(.numeral);
|
const imm_tok = try as.expect(.numeral);
|
||||||
const imm: Immediate = if (is_neg) blk: {
|
const imm: Instruction.Immediate = if (is_neg) blk: {
|
||||||
const imm = try std.fmt.parseInt(i32, as.source(imm_tok), 0);
|
const imm = try std.fmt.parseInt(i32, as.source(imm_tok), 0);
|
||||||
break :blk .{ .signed = imm * -1 };
|
break :blk .{ .signed = imm * -1 };
|
||||||
} else .{ .unsigned = try std.fmt.parseInt(u64, as.source(imm_tok), 0) };
|
} else .{ .unsigned = try std.fmt.parseInt(u64, as.source(imm_tok), 0) };
|
||||||
|
|||||||
@ -828,6 +828,9 @@ pub const GenResult = union(enum) {
|
|||||||
/// Reference to memory location but deferred until linker allocated the Decl in memory.
|
/// 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.
|
/// Traditionally, this corresponds to emitting a relocation in a relocatable object file.
|
||||||
load_symbol: u32,
|
load_symbol: 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.
|
||||||
|
lea_symbol: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn mcv(val: MCValue) GenResult {
|
fn mcv(val: MCValue) GenResult {
|
||||||
@ -895,16 +898,15 @@ fn genNavRef(
|
|||||||
if (lf.cast(.elf)) |elf_file| {
|
if (lf.cast(.elf)) |elf_file| {
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
const zo = elf_file.zigObjectPtr().?;
|
||||||
if (is_extern) {
|
if (is_extern) {
|
||||||
// TODO audit this
|
|
||||||
const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
|
const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
|
||||||
zo.symbol(sym_index).flags.needs_got = true;
|
zo.symbol(sym_index).flags.is_extern_ptr = true;
|
||||||
return GenResult.mcv(.{ .load_symbol = sym_index });
|
return GenResult.mcv(.{ .lea_symbol = sym_index });
|
||||||
}
|
}
|
||||||
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index);
|
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, nav_index);
|
||||||
if (!single_threaded and is_threadlocal) {
|
if (!single_threaded and is_threadlocal) {
|
||||||
return GenResult.mcv(.{ .load_tlv = sym_index });
|
return GenResult.mcv(.{ .load_tlv = sym_index });
|
||||||
}
|
}
|
||||||
return GenResult.mcv(.{ .load_symbol = sym_index });
|
return GenResult.mcv(.{ .lea_symbol = sym_index });
|
||||||
} else if (lf.cast(.macho)) |macho_file| {
|
} else if (lf.cast(.macho)) |macho_file| {
|
||||||
const zo = macho_file.getZigObject().?;
|
const zo = macho_file.getZigObject().?;
|
||||||
if (is_extern) {
|
if (is_extern) {
|
||||||
|
|||||||
115
src/link/Elf.zig
115
src/link/Elf.zig
@ -64,9 +64,6 @@ phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},
|
|||||||
/// Tracked loadable segments during incremental linking.
|
/// Tracked loadable segments during incremental linking.
|
||||||
/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
|
/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
|
||||||
phdr_zig_load_re_index: ?u16 = null,
|
phdr_zig_load_re_index: ?u16 = null,
|
||||||
/// The index into the program headers of the global offset table.
|
|
||||||
/// It needs PT_LOAD and Read flags.
|
|
||||||
phdr_zig_got_index: ?u16 = null,
|
|
||||||
/// The index into the program headers of a PT_LOAD program header with Read flag
|
/// The index into the program headers of a PT_LOAD program header with Read flag
|
||||||
phdr_zig_load_ro_index: ?u16 = null,
|
phdr_zig_load_ro_index: ?u16 = null,
|
||||||
/// The index into the program headers of a PT_LOAD program header with Write flag
|
/// The index into the program headers of a PT_LOAD program header with Write flag
|
||||||
@ -130,8 +127,6 @@ plt_got: PltGotSection = .{},
|
|||||||
copy_rel: CopyRelSection = .{},
|
copy_rel: CopyRelSection = .{},
|
||||||
/// .rela.plt section
|
/// .rela.plt section
|
||||||
rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
|
rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
|
||||||
/// .got.zig section
|
|
||||||
zig_got: ZigGotSection = .{},
|
|
||||||
/// SHT_GROUP sections
|
/// SHT_GROUP sections
|
||||||
/// Applies only to a relocatable.
|
/// Applies only to a relocatable.
|
||||||
comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{},
|
comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{},
|
||||||
@ -142,7 +137,6 @@ zig_text_section_index: ?u32 = null,
|
|||||||
zig_data_rel_ro_section_index: ?u32 = null,
|
zig_data_rel_ro_section_index: ?u32 = null,
|
||||||
zig_data_section_index: ?u32 = null,
|
zig_data_section_index: ?u32 = null,
|
||||||
zig_bss_section_index: ?u32 = null,
|
zig_bss_section_index: ?u32 = null,
|
||||||
zig_got_section_index: ?u32 = null,
|
|
||||||
|
|
||||||
debug_info_section_index: ?u32 = null,
|
debug_info_section_index: ?u32 = null,
|
||||||
debug_abbrev_section_index: ?u32 = null,
|
debug_abbrev_section_index: ?u32 = null,
|
||||||
@ -474,7 +468,6 @@ pub fn deinit(self: *Elf) void {
|
|||||||
self.copy_rel.deinit(gpa);
|
self.copy_rel.deinit(gpa);
|
||||||
self.rela_dyn.deinit(gpa);
|
self.rela_dyn.deinit(gpa);
|
||||||
self.rela_plt.deinit(gpa);
|
self.rela_plt.deinit(gpa);
|
||||||
self.zig_got.deinit(gpa);
|
|
||||||
self.comdat_group_sections.deinit(gpa);
|
self.comdat_group_sections.deinit(gpa);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,28 +604,13 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
|
|||||||
.type = elf.PT_LOAD,
|
.type = elf.PT_LOAD,
|
||||||
.offset = off,
|
.offset = off,
|
||||||
.filesz = filesz,
|
.filesz = filesz,
|
||||||
.addr = if (ptr_bit_width >= 32) 0x8000000 else 0x8000,
|
.addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000,
|
||||||
.memsz = filesz,
|
.memsz = filesz,
|
||||||
.@"align" = self.page_size,
|
.@"align" = self.page_size,
|
||||||
.flags = elf.PF_X | elf.PF_R | elf.PF_W,
|
.flags = elf.PF_X | elf.PF_R | elf.PF_W,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.phdr_zig_got_index == null) {
|
|
||||||
const alignment = self.page_size;
|
|
||||||
const filesz = @as(u64, ptr_size) * options.symbol_count_hint;
|
|
||||||
const off = self.findFreeSpace(filesz, alignment);
|
|
||||||
self.phdr_zig_got_index = try self.addPhdr(.{
|
|
||||||
.type = elf.PT_LOAD,
|
|
||||||
.offset = off,
|
|
||||||
.filesz = filesz,
|
|
||||||
.addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000,
|
|
||||||
.memsz = filesz,
|
|
||||||
.@"align" = alignment,
|
|
||||||
.flags = elf.PF_R | elf.PF_W,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.phdr_zig_load_ro_index == null) {
|
if (self.phdr_zig_load_ro_index == null) {
|
||||||
const alignment = self.page_size;
|
const alignment = self.page_size;
|
||||||
const filesz: u64 = 1024;
|
const filesz: u64 = 1024;
|
||||||
@ -701,27 +679,6 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
|
|||||||
try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
|
try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.zig_got_section_index == null and !self.base.isRelocatable()) {
|
|
||||||
self.zig_got_section_index = try self.addSection(.{
|
|
||||||
.name = try self.insertShString(".got.zig"),
|
|
||||||
.type = elf.SHT_PROGBITS,
|
|
||||||
.addralign = ptr_size,
|
|
||||||
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
|
|
||||||
.offset = std.math.maxInt(u64),
|
|
||||||
});
|
|
||||||
const shdr = &self.shdrs.items[self.zig_got_section_index.?];
|
|
||||||
const phndx = self.phdr_zig_got_index.?;
|
|
||||||
const phdr = self.phdrs.items[phndx];
|
|
||||||
shdr.sh_addr = phdr.p_vaddr;
|
|
||||||
shdr.sh_offset = phdr.p_offset;
|
|
||||||
shdr.sh_size = phdr.p_memsz;
|
|
||||||
try self.phdr_to_shdr_table.putNoClobber(
|
|
||||||
gpa,
|
|
||||||
self.zig_got_section_index.?,
|
|
||||||
self.phdr_zig_got_index.?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.zig_data_rel_ro_section_index == null) {
|
if (self.zig_data_rel_ro_section_index == null) {
|
||||||
self.zig_data_rel_ro_section_index = try self.addSection(.{
|
self.zig_data_rel_ro_section_index = try self.addSection(.{
|
||||||
.name = try self.insertShString(".data.rel.ro.zig"),
|
.name = try self.insertShString(".data.rel.ro.zig"),
|
||||||
@ -900,6 +857,11 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
|
|||||||
const shdr = &self.shdrs.items[shdr_index];
|
const shdr = &self.shdrs.items[shdr_index];
|
||||||
const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null;
|
const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null;
|
||||||
const is_zerofill = shdr.sh_type == elf.SHT_NOBITS;
|
const is_zerofill = shdr.sh_type == elf.SHT_NOBITS;
|
||||||
|
log.debug("allocated size {x} of {s}, needed size {x}", .{
|
||||||
|
self.allocatedSize(shdr.sh_offset),
|
||||||
|
self.getShString(shdr.sh_name),
|
||||||
|
needed_size,
|
||||||
|
});
|
||||||
|
|
||||||
if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {
|
if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {
|
||||||
const existing_size = shdr.sh_size;
|
const existing_size = shdr.sh_size;
|
||||||
@ -3156,8 +3118,8 @@ fn initSyntheticSections(self: *Elf) !void {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const needs_rela_dyn = blk: {
|
const needs_rela_dyn = blk: {
|
||||||
if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or
|
if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or self.copy_rel.symbols.items.len > 0)
|
||||||
self.zig_got.flags.needs_rela or self.copy_rel.symbols.items.len > 0) break :blk true;
|
break :blk true;
|
||||||
if (self.zigObjectPtr()) |zig_object| {
|
if (self.zigObjectPtr()) |zig_object| {
|
||||||
if (zig_object.num_dynrelocs > 0) break :blk true;
|
if (zig_object.num_dynrelocs > 0) break :blk true;
|
||||||
}
|
}
|
||||||
@ -3562,7 +3524,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
|
|||||||
|
|
||||||
for (&[_]*?u16{
|
for (&[_]*?u16{
|
||||||
&self.phdr_zig_load_re_index,
|
&self.phdr_zig_load_re_index,
|
||||||
&self.phdr_zig_got_index,
|
|
||||||
&self.phdr_zig_load_ro_index,
|
&self.phdr_zig_load_ro_index,
|
||||||
&self.phdr_zig_load_zerofill_index,
|
&self.phdr_zig_load_zerofill_index,
|
||||||
&self.phdr_table_index,
|
&self.phdr_table_index,
|
||||||
@ -3694,7 +3655,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
|
|||||||
&self.versym_section_index,
|
&self.versym_section_index,
|
||||||
&self.verneed_section_index,
|
&self.verneed_section_index,
|
||||||
&self.zig_text_section_index,
|
&self.zig_text_section_index,
|
||||||
&self.zig_got_section_index,
|
|
||||||
&self.zig_data_rel_ro_section_index,
|
&self.zig_data_rel_ro_section_index,
|
||||||
&self.zig_data_section_index,
|
&self.zig_data_section_index,
|
||||||
&self.zig_bss_section_index,
|
&self.zig_bss_section_index,
|
||||||
@ -3893,7 +3853,7 @@ fn updateSectionSizes(self: *Elf) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (self.rela_dyn_section_index) |shndx| {
|
if (self.rela_dyn_section_index) |shndx| {
|
||||||
var num = self.got.numRela(self) + self.copy_rel.numRela() + self.zig_got.numRela();
|
var num = self.got.numRela(self) + self.copy_rel.numRela();
|
||||||
if (self.zigObjectPtr()) |zig_object| {
|
if (self.zigObjectPtr()) |zig_object| {
|
||||||
num += zig_object.num_dynrelocs;
|
num += zig_object.num_dynrelocs;
|
||||||
}
|
}
|
||||||
@ -4431,15 +4391,6 @@ pub fn updateSymtabSize(self: *Elf) !void {
|
|||||||
strsize += ctx.strsize;
|
strsize += ctx.strsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.zigObjectPtr()) |_| {
|
|
||||||
if (self.zig_got_section_index) |_| {
|
|
||||||
self.zig_got.output_symtab_ctx.ilocal = nlocals + 1;
|
|
||||||
self.zig_got.updateSymtabSize(self);
|
|
||||||
nlocals += self.zig_got.output_symtab_ctx.nlocals;
|
|
||||||
strsize += self.zig_got.output_symtab_ctx.strsize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.got_section_index) |_| {
|
if (self.got_section_index) |_| {
|
||||||
self.got.output_symtab_ctx.ilocal = nlocals + 1;
|
self.got.output_symtab_ctx.ilocal = nlocals + 1;
|
||||||
self.got.updateSymtabSize(self);
|
self.got.updateSymtabSize(self);
|
||||||
@ -4576,9 +4527,6 @@ fn writeSyntheticSections(self: *Elf) !void {
|
|||||||
const shdr = self.shdrs.items[shndx];
|
const shdr = self.shdrs.items[shndx];
|
||||||
try self.got.addRela(self);
|
try self.got.addRela(self);
|
||||||
try self.copy_rel.addRela(self);
|
try self.copy_rel.addRela(self);
|
||||||
if (self.zigObjectPtr()) |_| {
|
|
||||||
try self.zig_got.addRela(self);
|
|
||||||
}
|
|
||||||
self.sortRelaDyn();
|
self.sortRelaDyn();
|
||||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);
|
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);
|
||||||
}
|
}
|
||||||
@ -4674,10 +4622,6 @@ pub fn writeSymtab(self: *Elf) !void {
|
|||||||
obj.asFile().writeSymtab(self);
|
obj.asFile().writeSymtab(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.zig_got_section_index) |_| {
|
|
||||||
self.zig_got.writeSymtab(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.got_section_index) |_| {
|
if (self.got_section_index) |_| {
|
||||||
self.got.writeSymtab(self);
|
self.got.writeSymtab(self);
|
||||||
}
|
}
|
||||||
@ -5085,7 +5029,6 @@ pub fn isZigSection(self: Elf, shndx: u32) bool {
|
|||||||
self.zig_data_rel_ro_section_index,
|
self.zig_data_rel_ro_section_index,
|
||||||
self.zig_data_section_index,
|
self.zig_data_section_index,
|
||||||
self.zig_bss_section_index,
|
self.zig_bss_section_index,
|
||||||
self.zig_got_section_index,
|
|
||||||
}) |maybe_index| {
|
}) |maybe_index| {
|
||||||
if (maybe_index) |index| {
|
if (maybe_index) |index| {
|
||||||
if (index == shndx) return true;
|
if (index == shndx) return true;
|
||||||
@ -5657,10 +5600,11 @@ fn fmtDumpState(
|
|||||||
|
|
||||||
if (self.zigObjectPtr()) |zig_object| {
|
if (self.zigObjectPtr()) |zig_object| {
|
||||||
try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path });
|
try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path });
|
||||||
try writer.print("{}{}\n", .{
|
try writer.print("{}{}", .{
|
||||||
zig_object.fmtAtoms(self),
|
zig_object.fmtAtoms(self),
|
||||||
zig_object.fmtSymtab(self),
|
zig_object.fmtSymtab(self),
|
||||||
});
|
});
|
||||||
|
try writer.writeByte('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
for (self.objects.items) |index| {
|
for (self.objects.items) |index| {
|
||||||
@ -5700,7 +5644,6 @@ fn fmtDumpState(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.print("{}\n", .{self.zig_got.fmt(self)});
|
|
||||||
try writer.print("{}\n", .{self.got.fmt(self)});
|
try writer.print("{}\n", .{self.got.fmt(self)});
|
||||||
try writer.print("{}\n", .{self.plt.fmt(self)});
|
try writer.print("{}\n", .{self.plt.fmt(self)});
|
||||||
|
|
||||||
@ -5991,41 +5934,6 @@ const RelaSection = struct {
|
|||||||
};
|
};
|
||||||
const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
|
const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
|
||||||
|
|
||||||
pub const R_ZIG_GOT32: u32 = 0xff00;
|
|
||||||
pub const R_ZIG_GOTPCREL: u32 = 0xff01;
|
|
||||||
pub const R_ZIG_GOT_HI20: u32 = 0xff02;
|
|
||||||
pub const R_ZIG_GOT_LO12: u32 = 0xff03;
|
|
||||||
pub const R_GOT_HI20_STATIC: u32 = 0xff04;
|
|
||||||
pub const R_GOT_LO12_I_STATIC: u32 = 0xff05;
|
|
||||||
|
|
||||||
// Comptime asserts that no Zig relocs overlap with another ISA's reloc number
|
|
||||||
comptime {
|
|
||||||
const zig_relocs = .{
|
|
||||||
R_ZIG_GOT32,
|
|
||||||
R_ZIG_GOT_HI20,
|
|
||||||
R_ZIG_GOT_LO12,
|
|
||||||
R_ZIG_GOTPCREL,
|
|
||||||
R_GOT_HI20_STATIC,
|
|
||||||
R_GOT_LO12_I_STATIC,
|
|
||||||
};
|
|
||||||
|
|
||||||
const other_relocs = .{
|
|
||||||
elf.R_X86_64,
|
|
||||||
elf.R_AARCH64,
|
|
||||||
elf.R_RISCV,
|
|
||||||
elf.R_PPC64,
|
|
||||||
};
|
|
||||||
|
|
||||||
@setEvalBranchQuota(@min(other_relocs.len * zig_relocs.len * 256, 6200));
|
|
||||||
for (other_relocs) |relocs| {
|
|
||||||
for (@typeInfo(relocs).Enum.fields) |reloc| {
|
|
||||||
for (zig_relocs) |zig_reloc| {
|
|
||||||
assert(reloc.value != zig_reloc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
|
fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
|
||||||
return switch (cpu_arch) {
|
return switch (cpu_arch) {
|
||||||
.mips, .mipsel, .mips64, .mips64el => "__start",
|
.mips, .mipsel, .mips64, .mips64el => "__start",
|
||||||
@ -6095,6 +6003,5 @@ const StringTable = @import("StringTable.zig");
|
|||||||
const Thunk = thunks.Thunk;
|
const Thunk = thunks.Thunk;
|
||||||
const Value = @import("../Value.zig");
|
const Value = @import("../Value.zig");
|
||||||
const VerneedSection = synthetic_sections.VerneedSection;
|
const VerneedSection = synthetic_sections.VerneedSection;
|
||||||
const ZigGotSection = synthetic_sections.ZigGotSection;
|
|
||||||
const ZigObject = @import("Elf/ZigObject.zig");
|
const ZigObject = @import("Elf/ZigObject.zig");
|
||||||
const riscv = @import("riscv.zig");
|
const riscv = @import("riscv.zig");
|
||||||
|
|||||||
@ -746,12 +746,10 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
|
|||||||
const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset));
|
const P = self.address(elf_file) + @as(i64, @intCast(rel.r_offset));
|
||||||
// Addend from the relocation.
|
// Addend from the relocation.
|
||||||
const A = rel.r_addend;
|
const A = rel.r_addend;
|
||||||
// Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
|
// Address of the target symbol - can be address of the symbol within an atom or address of PLT stub, or address of a Zig trampoline.
|
||||||
const S = target.address(.{}, elf_file);
|
const S = target.address(.{}, elf_file);
|
||||||
// Address of the global offset table.
|
// Address of the global offset table.
|
||||||
const GOT = elf_file.gotAddress();
|
const GOT = elf_file.gotAddress();
|
||||||
// Address of the .zig.got table entry if any.
|
|
||||||
const ZIG_GOT = target.zigGotAddress(elf_file);
|
|
||||||
// Relative offset to the start of the global offset table.
|
// Relative offset to the start of the global offset table.
|
||||||
const G = target.gotAddress(elf_file) - GOT;
|
const G = target.gotAddress(elf_file) - GOT;
|
||||||
// // Address of the thread pointer.
|
// // Address of the thread pointer.
|
||||||
@ -759,19 +757,18 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
|
|||||||
// Address of the dynamic thread pointer.
|
// Address of the dynamic thread pointer.
|
||||||
const DTP = elf_file.dtpAddress();
|
const DTP = elf_file.dtpAddress();
|
||||||
|
|
||||||
relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{
|
relocs_log.debug(" {s}: {x}: [{x} => {x}] GOT({x}) ({s})", .{
|
||||||
relocation.fmtRelocType(rel.r_type(), cpu_arch),
|
relocation.fmtRelocType(rel.r_type(), cpu_arch),
|
||||||
r_offset,
|
r_offset,
|
||||||
P,
|
P,
|
||||||
S + A,
|
S + A,
|
||||||
G + GOT + A,
|
G + GOT + A,
|
||||||
ZIG_GOT + A,
|
|
||||||
target.name(elf_file),
|
target.name(elf_file),
|
||||||
});
|
});
|
||||||
|
|
||||||
try stream.seekTo(r_offset);
|
try stream.seekTo(r_offset);
|
||||||
|
|
||||||
const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP, ZIG_GOT };
|
const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP };
|
||||||
|
|
||||||
switch (cpu_arch) {
|
switch (cpu_arch) {
|
||||||
.x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
|
.x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
|
||||||
@ -956,7 +953,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
|
|||||||
// Address of the dynamic thread pointer.
|
// Address of the dynamic thread pointer.
|
||||||
const DTP = elf_file.dtpAddress();
|
const DTP = elf_file.dtpAddress();
|
||||||
|
|
||||||
const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP, 0 };
|
const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP };
|
||||||
|
|
||||||
relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{
|
relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{
|
||||||
relocation.fmtRelocType(rel.r_type(), cpu_arch),
|
relocation.fmtRelocType(rel.r_type(), cpu_arch),
|
||||||
@ -1025,7 +1022,7 @@ pub fn format(
|
|||||||
_ = unused_fmt_string;
|
_ = unused_fmt_string;
|
||||||
_ = options;
|
_ = options;
|
||||||
_ = writer;
|
_ = writer;
|
||||||
@compileError("do not format symbols directly");
|
@compileError("do not format Atom directly");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fmt(atom: Atom, elf_file: *Elf) std.fmt.Formatter(format2) {
|
pub fn fmt(atom: Atom, elf_file: *Elf) std.fmt.Formatter(format2) {
|
||||||
@ -1051,8 +1048,8 @@ fn format2(
|
|||||||
const atom = ctx.atom;
|
const atom = ctx.atom;
|
||||||
const elf_file = ctx.elf_file;
|
const elf_file = ctx.elf_file;
|
||||||
try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{
|
try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{
|
||||||
atom.atom_index, atom.name(elf_file), atom.address(elf_file),
|
atom.atom_index, atom.name(elf_file), atom.address(elf_file),
|
||||||
atom.output_section_index, atom.alignment, atom.size,
|
atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size,
|
||||||
});
|
});
|
||||||
if (atom.fdes(elf_file).len > 0) {
|
if (atom.fdes(elf_file).len > 0) {
|
||||||
try writer.writeAll(" : fdes{ ");
|
try writer.writeAll(" : fdes{ ");
|
||||||
@ -1180,16 +1177,7 @@ const x86_64 = struct {
|
|||||||
.TLSDESC_CALL,
|
.TLSDESC_CALL,
|
||||||
=> {},
|
=> {},
|
||||||
|
|
||||||
else => |x| switch (@intFromEnum(x)) {
|
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
||||||
// Zig custom relocations
|
|
||||||
Elf.R_ZIG_GOT32,
|
|
||||||
Elf.R_ZIG_GOTPCREL,
|
|
||||||
=> {
|
|
||||||
assert(symbol.flags.has_zig_got);
|
|
||||||
},
|
|
||||||
|
|
||||||
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1209,7 +1197,7 @@ const x86_64 = struct {
|
|||||||
|
|
||||||
const cwriter = stream.writer();
|
const cwriter = stream.writer();
|
||||||
|
|
||||||
const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args;
|
const P, const A, const S, const GOT, const G, const TP, const DTP = args;
|
||||||
|
|
||||||
switch (r_type) {
|
switch (r_type) {
|
||||||
.NONE => unreachable,
|
.NONE => unreachable,
|
||||||
@ -1224,9 +1212,8 @@ const x86_64 = struct {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
.PLT32,
|
.PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
|
||||||
.PC32,
|
.PC32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
|
||||||
=> try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
|
|
||||||
|
|
||||||
.GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
|
.GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
|
||||||
.GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),
|
.GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),
|
||||||
@ -1327,15 +1314,9 @@ const x86_64 = struct {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little),
|
.GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + A)), .little),
|
||||||
|
|
||||||
else => |x| switch (@intFromEnum(x)) {
|
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
||||||
// Zig custom relocations
|
|
||||||
Elf.R_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little),
|
|
||||||
Elf.R_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little),
|
|
||||||
|
|
||||||
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1355,7 +1336,7 @@ const x86_64 = struct {
|
|||||||
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
|
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
|
||||||
const cwriter = stream.writer();
|
const cwriter = stream.writer();
|
||||||
|
|
||||||
_, const A, const S, const GOT, _, _, const DTP, _ = args;
|
_, const A, const S, const GOT, _, _, const DTP = args;
|
||||||
|
|
||||||
switch (r_type) {
|
switch (r_type) {
|
||||||
.NONE => unreachable,
|
.NONE => unreachable,
|
||||||
@ -1629,7 +1610,7 @@ const x86_64 = struct {
|
|||||||
const bits = @import("../../arch/x86_64/bits.zig");
|
const bits = @import("../../arch/x86_64/bits.zig");
|
||||||
const encoder = @import("../../arch/x86_64/encoder.zig");
|
const encoder = @import("../../arch/x86_64/encoder.zig");
|
||||||
const Disassembler = @import("../../arch/x86_64/Disassembler.zig");
|
const Disassembler = @import("../../arch/x86_64/Disassembler.zig");
|
||||||
const Immediate = bits.Immediate;
|
const Immediate = Instruction.Immediate;
|
||||||
const Instruction = encoder.Instruction;
|
const Instruction = encoder.Instruction;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1738,9 +1719,8 @@ const aarch64 = struct {
|
|||||||
const code = code_buffer[r_offset..][0..4];
|
const code = code_buffer[r_offset..][0..4];
|
||||||
const file_ptr = atom.file(elf_file).?;
|
const file_ptr = atom.file(elf_file).?;
|
||||||
|
|
||||||
const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args;
|
const P, const A, const S, const GOT, const G, const TP, const DTP = args;
|
||||||
_ = DTP;
|
_ = DTP;
|
||||||
_ = ZIG_GOT;
|
|
||||||
|
|
||||||
switch (r_type) {
|
switch (r_type) {
|
||||||
.NONE => unreachable,
|
.NONE => unreachable,
|
||||||
@ -1942,7 +1922,7 @@ const aarch64 = struct {
|
|||||||
const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
|
const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
|
||||||
const cwriter = stream.writer();
|
const cwriter = stream.writer();
|
||||||
|
|
||||||
_, const A, const S, _, _, _, _, _ = args;
|
_, const A, const S, _, _, _, _ = args;
|
||||||
|
|
||||||
switch (r_type) {
|
switch (r_type) {
|
||||||
.NONE => unreachable,
|
.NONE => unreachable,
|
||||||
@ -1998,19 +1978,7 @@ const riscv = struct {
|
|||||||
.SUB32,
|
.SUB32,
|
||||||
=> {},
|
=> {},
|
||||||
|
|
||||||
else => |x| switch (@intFromEnum(x)) {
|
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
||||||
Elf.R_ZIG_GOT_HI20,
|
|
||||||
Elf.R_ZIG_GOT_LO12,
|
|
||||||
=> {
|
|
||||||
assert(symbol.flags.has_zig_got);
|
|
||||||
},
|
|
||||||
|
|
||||||
Elf.R_GOT_HI20_STATIC,
|
|
||||||
Elf.R_GOT_LO12_I_STATIC,
|
|
||||||
=> symbol.flags.needs_got = true,
|
|
||||||
|
|
||||||
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2028,7 +1996,7 @@ const riscv = struct {
|
|||||||
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
|
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
|
||||||
const cwriter = stream.writer();
|
const cwriter = stream.writer();
|
||||||
|
|
||||||
const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args;
|
const P, const A, const S, const GOT, const G, const TP, const DTP = args;
|
||||||
_ = TP;
|
_ = TP;
|
||||||
_ = DTP;
|
_ = DTP;
|
||||||
|
|
||||||
@ -2147,34 +2115,7 @@ const riscv = struct {
|
|||||||
// TODO: annotates an ADD instruction that can be removed when TPREL is relaxed
|
// TODO: annotates an ADD instruction that can be removed when TPREL is relaxed
|
||||||
},
|
},
|
||||||
|
|
||||||
else => |x| switch (@intFromEnum(x)) {
|
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
||||||
// Zig custom relocations
|
|
||||||
Elf.R_ZIG_GOT_HI20 => {
|
|
||||||
assert(target.flags.has_zig_got);
|
|
||||||
const disp: u32 = @bitCast(math.cast(i32, ZIG_GOT + A) orelse return error.Overflow);
|
|
||||||
riscv_util.writeInstU(code[r_offset..][0..4], disp);
|
|
||||||
},
|
|
||||||
|
|
||||||
Elf.R_ZIG_GOT_LO12 => {
|
|
||||||
assert(target.flags.has_zig_got);
|
|
||||||
const value: u32 = @bitCast(math.cast(i32, ZIG_GOT + A) orelse return error.Overflow);
|
|
||||||
riscv_util.writeInstI(code[r_offset..][0..4], value);
|
|
||||||
},
|
|
||||||
|
|
||||||
Elf.R_GOT_HI20_STATIC => {
|
|
||||||
assert(target.flags.has_got);
|
|
||||||
const disp: u32 = @bitCast(math.cast(i32, G + GOT + A) orelse return error.Overflow);
|
|
||||||
riscv_util.writeInstU(code[r_offset..][0..4], disp);
|
|
||||||
},
|
|
||||||
|
|
||||||
Elf.R_GOT_LO12_I_STATIC => {
|
|
||||||
assert(target.flags.has_got);
|
|
||||||
const disp: u32 = @bitCast(math.cast(i32, G + GOT + A) orelse return error.Overflow);
|
|
||||||
riscv_util.writeInstI(code[r_offset..][0..4], disp);
|
|
||||||
},
|
|
||||||
|
|
||||||
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2194,7 +2135,7 @@ const riscv = struct {
|
|||||||
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
|
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
|
||||||
const cwriter = stream.writer();
|
const cwriter = stream.writer();
|
||||||
|
|
||||||
_, const A, const S, const GOT, _, _, const DTP, _ = args;
|
_, const A, const S, const GOT, _, _, const DTP = args;
|
||||||
_ = GOT;
|
_ = GOT;
|
||||||
_ = DTP;
|
_ = DTP;
|
||||||
|
|
||||||
@ -2230,7 +2171,7 @@ const riscv = struct {
|
|||||||
const riscv_util = @import("../riscv.zig");
|
const riscv_util = @import("../riscv.zig");
|
||||||
};
|
};
|
||||||
|
|
||||||
const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 };
|
const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64 };
|
||||||
|
|
||||||
const RelocError = error{
|
const RelocError = error{
|
||||||
Overflow,
|
Overflow,
|
||||||
|
|||||||
@ -101,7 +101,7 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
|
|||||||
return file_ptr.symbolRank(sym, in_archive);
|
return file_ptr.symbolRank(sym, in_archive);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) i64 {
|
pub fn address(symbol: Symbol, opts: struct { plt: bool = true, trampoline: bool = true }, elf_file: *Elf) i64 {
|
||||||
if (symbol.mergeSubsection(elf_file)) |msub| {
|
if (symbol.mergeSubsection(elf_file)) |msub| {
|
||||||
if (!msub.alive) return 0;
|
if (!msub.alive) return 0;
|
||||||
return msub.address(elf_file) + symbol.value;
|
return msub.address(elf_file) + symbol.value;
|
||||||
@ -109,6 +109,9 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
|
|||||||
if (symbol.flags.has_copy_rel) {
|
if (symbol.flags.has_copy_rel) {
|
||||||
return symbol.copyRelAddress(elf_file);
|
return symbol.copyRelAddress(elf_file);
|
||||||
}
|
}
|
||||||
|
if (symbol.flags.has_trampoline and opts.trampoline) {
|
||||||
|
return symbol.trampolineAddress(elf_file);
|
||||||
|
}
|
||||||
if (symbol.flags.has_plt and opts.plt) {
|
if (symbol.flags.has_plt and opts.plt) {
|
||||||
if (!symbol.flags.is_canonical and symbol.flags.has_got) {
|
if (!symbol.flags.is_canonical and symbol.flags.has_got) {
|
||||||
// We have a non-lazy bound function pointer, use that!
|
// We have a non-lazy bound function pointer, use that!
|
||||||
@ -217,23 +220,11 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 {
|
|||||||
return entry.address(elf_file);
|
return entry.address(elf_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetOrCreateZigGotEntryResult = struct {
|
pub fn trampolineAddress(symbol: Symbol, elf_file: *Elf) i64 {
|
||||||
found_existing: bool,
|
if (!symbol.flags.has_trampoline) return 0;
|
||||||
index: ZigGotSection.Index,
|
const zo = elf_file.zigObjectPtr().?;
|
||||||
};
|
const index = symbol.extra(elf_file).trampoline;
|
||||||
|
return zo.symbol(index).address(.{}, elf_file);
|
||||||
pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult {
|
|
||||||
assert(!elf_file.base.isRelocatable());
|
|
||||||
assert(symbol.flags.needs_zig_got);
|
|
||||||
if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).zig_got };
|
|
||||||
const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file);
|
|
||||||
return .{ .found_existing = false, .index = index };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
|
|
||||||
if (!symbol.flags.has_zig_got) return 0;
|
|
||||||
const extras = symbol.extra(elf_file);
|
|
||||||
return elf_file.zig_got.entryAddress(extras.zig_got, elf_file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
|
pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
|
||||||
@ -259,7 +250,7 @@ const AddExtraOpts = struct {
|
|||||||
tlsgd: ?u32 = null,
|
tlsgd: ?u32 = null,
|
||||||
gottp: ?u32 = null,
|
gottp: ?u32 = null,
|
||||||
tlsdesc: ?u32 = null,
|
tlsdesc: ?u32 = null,
|
||||||
zig_got: ?u32 = null,
|
trampoline: ?u32 = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void {
|
pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void {
|
||||||
@ -312,7 +303,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
|
|||||||
const shdr = elf_file.shdrs.items[st_shndx];
|
const shdr = elf_file.shdrs.items[st_shndx];
|
||||||
if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
|
if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
|
||||||
break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress();
|
break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress();
|
||||||
break :blk symbol.address(.{ .plt = false }, elf_file);
|
break :blk symbol.address(.{ .plt = false, .trampoline = false }, elf_file);
|
||||||
};
|
};
|
||||||
out.st_info = (st_bind << 4) | st_type;
|
out.st_info = (st_bind << 4) | st_type;
|
||||||
out.st_other = esym.st_other;
|
out.st_other = esym.st_other;
|
||||||
@ -331,7 +322,7 @@ pub fn format(
|
|||||||
_ = unused_fmt_string;
|
_ = unused_fmt_string;
|
||||||
_ = options;
|
_ = options;
|
||||||
_ = writer;
|
_ = writer;
|
||||||
@compileError("do not format symbols directly");
|
@compileError("do not format Symbol directly");
|
||||||
}
|
}
|
||||||
|
|
||||||
const FormatContext = struct {
|
const FormatContext = struct {
|
||||||
@ -388,7 +379,7 @@ fn format2(
|
|||||||
try writer.print("%{d} : {s} : @{x}", .{
|
try writer.print("%{d} : {s} : @{x}", .{
|
||||||
symbol.esym_index,
|
symbol.esym_index,
|
||||||
symbol.fmtName(elf_file),
|
symbol.fmtName(elf_file),
|
||||||
symbol.address(.{}, elf_file),
|
symbol.address(.{ .plt = false, .trampoline = false }, elf_file),
|
||||||
});
|
});
|
||||||
if (symbol.file(elf_file)) |file_ptr| {
|
if (symbol.file(elf_file)) |file_ptr| {
|
||||||
if (symbol.isAbs(elf_file)) {
|
if (symbol.isAbs(elf_file)) {
|
||||||
@ -456,17 +447,18 @@ pub const Flags = packed struct {
|
|||||||
needs_tlsdesc: bool = false,
|
needs_tlsdesc: bool = false,
|
||||||
has_tlsdesc: bool = false,
|
has_tlsdesc: bool = false,
|
||||||
|
|
||||||
/// Whether the symbol contains .zig.got indirection.
|
|
||||||
needs_zig_got: bool = false,
|
|
||||||
has_zig_got: bool = false,
|
|
||||||
|
|
||||||
/// Whether the symbol is a TLS variable.
|
|
||||||
/// TODO this is really not needed if only we operated on esyms between
|
|
||||||
/// codegen and ZigObject.
|
|
||||||
is_tls: bool = false,
|
|
||||||
|
|
||||||
/// Whether the symbol is a merge subsection.
|
/// Whether the symbol is a merge subsection.
|
||||||
merge_subsection: bool = false,
|
merge_subsection: bool = false,
|
||||||
|
|
||||||
|
/// ZigObject specific flags
|
||||||
|
/// Whether the symbol has a trampoline.
|
||||||
|
has_trampoline: bool = false,
|
||||||
|
|
||||||
|
/// Whether the symbol is a TLS variable.
|
||||||
|
is_tls: bool = false,
|
||||||
|
|
||||||
|
/// Whether the symbol is an extern pointer (as opposed to function).
|
||||||
|
is_extern_ptr: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Extra = struct {
|
pub const Extra = struct {
|
||||||
@ -479,8 +471,8 @@ pub const Extra = struct {
|
|||||||
tlsgd: u32 = 0,
|
tlsgd: u32 = 0,
|
||||||
gottp: u32 = 0,
|
gottp: u32 = 0,
|
||||||
tlsdesc: u32 = 0,
|
tlsdesc: u32 = 0,
|
||||||
zig_got: u32 = 0,
|
|
||||||
merge_section: u32 = 0,
|
merge_section: u32 = 0,
|
||||||
|
trampoline: u32 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Index = u32;
|
pub const Index = u32;
|
||||||
|
|||||||
@ -102,23 +102,17 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
|
|||||||
}
|
}
|
||||||
self.relocs.deinit(allocator);
|
self.relocs.deinit(allocator);
|
||||||
|
|
||||||
{
|
for (self.navs.values()) |*meta| {
|
||||||
var it = self.navs.iterator();
|
meta.exports.deinit(allocator);
|
||||||
while (it.next()) |entry| {
|
|
||||||
entry.value_ptr.exports.deinit(allocator);
|
|
||||||
}
|
|
||||||
self.navs.deinit(allocator);
|
|
||||||
}
|
}
|
||||||
|
self.navs.deinit(allocator);
|
||||||
|
|
||||||
self.lazy_syms.deinit(allocator);
|
self.lazy_syms.deinit(allocator);
|
||||||
|
|
||||||
{
|
for (self.uavs.values()) |*meta| {
|
||||||
var it = self.uavs.iterator();
|
meta.exports.deinit(allocator);
|
||||||
while (it.next()) |entry| {
|
|
||||||
entry.value_ptr.exports.deinit(allocator);
|
|
||||||
}
|
|
||||||
self.uavs.deinit(allocator);
|
|
||||||
}
|
}
|
||||||
|
self.uavs.deinit(allocator);
|
||||||
|
|
||||||
for (self.tls_variables.values()) |*tlv| {
|
for (self.tls_variables.values()) |*tlv| {
|
||||||
tlv.deinit(allocator);
|
tlv.deinit(allocator);
|
||||||
@ -161,6 +155,16 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
|
|||||||
if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
|
if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (build_options.enable_logging) {
|
||||||
|
const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
|
||||||
|
for (self.navs.keys(), self.navs.values()) |nav_index, meta| {
|
||||||
|
checkNavAllocated(pt, nav_index, meta);
|
||||||
|
}
|
||||||
|
for (self.uavs.keys(), self.uavs.values()) |uav_index, meta| {
|
||||||
|
checkUavAllocated(pt, uav_index, meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (self.dwarf) |*dw| {
|
if (self.dwarf) |*dw| {
|
||||||
const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
|
const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
|
||||||
try dw.flushModule(pt);
|
try dw.flushModule(pt);
|
||||||
@ -698,6 +702,7 @@ pub fn lowerUav(
|
|||||||
else => explicit_alignment,
|
else => explicit_alignment,
|
||||||
};
|
};
|
||||||
if (self.uavs.get(uav)) |metadata| {
|
if (self.uavs.get(uav)) |metadata| {
|
||||||
|
assert(metadata.allocated);
|
||||||
const sym = self.symbol(metadata.symbol_index);
|
const sym = self.symbol(metadata.symbol_index);
|
||||||
const existing_alignment = sym.atom(elf_file).?.alignment;
|
const existing_alignment = sym.atom(elf_file).?.alignment;
|
||||||
if (uav_alignment.order(existing_alignment).compare(.lte))
|
if (uav_alignment.order(existing_alignment).compare(.lte))
|
||||||
@ -729,7 +734,7 @@ pub fn lowerUav(
|
|||||||
.ok => |sym_index| sym_index,
|
.ok => |sym_index| sym_index,
|
||||||
.fail => |em| return .{ .fail = em },
|
.fail => |em| return .{ .fail = em },
|
||||||
};
|
};
|
||||||
try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index });
|
try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index, .allocated = true });
|
||||||
return .{ .mcv = .{ .load_symbol = sym_index } };
|
return .{ .mcv = .{ .load_symbol = sym_index } };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,13 +752,7 @@ pub fn getOrCreateMetadataForLazySymbol(
|
|||||||
.const_data => .{ &gop.value_ptr.rodata_symbol_index, &gop.value_ptr.rodata_state },
|
.const_data => .{ &gop.value_ptr.rodata_symbol_index, &gop.value_ptr.rodata_state },
|
||||||
};
|
};
|
||||||
switch (state_ptr.*) {
|
switch (state_ptr.*) {
|
||||||
.unused => {
|
.unused => symbol_index_ptr.* = try self.newSymbolWithAtom(pt.zcu.gpa, 0),
|
||||||
const gpa = elf_file.base.comp.gpa;
|
|
||||||
const symbol_index = try self.newSymbolWithAtom(gpa, 0);
|
|
||||||
const sym = self.symbol(symbol_index);
|
|
||||||
sym.flags.needs_zig_got = true;
|
|
||||||
symbol_index_ptr.* = symbol_index;
|
|
||||||
},
|
|
||||||
.pending_flush => return symbol_index_ptr.*,
|
.pending_flush => return symbol_index_ptr.*,
|
||||||
.flushed => {},
|
.flushed => {},
|
||||||
}
|
}
|
||||||
@ -807,9 +806,6 @@ pub fn getOrCreateMetadataForNav(
|
|||||||
sym.flags.is_tls = true;
|
sym.flags.is_tls = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sym.flags.is_tls) {
|
|
||||||
sym.flags.needs_zig_got = true;
|
|
||||||
}
|
|
||||||
gop.value_ptr.* = .{ .symbol_index = symbol_index };
|
gop.value_ptr.* = .{ .symbol_index = symbol_index };
|
||||||
}
|
}
|
||||||
return gop.value_ptr.symbol_index;
|
return gop.value_ptr.symbol_index;
|
||||||
@ -820,9 +816,9 @@ fn getNavShdrIndex(
|
|||||||
elf_file: *Elf,
|
elf_file: *Elf,
|
||||||
zcu: *Zcu,
|
zcu: *Zcu,
|
||||||
nav_index: InternPool.Nav.Index,
|
nav_index: InternPool.Nav.Index,
|
||||||
|
sym_index: Symbol.Index,
|
||||||
code: []const u8,
|
code: []const u8,
|
||||||
) error{OutOfMemory}!u32 {
|
) error{OutOfMemory}!u32 {
|
||||||
_ = self;
|
|
||||||
const ip = &zcu.intern_pool;
|
const ip = &zcu.intern_pool;
|
||||||
const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
|
const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
|
||||||
const nav_val = zcu.navValue(nav_index);
|
const nav_val = zcu.navValue(nav_index);
|
||||||
@ -832,10 +828,12 @@ fn getNavShdrIndex(
|
|||||||
.@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
|
.@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
|
||||||
else => .{ true, false, nav_val.toIntern() },
|
else => .{ true, false, nav_val.toIntern() },
|
||||||
};
|
};
|
||||||
|
const has_relocs = self.symbol(sym_index).atom(elf_file).?.relocs(elf_file).len > 0;
|
||||||
if (any_non_single_threaded and is_threadlocal) {
|
if (any_non_single_threaded and is_threadlocal) {
|
||||||
for (code) |byte| {
|
const is_bss = !has_relocs and for (code) |byte| {
|
||||||
if (byte != 0) break;
|
if (byte != 0) break false;
|
||||||
} else return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{
|
} else true;
|
||||||
|
if (is_bss) return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{
|
||||||
.type = elf.SHT_NOBITS,
|
.type = elf.SHT_NOBITS,
|
||||||
.flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
|
.flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
|
||||||
.name = try elf_file.insertShString(".tbss"),
|
.name = try elf_file.insertShString(".tbss"),
|
||||||
@ -854,9 +852,10 @@ fn getNavShdrIndex(
|
|||||||
.Debug, .ReleaseSafe => elf_file.zig_data_section_index.?,
|
.Debug, .ReleaseSafe => elf_file.zig_data_section_index.?,
|
||||||
.ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?,
|
.ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?,
|
||||||
};
|
};
|
||||||
for (code) |byte| {
|
const is_bss = !has_relocs and for (code) |byte| {
|
||||||
if (byte != 0) break;
|
if (byte != 0) break false;
|
||||||
} else return elf_file.zig_bss_section_index.?;
|
} else true;
|
||||||
|
if (is_bss) return elf_file.zig_bss_section_index.?;
|
||||||
return elf_file.zig_data_section_index.?;
|
return elf_file.zig_data_section_index.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,13 +908,6 @@ fn updateNavCode(
|
|||||||
if (old_vaddr != atom_ptr.value) {
|
if (old_vaddr != atom_ptr.value) {
|
||||||
sym.value = 0;
|
sym.value = 0;
|
||||||
esym.st_value = 0;
|
esym.st_value = 0;
|
||||||
|
|
||||||
if (!elf_file.base.isRelocatable()) {
|
|
||||||
log.debug(" (writing new offset table entry)", .{});
|
|
||||||
assert(sym.flags.has_zig_got);
|
|
||||||
const extra = sym.extra(elf_file);
|
|
||||||
try elf_file.zig_got.writeOne(elf_file, extra.zig_got);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (code.len < old_size) {
|
} else if (code.len < old_size) {
|
||||||
atom_ptr.shrink(elf_file);
|
atom_ptr.shrink(elf_file);
|
||||||
@ -925,15 +917,11 @@ fn updateNavCode(
|
|||||||
errdefer self.freeNavMetadata(elf_file, sym_index);
|
errdefer self.freeNavMetadata(elf_file, sym_index);
|
||||||
|
|
||||||
sym.value = 0;
|
sym.value = 0;
|
||||||
sym.flags.needs_zig_got = true;
|
|
||||||
esym.st_value = 0;
|
esym.st_value = 0;
|
||||||
|
|
||||||
if (!elf_file.base.isRelocatable()) {
|
|
||||||
const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
|
|
||||||
try elf_file.zig_got.writeOne(elf_file, gop.index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.navs.getPtr(nav_index).?.allocated = true;
|
||||||
|
|
||||||
if (elf_file.base.child_pid) |pid| {
|
if (elf_file.base.child_pid) |pid| {
|
||||||
switch (builtin.os.tag) {
|
switch (builtin.os.tag) {
|
||||||
.linux => {
|
.linux => {
|
||||||
@ -959,6 +947,7 @@ fn updateNavCode(
|
|||||||
if (shdr.sh_type != elf.SHT_NOBITS) {
|
if (shdr.sh_type != elf.SHT_NOBITS) {
|
||||||
const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
|
const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
|
||||||
try elf_file.base.file.?.pwriteAll(code, file_offset);
|
try elf_file.base.file.?.pwriteAll(code, file_offset);
|
||||||
|
log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1001,6 +990,8 @@ fn updateTlv(
|
|||||||
atom_ptr.alignment = required_alignment;
|
atom_ptr.alignment = required_alignment;
|
||||||
atom_ptr.size = code.len;
|
atom_ptr.size = code.len;
|
||||||
|
|
||||||
|
self.navs.getPtr(nav_index).?.allocated = true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index);
|
const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index);
|
||||||
assert(!gop.found_existing); // TODO incremental updates
|
assert(!gop.found_existing); // TODO incremental updates
|
||||||
@ -1065,8 +1056,21 @@ pub fn updateFunc(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, code);
|
const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code);
|
||||||
|
log.debug("setting shdr({x},{s}) for {}", .{
|
||||||
|
shndx,
|
||||||
|
elf_file.getShString(elf_file.shdrs.items[shndx].sh_name),
|
||||||
|
ip.getNav(func.owner_nav).fqn.fmt(ip),
|
||||||
|
});
|
||||||
|
const old_rva, const old_alignment = blk: {
|
||||||
|
const atom_ptr = self.symbol(sym_index).atom(elf_file).?;
|
||||||
|
break :blk .{ atom_ptr.value, atom_ptr.alignment };
|
||||||
|
};
|
||||||
try self.updateNavCode(elf_file, pt, func.owner_nav, sym_index, shndx, code, elf.STT_FUNC);
|
try self.updateNavCode(elf_file, pt, func.owner_nav, sym_index, shndx, code, elf.STT_FUNC);
|
||||||
|
const new_rva, const new_alignment = blk: {
|
||||||
|
const atom_ptr = self.symbol(sym_index).atom(elf_file).?;
|
||||||
|
break :blk .{ atom_ptr.value, atom_ptr.alignment };
|
||||||
|
};
|
||||||
|
|
||||||
if (dwarf_state) |*ds| {
|
if (dwarf_state) |*ds| {
|
||||||
const sym = self.symbol(sym_index);
|
const sym = self.symbol(sym_index);
|
||||||
@ -1080,6 +1084,41 @@ pub fn updateFunc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exports will be updated by `Zcu.processExports` after the update.
|
// Exports will be updated by `Zcu.processExports` after the update.
|
||||||
|
|
||||||
|
if (old_rva != new_rva and old_rva > 0) {
|
||||||
|
// If we had to reallocate the function, we re-use the existing slot for a trampoline.
|
||||||
|
// In the rare case that the function has been further overaligned we skip creating a
|
||||||
|
// trampoline and update all symbols referring this function.
|
||||||
|
if (old_alignment.order(new_alignment) == .lt) {
|
||||||
|
@panic("TODO update all symbols referring this function");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a trampoline to the new location at `old_rva`.
|
||||||
|
if (!self.symbol(sym_index).flags.has_trampoline) {
|
||||||
|
const name = try std.fmt.allocPrint(gpa, "{s}$trampoline", .{
|
||||||
|
self.symbol(sym_index).name(elf_file),
|
||||||
|
});
|
||||||
|
defer gpa.free(name);
|
||||||
|
const name_off = try self.addString(gpa, name);
|
||||||
|
const tr_size = trampolineSize(elf_file.getTarget().cpu.arch);
|
||||||
|
const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off);
|
||||||
|
const tr_sym = self.symbol(tr_sym_index);
|
||||||
|
const tr_esym = &self.symtab.items(.elf_sym)[tr_sym.esym_index];
|
||||||
|
tr_esym.st_info |= elf.STT_OBJECT;
|
||||||
|
tr_esym.st_size = tr_size;
|
||||||
|
const tr_atom_ptr = tr_sym.atom(elf_file).?;
|
||||||
|
tr_atom_ptr.value = old_rva;
|
||||||
|
tr_atom_ptr.alive = true;
|
||||||
|
tr_atom_ptr.alignment = old_alignment;
|
||||||
|
tr_atom_ptr.output_section_index = elf_file.zig_text_section_index.?;
|
||||||
|
tr_atom_ptr.size = tr_size;
|
||||||
|
const target_sym = self.symbol(sym_index);
|
||||||
|
target_sym.addExtra(.{ .trampoline = tr_sym_index }, elf_file);
|
||||||
|
target_sym.flags.has_trampoline = true;
|
||||||
|
}
|
||||||
|
const target_sym = self.symbol(sym_index);
|
||||||
|
try writeTrampoline(self.symbol(target_sym.extra(elf_file).trampoline).*, target_sym.*, elf_file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateNav(
|
pub fn updateNav(
|
||||||
@ -1102,13 +1141,12 @@ pub fn updateNav(
|
|||||||
.variable => |variable| Value.fromInterned(variable.init),
|
.variable => |variable| Value.fromInterned(variable.init),
|
||||||
.@"extern" => |@"extern"| {
|
.@"extern" => |@"extern"| {
|
||||||
if (ip.isFunctionType(@"extern".ty)) return;
|
if (ip.isFunctionType(@"extern".ty)) return;
|
||||||
// Extern variable gets a .got entry only.
|
|
||||||
const sym_index = try self.getGlobalSymbol(
|
const sym_index = try self.getGlobalSymbol(
|
||||||
elf_file,
|
elf_file,
|
||||||
nav.name.toSlice(ip),
|
nav.name.toSlice(ip),
|
||||||
@"extern".lib_name.toSlice(ip),
|
@"extern".lib_name.toSlice(ip),
|
||||||
);
|
);
|
||||||
self.symbol(sym_index).flags.needs_got = true;
|
self.symbol(sym_index).flags.is_extern_ptr = true;
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
else => nav_val,
|
else => nav_val,
|
||||||
@ -1142,7 +1180,12 @@ pub fn updateNav(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, code);
|
const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code);
|
||||||
|
log.debug("setting shdr({x},{s}) for {}", .{
|
||||||
|
shndx,
|
||||||
|
elf_file.getShString(elf_file.shdrs.items[shndx].sh_name),
|
||||||
|
nav.fqn.fmt(ip),
|
||||||
|
});
|
||||||
if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0)
|
if (elf_file.shdrs.items[shndx].sh_flags & elf.SHF_TLS != 0)
|
||||||
try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code)
|
try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code)
|
||||||
else
|
else
|
||||||
@ -1225,14 +1268,8 @@ fn updateLazySymbol(
|
|||||||
errdefer self.freeNavMetadata(elf_file, symbol_index);
|
errdefer self.freeNavMetadata(elf_file, symbol_index);
|
||||||
|
|
||||||
local_sym.value = 0;
|
local_sym.value = 0;
|
||||||
local_sym.flags.needs_zig_got = true;
|
|
||||||
local_esym.st_value = 0;
|
local_esym.st_value = 0;
|
||||||
|
|
||||||
if (!elf_file.base.isRelocatable()) {
|
|
||||||
const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file);
|
|
||||||
try elf_file.zig_got.writeOne(elf_file, gop.index);
|
|
||||||
}
|
|
||||||
|
|
||||||
const shdr = elf_file.shdrs.items[output_section_index];
|
const shdr = elf_file.shdrs.items[output_section_index];
|
||||||
const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
|
const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
|
||||||
try elf_file.base.file.?.pwriteAll(code, file_offset);
|
try elf_file.base.file.?.pwriteAll(code, file_offset);
|
||||||
@ -1440,6 +1477,52 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n
|
|||||||
return lookup_gop.value_ptr.*;
|
return lookup_gop.value_ptr.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const max_trampoline_len = 12;
|
||||||
|
|
||||||
|
fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 {
|
||||||
|
const len = switch (cpu_arch) {
|
||||||
|
.x86_64 => 5, // jmp rel32
|
||||||
|
else => @panic("TODO implement trampoline size for this CPU arch"),
|
||||||
|
};
|
||||||
|
comptime assert(len <= max_trampoline_len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
|
||||||
|
const atom_ptr = tr_sym.atom(elf_file).?;
|
||||||
|
const shdr = elf_file.shdrs.items[atom_ptr.output_section_index];
|
||||||
|
const fileoff = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
|
||||||
|
const source_addr = tr_sym.address(.{}, elf_file);
|
||||||
|
const target_addr = target.address(.{ .trampoline = false }, elf_file);
|
||||||
|
var buf: [max_trampoline_len]u8 = undefined;
|
||||||
|
const out = switch (elf_file.getTarget().cpu.arch) {
|
||||||
|
.x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf),
|
||||||
|
else => @panic("TODO implement write trampoline for this CPU arch"),
|
||||||
|
};
|
||||||
|
try elf_file.base.file.?.pwriteAll(out, fileoff);
|
||||||
|
|
||||||
|
if (elf_file.base.child_pid) |pid| {
|
||||||
|
switch (builtin.os.tag) {
|
||||||
|
.linux => {
|
||||||
|
var local_vec: [1]std.posix.iovec_const = .{.{
|
||||||
|
.base = out.ptr,
|
||||||
|
.len = out.len,
|
||||||
|
}};
|
||||||
|
var remote_vec: [1]std.posix.iovec_const = .{.{
|
||||||
|
.base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(source_addr)))),
|
||||||
|
.len = out.len,
|
||||||
|
}};
|
||||||
|
const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
|
||||||
|
switch (std.os.linux.E.init(rc)) {
|
||||||
|
.SUCCESS => assert(rc == out.len),
|
||||||
|
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => return error.HotSwapUnavailableOnHostOperatingSystem,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn asFile(self: *ZigObject) File {
|
pub fn asFile(self: *ZigObject) File {
|
||||||
return .{ .zig_object = self };
|
return .{ .zig_object = self };
|
||||||
}
|
}
|
||||||
@ -1662,6 +1745,8 @@ const AvMetadata = struct {
|
|||||||
symbol_index: Symbol.Index,
|
symbol_index: Symbol.Index,
|
||||||
/// A list of all exports aliases of this Av.
|
/// A list of all exports aliases of this Av.
|
||||||
exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||||
|
/// Set to true if the AV has been initialized and allocated.
|
||||||
|
allocated: bool = false,
|
||||||
|
|
||||||
fn @"export"(m: AvMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
|
fn @"export"(m: AvMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
|
||||||
for (m.exports.items) |*exp| {
|
for (m.exports.items) |*exp| {
|
||||||
@ -1672,6 +1757,32 @@ const AvMetadata = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn checkNavAllocated(pt: Zcu.PerThread, index: InternPool.Nav.Index, meta: AvMetadata) void {
|
||||||
|
if (!meta.allocated) {
|
||||||
|
const zcu = pt.zcu;
|
||||||
|
const ip = &zcu.intern_pool;
|
||||||
|
const nav = ip.getNav(index);
|
||||||
|
log.err("NAV {}({d}) assigned symbol {d} but not allocated!", .{
|
||||||
|
nav.fqn.fmt(ip),
|
||||||
|
index,
|
||||||
|
meta.symbol_index,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn checkUavAllocated(pt: Zcu.PerThread, index: InternPool.Index, meta: AvMetadata) void {
|
||||||
|
if (!meta.allocated) {
|
||||||
|
const zcu = pt.zcu;
|
||||||
|
const uav = Value.fromInterned(index);
|
||||||
|
const ty = uav.typeOf(zcu);
|
||||||
|
log.err("UAV {}({d}) assigned symbol {d} but not allocated!", .{
|
||||||
|
ty.fmt(pt),
|
||||||
|
index,
|
||||||
|
meta.symbol_index,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const TlsVariable = struct {
|
const TlsVariable = struct {
|
||||||
symbol_index: Symbol.Index,
|
symbol_index: Symbol.Index,
|
||||||
code: []const u8 = &[0]u8{},
|
code: []const u8 = &[0]u8{},
|
||||||
@ -1682,12 +1793,26 @@ const TlsVariable = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const AtomList = std.ArrayListUnmanaged(Atom.Index);
|
const AtomList = std.ArrayListUnmanaged(Atom.Index);
|
||||||
const NavTable = std.AutoHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);
|
const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);
|
||||||
const UavTable = std.AutoHashMapUnmanaged(InternPool.Index, AvMetadata);
|
const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata);
|
||||||
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);
|
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);
|
||||||
const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable);
|
const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable);
|
||||||
|
|
||||||
|
const x86_64 = struct {
|
||||||
|
fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 {
|
||||||
|
const disp = @as(i64, @intCast(target_addr)) - source_addr - 5;
|
||||||
|
var bytes = [_]u8{
|
||||||
|
0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32
|
||||||
|
};
|
||||||
|
assert(bytes.len == trampolineSize(.x86_64));
|
||||||
|
mem.writeInt(i32, bytes[1..][0..4], @intCast(disp), .little);
|
||||||
|
@memcpy(buf[0..bytes.len], &bytes);
|
||||||
|
return buf[0..bytes.len];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
const build_options = @import("build_options");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const codegen = @import("../../codegen.zig");
|
const codegen = @import("../../codegen.zig");
|
||||||
const elf = std.elf;
|
const elf = std.elf;
|
||||||
|
|||||||
@ -112,19 +112,11 @@ fn formatRelocType(
|
|||||||
_ = unused_fmt_string;
|
_ = unused_fmt_string;
|
||||||
_ = options;
|
_ = options;
|
||||||
const r_type = ctx.r_type;
|
const r_type = ctx.r_type;
|
||||||
switch (r_type) {
|
switch (ctx.cpu_arch) {
|
||||||
Elf.R_ZIG_GOT32 => try writer.writeAll("R_ZIG_GOT32"),
|
.x86_64 => try writer.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}),
|
||||||
Elf.R_ZIG_GOTPCREL => try writer.writeAll("R_ZIG_GOTPCREL"),
|
.aarch64 => try writer.print("R_AARCH64_{s}", .{@tagName(@as(elf.R_AARCH64, @enumFromInt(r_type)))}),
|
||||||
Elf.R_ZIG_GOT_HI20 => try writer.writeAll("R_ZIG_GOT_HI20"),
|
.riscv64 => try writer.print("R_RISCV_{s}", .{@tagName(@as(elf.R_RISCV, @enumFromInt(r_type)))}),
|
||||||
Elf.R_ZIG_GOT_LO12 => try writer.writeAll("R_ZIG_GOT_LO12"),
|
else => unreachable,
|
||||||
Elf.R_GOT_HI20_STATIC => try writer.writeAll("R_GOT_HI20_STATIC"),
|
|
||||||
Elf.R_GOT_LO12_I_STATIC => try writer.writeAll("R_GOT_LO12_I_STATIC"),
|
|
||||||
else => switch (ctx.cpu_arch) {
|
|
||||||
.x86_64 => try writer.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}),
|
|
||||||
.aarch64 => try writer.print("R_AARCH64_{s}", .{@tagName(@as(elf.R_AARCH64, @enumFromInt(r_type)))}),
|
|
||||||
.riscv64 => try writer.print("R_RISCV_{s}", .{@tagName(@as(elf.R_RISCV, @enumFromInt(r_type)))}),
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -223,215 +223,6 @@ pub const DynamicSection = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ZigGotSection = struct {
|
|
||||||
entries: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
|
||||||
output_symtab_ctx: Elf.SymtabCtx = .{},
|
|
||||||
flags: Flags = .{},
|
|
||||||
|
|
||||||
const Flags = packed struct {
|
|
||||||
needs_rela: bool = false,
|
|
||||||
dirty: bool = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Index = u32;
|
|
||||||
|
|
||||||
pub fn deinit(zig_got: *ZigGotSection, allocator: Allocator) void {
|
|
||||||
zig_got.entries.deinit(allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn allocateEntry(zig_got: *ZigGotSection, allocator: Allocator) !Index {
|
|
||||||
try zig_got.entries.ensureUnusedCapacity(allocator, 1);
|
|
||||||
// TODO add free list
|
|
||||||
const index = @as(Index, @intCast(zig_got.entries.items.len));
|
|
||||||
_ = zig_got.entries.addOneAssumeCapacity();
|
|
||||||
zig_got.flags.dirty = true;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index {
|
|
||||||
const comp = elf_file.base.comp;
|
|
||||||
const gpa = comp.gpa;
|
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
|
||||||
const index = try zig_got.allocateEntry(gpa);
|
|
||||||
const entry = &zig_got.entries.items[index];
|
|
||||||
entry.* = sym_index;
|
|
||||||
const symbol = zo.symbol(sym_index);
|
|
||||||
symbol.flags.has_zig_got = true;
|
|
||||||
if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) {
|
|
||||||
zig_got.flags.needs_rela = true;
|
|
||||||
}
|
|
||||||
symbol.addExtra(.{ .zig_got = index }, elf_file);
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn entryOffset(zig_got: ZigGotSection, index: Index, elf_file: *Elf) u64 {
|
|
||||||
_ = zig_got;
|
|
||||||
const entry_size = elf_file.archPtrWidthBytes();
|
|
||||||
const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?];
|
|
||||||
return shdr.sh_offset + @as(u64, entry_size) * index;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn entryAddress(zig_got: ZigGotSection, index: Index, elf_file: *Elf) i64 {
|
|
||||||
_ = zig_got;
|
|
||||||
const entry_size = elf_file.archPtrWidthBytes();
|
|
||||||
const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?];
|
|
||||||
return @as(i64, @intCast(shdr.sh_addr)) + entry_size * index;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn size(zig_got: ZigGotSection, elf_file: *Elf) usize {
|
|
||||||
return elf_file.archPtrWidthBytes() * zig_got.entries.items.len;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn writeOne(zig_got: *ZigGotSection, elf_file: *Elf, index: Index) !void {
|
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
|
||||||
if (zig_got.flags.dirty) {
|
|
||||||
const needed_size = zig_got.size(elf_file);
|
|
||||||
try elf_file.growAllocSection(elf_file.zig_got_section_index.?, needed_size);
|
|
||||||
zig_got.flags.dirty = false;
|
|
||||||
}
|
|
||||||
const entry_size: u16 = elf_file.archPtrWidthBytes();
|
|
||||||
const target = elf_file.getTarget();
|
|
||||||
const endian = target.cpu.arch.endian();
|
|
||||||
const off = zig_got.entryOffset(index, elf_file);
|
|
||||||
const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file));
|
|
||||||
const entry = zig_got.entries.items[index];
|
|
||||||
const value = zo.symbol(entry).address(.{}, elf_file);
|
|
||||||
switch (entry_size) {
|
|
||||||
2 => {
|
|
||||||
var buf: [2]u8 = undefined;
|
|
||||||
std.mem.writeInt(u16, &buf, @intCast(value), endian);
|
|
||||||
try elf_file.base.file.?.pwriteAll(&buf, off);
|
|
||||||
},
|
|
||||||
4 => {
|
|
||||||
var buf: [4]u8 = undefined;
|
|
||||||
std.mem.writeInt(u32, &buf, @intCast(value), endian);
|
|
||||||
try elf_file.base.file.?.pwriteAll(&buf, off);
|
|
||||||
},
|
|
||||||
8 => {
|
|
||||||
var buf: [8]u8 = undefined;
|
|
||||||
std.mem.writeInt(u64, &buf, @intCast(value), endian);
|
|
||||||
try elf_file.base.file.?.pwriteAll(&buf, off);
|
|
||||||
|
|
||||||
if (elf_file.base.child_pid) |pid| {
|
|
||||||
switch (builtin.os.tag) {
|
|
||||||
.linux => {
|
|
||||||
var local_vec: [1]std.posix.iovec_const = .{.{
|
|
||||||
.base = &buf,
|
|
||||||
.len = buf.len,
|
|
||||||
}};
|
|
||||||
var remote_vec: [1]std.posix.iovec_const = .{.{
|
|
||||||
.base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(vaddr)))),
|
|
||||||
.len = buf.len,
|
|
||||||
}};
|
|
||||||
const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
|
|
||||||
switch (std.os.linux.E.init(rc)) {
|
|
||||||
.SUCCESS => assert(rc == buf.len),
|
|
||||||
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => return error.HotSwapUnavailableOnHostOperatingSystem,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn writeAll(zig_got: ZigGotSection, elf_file: *Elf, writer: anytype) !void {
|
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
|
||||||
for (zig_got.entries.items) |entry| {
|
|
||||||
const symbol = zo.symbol(entry);
|
|
||||||
const value = symbol.address(.{ .plt = false }, elf_file);
|
|
||||||
try writeInt(value, elf_file, writer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn numRela(zig_got: ZigGotSection) usize {
|
|
||||||
return zig_got.entries.items.len;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addRela(zig_got: ZigGotSection, elf_file: *Elf) !void {
|
|
||||||
const comp = elf_file.base.comp;
|
|
||||||
const gpa = comp.gpa;
|
|
||||||
const cpu_arch = elf_file.getTarget().cpu.arch;
|
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
|
||||||
try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela());
|
|
||||||
for (zig_got.entries.items) |entry| {
|
|
||||||
const symbol = zo.symbol(entry);
|
|
||||||
const offset = symbol.zigGotAddress(elf_file);
|
|
||||||
elf_file.addRelaDynAssumeCapacity(.{
|
|
||||||
.offset = @intCast(offset),
|
|
||||||
.type = relocation.encode(.rel, cpu_arch),
|
|
||||||
.addend = symbol.address(.{ .plt = false }, elf_file),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
|
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
|
||||||
zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len));
|
|
||||||
for (zig_got.entries.items) |entry| {
|
|
||||||
const name = zo.symbol(entry).name(elf_file);
|
|
||||||
zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void {
|
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
|
||||||
for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| {
|
|
||||||
const symbol = zo.symbol(entry);
|
|
||||||
const symbol_name = symbol.name(elf_file);
|
|
||||||
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
|
||||||
elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
|
|
||||||
elf_file.strtab.appendSliceAssumeCapacity("$ziggot");
|
|
||||||
elf_file.strtab.appendAssumeCapacity(0);
|
|
||||||
const st_value = zig_got.entryAddress(@intCast(index), elf_file);
|
|
||||||
const st_size = elf_file.archPtrWidthBytes();
|
|
||||||
elf_file.symtab.items[ilocal] = .{
|
|
||||||
.st_name = st_name,
|
|
||||||
.st_info = elf.STT_OBJECT,
|
|
||||||
.st_other = 0,
|
|
||||||
.st_shndx = @intCast(elf_file.zig_got_section_index.?),
|
|
||||||
.st_value = @intCast(st_value),
|
|
||||||
.st_size = st_size,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const FormatCtx = struct {
|
|
||||||
zig_got: ZigGotSection,
|
|
||||||
elf_file: *Elf,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn fmt(zig_got: ZigGotSection, elf_file: *Elf) std.fmt.Formatter(format2) {
|
|
||||||
return .{ .data = .{ .zig_got = zig_got, .elf_file = elf_file } };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn format2(
|
|
||||||
ctx: FormatCtx,
|
|
||||||
comptime unused_fmt_string: []const u8,
|
|
||||||
options: std.fmt.FormatOptions,
|
|
||||||
writer: anytype,
|
|
||||||
) !void {
|
|
||||||
_ = options;
|
|
||||||
_ = unused_fmt_string;
|
|
||||||
const zig_got = ctx.zig_got;
|
|
||||||
const elf_file = ctx.elf_file;
|
|
||||||
try writer.writeAll(".zig.got\n");
|
|
||||||
for (zig_got.entries.items, 0..) |entry, index| {
|
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
|
||||||
const symbol = zo.symbol(entry);
|
|
||||||
try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
|
|
||||||
index,
|
|
||||||
zig_got.entryAddress(@intCast(index), elf_file),
|
|
||||||
entry,
|
|
||||||
symbol.address(.{}, elf_file),
|
|
||||||
symbol.name(elf_file),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const GotSection = struct {
|
pub const GotSection = struct {
|
||||||
entries: std.ArrayListUnmanaged(Entry) = .{},
|
entries: std.ArrayListUnmanaged(Entry) = .{},
|
||||||
output_symtab_ctx: Elf.SymtabCtx = .{},
|
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||||
|
|||||||
@ -733,7 +733,6 @@ test "extern variable with non-pointer opaque type" {
|
|||||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
||||||
|
|
||||||
@export(var_to_export, .{ .name = "opaque_extern_var" });
|
@export(var_to_export, .{ .name = "opaque_extern_var" });
|
||||||
try expect(@as(*align(1) u32, @ptrCast(&opaque_extern_var)).* == 42);
|
try expect(@as(*align(1) u32, @ptrCast(&opaque_extern_var)).* == 42);
|
||||||
|
|||||||
@ -48,7 +48,6 @@ test "exporting using field access" {
|
|||||||
test "exporting comptime-known value" {
|
test "exporting comptime-known value" {
|
||||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
||||||
if (builtin.zig_backend == .stage2_x86_64 and
|
if (builtin.zig_backend == .stage2_x86_64 and
|
||||||
(builtin.target.ofmt != .elf and
|
(builtin.target.ofmt != .elf and
|
||||||
builtin.target.ofmt != .macho and
|
builtin.target.ofmt != .macho and
|
||||||
@ -68,7 +67,6 @@ test "exporting comptime-known value" {
|
|||||||
test "exporting comptime var" {
|
test "exporting comptime var" {
|
||||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
||||||
if (builtin.zig_backend == .stage2_x86_64 and
|
if (builtin.zig_backend == .stage2_x86_64 and
|
||||||
(builtin.target.ofmt != .elf and
|
(builtin.target.ofmt != .elf and
|
||||||
builtin.target.ofmt != .macho and
|
builtin.target.ofmt != .macho and
|
||||||
|
|||||||
@ -7,7 +7,6 @@ test "anyopaque extern symbol" {
|
|||||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
||||||
|
|
||||||
const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" });
|
const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" });
|
||||||
const b: *i32 = @alignCast(@ptrCast(a));
|
const b: *i32 = @alignCast(@ptrCast(a));
|
||||||
|
|||||||
@ -429,7 +429,6 @@ test "implicit cast function to function ptr" {
|
|||||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
||||||
|
|
||||||
const S1 = struct {
|
const S1 = struct {
|
||||||
export fn someFunctionThatReturnsAValue() c_int {
|
export fn someFunctionThatReturnsAValue() c_int {
|
||||||
|
|||||||
@ -45,7 +45,6 @@ test "pointer-integer arithmetic" {
|
|||||||
|
|
||||||
test "pointer subtraction" {
|
test "pointer subtraction" {
|
||||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
const a: *u8 = @ptrFromInt(100);
|
const a: *u8 = @ptrFromInt(100);
|
||||||
|
|||||||
@ -1773,25 +1773,41 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
|
|||||||
.use_llvm = true,
|
.use_llvm = true,
|
||||||
}, .{
|
}, .{
|
||||||
.name = "a",
|
.name = "a",
|
||||||
.c_source_bytes = "int foo = 42;",
|
.c_source_bytes =
|
||||||
|
\\#include <stdio.h>
|
||||||
|
\\int foo = 42;
|
||||||
|
\\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); }
|
||||||
|
,
|
||||||
});
|
});
|
||||||
|
dso.linkLibC();
|
||||||
|
|
||||||
const main = addExecutable(b, opts, .{
|
const main = addExecutable(b, opts, .{
|
||||||
.name = "main",
|
.name = "main",
|
||||||
.zig_source_bytes =
|
.zig_source_bytes =
|
||||||
|
\\const std = @import("std");
|
||||||
\\extern var foo: i32;
|
\\extern var foo: i32;
|
||||||
|
\\extern fn printFoo() void;
|
||||||
\\pub fn main() void {
|
\\pub fn main() void {
|
||||||
\\ @import("std").debug.print("{d}\n", .{foo});
|
\\ std.debug.print("exe foo={d}\n", .{foo});
|
||||||
|
\\ printFoo();
|
||||||
|
\\ foo += 1;
|
||||||
|
\\ std.debug.print("exe foo={d}\n", .{foo});
|
||||||
|
\\ printFoo();
|
||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
.strip = true, // TODO temp hack
|
.strip = true, // TODO temp hack
|
||||||
});
|
});
|
||||||
main.pie = true;
|
main.pie = true;
|
||||||
main.linkLibrary(dso);
|
main.linkLibrary(dso);
|
||||||
main.linkLibC();
|
|
||||||
|
|
||||||
const run = addRunArtifact(main);
|
const run = addRunArtifact(main);
|
||||||
run.expectStdErrEqual("42\n");
|
run.expectStdErrEqual(
|
||||||
|
\\exe foo=42
|
||||||
|
\\lib foo=42
|
||||||
|
\\exe foo=43
|
||||||
|
\\lib foo=43
|
||||||
|
\\
|
||||||
|
);
|
||||||
test_step.dependOn(&run.step);
|
test_step.dependOn(&run.step);
|
||||||
|
|
||||||
return test_step;
|
return test_step;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user