Move Intel recipe_* bodies into intel/recipes.py.
Use a PUT_OP macro in the TailRecipe Python class to replace the code snippet that emits the prefixes + opcode part of the instruction encoding. Prepare for the addition of REX prefixes by giving the PUT_OP functions a third argument representing the REX prefix. For the non-REX encodings, verify that no REX bits wold be needed.
This commit is contained in:
@@ -43,7 +43,9 @@ OPCODE_PREFIX = {
|
||||
(0xf2, 0x0f, 0x3a): ('Mp3', 0b1111)
|
||||
}
|
||||
|
||||
# VEX/XOP and EVEX prefixes are not yet supported.
|
||||
# The table above does not include the REX prefix which goes after the
|
||||
# mandatory prefix. VEX/XOP and EVEX prefixes are not yet supported. Encodings
|
||||
# using any of these prefixes are represented by separate recipes.
|
||||
#
|
||||
# The encoding bits are:
|
||||
#
|
||||
@@ -79,6 +81,18 @@ def decode_ops(ops, rrr=0, w=0):
|
||||
return (name, op | (mmpp << 8) | (rrr << 12) | (w << 15))
|
||||
|
||||
|
||||
def replace_put_op(emit, prefix):
|
||||
# type: (str, str) -> str
|
||||
"""
|
||||
Given a snippet of Rust code (or None), replace the `PUT_OP` macro with the
|
||||
corresponding `put_*` function from the `binemit.rs` module.
|
||||
"""
|
||||
if emit is None:
|
||||
return None
|
||||
else:
|
||||
return emit.replace('PUT_OP', 'put_' + prefix.lower())
|
||||
|
||||
|
||||
class TailRecipe:
|
||||
"""
|
||||
Generate encoding recipes on demand.
|
||||
@@ -92,6 +106,10 @@ class TailRecipe:
|
||||
|
||||
The arguments are the same as for an `EncRecipe`, except for `size` which
|
||||
does not include the size of the opcode.
|
||||
|
||||
The `emit` parameter contains Rust code to actually emit an encoding, like
|
||||
`EncRecipe` does it. Additionally, the text `PUT_OP` is substituted with
|
||||
the proper `put_*` function from the `intel/binemit.rs` module.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -103,7 +121,8 @@ class TailRecipe:
|
||||
outs, # type: ConstraintSeq
|
||||
branch_range=None, # type: BranchRange
|
||||
instp=None, # type: PredNode
|
||||
isap=None # type: PredNode
|
||||
isap=None, # type: PredNode
|
||||
emit=None # type: str
|
||||
):
|
||||
# type: (...) -> None
|
||||
self.name = name
|
||||
@@ -114,6 +133,7 @@ class TailRecipe:
|
||||
self.branch_range = branch_range
|
||||
self.instp = instp
|
||||
self.isap = isap
|
||||
self.emit = emit
|
||||
|
||||
# Cached recipes, keyed by name prefix.
|
||||
self.recipes = dict() # type: Dict[str, EncRecipe]
|
||||
@@ -136,34 +156,69 @@ class TailRecipe:
|
||||
outs=self.outs,
|
||||
branch_range=self.branch_range,
|
||||
instp=self.instp,
|
||||
isap=self.isap)
|
||||
isap=self.isap,
|
||||
emit=replace_put_op(self.emit, name))
|
||||
return (self.recipes[name], bits)
|
||||
|
||||
|
||||
# XX /r
|
||||
rr = TailRecipe('rr', Binary, size=1, ins=(GPR, GPR), outs=0)
|
||||
rr = TailRecipe(
|
||||
'rr', Binary, size=1, ins=(GPR, GPR), outs=0,
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||
modrm_rr(in_reg0, in_reg1, sink);
|
||||
''')
|
||||
|
||||
# XX /r, but for a unary operator with separate input/output register, like
|
||||
# copies.
|
||||
ur = TailRecipe('ur', Unary, size=1, ins=GPR, outs=GPR)
|
||||
ur = TailRecipe(
|
||||
'ur', Unary, size=1, ins=GPR, outs=GPR,
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(out_reg0, in_reg0), sink);
|
||||
modrm_rr(out_reg0, in_reg0, sink);
|
||||
''')
|
||||
|
||||
# XX /n with one arg in %rcx, for shifts.
|
||||
rc = TailRecipe('rc', Binary, size=1, ins=(GPR, GPR.rcx), outs=0)
|
||||
rc = TailRecipe(
|
||||
'rc', Binary, size=1, ins=(GPR, GPR.rcx), outs=0,
|
||||
emit='''
|
||||
PUT_OP(bits, rex1(in_reg0), sink);
|
||||
modrm_r_bits(in_reg0, bits, sink);
|
||||
''')
|
||||
|
||||
# XX /n ib with 8-bit immediate sign-extended.
|
||||
rib = TailRecipe(
|
||||
'rib', BinaryImm, size=2, ins=GPR, outs=0,
|
||||
instp=IsSignedInt(BinaryImm.imm, 8))
|
||||
instp=IsSignedInt(BinaryImm.imm, 8),
|
||||
emit='''
|
||||
PUT_OP(bits, rex1(in_reg0), sink);
|
||||
modrm_r_bits(in_reg0, bits, sink);
|
||||
let imm: i64 = imm.into();
|
||||
sink.put1(imm as u8);
|
||||
''')
|
||||
|
||||
# XX /n id with 32-bit immediate sign-extended.
|
||||
rid = TailRecipe(
|
||||
'rid', BinaryImm, size=5, ins=GPR, outs=0,
|
||||
instp=IsSignedInt(BinaryImm.imm, 32))
|
||||
instp=IsSignedInt(BinaryImm.imm, 32),
|
||||
emit='''
|
||||
PUT_OP(bits, rex1(in_reg0), sink);
|
||||
modrm_r_bits(in_reg0, bits, sink);
|
||||
let imm: i64 = imm.into();
|
||||
sink.put4(imm as u32);
|
||||
''')
|
||||
|
||||
# XX+rd id unary with 32-bit immediate.
|
||||
uid = TailRecipe(
|
||||
'uid', UnaryImm, size=4, ins=(), outs=GPR,
|
||||
instp=IsSignedInt(UnaryImm.imm, 32))
|
||||
instp=IsSignedInt(UnaryImm.imm, 32),
|
||||
emit='''
|
||||
// The destination register is encoded in the low bits of the opcode.
|
||||
// No ModR/M.
|
||||
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
||||
let imm: i64 = imm.into();
|
||||
sink.put4(imm as u32);
|
||||
''')
|
||||
|
||||
#
|
||||
# Store recipes.
|
||||
@@ -172,26 +227,59 @@ uid = TailRecipe(
|
||||
# XX /r register-indirect store with no offset.
|
||||
st = TailRecipe(
|
||||
'st', Store, size=1, ins=(GPR, GPR), outs=(),
|
||||
instp=IsEqual(Store.offset, 0))
|
||||
instp=IsEqual(Store.offset, 0),
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||
modrm_rm(in_reg1, in_reg0, sink);
|
||||
''')
|
||||
|
||||
# XX /r register-indirect store with no offset.
|
||||
# Only ABCD allowed for stored value. This is for byte stores.
|
||||
st_abcd = TailRecipe(
|
||||
'st_abcd', Store, size=1, ins=(ABCD, GPR), outs=(),
|
||||
instp=IsEqual(Store.offset, 0))
|
||||
instp=IsEqual(Store.offset, 0),
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||
modrm_rm(in_reg1, in_reg0, sink);
|
||||
''')
|
||||
|
||||
# XX /r register-indirect store with 8-bit offset.
|
||||
stDisp8 = TailRecipe(
|
||||
'stDisp8', Store, size=2, ins=(GPR, GPR), outs=(),
|
||||
instp=IsSignedInt(Store.offset, 8))
|
||||
instp=IsSignedInt(Store.offset, 8),
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||
modrm_disp8(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put1(offset as u8);
|
||||
''')
|
||||
stDisp8_abcd = TailRecipe(
|
||||
'stDisp8_abcd', Store, size=2, ins=(ABCD, GPR), outs=(),
|
||||
instp=IsSignedInt(Store.offset, 8))
|
||||
instp=IsSignedInt(Store.offset, 8),
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||
modrm_disp8(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put1(offset as u8);
|
||||
''')
|
||||
|
||||
# XX /r register-indirect store with 32-bit offset.
|
||||
stDisp32 = TailRecipe('stDisp32', Store, size=5, ins=(GPR, GPR), outs=())
|
||||
stDisp32 = TailRecipe(
|
||||
'stDisp32', Store, size=5, ins=(GPR, GPR), outs=(),
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||
modrm_disp32(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put4(offset as u32);
|
||||
''')
|
||||
stDisp32_abcd = TailRecipe(
|
||||
'stDisp32_abcd', Store, size=5, ins=(ABCD, GPR), outs=())
|
||||
'stDisp32_abcd', Store, size=5, ins=(ABCD, GPR), outs=(),
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||
modrm_disp32(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put4(offset as u32);
|
||||
''')
|
||||
|
||||
#
|
||||
# Load recipes
|
||||
@@ -200,21 +288,54 @@ stDisp32_abcd = TailRecipe(
|
||||
# XX /r load with no offset.
|
||||
ld = TailRecipe(
|
||||
'ld', Load, size=1, ins=(GPR), outs=(GPR),
|
||||
instp=IsEqual(Load.offset, 0))
|
||||
instp=IsEqual(Load.offset, 0),
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(out_reg0, in_reg0), sink);
|
||||
modrm_rm(in_reg0, out_reg0, sink);
|
||||
''')
|
||||
|
||||
# XX /r load with 8-bit offset.
|
||||
ldDisp8 = TailRecipe(
|
||||
'ldDisp8', Load, size=2, ins=(GPR), outs=(GPR),
|
||||
instp=IsSignedInt(Load.offset, 8))
|
||||
instp=IsSignedInt(Load.offset, 8),
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(out_reg0, in_reg0), sink);
|
||||
modrm_disp8(in_reg0, out_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put1(offset as u8);
|
||||
''')
|
||||
|
||||
# XX /r load with 32-bit offset.
|
||||
ldDisp32 = TailRecipe(
|
||||
'ldDisp32', Load, size=5, ins=(GPR), outs=(GPR),
|
||||
instp=IsSignedInt(Load.offset, 32))
|
||||
instp=IsSignedInt(Load.offset, 32),
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(out_reg0, in_reg0), sink);
|
||||
modrm_disp32(in_reg0, out_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put4(offset as u32);
|
||||
''')
|
||||
|
||||
#
|
||||
# Call/return
|
||||
#
|
||||
call_id = TailRecipe('call_id', Call, size=4, ins=(), outs=())
|
||||
call_r = TailRecipe('call_r', IndirectCall, size=1, ins=GPR, outs=())
|
||||
ret = TailRecipe('ret', MultiAry, size=0, ins=(), outs=())
|
||||
call_id = TailRecipe(
|
||||
'call_id', Call, size=4, ins=(), outs=(),
|
||||
emit='''
|
||||
PUT_OP(bits, BASE_REX, sink);
|
||||
sink.reloc_func(RelocKind::PCRel4.into(), func_ref);
|
||||
sink.put4(0);
|
||||
''')
|
||||
|
||||
call_r = TailRecipe(
|
||||
'call_r', IndirectCall, size=1, ins=GPR, outs=(),
|
||||
emit='''
|
||||
PUT_OP(bits, rex1(in_reg0), sink);
|
||||
modrm_r_bits(in_reg0, bits, sink);
|
||||
''')
|
||||
|
||||
ret = TailRecipe(
|
||||
'ret', MultiAry, size=0, ins=(), outs=(),
|
||||
emit='''
|
||||
PUT_OP(bits, BASE_REX, sink);
|
||||
''')
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
//! Emitting binary Intel machine code.
|
||||
|
||||
use binemit::{CodeSink, Reloc, bad_encoding};
|
||||
use ir::{self, Function, Inst, InstructionData, MemFlags};
|
||||
use ir::immediates::{Imm64, Offset32};
|
||||
use ir::{Function, Inst, InstructionData};
|
||||
use isa::RegUnit;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs"));
|
||||
@@ -21,27 +20,51 @@ impl Into<Reloc> for RelocKind {
|
||||
}
|
||||
}
|
||||
|
||||
// Emit single-byte opcode.
|
||||
fn put_op1<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x0f00, 0, "Invalid encoding bits for Op1*");
|
||||
// Mandatory prefix bytes for Mp* opcodes.
|
||||
const PREFIX: [u8; 3] = [0x66, 0xf3, 0xf2];
|
||||
|
||||
// A REX prefix with no bits set: 0b0100WRXB.
|
||||
const BASE_REX: u8 = 0b0100_0000;
|
||||
|
||||
// Create a single-register REX prefix, setting the B bit to bit 3 of the register.
|
||||
// This is used for instructions that encode a register in the low 3 bits of the opcode and for
|
||||
// instructions that use the ModR/M `reg` field for something else.
|
||||
fn rex1(reg_b: RegUnit) -> u8 {
|
||||
let b = ((reg_b >> 3) & 1) as u8;
|
||||
BASE_REX | b
|
||||
}
|
||||
|
||||
// Create a dual-register REX prefix, setting:
|
||||
//
|
||||
// REX.B = bit 3 of r/m register.
|
||||
// REX.R = bit 3 of reg register.
|
||||
fn rex2(rm: RegUnit, reg: RegUnit) -> u8 {
|
||||
let b = ((rm >> 3) & 1) as u8;
|
||||
let r = ((reg >> 3) & 1) as u8;
|
||||
BASE_REX | b | (r << 2)
|
||||
}
|
||||
|
||||
// Emit a single-byte opcode with no REX prefix.
|
||||
fn put_op1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x8f00, 0, "Invalid encoding bits for Op1*");
|
||||
debug_assert_eq!(rex, BASE_REX, "Invalid registers for REX-less encoding");
|
||||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
// Emit two-byte opcode: 0F XX
|
||||
fn put_op2<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x0f00, 0x0400, "Invalid encoding bits for Op2*");
|
||||
fn put_op2<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x8f00, 0x0400, "Invalid encoding bits for Op2*");
|
||||
debug_assert_eq!(rex, BASE_REX, "Invalid registers for REX-less encoding");
|
||||
sink.put1(0x0f);
|
||||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
// Mandatory prefix bytes for Mp* opcodes.
|
||||
const PREFIX: [u8; 3] = [0x66, 0xf3, 0xf2];
|
||||
|
||||
// Emit single-byte opcode with mandatory prefix.
|
||||
fn put_mp1<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
|
||||
fn put_mp1<CS: CodeSink + ?Sized>(bits: u16, rex: u8, sink: &mut CS) {
|
||||
debug_assert_eq!(bits & 0x0c00, 0, "Invalid encoding bits for Mp1*");
|
||||
let pp = (bits >> 8) & 3;
|
||||
sink.put1(PREFIX[(pp - 1) as usize]);
|
||||
debug_assert_eq!(rex, BASE_REX, "Invalid registers for REX-less encoding");
|
||||
sink.put1(bits as u8);
|
||||
}
|
||||
|
||||
@@ -100,290 +123,3 @@ fn modrm_disp32<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS)
|
||||
b |= rm;
|
||||
sink.put1(b);
|
||||
}
|
||||
|
||||
fn recipe_op1rr<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
in_reg1: RegUnit) {
|
||||
put_op1(bits, sink);
|
||||
modrm_rr(in_reg0, in_reg1, sink);
|
||||
}
|
||||
|
||||
fn recipe_op1ur<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
out_reg0: RegUnit) {
|
||||
put_op1(bits, sink);
|
||||
modrm_rr(out_reg0, in_reg0, sink);
|
||||
}
|
||||
|
||||
fn recipe_op1rc<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit) {
|
||||
put_op1(bits, sink);
|
||||
modrm_r_bits(in_reg0, bits, sink);
|
||||
}
|
||||
|
||||
fn recipe_op1rib<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
imm: Imm64) {
|
||||
put_op1(bits, sink);
|
||||
modrm_r_bits(in_reg0, bits, sink);
|
||||
let imm: i64 = imm.into();
|
||||
sink.put1(imm as u8);
|
||||
}
|
||||
|
||||
fn recipe_op1rid<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
imm: Imm64) {
|
||||
put_op1(bits, sink);
|
||||
modrm_r_bits(in_reg0, bits, sink);
|
||||
let imm: i64 = imm.into();
|
||||
sink.put4(imm as u32);
|
||||
}
|
||||
|
||||
fn recipe_op1uid<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
imm: Imm64,
|
||||
out_reg0: RegUnit) {
|
||||
// The destination register is encoded in the low bits of the opcode. No ModR/M
|
||||
put_op1(bits | (out_reg0 & 7), sink);
|
||||
let imm: i64 = imm.into();
|
||||
sink.put4(imm as u32);
|
||||
}
|
||||
|
||||
// Store recipes.
|
||||
|
||||
fn recipe_op1st<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
in_reg1: RegUnit,
|
||||
_flags: MemFlags,
|
||||
_offset: Offset32) {
|
||||
put_op1(bits, sink);
|
||||
modrm_rm(in_reg1, in_reg0, sink);
|
||||
}
|
||||
|
||||
// This is just a tighter register class constraint.
|
||||
fn recipe_op1st_abcd<CS: CodeSink + ?Sized>(func: &Function,
|
||||
inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
in_reg1: RegUnit,
|
||||
flags: MemFlags,
|
||||
offset: Offset32) {
|
||||
recipe_op1st(func, inst, sink, bits, in_reg0, in_reg1, flags, offset)
|
||||
}
|
||||
|
||||
fn recipe_mp1st<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
in_reg1: RegUnit,
|
||||
_flags: MemFlags,
|
||||
_offset: Offset32) {
|
||||
put_mp1(bits, sink);
|
||||
modrm_rm(in_reg1, in_reg0, sink);
|
||||
}
|
||||
|
||||
fn recipe_op1stdisp8<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
in_reg1: RegUnit,
|
||||
_flags: MemFlags,
|
||||
offset: Offset32) {
|
||||
put_op1(bits, sink);
|
||||
modrm_disp8(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put1(offset as u8);
|
||||
}
|
||||
|
||||
fn recipe_op1stdisp8_abcd<CS: CodeSink + ?Sized>(func: &Function,
|
||||
inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
in_reg1: RegUnit,
|
||||
flags: MemFlags,
|
||||
offset: Offset32) {
|
||||
recipe_op1stdisp8(func, inst, sink, bits, in_reg0, in_reg1, flags, offset)
|
||||
}
|
||||
|
||||
fn recipe_mp1stdisp8<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
in_reg1: RegUnit,
|
||||
_flags: MemFlags,
|
||||
offset: Offset32) {
|
||||
put_mp1(bits, sink);
|
||||
modrm_disp8(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put1(offset as u8);
|
||||
}
|
||||
|
||||
fn recipe_op1stdisp32<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
in_reg1: RegUnit,
|
||||
_flags: MemFlags,
|
||||
offset: Offset32) {
|
||||
put_op1(bits, sink);
|
||||
modrm_disp32(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put4(offset as u32);
|
||||
}
|
||||
|
||||
fn recipe_op1stdisp32_abcd<CS: CodeSink + ?Sized>(func: &Function,
|
||||
inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
in_reg1: RegUnit,
|
||||
flags: MemFlags,
|
||||
offset: Offset32) {
|
||||
recipe_op1stdisp32(func, inst, sink, bits, in_reg0, in_reg1, flags, offset)
|
||||
}
|
||||
|
||||
fn recipe_mp1stdisp32<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
in_reg1: RegUnit,
|
||||
_flags: MemFlags,
|
||||
offset: Offset32) {
|
||||
put_mp1(bits, sink);
|
||||
modrm_disp32(in_reg1, in_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put4(offset as u32);
|
||||
}
|
||||
|
||||
// Load recipes
|
||||
|
||||
fn recipe_op1ld<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
_flags: MemFlags,
|
||||
_offset: Offset32,
|
||||
out_reg0: RegUnit) {
|
||||
put_op1(bits, sink);
|
||||
modrm_rm(in_reg0, out_reg0, sink);
|
||||
}
|
||||
|
||||
fn recipe_op1lddisp8<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
_flags: MemFlags,
|
||||
offset: Offset32,
|
||||
out_reg0: RegUnit) {
|
||||
put_op1(bits, sink);
|
||||
modrm_disp8(in_reg0, out_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put1(offset as u8);
|
||||
}
|
||||
|
||||
fn recipe_op1lddisp32<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
_flags: MemFlags,
|
||||
offset: Offset32,
|
||||
out_reg0: RegUnit) {
|
||||
put_op1(bits, sink);
|
||||
modrm_disp32(in_reg0, out_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put4(offset as u32);
|
||||
}
|
||||
|
||||
fn recipe_op2ld<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
_flags: MemFlags,
|
||||
_offset: Offset32,
|
||||
out_reg0: RegUnit) {
|
||||
put_op2(bits, sink);
|
||||
modrm_rm(in_reg0, out_reg0, sink);
|
||||
}
|
||||
|
||||
fn recipe_op2lddisp8<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
_flags: MemFlags,
|
||||
offset: Offset32,
|
||||
out_reg0: RegUnit) {
|
||||
put_op2(bits, sink);
|
||||
modrm_disp8(in_reg0, out_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put1(offset as u8);
|
||||
}
|
||||
|
||||
fn recipe_op2lddisp32<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
_flags: MemFlags,
|
||||
offset: Offset32,
|
||||
out_reg0: RegUnit) {
|
||||
put_op2(bits, sink);
|
||||
modrm_disp32(in_reg0, out_reg0, sink);
|
||||
let offset: i32 = offset.into();
|
||||
sink.put4(offset as u32);
|
||||
}
|
||||
|
||||
fn recipe_op1call_id<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
func_ref: ir::FuncRef) {
|
||||
put_op1(bits, sink);
|
||||
sink.reloc_func(RelocKind::PCRel4.into(), func_ref);
|
||||
sink.put4(0);
|
||||
}
|
||||
|
||||
fn recipe_op1call_r<CS: CodeSink + ?Sized>(_func: &Function,
|
||||
_inst: Inst,
|
||||
sink: &mut CS,
|
||||
bits: u16,
|
||||
in_reg0: RegUnit,
|
||||
_sig_ref: ir::SigRef) {
|
||||
put_op1(bits, sink);
|
||||
modrm_r_bits(in_reg0, bits, sink);
|
||||
}
|
||||
|
||||
fn recipe_op1ret<CS: CodeSink + ?Sized>(_func: &Function, _inst: Inst, sink: &mut CS, bits: u16) {
|
||||
put_op1(bits, sink);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user