Commit 96501d3385
Changed files (4)
src
arch
src/arch/x86_64/bits.zig
@@ -192,6 +192,7 @@ pub const Register = enum(u7) {
x87,
mmx,
sse,
+ ip,
};
pub fn class(reg: Register) Class {
@@ -209,6 +210,7 @@ pub const Register = enum(u7) {
@intFromEnum(Register.st0) ... @intFromEnum(Register.st7) => .x87,
@intFromEnum(Register.es) ... @intFromEnum(Register.gs) => .segment,
+ @intFromEnum(Register.rip) ... @intFromEnum(Register.ip) => .ip,
else => unreachable,
// zig fmt: on
@@ -370,13 +372,14 @@ pub const Register = enum(u7) {
.x87 => 33 + @as(u6, reg.enc()),
.mmx => 41 + @as(u6, reg.enc()),
.segment => 50 + @as(u6, reg.enc()),
+ .ip => unreachable,
};
}
};
test "Register id - different classes" {
try expect(Register.al.id() == Register.ax.id());
- try expect(Register.ah.id() == Register.spl.id());
+ try expect(Register.ah.id() != Register.spl.id());
try expect(Register.ax.id() == Register.eax.id());
try expect(Register.eax.id() == Register.rax.id());
@@ -391,6 +394,7 @@ test "Register id - different classes" {
test "Register enc - different classes" {
try expect(Register.al.enc() == Register.ax.enc());
+ try expect(Register.ah.enc() == Register.spl.enc());
try expect(Register.ax.enc() == Register.eax.enc());
try expect(Register.eax.enc() == Register.rax.enc());
try expect(Register.ymm0.enc() == Register.rax.enc());
src/arch/x86_64/CodeGen.zig
@@ -14529,6 +14529,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo
else => {},
},
},
+ .ip => {},
}
return self.fail("TODO moveStrategy for {}", .{ty.fmt(mod)});
}
@@ -14685,6 +14686,7 @@ fn genSetReg(
else => unreachable,
},
.segment, .x87, .mmx, .sse => try self.genSetReg(dst_reg, ty, try self.genTypedValue(try mod.undefValue(ty)), opts),
+ .ip => unreachable,
},
.eflags => |cc| try self.asmSetccRegister(cc, dst_reg.to8()),
.immediate => |imm| {
@@ -14722,7 +14724,7 @@ fn genSetReg(
registerAlias(dst_reg, abi_size),
src_reg,
),
- .x87, .mmx => unreachable,
+ .x87, .mmx, .ip => unreachable,
.sse => try self.asmRegisterRegister(
switch (abi_size) {
1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },
@@ -14738,7 +14740,7 @@ fn genSetReg(
dst_reg,
switch (src_reg.class()) {
.general_purpose, .segment => registerAlias(src_reg, abi_size),
- .x87, .mmx => unreachable,
+ .x87, .mmx, .ip => unreachable,
.sse => try self.copyToTmpRegister(ty, src_mcv),
},
),
@@ -14753,7 +14755,7 @@ fn genSetReg(
},
else => unreachable,
},
- .mmx, .sse => unreachable,
+ .mmx, .sse, .ip => unreachable,
},
.mmx => unreachable,
.sse => switch (src_reg.class()) {
@@ -14772,7 +14774,7 @@ fn genSetReg(
.{ .register = try self.copyToTmpRegister(ty, src_mcv) },
opts,
),
- .x87, .mmx => unreachable,
+ .x87, .mmx, .ip => unreachable,
.sse => try self.asmRegisterRegister(
@as(?Mir.Inst.FixedTag, switch (ty.scalarType(mod).zigTypeTag(mod)) {
else => switch (abi_size) {
@@ -14799,6 +14801,7 @@ fn genSetReg(
registerAlias(src_reg, abi_size),
),
},
+ .ip => unreachable,
},
.register_pair => |src_regs| try self.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }, opts),
.register_offset,
@@ -14866,7 +14869,7 @@ fn genSetReg(
});
return;
},
- .segment, .mmx => unreachable,
+ .segment, .mmx, .ip => unreachable,
.x87, .sse => {},
},
.load_direct => |sym_index| switch (dst_reg.class()) {
@@ -14884,7 +14887,7 @@ fn genSetReg(
});
return;
},
- .segment, .mmx => unreachable,
+ .segment, .mmx, .ip => unreachable,
.x87, .sse => {},
},
.load_got, .load_tlv => {},
@@ -15047,7 +15050,7 @@ fn genSetMem(
};
const src_alias = registerAlias(src_reg, abi_size);
const src_size: u32 = @intCast(switch (src_alias.class()) {
- .general_purpose, .segment, .x87 => @divExact(src_alias.bitSize(), 8),
+ .general_purpose, .segment, .x87, .ip => @divExact(src_alias.bitSize(), 8),
.mmx, .sse => abi_size,
});
const src_align = Alignment.fromNonzeroByteUnits(math.ceilPowerOfTwoAssert(u32, src_size));
@@ -19077,6 +19080,14 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
reg.to256()
else
unreachable,
+ .ip => if (size_bytes <= 2)
+ .ip
+ else if (size_bytes <= 4)
+ .eip
+ else if (size_bytes <= 8)
+ .rip
+ else
+ unreachable,
};
}
src/arch/x86_64/encoder.zig
@@ -536,59 +536,62 @@ pub const Instruction = struct {
}
try encoder.disp32(sib.disp);
},
- .reg => |base| if (base.class() == .segment) {
- // TODO audit this wrt SIB
- try encoder.modRm_SIBDisp0(operand_enc);
- if (mem.scaleIndex()) |si| {
- const scale = math.log2_int(u4, si.scale);
- try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc());
- } else {
- try encoder.sib_disp32();
- }
- try encoder.disp32(sib.disp);
- } else {
- assert(base.class() == .general_purpose);
- const dst = base.lowEnc();
- const src = operand_enc;
- if (dst == 4 or mem.scaleIndex() != null) {
- if (sib.disp == 0 and dst != 5) {
- try encoder.modRm_SIBDisp0(src);
- if (mem.scaleIndex()) |si| {
- const scale = math.log2_int(u4, si.scale);
- try encoder.sib_scaleIndexBase(scale, si.index.lowEnc(), dst);
- } else {
- try encoder.sib_base(dst);
- }
- } else if (math.cast(i8, sib.disp)) |_| {
- try encoder.modRm_SIBDisp8(src);
- if (mem.scaleIndex()) |si| {
- const scale = math.log2_int(u4, si.scale);
- try encoder.sib_scaleIndexBaseDisp8(scale, si.index.lowEnc(), dst);
+ .reg => |base| switch (base.class()) {
+ .segment => {
+ // TODO audit this wrt SIB
+ try encoder.modRm_SIBDisp0(operand_enc);
+ if (mem.scaleIndex()) |si| {
+ const scale = math.log2_int(u4, si.scale);
+ try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc());
+ } else {
+ try encoder.sib_disp32();
+ }
+ try encoder.disp32(sib.disp);
+ },
+ .general_purpose => {
+ const dst = base.lowEnc();
+ const src = operand_enc;
+ if (dst == 4 or mem.scaleIndex() != null) {
+ if (sib.disp == 0 and dst != 5) {
+ try encoder.modRm_SIBDisp0(src);
+ if (mem.scaleIndex()) |si| {
+ const scale = math.log2_int(u4, si.scale);
+ try encoder.sib_scaleIndexBase(scale, si.index.lowEnc(), dst);
+ } else {
+ try encoder.sib_base(dst);
+ }
+ } else if (math.cast(i8, sib.disp)) |_| {
+ try encoder.modRm_SIBDisp8(src);
+ if (mem.scaleIndex()) |si| {
+ const scale = math.log2_int(u4, si.scale);
+ try encoder.sib_scaleIndexBaseDisp8(scale, si.index.lowEnc(), dst);
+ } else {
+ try encoder.sib_baseDisp8(dst);
+ }
+ try encoder.disp8(@as(i8, @truncate(sib.disp)));
} else {
- try encoder.sib_baseDisp8(dst);
+ try encoder.modRm_SIBDisp32(src);
+ if (mem.scaleIndex()) |si| {
+ const scale = math.log2_int(u4, si.scale);
+ try encoder.sib_scaleIndexBaseDisp32(scale, si.index.lowEnc(), dst);
+ } else {
+ try encoder.sib_baseDisp32(dst);
+ }
+ try encoder.disp32(sib.disp);
}
- try encoder.disp8(@as(i8, @truncate(sib.disp)));
} else {
- try encoder.modRm_SIBDisp32(src);
- if (mem.scaleIndex()) |si| {
- const scale = math.log2_int(u4, si.scale);
- try encoder.sib_scaleIndexBaseDisp32(scale, si.index.lowEnc(), dst);
+ if (sib.disp == 0 and dst != 5) {
+ try encoder.modRm_indirectDisp0(src, dst);
+ } else if (math.cast(i8, sib.disp)) |_| {
+ try encoder.modRm_indirectDisp8(src, dst);
+ try encoder.disp8(@as(i8, @truncate(sib.disp)));
} else {
- try encoder.sib_baseDisp32(dst);
+ try encoder.modRm_indirectDisp32(src, dst);
+ try encoder.disp32(sib.disp);
}
- try encoder.disp32(sib.disp);
- }
- } else {
- if (sib.disp == 0 and dst != 5) {
- try encoder.modRm_indirectDisp0(src, dst);
- } else if (math.cast(i8, sib.disp)) |_| {
- try encoder.modRm_indirectDisp8(src, dst);
- try encoder.disp8(@as(i8, @truncate(sib.disp)));
- } else {
- try encoder.modRm_indirectDisp32(src, dst);
- try encoder.disp32(sib.disp);
}
- }
+ },
+ else => unreachable,
},
.frame => if (@TypeOf(encoder).options.allow_frame_locs) {
try encoder.modRm_indirectDisp32(operand_enc, undefined);
@@ -1101,7 +1104,7 @@ const TestEncode = struct {
var stream = std.io.fixedBufferStream(&enc.buffer);
var count_writer = std.io.countingWriter(stream.writer());
const inst = try Instruction.new(.none, mnemonic, ops);
- try inst.encode(count_writer.writer());
+ try inst.encode(count_writer.writer(), .{});
enc.index = count_writer.bytes_written;
}
@@ -1118,7 +1121,7 @@ test "encode" {
.{ .reg = .rbx },
.{ .imm = 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);
}
@@ -1181,7 +1184,7 @@ test "lower MI encoding" {
try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000");
try enc.encode(.mov, &.{
- .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .r12 }) },
+ .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10");
@@ -1205,7 +1208,7 @@ test "lower MI encoding" {
try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10");
try enc.encode(.mov, &.{
- .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r11 }) },
+ .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10");
@@ -1221,26 +1224,26 @@ test "lower MI encoding" {
);
try enc.encode(.mov, &.{
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -8 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) },
.{ .imm = 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 = .rbp, .disp = -2 }) },
+ .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) },
.{ .imm = 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 = .rbp, .disp = -1 }) },
+ .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10");
try enc.encode(.mov, &.{
.{ .mem = Instruction.Memory.sib(.qword, .{
- .base = .ds,
+ .base = .{ .reg = .ds },
.disp = 0x10000000,
.scale_index = .{ .scale = 2, .index = .rcx },
}) },
@@ -1253,7 +1256,7 @@ test "lower MI encoding" {
);
try enc.encode(.adc, &.{
- .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .rbp, .disp = -0x10 }) },
+ .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10");
@@ -1271,7 +1274,7 @@ test "lower MI encoding" {
try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10");
try enc.encode(.add, &.{
- .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .rdx, .disp = -8 }) },
+ .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10");
@@ -1283,13 +1286,13 @@ test "lower MI encoding" {
try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10");
try enc.encode(.add, &.{
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -0x10 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) },
.{ .imm = 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 = .ds, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings(
@@ -1299,7 +1302,7 @@ test "lower MI encoding" {
);
try enc.encode(.@"and", &.{
- .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .es, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings(
@@ -1309,7 +1312,7 @@ test "lower MI encoding" {
);
try enc.encode(.@"and", &.{
- .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r12, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings(
@@ -1319,7 +1322,7 @@ test "lower MI encoding" {
);
try enc.encode(.sub, &.{
- .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r11, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
.{ .imm = Immediate.u(0x10) },
});
try expectEqualHexStrings(
@@ -1334,26 +1337,26 @@ test "lower RM encoding" {
try enc.encode(.mov, &.{
.{ .reg = .rax },
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r11 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 } }) },
});
try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]");
try enc.encode(.mov, &.{
.{ .reg = .rbx },
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .ds, .disp = 0x10 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10 }) },
});
try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10");
try enc.encode(.mov, &.{
.{ .reg = .rax },
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) },
});
try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]");
try enc.encode(.mov, &.{
.{ .reg = .rax },
.{ .mem = Instruction.Memory.sib(.qword, .{
- .base = .rbp,
+ .base = .{ .reg = .rbp },
.scale_index = .{ .scale = 1, .index = .rcx },
.disp = -8,
}) },
@@ -1363,7 +1366,7 @@ test "lower RM encoding" {
try enc.encode(.mov, &.{
.{ .reg = .eax },
.{ .mem = Instruction.Memory.sib(.dword, .{
- .base = .rbp,
+ .base = .{ .reg = .rbp },
.scale_index = .{ .scale = 4, .index = .rdx },
.disp = -4,
}) },
@@ -1373,7 +1376,7 @@ test "lower RM encoding" {
try enc.encode(.mov, &.{
.{ .reg = .rax },
.{ .mem = Instruction.Memory.sib(.qword, .{
- .base = .rbp,
+ .base = .{ .reg = .rbp },
.scale_index = .{ .scale = 8, .index = .rcx },
.disp = -8,
}) },
@@ -1383,7 +1386,7 @@ test "lower RM encoding" {
try enc.encode(.mov, &.{
.{ .reg = .r8b },
.{ .mem = Instruction.Memory.sib(.byte, .{
- .base = .rsi,
+ .base = .{ .reg = .rsi },
.scale_index = .{ .scale = 1, .index = .rcx },
.disp = -24,
}) },
@@ -1398,10 +1401,10 @@ test "lower RM encoding" {
try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs");
try enc.encode(.mov, &.{
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -16 }) },
+ .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
.{ .reg = .fs },
});
- try expectEqualHexStrings("\x48\x8C\x65\xF0", enc.code(), "mov QWORD PTR [rbp - 16], fs");
+ try expectEqualHexStrings("\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs");
try enc.encode(.mov, &.{
.{ .reg = .r12w },
@@ -1409,12 +1412,6 @@ test "lower RM encoding" {
});
try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs");
- try enc.encode(.mov, &.{
- .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
- .{ .reg = .fs },
- });
- try expectEqualHexStrings("\x66\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs");
-
try enc.encode(.movsx, &.{
.{ .reg = .eax },
.{ .reg = .bx },
@@ -1435,7 +1432,7 @@ test "lower RM encoding" {
try enc.encode(.movsx, &.{
.{ .reg = .eax },
- .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp }) },
+ .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) },
});
try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]");
@@ -1496,7 +1493,7 @@ test "lower RM encoding" {
try enc.encode(.lea, &.{
.{ .reg = .rsi },
.{ .mem = Instruction.Memory.sib(.qword, .{
- .base = .rbp,
+ .base = .{ .reg = .rbp },
.scale_index = .{ .scale = 1, .index = .rcx },
}) },
});
@@ -1504,31 +1501,31 @@ test "lower RM encoding" {
try enc.encode(.add, &.{
.{ .reg = .r11 },
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .ds, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
});
try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000");
try enc.encode(.add, &.{
.{ .reg = .r12b },
- .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
});
try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000");
try enc.encode(.add, &.{
.{ .reg = .r12b },
- .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .fs, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .fs }, .disp = 0x10000000 }) },
});
try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000");
try enc.encode(.sub, &.{
.{ .reg = .r11 },
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r13, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r13 }, .disp = 0x10000000 }) },
});
try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]");
try enc.encode(.sub, &.{
.{ .reg = .r11 },
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r12, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) },
});
try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]");
@@ -1562,7 +1559,7 @@ test "lower RMI encoding" {
try enc.encode(.imul, &.{
.{ .reg = .bx },
- .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
+ .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
.{ .imm = Immediate.s(-1024) },
});
try expectEqualHexStrings(
@@ -1573,7 +1570,7 @@ test "lower RMI encoding" {
try enc.encode(.imul, &.{
.{ .reg = .bx },
- .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) },
+ .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) },
.{ .imm = Immediate.u(1024) },
});
try expectEqualHexStrings(
@@ -1593,7 +1590,7 @@ test "lower MR encoding" {
try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx");
try enc.encode(.mov, &.{
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) },
.{ .reg = .r11 },
});
try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11");
@@ -1606,7 +1603,7 @@ test "lower MR encoding" {
try enc.encode(.mov, &.{
.{ .mem = Instruction.Memory.sib(.qword, .{
- .base = .r11,
+ .base = .{ .reg = .r11 },
.scale_index = .{ .scale = 2, .index = .r12 },
.disp = 0x10,
}) },
@@ -1622,7 +1619,7 @@ test "lower MR encoding" {
try enc.encode(.mov, &.{
.{ .mem = Instruction.Memory.sib(.byte, .{
- .base = .r11,
+ .base = .{ .reg = .r11 },
.scale_index = .{ .scale = 2, .index = .r12 },
.disp = 0x10,
}) },
@@ -1631,25 +1628,25 @@ test "lower MR encoding" {
try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b");
try enc.encode(.add, &.{
- .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
.{ .reg = .r12b },
});
try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b");
try enc.encode(.add, &.{
- .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) },
.{ .reg = .r12d },
});
try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d");
try enc.encode(.add, &.{
- .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .gs, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .gs }, .disp = 0x10000000 }) },
.{ .reg = .r12d },
});
try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d");
try enc.encode(.sub, &.{
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r11, .disp = 0x10000000 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) },
.{ .reg = .r12 },
});
try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12");
@@ -1664,13 +1661,13 @@ test "lower M encoding" {
try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12");
try enc.encode(.call, &.{
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r12 }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r12 } }) },
});
try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]");
try enc.encode(.call, &.{
.{ .mem = Instruction.Memory.sib(.qword, .{
- .base = null,
+ .base = .none,
.scale_index = .{ .index = .r11, .scale = 2 },
}) },
});
@@ -1678,14 +1675,14 @@ test "lower M encoding" {
try enc.encode(.call, &.{
.{ .mem = Instruction.Memory.sib(.qword, .{
- .base = null,
+ .base = .none,
.scale_index = .{ .index = .r12, .scale = 2 },
}) },
});
try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]");
try enc.encode(.call, &.{
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .gs }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .gs } }) },
});
try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0");
@@ -1695,12 +1692,12 @@ test "lower M encoding" {
try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0");
try enc.encode(.push, &.{
- .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp }) },
+ .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp } }) },
});
try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
try enc.encode(.push, &.{
- .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp }) },
+ .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) },
});
try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]");
@@ -1913,7 +1910,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand
test "cannot encode" {
try cannotEncode(.@"test", &.{
- .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .r12 }) },
+ .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) },
.{ .reg = .ah },
});
try cannotEncode(.@"test", &.{
@@ -2093,7 +2090,7 @@ const Assembler = struct {
pub fn assemble(as: *Assembler, writer: anytype) !void {
while (try as.next()) |parsed_inst| {
const inst = try Instruction.new(.none, parsed_inst.mnemonic, &parsed_inst.ops);
- try inst.encode(writer);
+ try inst.encode(writer, .{});
}
}
@@ -2262,26 +2259,26 @@ const Assembler = struct {
// Supported rules and orderings.
const rules = .{
- .{ .open_br, .base, .close_br }, // [ base ]
- .{ .open_br, .base, .plus, .disp, .close_br }, // [ base + disp ]
- .{ .open_br, .base, .minus, .disp, .close_br }, // [ base - disp ]
- .{ .open_br, .disp, .plus, .base, .close_br }, // [ disp + base ]
- .{ .open_br, .base, .plus, .index, .close_br }, // [ base + index ]
- .{ .open_br, .base, .plus, .index, .star, .scale, .close_br }, // [ base + index * scale ]
- .{ .open_br, .index, .star, .scale, .plus, .base, .close_br }, // [ index * scale + base ]
- .{ .open_br, .base, .plus, .index, .star, .scale, .plus, .disp, .close_br }, // [ base + index * scale + disp ]
- .{ .open_br, .base, .plus, .index, .star, .scale, .minus, .disp, .close_br }, // [ base + index * scale - disp ]
- .{ .open_br, .index, .star, .scale, .plus, .base, .plus, .disp, .close_br }, // [ index * scale + base + disp ]
- .{ .open_br, .index, .star, .scale, .plus, .base, .minus, .disp, .close_br }, // [ index * scale + base - disp ]
- .{ .open_br, .disp, .plus, .index, .star, .scale, .plus, .base, .close_br }, // [ disp + index * scale + base ]
- .{ .open_br, .disp, .plus, .base, .plus, .index, .star, .scale, .close_br }, // [ disp + base + index * scale ]
- .{ .open_br, .base, .plus, .disp, .plus, .index, .star, .scale, .close_br }, // [ base + disp + index * scale ]
- .{ .open_br, .base, .minus, .disp, .plus, .index, .star, .scale, .close_br }, // [ base - disp + index * scale ]
- .{ .open_br, .base, .plus, .disp, .plus, .scale, .star, .index, .close_br }, // [ base + disp + scale * index ]
- .{ .open_br, .base, .minus, .disp, .plus, .scale, .star, .index, .close_br }, // [ base - disp + scale * index ]
+ .{ .open_br, .general_purpose, .close_br }, // [ general_purpose ]
+ .{ .open_br, .general_purpose, .plus, .disp, .close_br }, // [ general_purpose + disp ]
+ .{ .open_br, .general_purpose, .minus, .disp, .close_br }, // [ general_purpose - disp ]
+ .{ .open_br, .disp, .plus, .general_purpose, .close_br }, // [ disp + general_purpose ]
+ .{ .open_br, .general_purpose, .plus, .index, .close_br }, // [ general_purpose + index ]
+ .{ .open_br, .general_purpose, .plus, .index, .star, .scale, .close_br }, // [ general_purpose + index * scale ]
+ .{ .open_br, .index, .star, .scale, .plus, .general_purpose, .close_br }, // [ index * scale + general_purpose ]
+ .{ .open_br, .general_purpose, .plus, .index, .star, .scale, .plus, .disp, .close_br }, // [ general_purpose + index * scale + disp ]
+ .{ .open_br, .general_purpose, .plus, .index, .star, .scale, .minus, .disp, .close_br }, // [ general_purpose + index * scale - disp ]
+ .{ .open_br, .index, .star, .scale, .plus, .general_purpose, .plus, .disp, .close_br }, // [ index * scale + general_purpose + disp ]
+ .{ .open_br, .index, .star, .scale, .plus, .general_purpose, .minus, .disp, .close_br }, // [ index * scale + general_purpose - disp ]
+ .{ .open_br, .disp, .plus, .index, .star, .scale, .plus, .general_purpose, .close_br }, // [ disp + index * scale + general_purpose ]
+ .{ .open_br, .disp, .plus, .general_purpose, .plus, .index, .star, .scale, .close_br }, // [ disp + general_purpose + index * scale ]
+ .{ .open_br, .general_purpose, .plus, .disp, .plus, .index, .star, .scale, .close_br }, // [ general_purpose + disp + index * scale ]
+ .{ .open_br, .general_purpose, .minus, .disp, .plus, .index, .star, .scale, .close_br }, // [ general_purpose - disp + index * scale ]
+ .{ .open_br, .general_purpose, .plus, .disp, .plus, .scale, .star, .index, .close_br }, // [ general_purpose + disp + scale * index ]
+ .{ .open_br, .general_purpose, .minus, .disp, .plus, .scale, .star, .index, .close_br }, // [ general_purpose - disp + scale * index ]
.{ .open_br, .rip, .plus, .disp, .close_br }, // [ rip + disp ]
.{ .open_br, .rip, .minus, .disp, .close_br }, // [ rig - disp ]
- .{ .base, .colon, .disp }, // seg:disp
+ .{ .segment, .colon, .disp }, // seg:disp
};
const pos = as.it.pos;
@@ -2301,7 +2298,7 @@ const Assembler = struct {
return Instruction.Memory.moffs(base, offset);
}
return Instruction.Memory.sib(ptr_size orelse .qword, .{
- .base = base,
+ .base = .{ .reg = base },
.scale_index = res.scale_index,
.disp = res.disp orelse 0,
});
@@ -2323,7 +2320,7 @@ const Assembler = struct {
offset: ?u64 = null,
};
- fn parseMemoryRule(as: *Assembler, rule: anytype) ParseError!Instruction.MemoryParseResult {
+ fn parseMemoryRule(as: *Assembler, rule: anytype) ParseError!MemoryParseResult {
var res: MemoryParseResult = .{};
inline for (rule, 0..) |cond, i| {
if (@typeInfo(@TypeOf(cond)) != .EnumLiteral) {
@@ -2333,9 +2330,11 @@ const Assembler = struct {
.open_br, .close_br, .plus, .minus, .star, .colon => {
_ = try as.expect(cond);
},
- .base => {
+ .general_purpose, .segment => {
const tok = try as.expect(.string);
- res.base = registerFromString(as.source(tok)) orelse return error.InvalidMemoryOperand;
+ const base = registerFromString(as.source(tok)) orelse return error.InvalidMemoryOperand;
+ if (base.class() != cond) return error.InvalidMemoryOperand;
+ res.base = base;
},
.rip => {
const tok = try as.expect(.string);
@@ -2529,8 +2528,8 @@ test "assemble" {
0xF3, 0x45, 0x0F, 0x10, 0xF9,
0xF2, 0x44, 0x0F, 0x10, 0x45, 0xF0,
0xF2, 0x0F, 0x11, 0x45, 0xF8,
- 0xF3, 0x44, 0x0F, 0x7E, 0x45, 0xF0,
- 0x66, 0x44, 0x0F, 0xD6, 0x45, 0xF0,
+ 0x66, 0x4C, 0x0F, 0x6E, 0x45, 0xF0,
+ 0x66, 0x4C, 0x0F, 0x7E, 0x45, 0xF0,
0x66, 0x0F, 0x2E, 0x45, 0xF0,
0xDD, 0x4D, 0xF0,
0xDF, 0x0D, 0x20, 0x00, 0x00, 0x00,
src/arch/x86_64/Encoding.zig
@@ -487,6 +487,7 @@ pub const Op = enum {
256 => .ymm,
else => unreachable,
},
+ .ip => unreachable,
},
.mem => |mem| switch (mem) {