diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2024-06-16 12:43:18 -0400 |
|---|---|---|
| committer | Jacob Young <jacobly0@users.noreply.github.com> | 2024-06-16 14:59:56 -0400 |
| commit | 96501d338550f47671692c669cb76eb99513a8da (patch) | |
| tree | 61385f8edbd3e94c32befb476e4340a17b205ec0 /src/arch | |
| parent | 17f14e1d65b59ebb1a8b5b617cc31fb2614f0c6a (diff) | |
| download | zig-96501d338550f47671692c669cb76eb99513a8da.tar.gz zig-96501d338550f47671692c669cb76eb99513a8da.zip | |
x86_64: get encoder tests passing again
Diffstat (limited to 'src/arch')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 25 | ||||
| -rw-r--r-- | src/arch/x86_64/Encoding.zig | 1 | ||||
| -rw-r--r-- | src/arch/x86_64/bits.zig | 6 | ||||
| -rw-r--r-- | src/arch/x86_64/encoder.zig | 249 |
4 files changed, 148 insertions, 133 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index cc6e014080..b733f2b245 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/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, }; } diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig index e4c2a39d18..19534e3e3f 100644 --- a/src/arch/x86_64/Encoding.zig +++ b/src/arch/x86_64/Encoding.zig @@ -487,6 +487,7 @@ pub const Op = enum { 256 => .ymm, else => unreachable, }, + .ip => unreachable, }, .mem => |mem| switch (mem) { diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index 554f944054..6896d6c2e7 100644 --- a/src/arch/x86_64/bits.zig +++ b/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()); diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index b499ccfdca..5f49443934 100644 --- a/src/arch/x86_64/encoder.zig +++ b/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, |
