mirror of
https://github.com/ziglang/zig.git
synced 2025-12-29 09:33:18 +00:00
x86_64: emit call rel32 for near calls with linker reloc
This commit is contained in:
parent
ffcf0478fe
commit
d25c93a868
@ -1379,14 +1379,19 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.FixedTag, imm: Immediate) !void {
|
||||
.ops = switch (imm) {
|
||||
.signed => .i_s,
|
||||
.unsigned => .i_u,
|
||||
.reloc => .rel,
|
||||
},
|
||||
.data = switch (imm) {
|
||||
.reloc => |x| .{ .reloc = x },
|
||||
.signed, .unsigned => .{ .i = .{
|
||||
.fixes = tag[0],
|
||||
.i = switch (imm) {
|
||||
.signed => |s| @bitCast(s),
|
||||
.unsigned => |u| @intCast(u),
|
||||
.reloc => unreachable,
|
||||
},
|
||||
} },
|
||||
},
|
||||
.data = .{ .i = .{
|
||||
.fixes = tag[0],
|
||||
.i = switch (imm) {
|
||||
.signed => |s| @bitCast(s),
|
||||
.unsigned => |u| @intCast(u),
|
||||
},
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
@ -1406,6 +1411,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm:
|
||||
const ops: Mir.Inst.Ops = switch (imm) {
|
||||
.signed => .ri_s,
|
||||
.unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
|
||||
.reloc => unreachable,
|
||||
};
|
||||
_ = try self.addInst(.{
|
||||
.tag = tag[1],
|
||||
@ -1417,6 +1423,7 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.FixedTag, reg: Register, imm:
|
||||
.i = switch (imm) {
|
||||
.signed => |s| @bitCast(s),
|
||||
.unsigned => |u| @intCast(u),
|
||||
.reloc => unreachable,
|
||||
},
|
||||
} },
|
||||
.ri64 => .{ .rx = .{
|
||||
@ -1488,6 +1495,7 @@ fn asmRegisterRegisterRegisterImmediate(
|
||||
.i = switch (imm) {
|
||||
.signed => |s| @bitCast(@as(i8, @intCast(s))),
|
||||
.unsigned => |u| @intCast(u),
|
||||
.reloc => unreachable,
|
||||
},
|
||||
} },
|
||||
});
|
||||
@ -1505,6 +1513,7 @@ fn asmRegisterRegisterImmediate(
|
||||
.ops = switch (imm) {
|
||||
.signed => .rri_s,
|
||||
.unsigned => .rri_u,
|
||||
.reloc => unreachable,
|
||||
},
|
||||
.data = .{ .rri = .{
|
||||
.fixes = tag[0],
|
||||
@ -1513,6 +1522,7 @@ fn asmRegisterRegisterImmediate(
|
||||
.i = switch (imm) {
|
||||
.signed => |s| @bitCast(s),
|
||||
.unsigned => |u| @intCast(u),
|
||||
.reloc => unreachable,
|
||||
},
|
||||
} },
|
||||
});
|
||||
@ -1610,6 +1620,7 @@ fn asmRegisterMemoryImmediate(
|
||||
if (switch (imm) {
|
||||
.signed => |s| if (math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null,
|
||||
.unsigned => |u| math.cast(u16, u),
|
||||
.reloc => unreachable,
|
||||
}) |small_imm| {
|
||||
_ = try self.addInst(.{
|
||||
.tag = tag[1],
|
||||
@ -1625,6 +1636,7 @@ fn asmRegisterMemoryImmediate(
|
||||
const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
|
||||
.signed => |s| @bitCast(s),
|
||||
.unsigned => unreachable,
|
||||
.reloc => unreachable,
|
||||
} });
|
||||
assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));
|
||||
_ = try self.addInst(.{
|
||||
@ -1632,6 +1644,7 @@ fn asmRegisterMemoryImmediate(
|
||||
.ops = switch (imm) {
|
||||
.signed => .rmi_s,
|
||||
.unsigned => .rmi_u,
|
||||
.reloc => unreachable,
|
||||
},
|
||||
.data = .{ .rx = .{
|
||||
.fixes = tag[0],
|
||||
@ -1679,6 +1692,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed
|
||||
const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
|
||||
.signed => |s| @bitCast(s),
|
||||
.unsigned => |u| @intCast(u),
|
||||
.reloc => unreachable,
|
||||
} });
|
||||
assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));
|
||||
_ = try self.addInst(.{
|
||||
@ -1686,6 +1700,7 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.FixedTag, m: Memory, imm: Immed
|
||||
.ops = switch (imm) {
|
||||
.signed => .mi_s,
|
||||
.unsigned => .mi_u,
|
||||
.reloc => unreachable,
|
||||
},
|
||||
.data = .{ .x = .{
|
||||
.fixes = tag[0],
|
||||
@ -12310,33 +12325,10 @@ fn genCall(self: *Self, info: union(enum) {
|
||||
if (self.bin_file.cast(.elf)) |elf_file| {
|
||||
const zo = elf_file.zigObjectPtr().?;
|
||||
const sym_index = try zo.getOrCreateMetadataForNav(elf_file, func.owner_nav);
|
||||
if (self.mod.pic) {
|
||||
const callee_reg: Register = switch (resolved_cc) {
|
||||
.SysV => callee: {
|
||||
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,
|
||||
.{ .lea_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 } },
|
||||
});
|
||||
try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
|
||||
.atom_index = try self.owner.getSymbolIndex(self),
|
||||
.sym_index = sym_index,
|
||||
}));
|
||||
} else if (self.bin_file.cast(.coff)) |coff_file| {
|
||||
const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);
|
||||
const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
|
||||
|
||||
@ -8,7 +8,7 @@ const bits = @import("bits.zig");
|
||||
const encoder = @import("encoder.zig");
|
||||
|
||||
const Encoding = @import("Encoding.zig");
|
||||
const Immediate = bits.Immediate;
|
||||
const Immediate = Instruction.Immediate;
|
||||
const Instruction = encoder.Instruction;
|
||||
const LegacyPrefixes = encoder.LegacyPrefixes;
|
||||
const Memory = Instruction.Memory;
|
||||
|
||||
@ -475,7 +475,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
|
||||
.rrmi => inst.data.rrix.fixes,
|
||||
.mi_u, .mi_s => 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)}),
|
||||
};
|
||||
try lower.emit(switch (fixes) {
|
||||
@ -607,7 +607,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
|
||||
.{ .mem = lower.mem(inst.data.rrix.payload) },
|
||||
.{ .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 }) },
|
||||
},
|
||||
.got_reloc, .direct_reloc, .import_reloc => ops: {
|
||||
@ -650,7 +650,7 @@ const std = @import("std");
|
||||
const Air = @import("../../Air.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ErrorMsg = Zcu.ErrorMsg;
|
||||
const Immediate = bits.Immediate;
|
||||
const Immediate = Instruction.Immediate;
|
||||
const Instruction = encoder.Instruction;
|
||||
const Lower = @This();
|
||||
const Memory = Instruction.Memory;
|
||||
|
||||
@ -769,7 +769,7 @@ pub const Inst = struct {
|
||||
/// Uses `imm` payload.
|
||||
i_u,
|
||||
/// Relative displacement operand.
|
||||
/// Uses `imm` payload.
|
||||
/// Uses `reloc` payload.
|
||||
rel,
|
||||
/// Register, memory operands.
|
||||
/// Uses `rx` payload with extra data of type `Memory`.
|
||||
|
||||
@ -569,6 +569,7 @@ pub const Memory = struct {
|
||||
pub const Immediate = union(enum) {
|
||||
signed: i32,
|
||||
unsigned: u64,
|
||||
reloc: Symbol,
|
||||
|
||||
pub fn u(x: u64) Immediate {
|
||||
return .{ .unsigned = x };
|
||||
@ -578,39 +579,19 @@ pub const Immediate = union(enum) {
|
||||
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 rel(symbol: Symbol) Immediate {
|
||||
return .{ .reloc = symbol };
|
||||
}
|
||||
|
||||
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 fn format(
|
||||
imm: Immediate,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) @TypeOf(writer).Error!void {
|
||||
switch (imm) {
|
||||
.reloc => |x| try std.fmt.formatType(x, fmt, options, writer, 0),
|
||||
inline else => |x| try writer.print("{d}", .{x}),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -7,7 +7,6 @@ const testing = std.testing;
|
||||
const bits = @import("bits.zig");
|
||||
const Encoding = @import("Encoding.zig");
|
||||
const FrameIndex = bits.FrameIndex;
|
||||
const Immediate = bits.Immediate;
|
||||
const Register = bits.Register;
|
||||
const Symbol = bits.Symbol;
|
||||
|
||||
@ -28,6 +27,55 @@ pub const Instruction = struct {
|
||||
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) {
|
||||
sib: Sib,
|
||||
rip: Rip,
|
||||
@ -1119,7 +1167,7 @@ test "encode" {
|
||||
|
||||
const inst = try Instruction.new(.none, .mov, &.{
|
||||
.{ .reg = .rbx },
|
||||
.{ .imm = Immediate.u(4) },
|
||||
.{ .imm = Instruction.Immediate.u(4) },
|
||||
});
|
||||
try inst.encode(buf.writer(), .{});
|
||||
try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items);
|
||||
@ -1129,47 +1177,47 @@ test "lower I encoding" {
|
||||
var enc = TestEncode{};
|
||||
|
||||
try enc.encode(.push, &.{
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x6A\x10", enc.code(), "push 0x10");
|
||||
|
||||
try enc.encode(.push, &.{
|
||||
.{ .imm = Immediate.u(0x1000) },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\x68\x00\x10", enc.code(), "push 0x1000");
|
||||
|
||||
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 enc.encode(.adc, &.{
|
||||
.{ .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 enc.encode(.add, &.{
|
||||
.{ .reg = .al },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x04\x10", enc.code(), "add al, 0x10");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
|
||||
|
||||
try enc.encode(.sbb, &.{
|
||||
.{ .reg = .ax },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\x1D\x10\x00", enc.code(), "sbb ax, 0x10");
|
||||
|
||||
try enc.encode(.xor, &.{
|
||||
.{ .reg = .al },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x34\x10", enc.code(), "xor al, 0x10");
|
||||
}
|
||||
@ -1179,43 +1227,43 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .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 enc.encode(.mov, &.{
|
||||
.{ .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 enc.encode(.mov, &.{
|
||||
.{ .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 enc.encode(.mov, &.{
|
||||
.{ .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 enc.encode(.mov, &.{
|
||||
.{ .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 enc.encode(.mov, &.{
|
||||
.{ .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 enc.encode(.mov, &.{
|
||||
.{ .mem = Instruction.Memory.rip(.qword, 0x10) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
|
||||
@ -1225,19 +1273,19 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .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 enc.encode(.mov, &.{
|
||||
.{ .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 enc.encode(.mov, &.{
|
||||
.{ .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");
|
||||
|
||||
@ -1247,7 +1295,7 @@ test "lower MI encoding" {
|
||||
.disp = 0x10000000,
|
||||
.scale_index = .{ .scale = 2, .index = .rcx },
|
||||
}) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
|
||||
@ -1257,43 +1305,43 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.adc, &.{
|
||||
.{ .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 enc.encode(.adc, &.{
|
||||
.{ .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 enc.encode(.adc, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .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 enc.encode(.add, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
|
||||
|
||||
try enc.encode(.add, &.{
|
||||
.{ .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 enc.encode(.@"and", &.{
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x83\x24\x25\x00\x00\x00\x10\x10",
|
||||
@ -1303,7 +1351,7 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.@"and", &.{
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x26\x83\x24\x25\x00\x00\x00\x10\x10",
|
||||
@ -1313,7 +1361,7 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.@"and", &.{
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x41\x83\xA4\x24\x00\x00\x00\x10\x10",
|
||||
@ -1323,7 +1371,7 @@ test "lower MI encoding" {
|
||||
|
||||
try enc.encode(.sub, &.{
|
||||
.{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x41\x83\xAB\x00\x00\x00\x10\x10",
|
||||
@ -1542,14 +1590,14 @@ test "lower RMI encoding" {
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .r11 },
|
||||
.{ .reg = .r12 },
|
||||
.{ .imm = Immediate.s(-2) },
|
||||
.{ .imm = Instruction.Immediate.s(-2) },
|
||||
});
|
||||
try expectEqualHexStrings("\x4D\x6B\xDC\xFE", enc.code(), "imul r11, r12, -2");
|
||||
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .r11 },
|
||||
.{ .mem = Instruction.Memory.rip(.qword, -16) },
|
||||
.{ .imm = Immediate.s(-1024) },
|
||||
.{ .imm = Instruction.Immediate.s(-1024) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x4C\x69\x1D\xF0\xFF\xFF\xFF\x00\xFC\xFF\xFF",
|
||||
@ -1560,7 +1608,7 @@ test "lower RMI encoding" {
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .bx },
|
||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
|
||||
.{ .imm = Immediate.s(-1024) },
|
||||
.{ .imm = Instruction.Immediate.s(-1024) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x66\x69\x5D\xF0\x00\xFC",
|
||||
@ -1571,7 +1619,7 @@ test "lower RMI encoding" {
|
||||
try enc.encode(.imul, &.{
|
||||
.{ .reg = .bx },
|
||||
.{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
|
||||
.{ .imm = Immediate.u(1024) },
|
||||
.{ .imm = Instruction.Immediate.u(1024) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\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 enc.encode(.call, &.{
|
||||
.{ .imm = Immediate.s(0) },
|
||||
.{ .imm = Instruction.Immediate.s(0) },
|
||||
});
|
||||
try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
|
||||
|
||||
@ -1746,7 +1794,7 @@ test "lower OI encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .rax },
|
||||
.{ .imm = Immediate.u(0x1000000000000000) },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000000000000000) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
|
||||
@ -1756,7 +1804,7 @@ test "lower OI encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .r11 },
|
||||
.{ .imm = Immediate.u(0x1000000000000000) },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000000000000000) },
|
||||
});
|
||||
try expectEqualHexStrings(
|
||||
"\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
|
||||
@ -1766,19 +1814,19 @@ test "lower OI encoding" {
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .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 enc.encode(.mov, &.{
|
||||
.{ .reg = .r11w },
|
||||
.{ .imm = Immediate.u(0x1000) },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000) },
|
||||
});
|
||||
try expectEqualHexStrings("\x66\x41\xBB\x00\x10", enc.code(), "mov r11w, 0x1000");
|
||||
|
||||
try enc.encode(.mov, &.{
|
||||
.{ .reg = .r11b },
|
||||
.{ .imm = Immediate.u(0x10) },
|
||||
.{ .imm = Instruction.Immediate.u(0x10) },
|
||||
});
|
||||
try expectEqualHexStrings("\x41\xB3\x10", enc.code(), "mov r11b, 0x10");
|
||||
}
|
||||
@ -1900,7 +1948,7 @@ test "invalid instruction" {
|
||||
.{ .reg = .r12d },
|
||||
});
|
||||
try invalidInstruction(.push, &.{
|
||||
.{ .imm = Immediate.u(0x1000000000000000) },
|
||||
.{ .imm = Instruction.Immediate.u(0x1000000000000000) },
|
||||
});
|
||||
}
|
||||
|
||||
@ -2213,7 +2261,7 @@ const Assembler = struct {
|
||||
.immediate => {
|
||||
const is_neg = if (as.expect(.minus)) |_| true else |_| false;
|
||||
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);
|
||||
break :blk .{ .signed = imm * -1 };
|
||||
} else .{ .unsigned = try std.fmt.parseInt(u64, as.source(imm_tok), 0) };
|
||||
|
||||
@ -1215,12 +1215,11 @@ const x86_64 = struct {
|
||||
);
|
||||
},
|
||||
|
||||
.PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
|
||||
|
||||
.PC32 => {
|
||||
.PLT32 => {
|
||||
const S_ = if (target.flags.zig_jump_table) ZJT else S;
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
|
||||
},
|
||||
.PC32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + 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),
|
||||
@ -1620,7 +1619,7 @@ const x86_64 = struct {
|
||||
const bits = @import("../../arch/x86_64/bits.zig");
|
||||
const encoder = @import("../../arch/x86_64/encoder.zig");
|
||||
const Disassembler = @import("../../arch/x86_64/Disassembler.zig");
|
||||
const Immediate = bits.Immediate;
|
||||
const Immediate = Instruction.Immediate;
|
||||
const Instruction = encoder.Instruction;
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user