2020-09-13 21:32:55 -04:00
|
|
|
#pragma once
|
|
|
|
|
2020-08-29 19:13:29 -04:00
|
|
|
#ifndef JAK_INSTRUCTION_H
|
|
|
|
#define JAK_INSTRUCTION_H
|
2020-08-22 22:30:12 -04:00
|
|
|
|
|
|
|
#include "common/common_types.h"
|
2022-02-08 19:02:47 -05:00
|
|
|
#include "common/util/Assert.h"
|
2020-08-22 22:30:12 -04:00
|
|
|
|
2020-08-29 19:13:29 -04:00
|
|
|
namespace emitter {
|
2020-08-22 22:30:12 -04:00
|
|
|
/*!
|
|
|
|
* The ModRM byte
|
|
|
|
*/
|
|
|
|
struct ModRM {
|
|
|
|
uint8_t mod;
|
|
|
|
uint8_t reg_op;
|
|
|
|
uint8_t rm;
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
uint8_t operator()() const { return (mod << 6) | (reg_op << 3) | (rm << 0); }
|
2020-08-22 22:30:12 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* The SIB Byte
|
|
|
|
*/
|
|
|
|
struct SIB {
|
|
|
|
uint8_t scale, index, base;
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
uint8_t operator()() const { return (scale << 6) | (index << 3) | (base << 0); }
|
2020-08-22 22:30:12 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* An Immediate (either imm or disp)
|
|
|
|
*/
|
|
|
|
struct Imm {
|
|
|
|
Imm() = default;
|
2020-08-26 01:21:33 -04:00
|
|
|
Imm(uint8_t sz, uint64_t v) : size(sz), value(v) {}
|
2020-08-22 22:30:12 -04:00
|
|
|
uint8_t size;
|
|
|
|
union {
|
|
|
|
uint64_t value;
|
|
|
|
uint8_t v_arr[8];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* The REX prefix byte
|
|
|
|
*/
|
|
|
|
struct REX {
|
2020-08-26 01:21:33 -04:00
|
|
|
explicit REX(bool w = false, bool r = false, bool x = false, bool b = false)
|
|
|
|
: W(w), R(r), X(x), B(b) {}
|
2020-08-22 22:30:12 -04:00
|
|
|
// W - 64-bit operands
|
|
|
|
// R - reg extension
|
|
|
|
// X - SIB i extnsion
|
|
|
|
// B - other extension
|
|
|
|
bool W, R, X, B;
|
2020-08-26 01:21:33 -04:00
|
|
|
uint8_t operator()() const { return (1 << 6) | (W << 3) | (R << 2) | (X << 1) | (B << 0); }
|
2020-08-22 22:30:12 -04:00
|
|
|
};
|
|
|
|
|
2020-12-30 15:33:51 -05:00
|
|
|
enum class VexPrefix : u8 { P_NONE = 0, P_66 = 1, P_F3 = 2, P_F2 = 3 };
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* The "VEX" 3-byte format for AVX instructions
|
|
|
|
*/
|
|
|
|
struct VEX3 {
|
|
|
|
bool W, R, X, B;
|
|
|
|
enum class LeadingBytes : u8 { P_INVALID = 0, P_0F = 1, P_0F_38 = 2, P_0F_3A = 3 } leading_bytes;
|
|
|
|
u8 reg_id;
|
|
|
|
VexPrefix prefix;
|
|
|
|
bool L;
|
|
|
|
|
|
|
|
u8 emit(u8 byte) const {
|
|
|
|
if (byte == 0) {
|
|
|
|
return 0b11000100;
|
|
|
|
} else if (byte == 1) {
|
|
|
|
u8 result = 0;
|
|
|
|
result |= ((!R) << 7);
|
|
|
|
result |= ((!X) << 6);
|
|
|
|
result |= ((!B) << 5);
|
|
|
|
result |= (0b11111 & u8(leading_bytes));
|
|
|
|
return result;
|
|
|
|
} else if (byte == 2) {
|
|
|
|
u8 result = 0;
|
|
|
|
result |= (W << 7); // this may be inverted?
|
|
|
|
result |= ((~reg_id) & 0b1111) << 3;
|
|
|
|
result |= (L << 2);
|
|
|
|
result |= (u8(prefix) & 0b11);
|
|
|
|
return result;
|
|
|
|
} else {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(false);
|
2021-03-07 12:01:59 -05:00
|
|
|
return -1;
|
2020-12-30 15:33:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VEX3(bool w,
|
|
|
|
bool r,
|
|
|
|
bool x,
|
|
|
|
bool b,
|
|
|
|
LeadingBytes _leading_bytes,
|
|
|
|
u8 _reg_id = 0,
|
|
|
|
VexPrefix _prefix = VexPrefix::P_NONE,
|
|
|
|
bool l = false)
|
|
|
|
: W(w),
|
|
|
|
R(r),
|
|
|
|
X(x),
|
|
|
|
B(b),
|
|
|
|
leading_bytes(_leading_bytes),
|
|
|
|
reg_id(_reg_id),
|
|
|
|
prefix(_prefix),
|
|
|
|
L(l) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct VEX2 {
|
|
|
|
bool R;
|
|
|
|
u8 reg_id;
|
|
|
|
VexPrefix prefix;
|
|
|
|
bool L;
|
|
|
|
|
|
|
|
u8 emit(u8 byte) const {
|
|
|
|
if (byte == 0) {
|
|
|
|
return 0b11000101;
|
|
|
|
} else if (byte == 1) {
|
|
|
|
u8 result = 0;
|
|
|
|
result |= ((!R) << 7);
|
|
|
|
result |= ((~reg_id) & 0b1111) << 3;
|
|
|
|
result |= (L << 2);
|
|
|
|
result |= (u8(prefix) & 0b11);
|
|
|
|
return result;
|
|
|
|
} else {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(false);
|
2021-03-07 12:01:59 -05:00
|
|
|
return -1;
|
2020-12-30 15:33:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VEX2(bool r, u8 _reg_id = 0, VexPrefix _prefix = VexPrefix::P_NONE, bool l = false)
|
|
|
|
: R(r), reg_id(_reg_id), prefix(_prefix), L(l) {}
|
|
|
|
};
|
|
|
|
|
2020-08-22 22:30:12 -04:00
|
|
|
/*!
|
|
|
|
* A high-level description of an x86-64 opcode. It can emit itself.
|
|
|
|
*/
|
|
|
|
struct Instruction {
|
2020-08-26 01:21:33 -04:00
|
|
|
Instruction(uint8_t opcode) : op(opcode) {}
|
2020-08-22 22:30:12 -04:00
|
|
|
uint8_t op;
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
enum Flags {
|
|
|
|
kOp2Set = (1 << 0),
|
|
|
|
kOp3Set = (1 << 1),
|
|
|
|
kIsNull = (1 << 2),
|
|
|
|
kSetRex = (1 << 3),
|
|
|
|
kSetModrm = (1 << 4),
|
|
|
|
kSetSib = (1 << 5),
|
|
|
|
kSetDispImm = (1 << 6),
|
|
|
|
kSetImm = (1 << 7),
|
|
|
|
};
|
2020-08-22 22:30:12 -04:00
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
u8 m_flags = 0;
|
2020-08-22 22:30:12 -04:00
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
uint8_t op2;
|
2020-08-22 22:30:12 -04:00
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
uint8_t op3;
|
2020-08-22 22:30:12 -04:00
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
u8 n_vex = 0;
|
2020-12-30 15:33:51 -05:00
|
|
|
uint8_t vex[3] = {0, 0, 0};
|
|
|
|
|
2020-08-22 22:30:12 -04:00
|
|
|
// the rex byte
|
|
|
|
uint8_t m_rex = 0;
|
|
|
|
|
|
|
|
// the modrm byte
|
|
|
|
uint8_t m_modrm = 0;
|
|
|
|
|
|
|
|
// the sib byte
|
|
|
|
uint8_t m_sib = 0;
|
|
|
|
|
|
|
|
// the displacement
|
|
|
|
Imm disp;
|
|
|
|
|
|
|
|
// the immediate
|
|
|
|
Imm imm;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Move opcode byte 0 to before the rex prefix.
|
|
|
|
*/
|
|
|
|
void swap_op0_rex() {
|
2023-02-24 18:32:30 -05:00
|
|
|
if (!(m_flags & kSetRex))
|
2020-08-26 01:21:33 -04:00
|
|
|
return;
|
2020-08-22 22:30:12 -04:00
|
|
|
auto temp = op;
|
|
|
|
op = m_rex;
|
|
|
|
m_rex = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set(REX r) {
|
|
|
|
m_rex = r();
|
2023-02-24 18:32:30 -05:00
|
|
|
m_flags |= kSetRex;
|
2020-08-22 22:30:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void set(ModRM modrm) {
|
|
|
|
m_modrm = modrm();
|
2023-02-24 18:32:30 -05:00
|
|
|
m_flags |= kSetModrm;
|
2020-08-22 22:30:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void set(SIB sib) {
|
|
|
|
m_sib = sib();
|
2023-02-24 18:32:30 -05:00
|
|
|
m_flags |= kSetSib;
|
2020-08-22 22:30:12 -04:00
|
|
|
}
|
|
|
|
|
2020-12-30 15:33:51 -05:00
|
|
|
void set(VEX3 vex3) {
|
|
|
|
n_vex = 3;
|
|
|
|
for (int i = 0; i < n_vex; i++) {
|
|
|
|
vex[i] = vex3.emit(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void set(VEX2 vex2) {
|
|
|
|
n_vex = 2;
|
|
|
|
for (int i = 0; i < n_vex; i++) {
|
|
|
|
vex[i] = vex2.emit(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-22 22:30:12 -04:00
|
|
|
void set_disp(Imm i) {
|
|
|
|
disp = i;
|
2023-02-24 18:32:30 -05:00
|
|
|
m_flags |= kSetDispImm;
|
2020-08-22 22:30:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void set(Imm i) {
|
|
|
|
imm = i;
|
2023-02-24 18:32:30 -05:00
|
|
|
m_flags |= kSetImm;
|
2020-08-22 22:30:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_op2(uint8_t b) {
|
2023-02-24 18:32:30 -05:00
|
|
|
m_flags |= kOp2Set;
|
2020-08-22 22:30:12 -04:00
|
|
|
op2 = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_op3(uint8_t b) {
|
2023-02-24 18:32:30 -05:00
|
|
|
m_flags |= kOp3Set;
|
2020-08-22 22:30:12 -04:00
|
|
|
op3 = b;
|
|
|
|
}
|
|
|
|
|
2020-09-05 16:37:37 -04:00
|
|
|
int get_imm_size() const {
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetImm) {
|
2020-09-05 16:37:37 -04:00
|
|
|
return imm.size;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_disp_size() const {
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetDispImm) {
|
2020-09-05 16:37:37 -04:00
|
|
|
return disp.size;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-22 22:30:12 -04:00
|
|
|
/*!
|
|
|
|
* Set modrm and rex as needed for two regs.
|
|
|
|
*/
|
|
|
|
void set_modrm_and_rex(uint8_t reg, uint8_t rm, uint8_t mod, bool rex_w = false) {
|
|
|
|
bool rex_b = false, rex_r = false;
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
if (rm >= 8) {
|
2020-08-22 22:30:12 -04:00
|
|
|
rm -= 8;
|
|
|
|
rex_b = true;
|
|
|
|
}
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
if (reg >= 8) {
|
2020-08-22 22:30:12 -04:00
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
|
|
|
modrm.mod = mod;
|
|
|
|
modrm.reg_op = reg;
|
|
|
|
modrm.rm = rm;
|
|
|
|
|
|
|
|
set(modrm);
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
if (rex_b || rex_w || rex_r) {
|
2020-08-22 22:30:12 -04:00
|
|
|
set(REX(rex_w, rex_r, false, rex_b));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-30 15:33:51 -05:00
|
|
|
void set_vex_modrm_and_rex(uint8_t reg,
|
|
|
|
uint8_t rm,
|
|
|
|
VEX3::LeadingBytes lb,
|
|
|
|
uint8_t vex_reg = 0,
|
|
|
|
bool rex_w = false,
|
|
|
|
VexPrefix prefix = VexPrefix::P_NONE) {
|
|
|
|
bool rex_b = false, rex_r = false;
|
|
|
|
|
|
|
|
if (rm >= 8) {
|
|
|
|
rm -= 8;
|
|
|
|
rex_b = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg >= 8) {
|
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
|
|
|
modrm.mod = 3;
|
|
|
|
modrm.reg_op = reg;
|
|
|
|
modrm.rm = rm;
|
|
|
|
|
|
|
|
set(modrm);
|
|
|
|
if (rex_b || rex_w || lb != VEX3::LeadingBytes::P_0F) {
|
|
|
|
// need three byte version
|
|
|
|
set(VEX3(rex_w, rex_r, false, rex_b, lb, vex_reg, prefix));
|
|
|
|
} else {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(lb == VEX3::LeadingBytes::P_0F); // vex2 implies 0x0f
|
|
|
|
ASSERT(!rex_b);
|
|
|
|
ASSERT(!rex_w);
|
2020-12-30 15:33:51 -05:00
|
|
|
set(VEX2(rex_r, vex_reg, prefix));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Set VEX prefix for REX as needed for two registers.
|
|
|
|
*/
|
|
|
|
void set_vex_modrm_and_rex(uint8_t reg,
|
|
|
|
uint8_t rm,
|
|
|
|
uint8_t mod,
|
|
|
|
VEX3::LeadingBytes lb,
|
|
|
|
bool rex_w = false) {
|
|
|
|
bool rex_b = false;
|
|
|
|
bool rex_r = false;
|
|
|
|
if (rm >= 8) {
|
|
|
|
rm -= 8;
|
|
|
|
rex_b = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg >= 8) {
|
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
|
|
|
modrm.mod = mod;
|
|
|
|
modrm.reg_op = reg;
|
|
|
|
modrm.rm = rm;
|
|
|
|
set(modrm);
|
|
|
|
if (rex_b || rex_w || lb != VEX3::LeadingBytes::P_0F) {
|
|
|
|
// need three byte version
|
|
|
|
set(VEX3(rex_w, rex_r, false, rex_b, lb));
|
|
|
|
} else {
|
|
|
|
// can get away with two byte version
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(lb == VEX3::LeadingBytes::P_0F); // vex2 implies 0x0f
|
|
|
|
ASSERT(!rex_b);
|
|
|
|
ASSERT(!rex_w);
|
2020-12-30 15:33:51 -05:00
|
|
|
set(VEX2(rex_r));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-29 22:41:46 -04:00
|
|
|
void set_modrm_and_rex_for_reg_plus_reg_plus_s8(uint8_t reg,
|
|
|
|
uint8_t addr1,
|
|
|
|
uint8_t addr2,
|
|
|
|
s8 offset,
|
|
|
|
bool rex_w) {
|
2020-08-29 21:04:21 -04:00
|
|
|
bool rex_b = false, rex_r = false, rex_x = false;
|
|
|
|
bool addr1_ext = false;
|
|
|
|
bool addr2_ext = false;
|
|
|
|
|
|
|
|
if (addr1 >= 8) {
|
|
|
|
addr1 -= 8;
|
|
|
|
addr1_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr2 >= 8) {
|
|
|
|
addr2 -= 8;
|
|
|
|
addr2_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg >= 8) {
|
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
2020-08-29 22:41:46 -04:00
|
|
|
modrm.mod = 1; // no disp
|
|
|
|
modrm.rm = 4; // sib!
|
2020-08-29 21:04:21 -04:00
|
|
|
modrm.reg_op = reg;
|
|
|
|
|
|
|
|
SIB sib;
|
|
|
|
sib.scale = 0;
|
|
|
|
|
|
|
|
Imm imm2(1, offset);
|
|
|
|
|
|
|
|
// default addr1 in index
|
2020-08-29 22:41:46 -04:00
|
|
|
if (addr1 == 4) {
|
2020-08-29 21:04:21 -04:00
|
|
|
sib.index = addr2;
|
|
|
|
sib.base = addr1;
|
|
|
|
rex_x = addr2_ext;
|
|
|
|
rex_b = addr1_ext;
|
|
|
|
} else {
|
|
|
|
// addr1 in index
|
|
|
|
sib.index = addr1;
|
|
|
|
sib.base = addr2;
|
|
|
|
rex_x = addr1_ext;
|
|
|
|
rex_b = addr2_ext;
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(sib.index != 4);
|
2020-08-29 21:04:21 -04:00
|
|
|
|
2020-08-29 22:41:46 -04:00
|
|
|
if (rex_b || rex_w || rex_r || rex_x) {
|
2020-08-29 21:04:21 -04:00
|
|
|
set(REX(rex_w, rex_r, rex_x, rex_b));
|
|
|
|
}
|
|
|
|
|
|
|
|
set(modrm);
|
|
|
|
set(sib);
|
|
|
|
set_disp(imm2);
|
|
|
|
}
|
|
|
|
|
2020-12-30 15:33:51 -05:00
|
|
|
void set_vex_modrm_and_rex_for_reg_plus_reg_plus_s8(uint8_t reg,
|
|
|
|
uint8_t addr1,
|
|
|
|
uint8_t addr2,
|
|
|
|
s8 offset,
|
|
|
|
VEX3::LeadingBytes lb,
|
|
|
|
bool rex_w) {
|
|
|
|
bool rex_b = false, rex_r = false, rex_x = false;
|
|
|
|
bool addr1_ext = false;
|
|
|
|
bool addr2_ext = false;
|
|
|
|
|
|
|
|
if (addr1 >= 8) {
|
|
|
|
addr1 -= 8;
|
|
|
|
addr1_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr2 >= 8) {
|
|
|
|
addr2 -= 8;
|
|
|
|
addr2_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg >= 8) {
|
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
|
|
|
modrm.mod = 1; // no disp
|
|
|
|
modrm.rm = 4; // sib!
|
|
|
|
modrm.reg_op = reg;
|
|
|
|
|
|
|
|
SIB sib;
|
|
|
|
sib.scale = 0;
|
|
|
|
|
|
|
|
Imm imm2(1, offset);
|
|
|
|
|
|
|
|
// default addr1 in index
|
|
|
|
if (addr1 == 4) {
|
|
|
|
sib.index = addr2;
|
|
|
|
sib.base = addr1;
|
|
|
|
rex_x = addr2_ext;
|
|
|
|
rex_b = addr1_ext;
|
|
|
|
} else {
|
|
|
|
// addr1 in index
|
|
|
|
sib.index = addr1;
|
|
|
|
sib.base = addr2;
|
|
|
|
rex_x = addr1_ext;
|
|
|
|
rex_b = addr2_ext;
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(sib.index != 4);
|
2020-12-30 15:33:51 -05:00
|
|
|
|
|
|
|
if (rex_b || rex_w || rex_x || lb != VEX3::LeadingBytes::P_0F) {
|
|
|
|
// need three byte version
|
|
|
|
set(VEX3(rex_w, rex_r, rex_x, rex_b, lb));
|
|
|
|
} else {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(lb == VEX3::LeadingBytes::P_0F); // vex2 implies 0x0f
|
|
|
|
ASSERT(!rex_b);
|
|
|
|
ASSERT(!rex_w);
|
|
|
|
ASSERT(!rex_x);
|
2020-12-30 15:33:51 -05:00
|
|
|
set(VEX2(rex_r));
|
|
|
|
}
|
|
|
|
|
|
|
|
set(modrm);
|
|
|
|
set(sib);
|
|
|
|
set_disp(imm2);
|
|
|
|
}
|
|
|
|
|
2020-08-29 22:41:46 -04:00
|
|
|
void set_modrm_and_rex_for_reg_plus_reg_plus_s32(uint8_t reg,
|
|
|
|
uint8_t addr1,
|
|
|
|
uint8_t addr2,
|
2020-08-30 10:56:42 -04:00
|
|
|
s32 offset,
|
2020-08-29 22:41:46 -04:00
|
|
|
bool rex_w) {
|
2020-08-29 21:04:21 -04:00
|
|
|
bool rex_b = false, rex_r = false, rex_x = false;
|
|
|
|
bool addr1_ext = false;
|
|
|
|
bool addr2_ext = false;
|
|
|
|
|
|
|
|
if (addr1 >= 8) {
|
|
|
|
addr1 -= 8;
|
|
|
|
addr1_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr2 >= 8) {
|
|
|
|
addr2 -= 8;
|
|
|
|
addr2_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg >= 8) {
|
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
2020-08-29 22:41:46 -04:00
|
|
|
modrm.mod = 2; // no disp
|
|
|
|
modrm.rm = 4; // sib!
|
2020-08-29 21:04:21 -04:00
|
|
|
modrm.reg_op = reg;
|
|
|
|
|
|
|
|
SIB sib;
|
|
|
|
sib.scale = 0;
|
|
|
|
|
|
|
|
Imm imm2(4, offset);
|
|
|
|
|
|
|
|
// default addr1 in index
|
2020-08-29 22:41:46 -04:00
|
|
|
if (addr1 == 4) {
|
2020-08-29 21:04:21 -04:00
|
|
|
sib.index = addr2;
|
|
|
|
sib.base = addr1;
|
|
|
|
rex_x = addr2_ext;
|
|
|
|
rex_b = addr1_ext;
|
|
|
|
} else {
|
|
|
|
// addr1 in index
|
|
|
|
sib.index = addr1;
|
|
|
|
sib.base = addr2;
|
|
|
|
rex_x = addr1_ext;
|
|
|
|
rex_b = addr2_ext;
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(sib.index != 4);
|
2020-08-29 21:04:21 -04:00
|
|
|
|
2020-08-29 22:41:46 -04:00
|
|
|
if (rex_b || rex_w || rex_r || rex_x) {
|
2020-08-29 21:04:21 -04:00
|
|
|
set(REX(rex_w, rex_r, rex_x, rex_b));
|
|
|
|
}
|
|
|
|
|
|
|
|
set(modrm);
|
|
|
|
set(sib);
|
|
|
|
set_disp(imm2);
|
|
|
|
}
|
|
|
|
|
2020-12-30 15:33:51 -05:00
|
|
|
void set_vex_modrm_and_rex_for_reg_plus_reg_plus_s32(uint8_t reg,
|
|
|
|
uint8_t addr1,
|
|
|
|
uint8_t addr2,
|
|
|
|
s32 offset,
|
|
|
|
VEX3::LeadingBytes lb,
|
|
|
|
bool rex_w) {
|
|
|
|
bool rex_b = false, rex_r = false, rex_x = false;
|
|
|
|
bool addr1_ext = false;
|
|
|
|
bool addr2_ext = false;
|
|
|
|
|
|
|
|
if (addr1 >= 8) {
|
|
|
|
addr1 -= 8;
|
|
|
|
addr1_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr2 >= 8) {
|
|
|
|
addr2 -= 8;
|
|
|
|
addr2_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg >= 8) {
|
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
|
|
|
modrm.mod = 2; // no disp
|
|
|
|
modrm.rm = 4; // sib!
|
|
|
|
modrm.reg_op = reg;
|
|
|
|
|
|
|
|
SIB sib;
|
|
|
|
sib.scale = 0;
|
|
|
|
|
|
|
|
Imm imm2(4, offset);
|
|
|
|
|
|
|
|
// default addr1 in index
|
|
|
|
if (addr1 == 4) {
|
|
|
|
sib.index = addr2;
|
|
|
|
sib.base = addr1;
|
|
|
|
rex_x = addr2_ext;
|
|
|
|
rex_b = addr1_ext;
|
|
|
|
} else {
|
|
|
|
// addr1 in index
|
|
|
|
sib.index = addr1;
|
|
|
|
sib.base = addr2;
|
|
|
|
rex_x = addr1_ext;
|
|
|
|
rex_b = addr2_ext;
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(sib.index != 4);
|
2020-12-30 15:33:51 -05:00
|
|
|
|
|
|
|
if (rex_b || rex_w || rex_x || lb != VEX3::LeadingBytes::P_0F) {
|
|
|
|
// need three byte version
|
|
|
|
set(VEX3(rex_w, rex_r, rex_x, rex_b, lb));
|
|
|
|
} else {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(lb == VEX3::LeadingBytes::P_0F); // vex2 implies 0x0f
|
|
|
|
ASSERT(!rex_b);
|
|
|
|
ASSERT(!rex_w);
|
|
|
|
ASSERT(!rex_x);
|
2020-12-30 15:33:51 -05:00
|
|
|
set(VEX2(rex_r));
|
|
|
|
}
|
|
|
|
|
|
|
|
set(modrm);
|
|
|
|
set(sib);
|
|
|
|
set_disp(imm2);
|
|
|
|
}
|
|
|
|
|
2020-08-29 22:41:46 -04:00
|
|
|
void set_modrm_and_rex_for_reg_plus_reg_addr(uint8_t reg,
|
|
|
|
uint8_t addr1,
|
|
|
|
uint8_t addr2,
|
|
|
|
bool rex_w = false,
|
|
|
|
bool rex_always = false) {
|
2020-08-29 19:13:29 -04:00
|
|
|
bool rex_b = false, rex_r = false, rex_x = false;
|
|
|
|
bool addr1_ext = false;
|
|
|
|
bool addr2_ext = false;
|
|
|
|
|
|
|
|
if (addr1 >= 8) {
|
|
|
|
addr1 -= 8;
|
|
|
|
addr1_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr2 >= 8) {
|
|
|
|
addr2 -= 8;
|
|
|
|
addr2_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg >= 8) {
|
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
2020-08-29 22:41:46 -04:00
|
|
|
modrm.mod = 0; // no disp
|
|
|
|
modrm.rm = 4; // sib!
|
2020-08-29 19:13:29 -04:00
|
|
|
modrm.reg_op = reg;
|
|
|
|
|
|
|
|
SIB sib;
|
|
|
|
sib.scale = 0;
|
|
|
|
|
2020-08-29 22:41:46 -04:00
|
|
|
if (addr1 == 5 && addr2 == 5) {
|
2020-08-29 19:13:29 -04:00
|
|
|
sib.index = addr1;
|
|
|
|
sib.base = addr2;
|
|
|
|
rex_x = addr1_ext;
|
|
|
|
rex_b = addr2_ext;
|
|
|
|
modrm.mod = 1;
|
2020-08-29 21:04:21 -04:00
|
|
|
set_disp(Imm(1, 0));
|
2020-08-29 19:13:29 -04:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// default addr1 in index
|
|
|
|
bool flipped = (addr1 == 4) || (addr2 == 5);
|
|
|
|
|
2020-08-29 22:41:46 -04:00
|
|
|
if (flipped) {
|
2020-08-29 19:13:29 -04:00
|
|
|
sib.index = addr2;
|
|
|
|
sib.base = addr1;
|
|
|
|
rex_x = addr2_ext;
|
|
|
|
rex_b = addr1_ext;
|
|
|
|
} else {
|
|
|
|
// addr1 in index
|
|
|
|
sib.index = addr1;
|
|
|
|
sib.base = addr2;
|
|
|
|
rex_x = addr1_ext;
|
|
|
|
rex_b = addr2_ext;
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(sib.base != 5);
|
|
|
|
ASSERT(sib.index != 4);
|
2020-08-29 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
2020-08-29 22:41:46 -04:00
|
|
|
if (rex_b || rex_w || rex_r || rex_x || rex_always) {
|
2020-08-29 19:13:29 -04:00
|
|
|
set(REX(rex_w, rex_r, rex_x, rex_b));
|
|
|
|
}
|
|
|
|
|
|
|
|
set(modrm);
|
|
|
|
set(sib);
|
|
|
|
}
|
|
|
|
|
2020-12-30 15:33:51 -05:00
|
|
|
void set_vex_modrm_and_rex_for_reg_plus_reg_addr(uint8_t reg,
|
|
|
|
uint8_t addr1,
|
|
|
|
uint8_t addr2,
|
|
|
|
VEX3::LeadingBytes lb,
|
|
|
|
bool rex_w = false) {
|
|
|
|
bool rex_b = false, rex_r = false, rex_x = false;
|
|
|
|
bool addr1_ext = false;
|
|
|
|
bool addr2_ext = false;
|
|
|
|
|
|
|
|
if (addr1 >= 8) {
|
|
|
|
addr1 -= 8;
|
|
|
|
addr1_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr2 >= 8) {
|
|
|
|
addr2 -= 8;
|
|
|
|
addr2_ext = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg >= 8) {
|
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
|
|
|
modrm.mod = 0; // no disp
|
|
|
|
modrm.rm = 4; // sib!
|
|
|
|
modrm.reg_op = reg;
|
|
|
|
|
|
|
|
SIB sib;
|
|
|
|
sib.scale = 0;
|
|
|
|
|
|
|
|
if (addr1 == 5 && addr2 == 5) {
|
|
|
|
sib.index = addr1;
|
|
|
|
sib.base = addr2;
|
|
|
|
rex_x = addr1_ext;
|
|
|
|
rex_b = addr2_ext;
|
|
|
|
modrm.mod = 1;
|
|
|
|
set_disp(Imm(1, 0));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// default addr1 in index
|
|
|
|
bool flipped = (addr1 == 4) || (addr2 == 5);
|
|
|
|
|
|
|
|
if (flipped) {
|
|
|
|
sib.index = addr2;
|
|
|
|
sib.base = addr1;
|
|
|
|
rex_x = addr2_ext;
|
|
|
|
rex_b = addr1_ext;
|
|
|
|
} else {
|
|
|
|
// addr1 in index
|
|
|
|
sib.index = addr1;
|
|
|
|
sib.base = addr2;
|
|
|
|
rex_x = addr1_ext;
|
|
|
|
rex_b = addr2_ext;
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(sib.base != 5);
|
|
|
|
ASSERT(sib.index != 4);
|
2020-12-30 15:33:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rex_b || rex_w || rex_x || lb != VEX3::LeadingBytes::P_0F) {
|
|
|
|
// need three byte version
|
|
|
|
set(VEX3(rex_w, rex_r, rex_x, rex_b, lb));
|
|
|
|
} else {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(lb == VEX3::LeadingBytes::P_0F); // vex2 implies 0x0f
|
|
|
|
ASSERT(!rex_b);
|
|
|
|
ASSERT(!rex_w);
|
|
|
|
ASSERT(!rex_x);
|
2020-12-30 15:33:51 -05:00
|
|
|
set(VEX2(rex_r));
|
|
|
|
}
|
|
|
|
|
|
|
|
set(modrm);
|
|
|
|
set(sib);
|
|
|
|
}
|
|
|
|
|
2020-08-22 22:30:12 -04:00
|
|
|
/*!
|
|
|
|
* Set modrm and rex as needed for two regs for an addressing mode.
|
|
|
|
* Will set SIB if R12 or RSP indexing is used.
|
|
|
|
*/
|
2020-08-29 19:13:29 -04:00
|
|
|
void set_modrm_and_rex_for_reg_addr(uint8_t reg, uint8_t rm, bool rex_w = false) {
|
2020-08-22 22:30:12 -04:00
|
|
|
bool rex_b = false, rex_r = false;
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
if (rm >= 8) {
|
2020-08-22 22:30:12 -04:00
|
|
|
rm -= 8;
|
|
|
|
rex_b = true;
|
|
|
|
}
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
if (reg >= 8) {
|
2020-08-22 22:30:12 -04:00
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
2020-08-29 19:13:29 -04:00
|
|
|
modrm.mod = 0;
|
2020-08-22 22:30:12 -04:00
|
|
|
modrm.reg_op = reg;
|
|
|
|
modrm.rm = rm;
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
if (rm == 4) {
|
2020-08-22 22:30:12 -04:00
|
|
|
SIB sib;
|
|
|
|
sib.scale = 0;
|
|
|
|
sib.base = 4;
|
|
|
|
sib.index = 4;
|
|
|
|
|
|
|
|
set(sib);
|
|
|
|
}
|
|
|
|
|
2020-08-29 19:13:29 -04:00
|
|
|
if (rm == 5) {
|
|
|
|
modrm.mod = 1; // 1 byte imm
|
2020-08-29 21:04:21 -04:00
|
|
|
set_disp(Imm(1, 0));
|
2020-08-29 19:13:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
set(modrm);
|
2020-08-26 01:21:33 -04:00
|
|
|
if (rex_b || rex_w || rex_r) {
|
2020-08-22 22:30:12 -04:00
|
|
|
set(REX(rex_w, rex_r, false, rex_b));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-30 20:39:39 -04:00
|
|
|
void set_modrm_and_rex_for_rip_plus_s32(uint8_t reg, s32 offset, bool rex_w = false) {
|
|
|
|
bool rex_r = false;
|
|
|
|
|
|
|
|
if (reg >= 8) {
|
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
|
|
|
modrm.mod = 0;
|
|
|
|
modrm.reg_op = reg;
|
|
|
|
modrm.rm = 5; // use the RIP addressing mode
|
|
|
|
set(modrm);
|
|
|
|
|
|
|
|
if (rex_r || rex_w) {
|
|
|
|
set(REX(rex_w, rex_r, false, false));
|
|
|
|
}
|
|
|
|
|
|
|
|
set_disp(Imm(4, offset));
|
|
|
|
}
|
|
|
|
|
2020-08-22 22:30:12 -04:00
|
|
|
void add_rex() {
|
2023-02-24 18:32:30 -05:00
|
|
|
if (!(m_flags & kSetRex)) {
|
2020-08-22 22:30:12 -04:00
|
|
|
set(REX());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-30 15:33:51 -05:00
|
|
|
void set_vex_modrm_and_rex_for_rip_plus_s32(uint8_t reg,
|
|
|
|
s32 offset,
|
|
|
|
VEX3::LeadingBytes lb = VEX3::LeadingBytes::P_0F,
|
|
|
|
bool rex_w = false) {
|
|
|
|
bool rex_r = false;
|
|
|
|
|
|
|
|
if (reg >= 8) {
|
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ModRM modrm;
|
|
|
|
modrm.mod = 0;
|
|
|
|
modrm.reg_op = reg;
|
|
|
|
modrm.rm = 5; // use the RIP addressing mode
|
|
|
|
set(modrm);
|
|
|
|
|
|
|
|
if (rex_w || lb != VEX3::LeadingBytes::P_0F) {
|
|
|
|
// need three byte version
|
|
|
|
set(VEX3(rex_w, rex_r, false, false, lb));
|
|
|
|
} else {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(lb == VEX3::LeadingBytes::P_0F); // vex2 implies 0x0f
|
|
|
|
ASSERT(!rex_w);
|
2020-12-30 15:33:51 -05:00
|
|
|
set(VEX2(rex_r));
|
|
|
|
}
|
|
|
|
|
|
|
|
set_disp(Imm(4, offset));
|
|
|
|
}
|
|
|
|
|
2020-08-22 22:30:12 -04:00
|
|
|
/*!
|
2020-12-31 15:59:11 -05:00
|
|
|
* Set up modrm and rex for the commonly used immediate displacement indexing mode.
|
2020-08-22 22:30:12 -04:00
|
|
|
*/
|
2020-12-31 15:59:11 -05:00
|
|
|
void set_modrm_rex_sib_for_reg_reg_disp(uint8_t reg, uint8_t mod, uint8_t rm, bool rex_w) {
|
2020-08-22 22:30:12 -04:00
|
|
|
ModRM modrm;
|
|
|
|
|
|
|
|
bool rex_r = false;
|
2020-08-26 01:21:33 -04:00
|
|
|
if (reg >= 8) {
|
2020-08-22 22:30:12 -04:00
|
|
|
reg -= 8;
|
|
|
|
rex_r = true;
|
|
|
|
}
|
|
|
|
modrm.reg_op = reg;
|
|
|
|
|
|
|
|
modrm.mod = mod;
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
modrm.rm = 4; // use sib
|
2020-08-22 22:30:12 -04:00
|
|
|
|
|
|
|
SIB sib;
|
|
|
|
sib.scale = 0;
|
|
|
|
sib.index = 4;
|
|
|
|
bool rex_b = false;
|
2020-08-26 01:21:33 -04:00
|
|
|
if (rm >= 8) {
|
2020-08-22 22:30:12 -04:00
|
|
|
rex_b = true;
|
|
|
|
rm -= 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
sib.base = rm;
|
|
|
|
|
|
|
|
set(modrm);
|
|
|
|
set(sib);
|
|
|
|
|
2020-08-26 01:21:33 -04:00
|
|
|
if (rex_r || rex_w || rex_b) {
|
2020-08-22 22:30:12 -04:00
|
|
|
set(REX(rex_w, rex_r, false, rex_b));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Get the position of the disp immediate relative to the start of the instruction
|
|
|
|
*/
|
|
|
|
int offset_of_disp() const {
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kIsNull)
|
2020-08-26 01:21:33 -04:00
|
|
|
return 0;
|
2023-02-24 18:32:30 -05:00
|
|
|
ASSERT(m_flags & kSetDispImm);
|
2020-08-22 22:30:12 -04:00
|
|
|
int offset = 0;
|
2020-12-30 15:33:51 -05:00
|
|
|
offset += n_vex;
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetRex)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset++;
|
|
|
|
offset++; // opcode
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kOp2Set)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset++;
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kOp3Set)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset++;
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetModrm)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset++;
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetSib)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset++;
|
2020-08-22 22:30:12 -04:00
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Get the position of the imm immediate relative to the start of the instruction
|
|
|
|
*/
|
|
|
|
int offset_of_imm() const {
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kIsNull)
|
2020-08-26 01:21:33 -04:00
|
|
|
return 0;
|
2023-02-24 18:32:30 -05:00
|
|
|
ASSERT(m_flags & kSetImm);
|
2020-08-22 22:30:12 -04:00
|
|
|
int offset = 0;
|
2020-12-30 15:33:51 -05:00
|
|
|
offset += n_vex;
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetRex)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset++;
|
|
|
|
offset++; // opcode
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kOp2Set)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset++;
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kOp3Set)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset++;
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetModrm)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset++;
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetSib)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset++;
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetDispImm)
|
2020-08-26 01:21:33 -04:00
|
|
|
offset += disp.size;
|
2020-08-22 22:30:12 -04:00
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Emit into a buffer and return how many bytes written (can be zero)
|
|
|
|
*/
|
|
|
|
uint8_t emit(uint8_t* buffer) const {
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kIsNull)
|
2020-08-26 01:21:33 -04:00
|
|
|
return 0;
|
2020-08-22 22:30:12 -04:00
|
|
|
uint8_t count = 0;
|
2020-12-30 15:33:51 -05:00
|
|
|
|
|
|
|
for (int i = 0; i < n_vex; i++) {
|
|
|
|
buffer[count++] = vex[i];
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetRex) {
|
2020-08-22 22:30:12 -04:00
|
|
|
buffer[count++] = m_rex;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer[count++] = op;
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kOp2Set) {
|
2020-08-22 22:30:12 -04:00
|
|
|
buffer[count++] = op2;
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kOp3Set) {
|
2020-08-22 22:30:12 -04:00
|
|
|
buffer[count++] = op3;
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetModrm) {
|
2020-08-22 22:30:12 -04:00
|
|
|
buffer[count++] = m_modrm;
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetSib) {
|
2020-08-22 22:30:12 -04:00
|
|
|
buffer[count++] = m_sib;
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetDispImm) {
|
2020-08-26 01:21:33 -04:00
|
|
|
for (int i = 0; i < disp.size; i++) {
|
2020-08-22 22:30:12 -04:00
|
|
|
buffer[count++] = disp.v_arr[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetImm) {
|
2020-08-26 01:21:33 -04:00
|
|
|
for (int i = 0; i < imm.size; i++) {
|
2020-08-22 22:30:12 -04:00
|
|
|
buffer[count++] = imm.v_arr[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
2020-09-02 16:24:13 -04:00
|
|
|
|
|
|
|
uint8_t length() const {
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kIsNull)
|
2020-09-02 16:24:13 -04:00
|
|
|
return 0;
|
|
|
|
uint8_t count = 0;
|
2020-12-30 15:33:51 -05:00
|
|
|
|
|
|
|
count += n_vex;
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetRex) {
|
2020-09-02 16:24:13 -04:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
count++;
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kOp2Set) {
|
2020-09-02 16:24:13 -04:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kOp3Set) {
|
2020-09-02 16:24:13 -04:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetModrm) {
|
2020-09-02 16:24:13 -04:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetSib) {
|
2020-09-02 16:24:13 -04:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetDispImm) {
|
2020-09-02 16:24:13 -04:00
|
|
|
for (int i = 0; i < disp.size; i++) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:32:30 -05:00
|
|
|
if (m_flags & kSetImm) {
|
2020-09-02 16:24:13 -04:00
|
|
|
for (int i = 0; i < imm.size; i++) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
2020-08-22 22:30:12 -04:00
|
|
|
};
|
2020-08-29 19:13:29 -04:00
|
|
|
} // namespace emitter
|
2020-08-22 22:30:12 -04:00
|
|
|
|
2020-08-29 19:13:29 -04:00
|
|
|
#endif // JAK_INSTRUCTION_H
|