| ... | @@ -536,59 +536,62 @@ pub const Instruction = struct { | ... | @@ -536,59 +536,62 @@ pub const Instruction = struct { |
| 536 | } | 536 | } |
| 537 | try encoder.disp32(sib.disp); | 537 | try encoder.disp32(sib.disp); |
| 538 | }, | 538 | }, |
| 539 | .reg => |base| if (base.class() == .segment) { | 539 | .reg => |base| switch (base.class()) { |
| 540 | // TODO audit this wrt SIB | 540 | .segment => { |
| 541 | try encoder.modRm_SIBDisp0(operand_enc); | 541 | // TODO audit this wrt SIB |
| 542 | if (mem.scaleIndex()) |si| { | 542 | try encoder.modRm_SIBDisp0(operand_enc); |
| 543 | const scale = math.log2_int(u4, si.scale); | 543 | if (mem.scaleIndex()) |si| { |
| 544 | try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc()); | 544 | const scale = math.log2_int(u4, si.scale); |
| 545 | } else { | 545 | try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc()); |
| 546 | try encoder.sib_disp32(); | 546 | } else { |
| 547 | } | 547 | try encoder.sib_disp32(); |
| 548 | try encoder.disp32(sib.disp); | 548 | } |
| 549 | } else { | 549 | try encoder.disp32(sib.disp); |
| 550 | assert(base.class() == .general_purpose); | 550 | }, |
| 551 | const dst = base.lowEnc(); | 551 | .general_purpose => { |
| 552 | const src = operand_enc; | 552 | const dst = base.lowEnc(); |
| 553 | if (dst == 4 or mem.scaleIndex() != null) { | 553 | const src = operand_enc; |
| 554 | if (sib.disp == 0 and dst != 5) { | 554 | if (dst == 4 or mem.scaleIndex() != null) { |
| 555 | try encoder.modRm_SIBDisp0(src); | 555 | if (sib.disp == 0 and dst != 5) { |
| 556 | if (mem.scaleIndex()) |si| { | 556 | try encoder.modRm_SIBDisp0(src); |
| 557 | const scale = math.log2_int(u4, si.scale); | 557 | if (mem.scaleIndex()) |si| { |
| 558 | try encoder.sib_scaleIndexBase(scale, si.index.lowEnc(), dst); | 558 | const scale = math.log2_int(u4, si.scale); |
| 559 | } else { | 559 | try encoder.sib_scaleIndexBase(scale, si.index.lowEnc(), dst); |
| 560 | try encoder.sib_base(dst); | 560 | } else { |
| 561 | } | 561 | try encoder.sib_base(dst); |
| 562 | } else if (math.cast(i8, sib.disp)) |_| { | 562 | } |
| 563 | try encoder.modRm_SIBDisp8(src); | 563 | } else if (math.cast(i8, sib.disp)) |_| { |
| 564 | if (mem.scaleIndex()) |si| { | 564 | try encoder.modRm_SIBDisp8(src); |
| 565 | const scale = math.log2_int(u4, si.scale); | 565 | if (mem.scaleIndex()) |si| { |
| 566 | try encoder.sib_scaleIndexBaseDisp8(scale, si.index.lowEnc(), dst); | 566 | const scale = math.log2_int(u4, si.scale); |
| | 567 | try encoder.sib_scaleIndexBaseDisp8(scale, si.index.lowEnc(), dst); |
| | 568 | } else { |
| | 569 | try encoder.sib_baseDisp8(dst); |
| | 570 | } |
| | 571 | try encoder.disp8(@as(i8, @truncate(sib.disp))); |
| 567 | } else { | 572 | } else { |
| 568 | try encoder.sib_baseDisp8(dst); | 573 | try encoder.modRm_SIBDisp32(src); |
| | 574 | if (mem.scaleIndex()) |si| { |
| | 575 | const scale = math.log2_int(u4, si.scale); |
| | 576 | try encoder.sib_scaleIndexBaseDisp32(scale, si.index.lowEnc(), dst); |
| | 577 | } else { |
| | 578 | try encoder.sib_baseDisp32(dst); |
| | 579 | } |
| | 580 | try encoder.disp32(sib.disp); |
| 569 | } | 581 | } |
| 570 | try encoder.disp8(@as(i8, @truncate(sib.disp))); | | |
| 571 | } else { | 582 | } else { |
| 572 | try encoder.modRm_SIBDisp32(src); | 583 | if (sib.disp == 0 and dst != 5) { |
| 573 | if (mem.scaleIndex()) |si| { | 584 | try encoder.modRm_indirectDisp0(src, dst); |
| 574 | const scale = math.log2_int(u4, si.scale); | 585 | } else if (math.cast(i8, sib.disp)) |_| { |
| 575 | try encoder.sib_scaleIndexBaseDisp32(scale, si.index.lowEnc(), dst); | 586 | try encoder.modRm_indirectDisp8(src, dst); |
| | 587 | try encoder.disp8(@as(i8, @truncate(sib.disp))); |
| 576 | } else { | 588 | } else { |
| 577 | try encoder.sib_baseDisp32(dst); | 589 | try encoder.modRm_indirectDisp32(src, dst); |
| | 590 | try encoder.disp32(sib.disp); |
| 578 | } | 591 | } |
| 579 | try encoder.disp32(sib.disp); | | |
| 580 | } | | |
| 581 | } else { | | |
| 582 | if (sib.disp == 0 and dst != 5) { | | |
| 583 | try encoder.modRm_indirectDisp0(src, dst); | | |
| 584 | } else if (math.cast(i8, sib.disp)) |_| { | | |
| 585 | try encoder.modRm_indirectDisp8(src, dst); | | |
| 586 | try encoder.disp8(@as(i8, @truncate(sib.disp))); | | |
| 587 | } else { | | |
| 588 | try encoder.modRm_indirectDisp32(src, dst); | | |
| 589 | try encoder.disp32(sib.disp); | | |
| 590 | } | 592 | } |
| 591 | } | 593 | }, |
| | 594 | else => unreachable, |
| 592 | }, | 595 | }, |
| 593 | .frame => if (@TypeOf(encoder).options.allow_frame_locs) { | 596 | .frame => if (@TypeOf(encoder).options.allow_frame_locs) { |
| 594 | try encoder.modRm_indirectDisp32(operand_enc, undefined); | 597 | try encoder.modRm_indirectDisp32(operand_enc, undefined); |
| ... | @@ -1101,7 +1104,7 @@ const TestEncode = struct { | ... | @@ -1101,7 +1104,7 @@ const TestEncode = struct { |
| 1101 | var stream = std.io.fixedBufferStream(&enc.buffer); | 1104 | var stream = std.io.fixedBufferStream(&enc.buffer); |
| 1102 | var count_writer = std.io.countingWriter(stream.writer()); | 1105 | var count_writer = std.io.countingWriter(stream.writer()); |
| 1103 | const inst = try Instruction.new(.none, mnemonic, ops); | 1106 | const inst = try Instruction.new(.none, mnemonic, ops); |
| 1104 | try inst.encode(count_writer.writer()); | 1107 | try inst.encode(count_writer.writer(), .{}); |
| 1105 | enc.index = count_writer.bytes_written; | 1108 | enc.index = count_writer.bytes_written; |
| 1106 | } | 1109 | } |
| 1107 | | 1110 | |
| ... | @@ -1118,7 +1121,7 @@ test "encode" { | ... | @@ -1118,7 +1121,7 @@ test "encode" { |
| 1118 | .{ .reg = .rbx }, | 1121 | .{ .reg = .rbx }, |
| 1119 | .{ .imm = Immediate.u(4) }, | 1122 | .{ .imm = Immediate.u(4) }, |
| 1120 | }); | 1123 | }); |
| 1121 | try inst.encode(buf.writer()); | 1124 | try inst.encode(buf.writer(), .{}); |
| 1122 | try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items); | 1125 | try testing.expectEqualSlices(u8, &.{ 0x48, 0xc7, 0xc3, 0x4, 0x0, 0x0, 0x0 }, buf.items); |
| 1123 | } | 1126 | } |
| 1124 | | 1127 | |
| ... | @@ -1181,7 +1184,7 @@ test "lower MI encoding" { | ... | @@ -1181,7 +1184,7 @@ test "lower MI encoding" { |
| 1181 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); | 1184 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); |
| 1182 | | 1185 | |
| 1183 | try enc.encode(.mov, &.{ | 1186 | try enc.encode(.mov, &.{ |
| 1184 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .r12 }) }, | 1187 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) }, |
| 1185 | .{ .imm = Immediate.u(0x10) }, | 1188 | .{ .imm = Immediate.u(0x10) }, |
| 1186 | }); | 1189 | }); |
| 1187 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); | 1190 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); |
| ... | @@ -1205,7 +1208,7 @@ test "lower MI encoding" { | ... | @@ -1205,7 +1208,7 @@ test "lower MI encoding" { |
| 1205 | try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); | 1208 | try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); |
| 1206 | | 1209 | |
| 1207 | try enc.encode(.mov, &.{ | 1210 | try enc.encode(.mov, &.{ |
| 1208 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r11 }) }, | 1211 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) }, |
| 1209 | .{ .imm = Immediate.u(0x10) }, | 1212 | .{ .imm = Immediate.u(0x10) }, |
| 1210 | }); | 1213 | }); |
| 1211 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); | 1214 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); |
| ... | @@ -1221,26 +1224,26 @@ test "lower MI encoding" { | ... | @@ -1221,26 +1224,26 @@ test "lower MI encoding" { |
| 1221 | ); | 1224 | ); |
| 1222 | | 1225 | |
| 1223 | try enc.encode(.mov, &.{ | 1226 | try enc.encode(.mov, &.{ |
| 1224 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -8 }) }, | 1227 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) }, |
| 1225 | .{ .imm = Immediate.u(0x10) }, | 1228 | .{ .imm = Immediate.u(0x10) }, |
| 1226 | }); | 1229 | }); |
| 1227 | try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10"); | 1230 | try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10"); |
| 1228 | | 1231 | |
| 1229 | try enc.encode(.mov, &.{ | 1232 | try enc.encode(.mov, &.{ |
| 1230 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -2 }) }, | 1233 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) }, |
| 1231 | .{ .imm = Immediate.s(-16) }, | 1234 | .{ .imm = Immediate.s(-16) }, |
| 1232 | }); | 1235 | }); |
| 1233 | try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16"); | 1236 | try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16"); |
| 1234 | | 1237 | |
| 1235 | try enc.encode(.mov, &.{ | 1238 | try enc.encode(.mov, &.{ |
| 1236 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .rbp, .disp = -1 }) }, | 1239 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) }, |
| 1237 | .{ .imm = Immediate.u(0x10) }, | 1240 | .{ .imm = Immediate.u(0x10) }, |
| 1238 | }); | 1241 | }); |
| 1239 | try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10"); | 1242 | try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10"); |
| 1240 | | 1243 | |
| 1241 | try enc.encode(.mov, &.{ | 1244 | try enc.encode(.mov, &.{ |
| 1242 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1245 | .{ .mem = Instruction.Memory.sib(.qword, .{ |
| 1243 | .base = .ds, | 1246 | .base = .{ .reg = .ds }, |
| 1244 | .disp = 0x10000000, | 1247 | .disp = 0x10000000, |
| 1245 | .scale_index = .{ .scale = 2, .index = .rcx }, | 1248 | .scale_index = .{ .scale = 2, .index = .rcx }, |
| 1246 | }) }, | 1249 | }) }, |
| ... | @@ -1253,7 +1256,7 @@ test "lower MI encoding" { | ... | @@ -1253,7 +1256,7 @@ test "lower MI encoding" { |
| 1253 | ); | 1256 | ); |
| 1254 | | 1257 | |
| 1255 | try enc.encode(.adc, &.{ | 1258 | try enc.encode(.adc, &.{ |
| 1256 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .rbp, .disp = -0x10 }) }, | 1259 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, |
| 1257 | .{ .imm = Immediate.u(0x10) }, | 1260 | .{ .imm = Immediate.u(0x10) }, |
| 1258 | }); | 1261 | }); |
| 1259 | try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10"); | 1262 | try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10"); |
| ... | @@ -1271,7 +1274,7 @@ test "lower MI encoding" { | ... | @@ -1271,7 +1274,7 @@ test "lower MI encoding" { |
| 1271 | try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10"); | 1274 | try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10"); |
| 1272 | | 1275 | |
| 1273 | try enc.encode(.add, &.{ | 1276 | try enc.encode(.add, &.{ |
| 1274 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .rdx, .disp = -8 }) }, | 1277 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) }, |
| 1275 | .{ .imm = Immediate.u(0x10) }, | 1278 | .{ .imm = Immediate.u(0x10) }, |
| 1276 | }); | 1279 | }); |
| 1277 | try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10"); | 1280 | try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10"); |
| ... | @@ -1283,13 +1286,13 @@ test "lower MI encoding" { | ... | @@ -1283,13 +1286,13 @@ test "lower MI encoding" { |
| 1283 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); | 1286 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); |
| 1284 | | 1287 | |
| 1285 | try enc.encode(.add, &.{ | 1288 | try enc.encode(.add, &.{ |
| 1286 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -0x10 }) }, | 1289 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, |
| 1287 | .{ .imm = Immediate.s(-0x10) }, | 1290 | .{ .imm = Immediate.s(-0x10) }, |
| 1288 | }); | 1291 | }); |
| 1289 | try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10"); | 1292 | try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10"); |
| 1290 | | 1293 | |
| 1291 | try enc.encode(.@"and", &.{ | 1294 | try enc.encode(.@"and", &.{ |
| 1292 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) }, | 1295 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1293 | .{ .imm = Immediate.u(0x10) }, | 1296 | .{ .imm = Immediate.u(0x10) }, |
| 1294 | }); | 1297 | }); |
| 1295 | try expectEqualHexStrings( | 1298 | try expectEqualHexStrings( |
| ... | @@ -1299,7 +1302,7 @@ test "lower MI encoding" { | ... | @@ -1299,7 +1302,7 @@ test "lower MI encoding" { |
| 1299 | ); | 1302 | ); |
| 1300 | | 1303 | |
| 1301 | try enc.encode(.@"and", &.{ | 1304 | try enc.encode(.@"and", &.{ |
| 1302 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .es, .disp = 0x10000000 }) }, | 1305 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) }, |
| 1303 | .{ .imm = Immediate.u(0x10) }, | 1306 | .{ .imm = Immediate.u(0x10) }, |
| 1304 | }); | 1307 | }); |
| 1305 | try expectEqualHexStrings( | 1308 | try expectEqualHexStrings( |
| ... | @@ -1309,7 +1312,7 @@ test "lower MI encoding" { | ... | @@ -1309,7 +1312,7 @@ test "lower MI encoding" { |
| 1309 | ); | 1312 | ); |
| 1310 | | 1313 | |
| 1311 | try enc.encode(.@"and", &.{ | 1314 | try enc.encode(.@"and", &.{ |
| 1312 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r12, .disp = 0x10000000 }) }, | 1315 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) }, |
| 1313 | .{ .imm = Immediate.u(0x10) }, | 1316 | .{ .imm = Immediate.u(0x10) }, |
| 1314 | }); | 1317 | }); |
| 1315 | try expectEqualHexStrings( | 1318 | try expectEqualHexStrings( |
| ... | @@ -1319,7 +1322,7 @@ test "lower MI encoding" { | ... | @@ -1319,7 +1322,7 @@ test "lower MI encoding" { |
| 1319 | ); | 1322 | ); |
| 1320 | | 1323 | |
| 1321 | try enc.encode(.sub, &.{ | 1324 | try enc.encode(.sub, &.{ |
| 1322 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .r11, .disp = 0x10000000 }) }, | 1325 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) }, |
| 1323 | .{ .imm = Immediate.u(0x10) }, | 1326 | .{ .imm = Immediate.u(0x10) }, |
| 1324 | }); | 1327 | }); |
| 1325 | try expectEqualHexStrings( | 1328 | try expectEqualHexStrings( |
| ... | @@ -1334,26 +1337,26 @@ test "lower RM encoding" { | ... | @@ -1334,26 +1337,26 @@ test "lower RM encoding" { |
| 1334 | | 1337 | |
| 1335 | try enc.encode(.mov, &.{ | 1338 | try enc.encode(.mov, &.{ |
| 1336 | .{ .reg = .rax }, | 1339 | .{ .reg = .rax }, |
| 1337 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r11 }) }, | 1340 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 } }) }, |
| 1338 | }); | 1341 | }); |
| 1339 | try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]"); | 1342 | try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]"); |
| 1340 | | 1343 | |
| 1341 | try enc.encode(.mov, &.{ | 1344 | try enc.encode(.mov, &.{ |
| 1342 | .{ .reg = .rbx }, | 1345 | .{ .reg = .rbx }, |
| 1343 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .ds, .disp = 0x10 }) }, | 1346 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10 }) }, |
| 1344 | }); | 1347 | }); |
| 1345 | try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10"); | 1348 | try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10"); |
| 1346 | | 1349 | |
| 1347 | try enc.encode(.mov, &.{ | 1350 | try enc.encode(.mov, &.{ |
| 1348 | .{ .reg = .rax }, | 1351 | .{ .reg = .rax }, |
| 1349 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) }, | 1352 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) }, |
| 1350 | }); | 1353 | }); |
| 1351 | try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]"); | 1354 | try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]"); |
| 1352 | | 1355 | |
| 1353 | try enc.encode(.mov, &.{ | 1356 | try enc.encode(.mov, &.{ |
| 1354 | .{ .reg = .rax }, | 1357 | .{ .reg = .rax }, |
| 1355 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1358 | .{ .mem = Instruction.Memory.sib(.qword, .{ |
| 1356 | .base = .rbp, | 1359 | .base = .{ .reg = .rbp }, |
| 1357 | .scale_index = .{ .scale = 1, .index = .rcx }, | 1360 | .scale_index = .{ .scale = 1, .index = .rcx }, |
| 1358 | .disp = -8, | 1361 | .disp = -8, |
| 1359 | }) }, | 1362 | }) }, |
| ... | @@ -1363,7 +1366,7 @@ test "lower RM encoding" { | ... | @@ -1363,7 +1366,7 @@ test "lower RM encoding" { |
| 1363 | try enc.encode(.mov, &.{ | 1366 | try enc.encode(.mov, &.{ |
| 1364 | .{ .reg = .eax }, | 1367 | .{ .reg = .eax }, |
| 1365 | .{ .mem = Instruction.Memory.sib(.dword, .{ | 1368 | .{ .mem = Instruction.Memory.sib(.dword, .{ |
| 1366 | .base = .rbp, | 1369 | .base = .{ .reg = .rbp }, |
| 1367 | .scale_index = .{ .scale = 4, .index = .rdx }, | 1370 | .scale_index = .{ .scale = 4, .index = .rdx }, |
| 1368 | .disp = -4, | 1371 | .disp = -4, |
| 1369 | }) }, | 1372 | }) }, |
| ... | @@ -1373,7 +1376,7 @@ test "lower RM encoding" { | ... | @@ -1373,7 +1376,7 @@ test "lower RM encoding" { |
| 1373 | try enc.encode(.mov, &.{ | 1376 | try enc.encode(.mov, &.{ |
| 1374 | .{ .reg = .rax }, | 1377 | .{ .reg = .rax }, |
| 1375 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1378 | .{ .mem = Instruction.Memory.sib(.qword, .{ |
| 1376 | .base = .rbp, | 1379 | .base = .{ .reg = .rbp }, |
| 1377 | .scale_index = .{ .scale = 8, .index = .rcx }, | 1380 | .scale_index = .{ .scale = 8, .index = .rcx }, |
| 1378 | .disp = -8, | 1381 | .disp = -8, |
| 1379 | }) }, | 1382 | }) }, |
| ... | @@ -1383,7 +1386,7 @@ test "lower RM encoding" { | ... | @@ -1383,7 +1386,7 @@ test "lower RM encoding" { |
| 1383 | try enc.encode(.mov, &.{ | 1386 | try enc.encode(.mov, &.{ |
| 1384 | .{ .reg = .r8b }, | 1387 | .{ .reg = .r8b }, |
| 1385 | .{ .mem = Instruction.Memory.sib(.byte, .{ | 1388 | .{ .mem = Instruction.Memory.sib(.byte, .{ |
| 1386 | .base = .rsi, | 1389 | .base = .{ .reg = .rsi }, |
| 1387 | .scale_index = .{ .scale = 1, .index = .rcx }, | 1390 | .scale_index = .{ .scale = 1, .index = .rcx }, |
| 1388 | .disp = -24, | 1391 | .disp = -24, |
| 1389 | }) }, | 1392 | }) }, |
| ... | @@ -1398,10 +1401,10 @@ test "lower RM encoding" { | ... | @@ -1398,10 +1401,10 @@ test "lower RM encoding" { |
| 1398 | try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs"); | 1401 | try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs"); |
| 1399 | | 1402 | |
| 1400 | try enc.encode(.mov, &.{ | 1403 | try enc.encode(.mov, &.{ |
| 1401 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -16 }) }, | 1404 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, |
| 1402 | .{ .reg = .fs }, | 1405 | .{ .reg = .fs }, |
| 1403 | }); | 1406 | }); |
| 1404 | try expectEqualHexStrings("\x48\x8C\x65\xF0", enc.code(), "mov QWORD PTR [rbp - 16], fs"); | 1407 | try expectEqualHexStrings("\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs"); |
| 1405 | | 1408 | |
| 1406 | try enc.encode(.mov, &.{ | 1409 | try enc.encode(.mov, &.{ |
| 1407 | .{ .reg = .r12w }, | 1410 | .{ .reg = .r12w }, |
| ... | @@ -1409,12 +1412,6 @@ test "lower RM encoding" { | ... | @@ -1409,12 +1412,6 @@ test "lower RM encoding" { |
| 1409 | }); | 1412 | }); |
| 1410 | try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs"); | 1413 | try expectEqualHexStrings("\x66\x41\x8C\xCC", enc.code(), "mov r12w, cs"); |
| 1411 | | 1414 | |
| 1412 | try enc.encode(.mov, &.{ | | |
| 1413 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) }, | | |
| 1414 | .{ .reg = .fs }, | | |
| 1415 | }); | | |
| 1416 | try expectEqualHexStrings("\x66\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs"); | | |
| 1417 | | | |
| 1418 | try enc.encode(.movsx, &.{ | 1415 | try enc.encode(.movsx, &.{ |
| 1419 | .{ .reg = .eax }, | 1416 | .{ .reg = .eax }, |
| 1420 | .{ .reg = .bx }, | 1417 | .{ .reg = .bx }, |
| ... | @@ -1435,7 +1432,7 @@ test "lower RM encoding" { | ... | @@ -1435,7 +1432,7 @@ test "lower RM encoding" { |
| 1435 | | 1432 | |
| 1436 | try enc.encode(.movsx, &.{ | 1433 | try enc.encode(.movsx, &.{ |
| 1437 | .{ .reg = .eax }, | 1434 | .{ .reg = .eax }, |
| 1438 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp }) }, | 1435 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) }, |
| 1439 | }); | 1436 | }); |
| 1440 | try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]"); | 1437 | try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]"); |
| 1441 | | 1438 | |
| ... | @@ -1496,7 +1493,7 @@ test "lower RM encoding" { | ... | @@ -1496,7 +1493,7 @@ test "lower RM encoding" { |
| 1496 | try enc.encode(.lea, &.{ | 1493 | try enc.encode(.lea, &.{ |
| 1497 | .{ .reg = .rsi }, | 1494 | .{ .reg = .rsi }, |
| 1498 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1495 | .{ .mem = Instruction.Memory.sib(.qword, .{ |
| 1499 | .base = .rbp, | 1496 | .base = .{ .reg = .rbp }, |
| 1500 | .scale_index = .{ .scale = 1, .index = .rcx }, | 1497 | .scale_index = .{ .scale = 1, .index = .rcx }, |
| 1501 | }) }, | 1498 | }) }, |
| 1502 | }); | 1499 | }); |
| ... | @@ -1504,31 +1501,31 @@ test "lower RM encoding" { | ... | @@ -1504,31 +1501,31 @@ test "lower RM encoding" { |
| 1504 | | 1501 | |
| 1505 | try enc.encode(.add, &.{ | 1502 | try enc.encode(.add, &.{ |
| 1506 | .{ .reg = .r11 }, | 1503 | .{ .reg = .r11 }, |
| 1507 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .ds, .disp = 0x10000000 }) }, | 1504 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1508 | }); | 1505 | }); |
| 1509 | try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000"); | 1506 | try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000"); |
| 1510 | | 1507 | |
| 1511 | try enc.encode(.add, &.{ | 1508 | try enc.encode(.add, &.{ |
| 1512 | .{ .reg = .r12b }, | 1509 | .{ .reg = .r12b }, |
| 1513 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) }, | 1510 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1514 | }); | 1511 | }); |
| 1515 | try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000"); | 1512 | try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000"); |
| 1516 | | 1513 | |
| 1517 | try enc.encode(.add, &.{ | 1514 | try enc.encode(.add, &.{ |
| 1518 | .{ .reg = .r12b }, | 1515 | .{ .reg = .r12b }, |
| 1519 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .fs, .disp = 0x10000000 }) }, | 1516 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .fs }, .disp = 0x10000000 }) }, |
| 1520 | }); | 1517 | }); |
| 1521 | try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000"); | 1518 | try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000"); |
| 1522 | | 1519 | |
| 1523 | try enc.encode(.sub, &.{ | 1520 | try enc.encode(.sub, &.{ |
| 1524 | .{ .reg = .r11 }, | 1521 | .{ .reg = .r11 }, |
| 1525 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r13, .disp = 0x10000000 }) }, | 1522 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r13 }, .disp = 0x10000000 }) }, |
| 1526 | }); | 1523 | }); |
| 1527 | try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]"); | 1524 | try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]"); |
| 1528 | | 1525 | |
| 1529 | try enc.encode(.sub, &.{ | 1526 | try enc.encode(.sub, &.{ |
| 1530 | .{ .reg = .r11 }, | 1527 | .{ .reg = .r11 }, |
| 1531 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r12, .disp = 0x10000000 }) }, | 1528 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) }, |
| 1532 | }); | 1529 | }); |
| 1533 | try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]"); | 1530 | try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]"); |
| 1534 | | 1531 | |
| ... | @@ -1562,7 +1559,7 @@ test "lower RMI encoding" { | ... | @@ -1562,7 +1559,7 @@ test "lower RMI encoding" { |
| 1562 | | 1559 | |
| 1563 | try enc.encode(.imul, &.{ | 1560 | try enc.encode(.imul, &.{ |
| 1564 | .{ .reg = .bx }, | 1561 | .{ .reg = .bx }, |
| 1565 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) }, | 1562 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, |
| 1566 | .{ .imm = Immediate.s(-1024) }, | 1563 | .{ .imm = Immediate.s(-1024) }, |
| 1567 | }); | 1564 | }); |
| 1568 | try expectEqualHexStrings( | 1565 | try expectEqualHexStrings( |
| ... | @@ -1573,7 +1570,7 @@ test "lower RMI encoding" { | ... | @@ -1573,7 +1570,7 @@ test "lower RMI encoding" { |
| 1573 | | 1570 | |
| 1574 | try enc.encode(.imul, &.{ | 1571 | try enc.encode(.imul, &.{ |
| 1575 | .{ .reg = .bx }, | 1572 | .{ .reg = .bx }, |
| 1576 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp, .disp = -16 }) }, | 1573 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, |
| 1577 | .{ .imm = Immediate.u(1024) }, | 1574 | .{ .imm = Immediate.u(1024) }, |
| 1578 | }); | 1575 | }); |
| 1579 | try expectEqualHexStrings( | 1576 | try expectEqualHexStrings( |
| ... | @@ -1593,7 +1590,7 @@ test "lower MR encoding" { | ... | @@ -1593,7 +1590,7 @@ test "lower MR encoding" { |
| 1593 | try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx"); | 1590 | try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx"); |
| 1594 | | 1591 | |
| 1595 | try enc.encode(.mov, &.{ | 1592 | try enc.encode(.mov, &.{ |
| 1596 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp, .disp = -4 }) }, | 1593 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) }, |
| 1597 | .{ .reg = .r11 }, | 1594 | .{ .reg = .r11 }, |
| 1598 | }); | 1595 | }); |
| 1599 | try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11"); | 1596 | try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11"); |
| ... | @@ -1606,7 +1603,7 @@ test "lower MR encoding" { | ... | @@ -1606,7 +1603,7 @@ test "lower MR encoding" { |
| 1606 | | 1603 | |
| 1607 | try enc.encode(.mov, &.{ | 1604 | try enc.encode(.mov, &.{ |
| 1608 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1605 | .{ .mem = Instruction.Memory.sib(.qword, .{ |
| 1609 | .base = .r11, | 1606 | .base = .{ .reg = .r11 }, |
| 1610 | .scale_index = .{ .scale = 2, .index = .r12 }, | 1607 | .scale_index = .{ .scale = 2, .index = .r12 }, |
| 1611 | .disp = 0x10, | 1608 | .disp = 0x10, |
| 1612 | }) }, | 1609 | }) }, |
| ... | @@ -1622,7 +1619,7 @@ test "lower MR encoding" { | ... | @@ -1622,7 +1619,7 @@ test "lower MR encoding" { |
| 1622 | | 1619 | |
| 1623 | try enc.encode(.mov, &.{ | 1620 | try enc.encode(.mov, &.{ |
| 1624 | .{ .mem = Instruction.Memory.sib(.byte, .{ | 1621 | .{ .mem = Instruction.Memory.sib(.byte, .{ |
| 1625 | .base = .r11, | 1622 | .base = .{ .reg = .r11 }, |
| 1626 | .scale_index = .{ .scale = 2, .index = .r12 }, | 1623 | .scale_index = .{ .scale = 2, .index = .r12 }, |
| 1627 | .disp = 0x10, | 1624 | .disp = 0x10, |
| 1628 | }) }, | 1625 | }) }, |
| ... | @@ -1631,25 +1628,25 @@ test "lower MR encoding" { | ... | @@ -1631,25 +1628,25 @@ test "lower MR encoding" { |
| 1631 | try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b"); | 1628 | try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b"); |
| 1632 | | 1629 | |
| 1633 | try enc.encode(.add, &.{ | 1630 | try enc.encode(.add, &.{ |
| 1634 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .ds, .disp = 0x10000000 }) }, | 1631 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1635 | .{ .reg = .r12b }, | 1632 | .{ .reg = .r12b }, |
| 1636 | }); | 1633 | }); |
| 1637 | try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b"); | 1634 | try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b"); |
| 1638 | | 1635 | |
| 1639 | try enc.encode(.add, &.{ | 1636 | try enc.encode(.add, &.{ |
| 1640 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .ds, .disp = 0x10000000 }) }, | 1637 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1641 | .{ .reg = .r12d }, | 1638 | .{ .reg = .r12d }, |
| 1642 | }); | 1639 | }); |
| 1643 | try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d"); | 1640 | try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d"); |
| 1644 | | 1641 | |
| 1645 | try enc.encode(.add, &.{ | 1642 | try enc.encode(.add, &.{ |
| 1646 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .gs, .disp = 0x10000000 }) }, | 1643 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .gs }, .disp = 0x10000000 }) }, |
| 1647 | .{ .reg = .r12d }, | 1644 | .{ .reg = .r12d }, |
| 1648 | }); | 1645 | }); |
| 1649 | try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d"); | 1646 | try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d"); |
| 1650 | | 1647 | |
| 1651 | try enc.encode(.sub, &.{ | 1648 | try enc.encode(.sub, &.{ |
| 1652 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r11, .disp = 0x10000000 }) }, | 1649 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) }, |
| 1653 | .{ .reg = .r12 }, | 1650 | .{ .reg = .r12 }, |
| 1654 | }); | 1651 | }); |
| 1655 | try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12"); | 1652 | 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" { | ... | @@ -1664,13 +1661,13 @@ test "lower M encoding" { |
| 1664 | try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12"); | 1661 | try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12"); |
| 1665 | | 1662 | |
| 1666 | try enc.encode(.call, &.{ | 1663 | try enc.encode(.call, &.{ |
| 1667 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .r12 }) }, | 1664 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r12 } }) }, |
| 1668 | }); | 1665 | }); |
| 1669 | try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]"); | 1666 | try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]"); |
| 1670 | | 1667 | |
| 1671 | try enc.encode(.call, &.{ | 1668 | try enc.encode(.call, &.{ |
| 1672 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1669 | .{ .mem = Instruction.Memory.sib(.qword, .{ |
| 1673 | .base = null, | 1670 | .base = .none, |
| 1674 | .scale_index = .{ .index = .r11, .scale = 2 }, | 1671 | .scale_index = .{ .index = .r11, .scale = 2 }, |
| 1675 | }) }, | 1672 | }) }, |
| 1676 | }); | 1673 | }); |
| ... | @@ -1678,14 +1675,14 @@ test "lower M encoding" { | ... | @@ -1678,14 +1675,14 @@ test "lower M encoding" { |
| 1678 | | 1675 | |
| 1679 | try enc.encode(.call, &.{ | 1676 | try enc.encode(.call, &.{ |
| 1680 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1677 | .{ .mem = Instruction.Memory.sib(.qword, .{ |
| 1681 | .base = null, | 1678 | .base = .none, |
| 1682 | .scale_index = .{ .index = .r12, .scale = 2 }, | 1679 | .scale_index = .{ .index = .r12, .scale = 2 }, |
| 1683 | }) }, | 1680 | }) }, |
| 1684 | }); | 1681 | }); |
| 1685 | try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]"); | 1682 | try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]"); |
| 1686 | | 1683 | |
| 1687 | try enc.encode(.call, &.{ | 1684 | try enc.encode(.call, &.{ |
| 1688 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .gs }) }, | 1685 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .gs } }) }, |
| 1689 | }); | 1686 | }); |
| 1690 | try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); | 1687 | try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); |
| 1691 | | 1688 | |
| ... | @@ -1695,12 +1692,12 @@ test "lower M encoding" { | ... | @@ -1695,12 +1692,12 @@ test "lower M encoding" { |
| 1695 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); | 1692 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); |
| 1696 | | 1693 | |
| 1697 | try enc.encode(.push, &.{ | 1694 | try enc.encode(.push, &.{ |
| 1698 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .rbp }) }, | 1695 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp } }) }, |
| 1699 | }); | 1696 | }); |
| 1700 | try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); | 1697 | try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); |
| 1701 | | 1698 | |
| 1702 | try enc.encode(.push, &.{ | 1699 | try enc.encode(.push, &.{ |
| 1703 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .rbp }) }, | 1700 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) }, |
| 1704 | }); | 1701 | }); |
| 1705 | try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); | 1702 | try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); |
| 1706 | | 1703 | |
| ... | @@ -1913,7 +1910,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand | ... | @@ -1913,7 +1910,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand |
| 1913 | | 1910 | |
| 1914 | test "cannot encode" { | 1911 | test "cannot encode" { |
| 1915 | try cannotEncode(.@"test", &.{ | 1912 | try cannotEncode(.@"test", &.{ |
| 1916 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .r12 }) }, | 1913 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) }, |
| 1917 | .{ .reg = .ah }, | 1914 | .{ .reg = .ah }, |
| 1918 | }); | 1915 | }); |
| 1919 | try cannotEncode(.@"test", &.{ | 1916 | try cannotEncode(.@"test", &.{ |
| ... | @@ -2093,7 +2090,7 @@ const Assembler = struct { | ... | @@ -2093,7 +2090,7 @@ const Assembler = struct { |
| 2093 | pub fn assemble(as: *Assembler, writer: anytype) !void { | 2090 | pub fn assemble(as: *Assembler, writer: anytype) !void { |
| 2094 | while (try as.next()) |parsed_inst| { | 2091 | while (try as.next()) |parsed_inst| { |
| 2095 | const inst = try Instruction.new(.none, parsed_inst.mnemonic, &parsed_inst.ops); | 2092 | const inst = try Instruction.new(.none, parsed_inst.mnemonic, &parsed_inst.ops); |
| 2096 | try inst.encode(writer); | 2093 | try inst.encode(writer, .{}); |
| 2097 | } | 2094 | } |
| 2098 | } | 2095 | } |
| 2099 | | 2096 | |
| ... | @@ -2262,26 +2259,26 @@ const Assembler = struct { | ... | @@ -2262,26 +2259,26 @@ const Assembler = struct { |
| 2262 | | 2259 | |
| 2263 | // Supported rules and orderings. | 2260 | // Supported rules and orderings. |
| 2264 | const rules = .{ | 2261 | const rules = .{ |
| 2265 | .{ .open_br, .base, .close_br }, // [ base ] | 2262 | .{ .open_br, .general_purpose, .close_br }, // [ general_purpose ] |
| 2266 | .{ .open_br, .base, .plus, .disp, .close_br }, // [ base + disp ] | 2263 | .{ .open_br, .general_purpose, .plus, .disp, .close_br }, // [ general_purpose + disp ] |
| 2267 | .{ .open_br, .base, .minus, .disp, .close_br }, // [ base - disp ] | 2264 | .{ .open_br, .general_purpose, .minus, .disp, .close_br }, // [ general_purpose - disp ] |
| 2268 | .{ .open_br, .disp, .plus, .base, .close_br }, // [ disp + base ] | 2265 | .{ .open_br, .disp, .plus, .general_purpose, .close_br }, // [ disp + general_purpose ] |
| 2269 | .{ .open_br, .base, .plus, .index, .close_br }, // [ base + index ] | 2266 | .{ .open_br, .general_purpose, .plus, .index, .close_br }, // [ general_purpose + index ] |
| 2270 | .{ .open_br, .base, .plus, .index, .star, .scale, .close_br }, // [ base + index * scale ] | 2267 | .{ .open_br, .general_purpose, .plus, .index, .star, .scale, .close_br }, // [ general_purpose + index * scale ] |
| 2271 | .{ .open_br, .index, .star, .scale, .plus, .base, .close_br }, // [ index * scale + base ] | 2268 | .{ .open_br, .index, .star, .scale, .plus, .general_purpose, .close_br }, // [ index * scale + general_purpose ] |
| 2272 | .{ .open_br, .base, .plus, .index, .star, .scale, .plus, .disp, .close_br }, // [ base + index * scale + disp ] | 2269 | .{ .open_br, .general_purpose, .plus, .index, .star, .scale, .plus, .disp, .close_br }, // [ general_purpose + index * scale + disp ] |
| 2273 | .{ .open_br, .base, .plus, .index, .star, .scale, .minus, .disp, .close_br }, // [ base + index * scale - disp ] | 2270 | .{ .open_br, .general_purpose, .plus, .index, .star, .scale, .minus, .disp, .close_br }, // [ general_purpose + index * scale - disp ] |
| 2274 | .{ .open_br, .index, .star, .scale, .plus, .base, .plus, .disp, .close_br }, // [ index * scale + base + disp ] | 2271 | .{ .open_br, .index, .star, .scale, .plus, .general_purpose, .plus, .disp, .close_br }, // [ index * scale + general_purpose + disp ] |
| 2275 | .{ .open_br, .index, .star, .scale, .plus, .base, .minus, .disp, .close_br }, // [ index * scale + base - disp ] | 2272 | .{ .open_br, .index, .star, .scale, .plus, .general_purpose, .minus, .disp, .close_br }, // [ index * scale + general_purpose - disp ] |
| 2276 | .{ .open_br, .disp, .plus, .index, .star, .scale, .plus, .base, .close_br }, // [ disp + index * scale + base ] | 2273 | .{ .open_br, .disp, .plus, .index, .star, .scale, .plus, .general_purpose, .close_br }, // [ disp + index * scale + general_purpose ] |
| 2277 | .{ .open_br, .disp, .plus, .base, .plus, .index, .star, .scale, .close_br }, // [ disp + base + index * scale ] | 2274 | .{ .open_br, .disp, .plus, .general_purpose, .plus, .index, .star, .scale, .close_br }, // [ disp + general_purpose + index * scale ] |
| 2278 | .{ .open_br, .base, .plus, .disp, .plus, .index, .star, .scale, .close_br }, // [ base + disp + index * scale ] | 2275 | .{ .open_br, .general_purpose, .plus, .disp, .plus, .index, .star, .scale, .close_br }, // [ general_purpose + disp + index * scale ] |
| 2279 | .{ .open_br, .base, .minus, .disp, .plus, .index, .star, .scale, .close_br }, // [ base - disp + index * scale ] | 2276 | .{ .open_br, .general_purpose, .minus, .disp, .plus, .index, .star, .scale, .close_br }, // [ general_purpose - disp + index * scale ] |
| 2280 | .{ .open_br, .base, .plus, .disp, .plus, .scale, .star, .index, .close_br }, // [ base + disp + scale * index ] | 2277 | .{ .open_br, .general_purpose, .plus, .disp, .plus, .scale, .star, .index, .close_br }, // [ general_purpose + disp + scale * index ] |
| 2281 | .{ .open_br, .base, .minus, .disp, .plus, .scale, .star, .index, .close_br }, // [ base - disp + scale * index ] | 2278 | .{ .open_br, .general_purpose, .minus, .disp, .plus, .scale, .star, .index, .close_br }, // [ general_purpose - disp + scale * index ] |
| 2282 | .{ .open_br, .rip, .plus, .disp, .close_br }, // [ rip + disp ] | 2279 | .{ .open_br, .rip, .plus, .disp, .close_br }, // [ rip + disp ] |
| 2283 | .{ .open_br, .rip, .minus, .disp, .close_br }, // [ rig - disp ] | 2280 | .{ .open_br, .rip, .minus, .disp, .close_br }, // [ rig - disp ] |
| 2284 | .{ .base, .colon, .disp }, // seg:disp | 2281 | .{ .segment, .colon, .disp }, // seg:disp |
| 2285 | }; | 2282 | }; |
| 2286 | | 2283 | |
| 2287 | const pos = as.it.pos; | 2284 | const pos = as.it.pos; |
| ... | @@ -2301,7 +2298,7 @@ const Assembler = struct { | ... | @@ -2301,7 +2298,7 @@ const Assembler = struct { |
| 2301 | return Instruction.Memory.moffs(base, offset); | 2298 | return Instruction.Memory.moffs(base, offset); |
| 2302 | } | 2299 | } |
| 2303 | return Instruction.Memory.sib(ptr_size orelse .qword, .{ | 2300 | return Instruction.Memory.sib(ptr_size orelse .qword, .{ |
| 2304 | .base = base, | 2301 | .base = .{ .reg = base }, |
| 2305 | .scale_index = res.scale_index, | 2302 | .scale_index = res.scale_index, |
| 2306 | .disp = res.disp orelse 0, | 2303 | .disp = res.disp orelse 0, |
| 2307 | }); | 2304 | }); |
| ... | @@ -2323,7 +2320,7 @@ const Assembler = struct { | ... | @@ -2323,7 +2320,7 @@ const Assembler = struct { |
| 2323 | offset: ?u64 = null, | 2320 | offset: ?u64 = null, |
| 2324 | }; | 2321 | }; |
| 2325 | | 2322 | |
| 2326 | fn parseMemoryRule(as: *Assembler, rule: anytype) ParseError!Instruction.MemoryParseResult { | 2323 | fn parseMemoryRule(as: *Assembler, rule: anytype) ParseError!MemoryParseResult { |
| 2327 | var res: MemoryParseResult = .{}; | 2324 | var res: MemoryParseResult = .{}; |
| 2328 | inline for (rule, 0..) |cond, i| { | 2325 | inline for (rule, 0..) |cond, i| { |
| 2329 | if (@typeInfo(@TypeOf(cond)) != .EnumLiteral) { | 2326 | if (@typeInfo(@TypeOf(cond)) != .EnumLiteral) { |
| ... | @@ -2333,9 +2330,11 @@ const Assembler = struct { | ... | @@ -2333,9 +2330,11 @@ const Assembler = struct { |
| 2333 | .open_br, .close_br, .plus, .minus, .star, .colon => { | 2330 | .open_br, .close_br, .plus, .minus, .star, .colon => { |
| 2334 | _ = try as.expect(cond); | 2331 | _ = try as.expect(cond); |
| 2335 | }, | 2332 | }, |
| 2336 | .base => { | 2333 | .general_purpose, .segment => { |
| 2337 | const tok = try as.expect(.string); | 2334 | const tok = try as.expect(.string); |
| 2338 | res.base = registerFromString(as.source(tok)) orelse return error.InvalidMemoryOperand; | 2335 | const base = registerFromString(as.source(tok)) orelse return error.InvalidMemoryOperand; |
| | 2336 | if (base.class() != cond) return error.InvalidMemoryOperand; |
| | 2337 | res.base = base; |
| 2339 | }, | 2338 | }, |
| 2340 | .rip => { | 2339 | .rip => { |
| 2341 | const tok = try as.expect(.string); | 2340 | const tok = try as.expect(.string); |
| ... | @@ -2529,8 +2528,8 @@ test "assemble" { | ... | @@ -2529,8 +2528,8 @@ test "assemble" { |
| 2529 | 0xF3, 0x45, 0x0F, 0x10, 0xF9, | 2528 | 0xF3, 0x45, 0x0F, 0x10, 0xF9, |
| 2530 | 0xF2, 0x44, 0x0F, 0x10, 0x45, 0xF0, | 2529 | 0xF2, 0x44, 0x0F, 0x10, 0x45, 0xF0, |
| 2531 | 0xF2, 0x0F, 0x11, 0x45, 0xF8, | 2530 | 0xF2, 0x0F, 0x11, 0x45, 0xF8, |
| 2532 | 0xF3, 0x44, 0x0F, 0x7E, 0x45, 0xF0, | 2531 | 0x66, 0x4C, 0x0F, 0x6E, 0x45, 0xF0, |
| 2533 | 0x66, 0x44, 0x0F, 0xD6, 0x45, 0xF0, | 2532 | 0x66, 0x4C, 0x0F, 0x7E, 0x45, 0xF0, |
| 2534 | 0x66, 0x0F, 0x2E, 0x45, 0xF0, | 2533 | 0x66, 0x0F, 0x2E, 0x45, 0xF0, |
| 2535 | 0xDD, 0x4D, 0xF0, | 2534 | 0xDD, 0x4D, 0xF0, |
| 2536 | 0xDF, 0x0D, 0x20, 0x00, 0x00, 0x00, | 2535 | 0xDF, 0x0D, 0x20, 0x00, 0x00, 0x00, |