| ... | @@ -1230,18 +1230,17 @@ inline fn getModRmExt(tag: Tag) ?u3 { | ... | @@ -1230,18 +1230,17 @@ inline fn getModRmExt(tag: Tag) ?u3 { |
| 1230 | }; | 1230 | }; |
| 1231 | } | 1231 | } |
| 1232 | | 1232 | |
| 1233 | const ScaleIndexBase = struct { | 1233 | const ScaleIndex = struct { |
| 1234 | scale: u2, | 1234 | scale: u2, |
| 1235 | index_reg: ?Register, | 1235 | index: Register, |
| 1236 | base_reg: ?Register, | | |
| 1237 | }; | 1236 | }; |
| 1238 | | 1237 | |
| 1239 | const Memory = struct { | 1238 | const Memory = struct { |
| 1240 | reg: ?Register, | 1239 | base: ?Register, |
| 1241 | rip: bool = false, | 1240 | rip: bool = false, |
| 1242 | disp: i32, | 1241 | disp: i32, |
| 1243 | ptr_size: PtrSize, | 1242 | ptr_size: PtrSize, |
| 1244 | sib: ?ScaleIndexBase = null, | 1243 | scale_index: ?ScaleIndex = null, |
| 1245 | | 1244 | |
| 1246 | const PtrSize = enum { | 1245 | const PtrSize = enum { |
| 1247 | byte_ptr, | 1246 | byte_ptr, |
| ... | @@ -1270,42 +1269,44 @@ const Memory = struct { | ... | @@ -1270,42 +1269,44 @@ const Memory = struct { |
| 1270 | } | 1269 | } |
| 1271 | }; | 1270 | }; |
| 1272 | | 1271 | |
| 1273 | fn encodeWithReg(encoder: Encoder, dst: u3, src: u3, disp: i32) void { | 1272 | fn encode(mem_op: Memory, encoder: Encoder, operand: u3) void { |
| 1274 | if (dst == 4) { | 1273 | if (mem_op.base) |base| { |
| 1275 | if (disp == 0) { | 1274 | const dst = base.lowId(); |
| 1276 | encoder.modRm_SIBDisp0(src); | 1275 | const src = operand; |
| 1277 | encoder.sib_base(dst); | 1276 | if (dst == 4) { |
| 1278 | } else if (immOpSize(disp) == 8) { | 1277 | if (mem_op.disp == 0) { |
| 1279 | encoder.modRm_SIBDisp8(src); | 1278 | encoder.modRm_SIBDisp0(src); |
| 1280 | encoder.sib_baseDisp8(dst); | 1279 | encoder.sib_base(dst); |
| 1281 | encoder.disp8(@intCast(i8, disp)); | 1280 | } else if (immOpSize(mem_op.disp) == 8) { |
| | 1281 | encoder.modRm_SIBDisp8(src); |
| | 1282 | encoder.sib_baseDisp8(dst); |
| | 1283 | encoder.disp8(@intCast(i8, mem_op.disp)); |
| | 1284 | } else { |
| | 1285 | encoder.modRm_SIBDisp32(src); |
| | 1286 | encoder.sib_baseDisp32(dst); |
| | 1287 | encoder.disp32(mem_op.disp); |
| | 1288 | } |
| 1282 | } else { | 1289 | } else { |
| 1283 | encoder.modRm_SIBDisp32(src); | 1290 | if (mem_op.disp == 0) { |
| 1284 | encoder.sib_baseDisp32(dst); | 1291 | encoder.modRm_indirectDisp0(src, dst); |
| 1285 | encoder.disp32(disp); | 1292 | } else if (immOpSize(mem_op.disp) == 8) { |
| | 1293 | encoder.modRm_indirectDisp8(src, dst); |
| | 1294 | encoder.disp8(@intCast(i8, mem_op.disp)); |
| | 1295 | } else { |
| | 1296 | encoder.modRm_indirectDisp32(src, dst); |
| | 1297 | encoder.disp32(mem_op.disp); |
| | 1298 | } |
| 1286 | } | 1299 | } |
| 1287 | } else { | 1300 | } else { |
| 1288 | if (disp == 0) { | 1301 | if (mem_op.rip) { |
| 1289 | encoder.modRm_indirectDisp0(src, dst); | 1302 | encoder.modRm_RIPDisp32(operand); |
| 1290 | } else if (immOpSize(disp) == 8) { | | |
| 1291 | encoder.modRm_indirectDisp8(src, dst); | | |
| 1292 | encoder.disp8(@intCast(i8, disp)); | | |
| 1293 | } else { | 1303 | } else { |
| 1294 | encoder.modRm_indirectDisp32(src, dst); | 1304 | encoder.modRm_SIBDisp0(operand); |
| 1295 | encoder.disp32(disp); | 1305 | encoder.sib_disp32(); |
| 1296 | } | 1306 | } |
| | 1307 | encoder.disp32(mem_op.disp); |
| 1297 | } | 1308 | } |
| 1298 | } | 1309 | } |
| 1299 | | | |
| 1300 | fn encodeDsOrRip(encoder: Encoder, op: u3, disp: i32, rip: bool) void { | | |
| 1301 | if (rip) { | | |
| 1302 | encoder.modRm_RIPDisp32(op); | | |
| 1303 | } else { | | |
| 1304 | encoder.modRm_SIBDisp0(op); | | |
| 1305 | encoder.sib_disp32(); | | |
| 1306 | } | | |
| 1307 | encoder.disp32(disp); | | |
| 1308 | } | | |
| 1309 | }; | 1310 | }; |
| 1310 | | 1311 | |
| 1311 | fn encodeImm(encoder: Encoder, imm: i32, size: u64) void { | 1312 | fn encodeImm(encoder: Encoder, imm: i32, size: u64) void { |
| ... | @@ -1325,10 +1326,10 @@ const RegisterOrMemory = union(enum) { | ... | @@ -1325,10 +1326,10 @@ const RegisterOrMemory = union(enum) { |
| 1325 | return .{ .register = register }; | 1326 | return .{ .register = register }; |
| 1326 | } | 1327 | } |
| 1327 | | 1328 | |
| 1328 | fn mem(register: ?Register, disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory { | 1329 | fn mem(base: ?Register, disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory { |
| 1329 | return .{ | 1330 | return .{ |
| 1330 | .memory = .{ | 1331 | .memory = .{ |
| 1331 | .reg = register, | 1332 | .base = base, |
| 1332 | .disp = disp, | 1333 | .disp = disp, |
| 1333 | .ptr_size = ptr_size, | 1334 | .ptr_size = ptr_size, |
| 1334 | }, | 1335 | }, |
| ... | @@ -1338,7 +1339,7 @@ const RegisterOrMemory = union(enum) { | ... | @@ -1338,7 +1339,7 @@ const RegisterOrMemory = union(enum) { |
| 1338 | fn rip(disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory { | 1339 | fn rip(disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory { |
| 1339 | return .{ | 1340 | return .{ |
| 1340 | .memory = .{ | 1341 | .memory = .{ |
| 1341 | .reg = null, | 1342 | .base = null, |
| 1342 | .rip = true, | 1343 | .rip = true, |
| 1343 | .disp = disp, | 1344 | .disp = disp, |
| 1344 | .ptr_size = ptr_size, | 1345 | .ptr_size = ptr_size, |
| ... | @@ -1435,20 +1436,17 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) | ... | @@ -1435,20 +1436,17 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) |
| 1435 | if (mem_op.ptr_size == .word_ptr) { | 1436 | if (mem_op.ptr_size == .word_ptr) { |
| 1436 | encoder.prefix16BitMode(); | 1437 | encoder.prefix16BitMode(); |
| 1437 | } | 1438 | } |
| 1438 | if (mem_op.reg) |reg| { | 1439 | if (mem_op.base) |base| { |
| 1439 | if (reg.size() != 64) { | 1440 | if (base.size() != 64) { |
| 1440 | return error.OperandSizeMismatch; | 1441 | return error.OperandSizeMismatch; |
| 1441 | } | 1442 | } |
| 1442 | encoder.rex(.{ | 1443 | encoder.rex(.{ |
| 1443 | .w = false, | 1444 | .w = false, |
| 1444 | .b = reg.isExtended(), | 1445 | .b = base.isExtended(), |
| 1445 | }); | 1446 | }); |
| 1446 | opc.encode(encoder); | | |
| 1447 | Memory.encodeWithReg(encoder, reg.lowId(), modrm_ext, mem_op.disp); | | |
| 1448 | } else { | | |
| 1449 | opc.encode(encoder); | | |
| 1450 | Memory.encodeDsOrRip(encoder, modrm_ext, mem_op.disp, mem_op.rip); | | |
| 1451 | } | 1447 | } |
| | 1448 | opc.encode(encoder); |
| | 1449 | mem_op.encode(encoder, modrm_ext); |
| 1452 | }, | 1450 | }, |
| 1453 | } | 1451 | } |
| 1454 | } | 1452 | } |
| ... | @@ -1560,20 +1558,17 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr | ... | @@ -1560,20 +1558,17 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr |
| 1560 | if (dst_mem.ptr_size == .word_ptr) { | 1558 | if (dst_mem.ptr_size == .word_ptr) { |
| 1561 | encoder.prefix16BitMode(); | 1559 | encoder.prefix16BitMode(); |
| 1562 | } | 1560 | } |
| 1563 | if (dst_mem.reg) |dst_reg| { | 1561 | if (dst_mem.base) |base| { |
| 1564 | if (dst_reg.size() != 64) { | 1562 | if (base.size() != 64) { |
| 1565 | return error.OperandSizeMismatch; | 1563 | return error.OperandSizeMismatch; |
| 1566 | } | 1564 | } |
| 1567 | encoder.rex(.{ | 1565 | encoder.rex(.{ |
| 1568 | .w = dst_mem.ptr_size == .qword_ptr, | 1566 | .w = dst_mem.ptr_size == .qword_ptr, |
| 1569 | .b = dst_reg.isExtended(), | 1567 | .b = base.isExtended(), |
| 1570 | }); | 1568 | }); |
| 1571 | opc.encode(encoder); | | |
| 1572 | Memory.encodeWithReg(encoder, dst_reg.lowId(), modrm_ext, dst_mem.disp); | | |
| 1573 | } else { | | |
| 1574 | opc.encode(encoder); | | |
| 1575 | Memory.encodeDsOrRip(encoder, modrm_ext, dst_mem.disp, dst_mem.rip); | | |
| 1576 | } | 1569 | } |
| | 1570 | opc.encode(encoder); |
| | 1571 | dst_mem.encode(encoder, modrm_ext); |
| 1577 | encodeImm(encoder, imm, dst_mem.ptr_size.size()); | 1572 | encodeImm(encoder, imm, dst_mem.ptr_size.size()); |
| 1578 | }, | 1573 | }, |
| 1579 | } | 1574 | } |
| ... | @@ -1608,27 +1603,25 @@ fn lowerToRmEnc( | ... | @@ -1608,27 +1603,25 @@ fn lowerToRmEnc( |
| 1608 | if (reg.size() == 16) { | 1603 | if (reg.size() == 16) { |
| 1609 | encoder.prefix16BitMode(); | 1604 | encoder.prefix16BitMode(); |
| 1610 | } | 1605 | } |
| 1611 | if (src_mem.reg) |src_reg| { | 1606 | if (src_mem.base) |base| { |
| 1612 | // TODO handle 32-bit base register - requires prefix 0x67 | 1607 | // TODO handle 32-bit base register - requires prefix 0x67 |
| 1613 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 | 1608 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 |
| 1614 | if (src_reg.size() != 64) { | 1609 | if (base.size() != 64) { |
| 1615 | return error.OperandSizeMismatch; | 1610 | return error.OperandSizeMismatch; |
| 1616 | } | 1611 | } |
| 1617 | encoder.rex(.{ | 1612 | encoder.rex(.{ |
| 1618 | .w = setRexWRegister(reg), | 1613 | .w = setRexWRegister(reg), |
| 1619 | .r = reg.isExtended(), | 1614 | .r = reg.isExtended(), |
| 1620 | .b = src_reg.isExtended(), | 1615 | .b = base.isExtended(), |
| 1621 | }); | 1616 | }); |
| 1622 | opc.encode(encoder); | | |
| 1623 | Memory.encodeWithReg(encoder, src_reg.lowId(), reg.lowId(), src_mem.disp); | | |
| 1624 | } else { | 1617 | } else { |
| 1625 | encoder.rex(.{ | 1618 | encoder.rex(.{ |
| 1626 | .w = setRexWRegister(reg), | 1619 | .w = setRexWRegister(reg), |
| 1627 | .r = reg.isExtended(), | 1620 | .r = reg.isExtended(), |
| 1628 | }); | 1621 | }); |
| 1629 | opc.encode(encoder); | | |
| 1630 | Memory.encodeDsOrRip(encoder, reg.lowId(), src_mem.disp, src_mem.rip); | | |
| 1631 | } | 1622 | } |
| | 1623 | opc.encode(encoder); |
| | 1624 | src_mem.encode(encoder, reg.lowId()); |
| 1632 | }, | 1625 | }, |
| 1633 | } | 1626 | } |
| 1634 | } | 1627 | } |
| ... | @@ -1662,25 +1655,23 @@ fn lowerToMrEnc( | ... | @@ -1662,25 +1655,23 @@ fn lowerToMrEnc( |
| 1662 | if (reg.size() == 16) { | 1655 | if (reg.size() == 16) { |
| 1663 | encoder.prefix16BitMode(); | 1656 | encoder.prefix16BitMode(); |
| 1664 | } | 1657 | } |
| 1665 | if (dst_mem.reg) |dst_reg| { | 1658 | if (dst_mem.base) |base| { |
| 1666 | if (dst_reg.size() != 64) { | 1659 | if (base.size() != 64) { |
| 1667 | return error.OperandSizeMismatch; | 1660 | return error.OperandSizeMismatch; |
| 1668 | } | 1661 | } |
| 1669 | encoder.rex(.{ | 1662 | encoder.rex(.{ |
| 1670 | .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg), | 1663 | .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg), |
| 1671 | .r = reg.isExtended(), | 1664 | .r = reg.isExtended(), |
| 1672 | .b = dst_reg.isExtended(), | 1665 | .b = base.isExtended(), |
| 1673 | }); | 1666 | }); |
| 1674 | opc.encode(encoder); | | |
| 1675 | Memory.encodeWithReg(encoder, dst_reg.lowId(), reg.lowId(), dst_mem.disp); | | |
| 1676 | } else { | 1667 | } else { |
| 1677 | encoder.rex(.{ | 1668 | encoder.rex(.{ |
| 1678 | .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg), | 1669 | .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg), |
| 1679 | .r = reg.isExtended(), | 1670 | .r = reg.isExtended(), |
| 1680 | }); | 1671 | }); |
| 1681 | opc.encode(encoder); | | |
| 1682 | Memory.encodeDsOrRip(encoder, reg.lowId(), dst_mem.disp, dst_mem.rip); | | |
| 1683 | } | 1672 | } |
| | 1673 | opc.encode(encoder); |
| | 1674 | dst_mem.encode(encoder, reg.lowId()); |
| 1684 | }, | 1675 | }, |
| 1685 | } | 1676 | } |
| 1686 | } | 1677 | } |
| ... | @@ -1714,10 +1705,10 @@ fn lowerToRmiEnc( | ... | @@ -1714,10 +1705,10 @@ fn lowerToRmiEnc( |
| 1714 | encoder.modRm_direct(reg.lowId(), src_reg.lowId()); | 1705 | encoder.modRm_direct(reg.lowId(), src_reg.lowId()); |
| 1715 | }, | 1706 | }, |
| 1716 | .memory => |src_mem| { | 1707 | .memory => |src_mem| { |
| 1717 | if (src_mem.reg) |src_reg| { | 1708 | if (src_mem.base) |base| { |
| 1718 | // TODO handle 32-bit base register - requires prefix 0x67 | 1709 | // TODO handle 32-bit base register - requires prefix 0x67 |
| 1719 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 | 1710 | // Intel Manual, Vol 1, chapter 3.6 and 3.6.1 |
| 1720 | if (src_reg.size() != 64) { | 1711 | if (base.size() != 64) { |
| 1721 | return error.OperandSizeMismatch; | 1712 | return error.OperandSizeMismatch; |
| 1722 | } | 1713 | } |
| 1723 | if (src_mem.ptr_size == .byte_ptr) { | 1714 | if (src_mem.ptr_size == .byte_ptr) { |
| ... | @@ -1726,18 +1717,16 @@ fn lowerToRmiEnc( | ... | @@ -1726,18 +1717,16 @@ fn lowerToRmiEnc( |
| 1726 | encoder.rex(.{ | 1717 | encoder.rex(.{ |
| 1727 | .w = setRexWRegister(reg), | 1718 | .w = setRexWRegister(reg), |
| 1728 | .r = reg.isExtended(), | 1719 | .r = reg.isExtended(), |
| 1729 | .b = src_reg.isExtended(), | 1720 | .b = base.isExtended(), |
| 1730 | }); | 1721 | }); |
| 1731 | opc.encode(encoder); | | |
| 1732 | Memory.encodeWithReg(encoder, src_reg.lowId(), reg.lowId(), src_mem.disp); | | |
| 1733 | } else { | 1722 | } else { |
| 1734 | encoder.rex(.{ | 1723 | encoder.rex(.{ |
| 1735 | .w = setRexWRegister(reg), | 1724 | .w = setRexWRegister(reg), |
| 1736 | .r = reg.isExtended(), | 1725 | .r = reg.isExtended(), |
| 1737 | }); | 1726 | }); |
| 1738 | opc.encode(encoder); | | |
| 1739 | Memory.encodeDsOrRip(encoder, reg.lowId(), src_mem.disp, src_mem.rip); | | |
| 1740 | } | 1727 | } |
| | 1728 | opc.encode(encoder); |
| | 1729 | src_mem.encode(encoder, reg.lowId()); |
| 1741 | }, | 1730 | }, |
| 1742 | } | 1731 | } |
| 1743 | encodeImm(encoder, imm, reg.size()); | 1732 | encodeImm(encoder, imm, reg.size()); |