Skip to content

Commit

Permalink
Add compare_only directive to eliminate different sub/cmp implementat…
Browse files Browse the repository at this point in the history
…ions
  • Loading branch information
Earlz committed Sep 25, 2019
1 parent a4e1e6d commit 839f592
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 67 deletions.
41 changes: 29 additions & 12 deletions src/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ pub struct Opcode{
pub arg_source: [ArgSource; MAX_ARGS],
pub gas_cost: GasCost,
pub pipeline_behavior: PipelineBehavior,
pub defined: bool
pub defined: bool,
pub compare_only: bool
}

/// This is a "super-opcode" which may have multiple child opcodes.
Expand Down Expand Up @@ -137,7 +138,8 @@ impl Default for Opcode{
gas_cost: GasCost::None,
//this defaults to conditional so that an unknown opcode is considered conditional
pipeline_behavior: PipelineBehavior::Unpredictable,
defined: false
defined: false,
compare_only: false
}
}
}
Expand All @@ -161,7 +163,8 @@ pub struct OpcodeDefiner{
function: Option<OpcodeFn>,
jump: Option<PipelineBehavior>,
has_modrm: bool,
reg_suffix: bool
reg_suffix: bool,
compare_only: bool
}

impl OpcodeDefiner{
Expand All @@ -170,6 +173,10 @@ impl OpcodeDefiner{
self.two_byte = true;
self
}
pub fn compares_only(&mut self) -> &mut OpcodeDefiner {
self.compare_only = true;
self
}
/// Specifies that the opcode is a group opcode.
/// Example: to encode `0xFF /0` one would use define_opcode(0xFF).is_group(0)
pub fn is_group(&mut self, group: u8) -> &mut OpcodeDefiner{
Expand Down Expand Up @@ -313,6 +320,7 @@ impl OpcodeDefiner{
table[op].opcodes[inner].function = self.function.unwrap();
table[op].opcodes[inner].gas_cost = self.gas_level.unwrap();
table[op].opcodes[inner].pipeline_behavior = self.jump.unwrap();
table[op].opcodes[inner].compare_only = self.compare_only;
for n in 0..self.args.len(){
let (source, size) = self.args[n];
table[op].opcodes[inner].arg_source[n] = source;
Expand Down Expand Up @@ -658,54 +666,63 @@ lazy_static! {
.into_table(&mut ops);
// Begin cmp opcodes
//0x38 cmp r/m8, r8
define_opcode(0x38).calls(cmp_8bit).with_gas(Low)
define_opcode(0x38).calls(sub_8bit).with_gas(Low)
.with_rm8()
.with_rm_reg8()
.compares_only()
.into_table(&mut ops);
//0x39 cmp, r/m16, r16
//0x39 cmp, r/m32, r32
define_opcode(0x39).calls(cmp_native_word).with_gas(Low)
define_opcode(0x39).calls(sub_native_word).with_gas(Low)
.with_rmw()
.with_rm_regw()
.compares_only()
.into_table(&mut ops);
//0x3A cmp r8, r/m8
define_opcode(0x3A).calls(cmp_8bit).with_gas(Low)
define_opcode(0x3A).calls(sub_8bit).with_gas(Low)
.with_rm_reg8()
.with_rm8()
.compares_only()
.into_table(&mut ops);
//0x3B cmp r16, r/m16
//0x3B cmp r32, r/m32
define_opcode(0x3B).calls(cmp_native_word).with_gas(Low)
define_opcode(0x3B).calls(sub_native_word).with_gas(Low)
.with_rm_regw()
.with_rmw()
.compares_only()
.into_table(&mut ops);
//0x3C cmp AL, imm8
define_opcode(0x3C).calls(cmp_8bit).with_gas(Low)
define_opcode(0x3C).calls(sub_8bit).with_gas(Low)
.with_arg(HardcodedRegister(Reg8::AL as u8), Fixed(Byte))
.with_imm8()
.compares_only()
.into_table(&mut ops);
//0x3D cmp AX, imm16
//0x3D cmp EAX, imm32
define_opcode(0x3D).calls(cmp_native_word).with_gas(Low)
define_opcode(0x3D).calls(sub_native_word).with_gas(Low)
.with_arg(HardcodedRegister(Reg32::EAX as u8), NativeWord) //Reg32::EAX resolves to the same as Reg16:AX
.with_immw()
.compares_only()
.into_table(&mut ops);
//0x80 cmp r/m8, imm8
define_opcode(0x80).is_group(7).calls(cmp_8bit).with_gas(Low)
define_opcode(0x80).is_group(7).calls(sub_8bit).with_gas(Low)
.with_rm8()
.with_imm8()
.compares_only()
.into_table(&mut ops);
//0x81 cmp r/m16, imm16
//0x81 cmp r/m32, imm32
define_opcode(0x81).is_group(7).calls(cmp_native_word).with_gas(Low)
define_opcode(0x81).is_group(7).calls(sub_native_word).with_gas(Low)
.with_rmw()
.with_immw()
.compares_only()
.into_table(&mut ops);
//0x83 cmp r/m16, imm8
//0x83 cmp r/m32, imm8
define_opcode(0x83).is_group(7).calls(cmp_native_word).with_gas(Low)
define_opcode(0x83).is_group(7).calls(sub_native_word).with_gas(Low)
.with_rmw()
.with_imm8()
.compares_only()
.into_table(&mut ops);
// Bitwise AND
//0x20 and r/m8, r8
Expand Down
62 changes: 9 additions & 53 deletions src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,9 @@ pub fn sub_8bit(vm: &mut VM, pipeline: &Pipeline, _hv: &mut dyn Hypervisor) -> R
vm.flags.calculate_parity(result as u32);
vm.flags.calculate_sign8(result);
vm.flags.adjust = ((base as i32)&0x0F) - ((subt as i32)&0x0F) < 0;
vm.set_arg(pipeline.args[0].location, SizedValue::Byte(result))?;
if !pipeline.compare_only {
vm.set_arg(pipeline.args[0].location, SizedValue::Byte(result))?;
}
Ok(())
}

Expand All @@ -446,7 +448,9 @@ pub fn sub_16bit(vm: &mut VM, pipeline: &Pipeline, _hv: &mut dyn Hypervisor) ->
vm.flags.calculate_parity(result as u32);
vm.flags.calculate_sign16(result);
vm.flags.adjust = ((base as i32)&0x0F) - ((subt as i32)&0x0F) < 0;
vm.set_arg(pipeline.args[0].location, SizedValue::Word(result))?;
if !pipeline.compare_only {
vm.set_arg(pipeline.args[0].location, SizedValue::Word(result))?;
}
Ok(())
}

Expand All @@ -461,7 +465,9 @@ pub fn sub_32bit(vm: &mut VM, pipeline: &Pipeline, _hv: &mut dyn Hypervisor) ->
vm.flags.calculate_parity(result);
vm.flags.calculate_sign32(result);
vm.flags.adjust = ((base as i32)&0x0F) - ((subt as i32)&0x0F) < 0;
vm.set_arg(pipeline.args[0].location, SizedValue::Dword(result))?;
if !pipeline.compare_only {
vm.set_arg(pipeline.args[0].location, SizedValue::Dword(result))?;
}
Ok(())
}

Expand Down Expand Up @@ -509,56 +515,6 @@ pub fn decrement_32bit(vm: &mut VM, pipeline: &Pipeline, _hv: &mut dyn Hyperviso
Ok(())
}

pub fn cmp_8bit(vm: &mut VM, pipeline: &Pipeline, _hv: &mut dyn Hypervisor) -> Result<(), VMError>{
let base = vm.get_arg(pipeline.args[0].location)?.u8_exact()?;
let cmpt = vm.get_arg(pipeline.args[1].location)?.u8_exact()?;
let (result, carry) = base.overflowing_sub(cmpt);
let (_, overflow) = (base as i8).overflowing_sub(cmpt as i8);
vm.flags.overflow = overflow;
vm.flags.carry = carry;
vm.flags.calculate_zero(result as u32);
vm.flags.calculate_parity(result as u32);
vm.flags.calculate_sign8(result);
vm.flags.adjust = ((base as i32)&0x0F) - ((cmpt as i32)&0x0F) < 0;
Ok(())
}

pub fn cmp_native_word(vm: &mut VM, pipeline: &Pipeline, hv: &mut dyn Hypervisor) -> Result<(), VMError> {
if pipeline.size_override {
return cmp_16bit(vm, pipeline, hv);
} else {
return cmp_32bit(vm, pipeline, hv);
}
}

pub fn cmp_16bit(vm: &mut VM, pipeline: &Pipeline, _hv: &mut dyn Hypervisor) -> Result<(), VMError>{
let base = vm.get_arg(pipeline.args[0].location)?.u16_exact()?;
let cmpt = vm.get_arg(pipeline.args[1].location)?.u16_sx()?;
let (result, carry) = base.overflowing_sub(cmpt);
let (_, overflow) = (base as i16).overflowing_sub(cmpt as i16);
vm.flags.overflow = overflow;
vm.flags.carry = carry;
vm.flags.calculate_zero(result as u32);
vm.flags.calculate_parity(result as u32);
vm.flags.calculate_sign16(result);
vm.flags.adjust = ((base as i32)&0x0F) - ((cmpt as i32)&0x0F) < 0;
Ok(())
}

pub fn cmp_32bit(vm: &mut VM, pipeline: &Pipeline, _hv: &mut dyn Hypervisor) -> Result<(), VMError>{
let base = vm.get_arg(pipeline.args[0].location)?.u32_exact()?;
let cmpt = vm.get_arg(pipeline.args[1].location)?.u32_sx()?;
let (result, carry) = base.overflowing_sub(cmpt);
let (_, overflow) = (base as i32).overflowing_sub(cmpt as i32);
vm.flags.overflow = overflow;
vm.flags.carry = carry;
vm.flags.calculate_zero(result);
vm.flags.calculate_parity(result);
vm.flags.calculate_sign32(result);
vm.flags.adjust = ((base as i32)&0x0F) - ((cmpt as i32)&0x0F) < 0;
Ok(())
}

pub fn and_8bit(vm: &mut VM, pipeline: &Pipeline, _hv: &mut dyn Hypervisor) -> Result<(), VMError>{
let base = vm.get_arg(pipeline.args[0].location)?.u8_exact()?;
let mask = vm.get_arg(pipeline.args[1].location)?.u8_exact()?;
Expand Down
8 changes: 6 additions & 2 deletions src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ pub struct Pipeline{
/// Set to true if an operand size override prefix is present
pub size_override: bool,
/// The final opcode byte in the total opcode
pub opcode: u8
pub opcode: u8,
/// A marker that can be used to indicate the opcode function should only compare and not set any arguments
pub compare_only: bool
}

impl Default for Pipeline{
Expand All @@ -55,7 +57,8 @@ impl Default for Pipeline{
gas_cost: 0,
eip_size: 1,
size_override: false,
opcode: 0
opcode: 0,
compare_only: false
}
}
}
Expand Down Expand Up @@ -99,6 +102,7 @@ pub fn fill_pipeline(vm: &VM, opcodes: &[OpcodeProperties], pipeline: &mut [Pipe
}else{
&prop.opcodes[0]
};
p.compare_only = opcode.compare_only;
p.function = opcode.function;
p.gas_cost += vm.charger.cost(opcode.gas_cost);
p.size_override = prefixes.size_override;
Expand Down

0 comments on commit 839f592

Please sign in to comment.