diff --git a/example.ps1 b/example.ps1 index f0b6972b..f8dcadce 100644 --- a/example.ps1 +++ b/example.ps1 @@ -46,14 +46,14 @@ switch ($language) { $manifest = [Path]::GetFullPath($manifest) $package = $metadata.packages | - Where-Object { - [Path]::GetFullPath($_.manifest_path) -eq $manifest - } | - Select-Object -First 1 + Where-Object { + [Path]::GetFullPath($_.manifest_path) -eq $manifest + } | + Select-Object -First 1 $target = $package.targets | - Where-Object { $_.kind -contains "bin" } | - Select-Object -First 1 + Where-Object { $_.kind -contains "bin" } | + Select-Object -First 1 $source = Join-Path ` $metadata.target_directory ` diff --git a/example.tape b/example.tape index f6345b19..7b9540c1 100644 --- a/example.tape +++ b/example.tape @@ -9,7 +9,7 @@ Type "eco zenburn" Enter Type "aa" Enter -Sleep 5s +Sleep 2.5s Type "s section..binsafe" Enter Type "pdui add byte [rax], al~:0..-1" @@ -24,7 +24,7 @@ Type "eco zenburn" Enter Type "aa" Enter -Sleep 5s +Sleep 2.5s Type "s section..binsafe" Enter Type "pdui add byte [rax], al~:0..-1" diff --git a/logger/src/lib.rs b/logger/src/lib.rs index e9a35a84..1a2679fd 100644 --- a/logger/src/lib.rs +++ b/logger/src/lib.rs @@ -54,10 +54,7 @@ pub fn error(fmt: impl fmt::Display) { #[macro_export] macro_rules! debug { ($($arg:tt)*) => {{ - #[cfg(debug_assertions)] $crate::debug(format_args!($($arg)*)); - #[cfg(not(debug_assertions))] - let _ = format_args!($($arg)*); }}; } diff --git a/obfuscator/src/protections/virtualization/attestation/anti_debug.rs b/obfuscator/src/protections/virtualization/attestation/anti_debug.rs index 059aa8a9..01fff659 100644 --- a/obfuscator/src/protections/virtualization/attestation/anti_debug.rs +++ b/obfuscator/src/protections/virtualization/attestation/anti_debug.rs @@ -1,6 +1,5 @@ use crate::engine::Engine; use crate::protections::virtualization::attestation::*; -use rand::Rng; use runtime::runtime::ImportDef; use runtime::vm::bytecode::{VMReg, VMSeg, VMWidth}; use runtime::vm::encoders::Encode; @@ -22,32 +21,24 @@ const THREAD_HIDE_FROM_DEBUGGER: u64 = 0x11; const STATUS_PORT_NOT_SET: u64 = 0xc0000353; const STATUS_SUCCESS: u64 = 0; -pub fn generate( - engine: &mut Engine, - rng: &mut impl Rng, - expected: &mut u64, -) -> Vec> { +pub fn generate(engine: &mut Engine, expected: &mut u64) -> Vec> { let mut instructions = Vec::>::new(); instructions.extend(reserve(0x30)); instructions.extend(set_register(VMReg::Vp0, 0)); - instructions.extend(query_kd_debugger_enabled(engine, rng, expected)); - instructions.extend(query_process_debug_object_handle(engine, rng, expected)); - instructions.extend(set_hide_from_debugger(engine, rng, expected)); - instructions.extend(query_hide_from_debbuger(engine, rng, expected)); + instructions.extend(query_kd_debugger_enabled(engine, expected)); + instructions.extend(query_process_debug_object_handle(engine, expected)); + instructions.extend(set_hide_from_debugger(engine, expected)); + instructions.extend(query_hide_from_debbuger(engine, expected)); instructions.extend(release(0x30)); instructions } -fn query_kd_debugger_enabled( - engine: &mut Engine, - rng: &mut impl Rng, - expected: &mut u64, -) -> Vec> { +fn query_kd_debugger_enabled(engine: &mut Engine, expected: &mut u64) -> Vec> { let mut b = Vec::new(); b.extend(load_memory( @@ -59,7 +50,7 @@ fn query_kd_debugger_enabled( VMWidth::Lower8, )); b.extend(accumulate_immediate( - rng, + engine, VMReg::Vp0, None, 0, @@ -68,7 +59,7 @@ fn query_kd_debugger_enabled( b.extend(import(engine, ImportDef::NtQuerySystemInformation)); b.extend(accumulate_prologue( - rng, + engine, VMReg::Vp0, VMReg::Rax, &NT_QUERY_INFORMATION_PROCESS_PROLOGUE, @@ -94,16 +85,16 @@ fn query_kd_debugger_enabled( b.extend(invoke(VMReg::Rax)); b.extend(accumulate_immediate( - rng, + engine, VMReg::Vp0, Some(VMReg::Rax), STATUS_SUCCESS, expected, )); - // READ KernelDebuggerEnabled + KernelDebuggerNotPresent + // KernelDebuggerEnabled + KernelDebuggerNotPresent b.extend(accumulate_memory( - rng, + engine, VMReg::Vp0, VMReg::Rsp, 0x20, @@ -117,14 +108,13 @@ fn query_kd_debugger_enabled( fn query_process_debug_object_handle( engine: &mut Engine, - rng: &mut impl Rng, expected: &mut u64, ) -> Vec> { let mut b = Vec::new(); b.extend(import(engine, ImportDef::NtQueryInformationProcess)); b.extend(accumulate_prologue( - rng, + engine, VMReg::Vp0, VMReg::Rax, &NT_QUERY_INFORMATION_PROCESS_PROLOGUE, @@ -152,16 +142,16 @@ fn query_process_debug_object_handle( b.extend(invoke(VMReg::Rax)); b.extend(accumulate_immediate( - rng, + engine, VMReg::Vp0, Some(VMReg::Rax), STATUS_PORT_NOT_SET, expected, )); - // READ ProcessDebugObjectHandle + // ProcessDebugObjectHandle b.extend(accumulate_memory( - rng, + engine, VMReg::Vp0, VMReg::Rsp, 0x28, @@ -173,16 +163,12 @@ fn query_process_debug_object_handle( b } -fn set_hide_from_debugger( - engine: &mut Engine, - rng: &mut impl Rng, - expected: &mut u64, -) -> Vec> { +fn set_hide_from_debugger(engine: &mut Engine, expected: &mut u64) -> Vec> { let mut b = Vec::new(); b.extend(import(engine, ImportDef::NtSetInformationThread)); b.extend(accumulate_prologue( - rng, + engine, VMReg::Vp0, VMReg::Rax, &NT_SET_INFORMATION_THREAD_PROLOGUE, @@ -200,7 +186,7 @@ fn set_hide_from_debugger( b.extend(invoke(VMReg::Rax)); b.extend(accumulate_immediate( - rng, + engine, VMReg::Vp0, Some(VMReg::Rax), STATUS_SUCCESS, @@ -210,16 +196,12 @@ fn set_hide_from_debugger( b } -fn query_hide_from_debbuger( - engine: &mut Engine, - rng: &mut impl Rng, - expected: &mut u64, -) -> Vec> { +fn query_hide_from_debbuger(engine: &mut Engine, expected: &mut u64) -> Vec> { let mut b = Vec::new(); b.extend(import(engine, ImportDef::NtQueryInformationThread)); b.extend(accumulate_prologue( - rng, + engine, VMReg::Vp0, VMReg::Rax, &NT_QUERY_INFORMATION_THREAD_PROLOGUE, @@ -248,16 +230,16 @@ fn query_hide_from_debbuger( b.extend(invoke(VMReg::Rax)); b.extend(accumulate_immediate( - rng, + engine, VMReg::Vp0, Some(VMReg::Rax), STATUS_SUCCESS, expected, )); - // READ ThreadHideFromDebugger + // ThreadHideFromDebugger b.extend(accumulate_byte( - rng, + engine, VMReg::Vp0, VMReg::Rsp, 0x28, diff --git a/obfuscator/src/protections/virtualization/attestation/anti_emulation.rs b/obfuscator/src/protections/virtualization/attestation/anti_emulation.rs new file mode 100644 index 00000000..d372405c --- /dev/null +++ b/obfuscator/src/protections/virtualization/attestation/anti_emulation.rs @@ -0,0 +1,37 @@ +use crate::engine::Engine; +use crate::protections::virtualization::attestation::*; +use runtime::vm::bytecode::{Flag, VMReg}; +use runtime::vm::encoders::Encode; + +// CPUID.1:ECX[31] +const HYPERVISOR_PRESENT_BIT: u64 = 31; + +const HYPERVISOR_VENDOR_LEAF: u32 = 0x4000_0000; + +pub fn generate(engine: &mut Engine, expected: &mut u64) -> Vec> { + let mut b = Vec::>::new(); + + b.extend(cpuid(1, 0)); + b.extend(discard()); + b.extend(immediate(HYPERVISOR_PRESENT_BIT)); + b.extend(shr(None, None)); + b.extend(store_register(VMReg::R8)); + b.extend(discard()); + b.extend(discard()); + + b.extend(cpuid(HYPERVISOR_VENDOR_LEAF, 0)); + b.extend(or(None, None)); + b.extend(or(None, None)); + b.extend(or(None, None)); + + b.extend(immediate(1)); + b.extend(sub(None, None)); + b.extend(discard()); + b.extend(flag(Flag::Carry)); + + b.extend(and(Some(VMReg::R8), None)); + + b.extend(accumulate_immediate(engine, VMReg::Vp0, None, 0, expected)); + + b +} diff --git a/obfuscator/src/protections/virtualization/attestation/anti_tamper.rs b/obfuscator/src/protections/virtualization/attestation/anti_tamper.rs index 8cc15a54..9a3fe6a0 100644 --- a/obfuscator/src/protections/virtualization/attestation/anti_tamper.rs +++ b/obfuscator/src/protections/virtualization/attestation/anti_tamper.rs @@ -3,22 +3,13 @@ use std::convert::TryInto; use crate::engine::Engine; use crate::protections::virtualization::attestation::*; use exe::{Buffer, PE, RVA}; -use rand::Rng; use runtime::mapper::Mappable; use runtime::runtime::{DataDef, FnDef}; use runtime::vm::bytecode::{VMReg, VMSeg, VMWidth}; use runtime::vm::encoders::Encode; -pub fn generate( - engine: &mut Engine, - rng: &mut impl Rng, - expected: &mut u64, -) -> Vec> { - let operation = Operation::random(rng); - - let seed = engine.rt.keys.initializer; - - let mut hash = seed; +pub fn generate(engine: &mut Engine, expected: &mut u64) -> Vec> { + let mut hash = *expected; for &function in FnDef::VARIANTS.iter() { let rva = engine.rt.lookup(engine.rt.function_labels[&function]) as u32; @@ -31,13 +22,11 @@ pub fn generate( for chunk in &mut chunks { let word = u64::from_le_bytes(chunk.try_into().unwrap()); - apply_operation(operation, word, &mut hash); - hash = apply_lcg(engine, hash); + hash = apply_lcg(engine, hash ^ word); } for &byte in chunks.remainder() { - apply_operation(operation, byte as u64, &mut hash); - hash = apply_lcg(engine, hash); + hash = apply_lcg(engine, hash ^ byte as u64); } } @@ -49,8 +38,6 @@ pub fn generate( let mut instructions = Vec::>::new(); - instructions.extend(set_register(VMReg::Vp1, seed)); - instructions.extend(foreach( engine, VMReg::Rax, @@ -92,7 +79,7 @@ pub fn generate( |engine| { let mut inner = Vec::>::new(); - inner.extend(load_register(VMReg::Vp1)); + inner.extend(load_register(VMReg::Vp0)); inner.extend(load_memory( VMReg::Rcx, VMReg::R10, @@ -101,9 +88,9 @@ pub fn generate( VMSeg::None, VMWidth::Lower64, )); - inner.extend(register_operation(operation, None, None)); + inner.extend(xor(None, None)); inner.extend(register_lcg(engine, None)); - inner.extend(store_register(VMReg::Vp1)); + inner.extend(store_register(VMReg::Vp0)); inner }, @@ -120,7 +107,7 @@ pub fn generate( |engine| { let mut inner = Vec::>::new(); - inner.extend(load_register(VMReg::Vp1)); + inner.extend(load_register(VMReg::Vp0)); inner.extend(load_memory( VMReg::Rdx, VMReg::R9, @@ -129,9 +116,9 @@ pub fn generate( VMSeg::None, VMWidth::Lower8, )); - inner.extend(register_operation(operation, None, None)); + inner.extend(xor(None, None)); inner.extend(register_lcg(engine, None)); - inner.extend(store_register(VMReg::Vp1)); + inner.extend(store_register(VMReg::Vp0)); inner }, diff --git a/obfuscator/src/protections/virtualization/attestation/debug_registers.rs b/obfuscator/src/protections/virtualization/attestation/debug_registers.rs new file mode 100644 index 00000000..09f0394e --- /dev/null +++ b/obfuscator/src/protections/virtualization/attestation/debug_registers.rs @@ -0,0 +1,80 @@ +use crate::engine::Engine; +use crate::protections::virtualization::attestation::*; +use runtime::runtime::ImportDef; +use runtime::vm::bytecode::{VMReg, VMSeg, VMWidth}; +use runtime::vm::encoders::Encode; + +const NT_GET_CONTEXT_THREAD_PROLOGUE: [u8; 3] = [0x4C, 0x8B, 0xD1]; + +const NT_CURRENT_THREAD: i64 = -2; + +const STATUS_SUCCESS: u64 = 0; + +const CONTEXT_DEBUG_REGISTERS: u64 = 0x0010_0010; + +const DR0: i32 = 0x68; +const DR1: i32 = 0x70; +const DR2: i32 = 0x78; +const DR3: i32 = 0x80; +const DR7: i32 = 0x90; + +pub fn generate(engine: &mut Engine, expected: &mut u64) -> Vec> { + let mut b = Vec::>::new(); + + b.extend(reserve(0x4F0)); + + b.extend(import(engine, ImportDef::NtGetContextThread)); + b.extend(accumulate_prologue( + engine, + VMReg::Vp0, + VMReg::Rax, + &NT_GET_CONTEXT_THREAD_PROLOGUE, + expected, + )); + // ThreadHandle -> RCX + b.extend(set_register(VMReg::Rcx, NT_CURRENT_THREAD as u64)); + // ThreadContext -> RDX + b.extend(compute_memory( + VMReg::Rsp, + VMReg::None, + 1, + 0x20, + VMSeg::None, + )); + b.extend(store_register(VMReg::Rdx)); + // ContextFlags -> [RSP + ...] + b.extend(store_immediate( + VMReg::Rsp, + VMReg::None, + 1, + 0x50, + CONTEXT_DEBUG_REGISTERS, + )); + // NtGetContextThread + b.extend(invoke(VMReg::Rax)); + + b.extend(accumulate_immediate( + engine, + VMReg::Vp0, + Some(VMReg::Rax), + STATUS_SUCCESS, + expected, + )); + + // Read Dr0..Dr3 + Dr7: + for displacement in [DR0, DR1, DR2, DR3, DR7] { + b.extend(accumulate_memory( + engine, + VMReg::Vp0, + VMReg::Rsp, + displacement, + VMWidth::Lower64, + 0, + expected, + )); + } + + b.extend(release(0x4F0)); + + b +} diff --git a/obfuscator/src/protections/virtualization/attestation/mod.rs b/obfuscator/src/protections/virtualization/attestation/mod.rs index 54f36334..f030d3d7 100644 --- a/obfuscator/src/protections/virtualization/attestation/mod.rs +++ b/obfuscator/src/protections/virtualization/attestation/mod.rs @@ -2,221 +2,196 @@ use std::i32; use crate::engine::Engine; use crate::protections::virtualization::{crypt, language::*}; -use rand::Rng; -use runtime::runtime::DataDef; +use runtime::runtime::{DataDef, ImportDef}; use runtime::vm::bytecode::{Flag, VMCondition, VMReg, VMSeg, VMWidth}; use runtime::vm::encoders::Encode; mod anti_debug; +mod anti_emulation; mod anti_tamper; #[cfg(debug_assertions)] mod debug; +mod debug_registers; -// Masks lower 32 bits of timestamp, creating a ~1s window on a 3.5 GHz CPU -const WINDOW: u64 = 0x20; +// Masks the timestamp down to a ~1s tick on a 3.5 GHz CPU +const TICK: u64 = 0x20; -const MINIMUM_CYCLES: u64 = 1_000_000; -const MAXIMUM_CYCLES: u64 = 100_000_000; +const STALE: u64 = 1u64 << TICK; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Operation { - Add, - Sub, - Xor, -} - -impl Operation { - pub fn random(rng: &mut impl Rng) -> Self { - match rng.gen_range(0..3) { - 0 => Operation::Add, - 1 => Operation::Sub, - _ => Operation::Xor, - } - } - - fn inverse(self) -> Self { - match self { - Operation::Add => Operation::Sub, - Operation::Sub => Operation::Add, - Operation::Xor => Operation::Xor, - } - } -} +pub fn service(engine: &mut Engine, expected: &mut u64) -> Vec> { + let mut instructions = Vec::>::new(); -pub fn generate(engine: &mut Engine, key: u64) -> Vec>> { - let mut rng = rand::thread_rng(); + instructions.extend(anti_debug::generate(engine, expected)); + instructions.extend(anti_emulation::generate(engine, expected)); + instructions.extend(debug_registers::generate(engine, expected)); + instructions.extend(anti_tamper::generate(engine, expected)); - let mut blocks = Vec::>>::new(); + instructions.extend(hash(engine)); - let mut block = Vec::>::new(); + instructions.extend(publish(engine)); - let mut vp0 = 0; - let mut vp1 = 0; + instructions.extend(delay(engine)); - let mix0 = Operation::random(&mut rng); - let mix1 = Operation::random(&mut rng); + forever(instructions) +} - block.extend(timestamp()); - block.extend(mask(None, !((1u64 << WINDOW) - 1))); - block.extend(register_lcg(engine, None)); - block.extend(store_register(VMReg::Vt0)); +pub fn program(engine: &mut Engine, key: u64, expected: u64) -> Vec> { + let mut instructions = Vec::>::new(); - block.extend(sub(Some(VMReg::Vt0), Some(VMReg::Vt1))); + instructions.extend(unlock(engine)); - block.extend(store_register(VMReg::Rax)); + instructions.extend(correct(engine, key, expected)); - block.extend(skip( - engine, - VMReg::Rax, - VMCondition::cmp(Flag::Zero, 1), - |engine| { - let mut b = Vec::>::new(); - - b.extend(timestamp()); - - b.extend(anti_debug::generate(engine, &mut rng, &mut vp0)); - b.extend(anti_tamper::generate(engine, &mut rng, &mut vp1)); + instructions +} - b.extend(store_register(VMReg::Rax)); +fn delay(engine: &mut Engine) -> Vec> { + let mut instructions = Vec::>::new(); - b.extend(timestamp()); + instructions.extend(reserve(0x30)); + + instructions.extend(import(engine, ImportDef::NtDelayExecution)); + // Alertable -> RCX + instructions.extend(set_register(VMReg::Rcx, 0)); + // Interval -> RDX + instructions.extend(compute_memory( + VMReg::Rsp, + VMReg::None, + 1, + 0x20, + VMSeg::None, + )); + instructions.extend(store_register(VMReg::Rdx)); + // Interval -> [RSP + ...] + instructions.extend(store_immediate( + VMReg::Rsp, + VMReg::None, + 1, + 0x20, + (-10000i64) as u64, + )); + // NtDelayExecution + instructions.extend(invoke(VMReg::Rax)); - b.extend(sub(Some(VMReg::Rax), None)); + instructions.extend(release(0x30)); - b.extend(store_register(VMReg::Rax)); + instructions +} - b.extend(load_register(VMReg::Rax)); - b.extend(immediate(MINIMUM_CYCLES)); - b.extend(sub(None, None)); - b.extend(discard()); +fn publish(engine: &mut Engine) -> Vec> { + let mut instructions = Vec::>::new(); - b.extend(flag(Flag::Carry)); + // Tick the current timestamp into RAX and write it as the freshness stamp: + instructions.extend(timestamp()); + instructions.extend(mask(None, !((1u64 << TICK) - 1))); + instructions.extend(store_register(VMReg::Rax)); - b.extend(store_register(VMReg::Rcx)); + instructions.extend(load_register(VMReg::Rax)); + instructions.extend(store_data_at(engine, DataDef::VmServiceBox, 0)); - b.extend(accumulate_immediate( - &mut rng, - VMReg::Vp0, - Some(VMReg::Rcx), - 0, - &mut vp0, - )); - b.extend(accumulate_immediate( - &mut rng, - VMReg::Vp1, - Some(VMReg::Rcx), - 0, - &mut vp1, - )); + // Derive the keystream from the tick so the stored value is time-locked: + instructions.extend(load_register(VMReg::Rax)); + instructions.extend(load_data( + engine, + DataDef::VmKeyInitializer, + VMWidth::Lower64, + )); + instructions.extend(xor(None, None)); + instructions.extend(register_lcg(engine, None)); + instructions.extend(store_register(VMReg::Rcx)); - b.extend(immediate(MAXIMUM_CYCLES)); - b.extend(load_register(VMReg::Rax)); - b.extend(sub(None, None)); - b.extend(discard()); + // Store the fingerprint XORed with the keystream: + instructions.extend(load_register(VMReg::Vp0)); + instructions.extend(load_register(VMReg::Rcx)); + instructions.extend(xor(None, None)); + instructions.extend(store_data_at(engine, DataDef::VmServiceBox, 8)); - b.extend(flag(Flag::Carry)); + instructions +} - b.extend(store_register(VMReg::Rcx)); +fn unlock(engine: &mut Engine) -> Vec> { + let mut instructions = Vec::>::new(); - b.extend(accumulate_immediate( - &mut rng, - VMReg::Vp0, - Some(VMReg::Rcx), - 0, - &mut vp0, - )); - b.extend(accumulate_immediate( - &mut rng, - VMReg::Vp1, - Some(VMReg::Rcx), - 0, - &mut vp1, - )); + // Load the value published by the service: + instructions.extend(load_data_at( + engine, + DataDef::VmServiceBox, + 0, + VMWidth::Lower64, + )); + instructions.extend(store_register(VMReg::Rax)); - b.extend(register_operation(mix0, Some(VMReg::Vp0), Some(VMReg::Vt0))); - b.extend(register_lcg(engine, None)); - b.extend(store_register(VMReg::Vp0)); + // Derive the keystream from the stored tick: + instructions.extend(load_register(VMReg::Rax)); + instructions.extend(load_data( + engine, + DataDef::VmKeyInitializer, + VMWidth::Lower64, + )); + instructions.extend(xor(None, None)); + instructions.extend(register_lcg(engine, None)); + instructions.extend(store_register(VMReg::Rcx)); - b.extend(register_operation(mix1, Some(VMReg::Vp1), Some(VMReg::Vt0))); - b.extend(register_lcg(engine, None)); - b.extend(store_register(VMReg::Vp1)); + // Recover the fingerprint into Vp0: + instructions.extend(load_data_at( + engine, + DataDef::VmServiceBox, + 8, + VMWidth::Lower64, + )); + instructions.extend(load_register(VMReg::Rcx)); + instructions.extend(xor(None, None)); + instructions.extend(store_register(VMReg::Vp0)); - b.extend(copy(VMReg::Vt0, VMReg::Vt1)); + // Measure how many ticks old the fingerprint is: + instructions.extend(timestamp()); + instructions.extend(mask(None, !((1u64 << TICK) - 1))); + instructions.extend(load_register(VMReg::Rax)); + instructions.extend(sub(None, None)); + instructions.extend(store_register(VMReg::Rdx)); - b - }, - )); + // Store CF into RDX (CF=0 if the service is not stale) + instructions.extend(immediate(STALE)); + instructions.extend(load_register(VMReg::Rdx)); + instructions.extend(sub(None, None)); + instructions.extend(discard()); + instructions.extend(flag(Flag::Carry)); + instructions.extend(store_register(VMReg::Rdx)); - block.extend(correct(engine, &mut rng, key, vp0, vp1, mix0, mix1)); + // Flip the bits of RDX in-case it's non-zero to increase effectiveness: + instructions.extend(immediate(0)); + instructions.extend(load_register(VMReg::Rdx)); + instructions.extend(sub(None, None)); + instructions.extend(store_register(VMReg::Rdx)); - blocks.push(block); + // XOR Vp0 with Rdx to corrupt it in-case RDX was non-zero: + instructions.extend(load_register(VMReg::Vp0)); + instructions.extend(load_register(VMReg::Rdx)); + instructions.extend(xor(None, None)); + instructions.extend(store_register(VMReg::Vp0)); - blocks + instructions } -fn correct( - engine: &mut Engine, - rng: &mut impl Rng, - key: u64, - vp0: u64, - vp1: u64, - mix0: Operation, - mix1: Operation, -) -> Vec> { +fn correct(engine: &mut Engine, key: u64, expected: u64) -> Vec> { let mut instructions = Vec::>::new(); - instructions.extend(load_absolute(engine, DataDef::VmCodeEnd, VMReg::Rax)); - instructions.extend(load_absolute(engine, DataDef::VmAttestation, VMReg::Rcx)); - instructions.extend(load_absolute(engine, DataDef::VmCodeStart, VMReg::R8)); + let correction = expected ^ key; + // Offset of the block being decrypted (zero for the first block): + instructions.extend(load_absolute(engine, DataDef::VmCodeStart, VMReg::R8)); instructions.extend(sub(Some(VMReg::Vg0), Some(VMReg::R8))); instructions.extend(store_register(VMReg::Rdx)); + // First block chains off the initializer: instructions.extend(skip( engine, VMReg::Rdx, VMCondition::cmp(Flag::Zero, 0), - |engine| { - let mut b = Vec::new(); - - b.extend(sub(Some(VMReg::Rax), Some(VMReg::Rcx))); - b.extend(immediate((crypt::HEADER_SIZE + crypt::TRAILER_SIZE) as u64)); - b.extend(sub(None, None)); - b.extend(store_register(VMReg::R9)); - - b.extend(set_register(VMReg::R10, 0)); - - b.extend(foreach( - engine, - VMReg::R8, - Bound::Register(VMReg::R9), - 8, - |engine| { - let mut outer = Vec::new(); - - outer.extend(load_register(VMReg::R10)); - outer.extend(load_memory( - VMReg::Rcx, - VMReg::R8, - 1, - crypt::HEADER_SIZE as i32, - VMSeg::None, - VMWidth::Lower64, - )); - outer.extend(xor(None, None)); - outer.extend(register_lcg(engine, None)); - outer.extend(store_register(VMReg::R10)); - - outer - }, - )); - - b.extend(load_register(VMReg::R10)); - - b - }, + |engine| immediate(engine.rt.keys.initializer), )); + // Every other block chains off the previous block's trailing qword: instructions.extend(skip( engine, VMReg::Rdx, @@ -233,20 +208,9 @@ fn correct( }, )); - let operation = Operation::random(rng); - let combined = combine_operation(operation, vp0, vp1); - let correction = combined ^ key; - - instructions.extend(register_lcg_inverse(engine, Some(VMReg::Vp0))); - instructions.extend(register_operation(mix0.inverse(), None, Some(VMReg::Vt1))); - - instructions.extend(register_lcg_inverse(engine, Some(VMReg::Vp1))); - instructions.extend(register_operation(mix1.inverse(), None, Some(VMReg::Vt1))); - - instructions.extend(register_operation(operation, None, None)); - instructions.extend(immediate(correction)); + instructions.extend(load_register(VMReg::Vp0)); instructions.extend(xor(None, None)); - + instructions.extend(immediate(correction)); instructions.extend(xor(None, None)); instructions.extend(register_lcg(engine, None)); @@ -256,43 +220,113 @@ fn correct( instructions } -fn register_lcg(engine: &mut Engine, register: Option) -> Vec> { +fn hash(engine: &mut Engine) -> Vec> { let mut instructions = Vec::>::new(); - if let Some(register) = register { - instructions.extend(load_register(register)); - } + instructions.extend(load_absolute(engine, DataDef::VmCodeEnd, VMReg::Rax)); + instructions.extend(load_absolute( + engine, + DataDef::VmAttestationProgram, + VMReg::Rcx, + )); - instructions.extend(load_data( + instructions.extend(sub(Some(VMReg::Rax), Some(VMReg::Rcx))); + instructions.extend(immediate((crypt::HEADER_SIZE + crypt::TRAILER_SIZE) as u64)); + instructions.extend(sub(None, None)); + instructions.extend(store_register(VMReg::R9)); + + instructions.extend(mask(Some(VMReg::R9), size_of::() as u64 - 1)); + instructions.extend(store_register(VMReg::R8)); + + instructions.extend(sub(Some(VMReg::R9), Some(VMReg::R8))); + instructions.extend(store_register(VMReg::R9)); + + instructions.extend(set_register(VMReg::R10, 0)); + + instructions.extend(foreach( engine, - DataDef::VmKeyMultiplier, - VMWidth::Lower64, + VMReg::Rax, + Bound::Register(VMReg::R9), + 8, + |engine| { + let mut b = Vec::new(); + + b.extend(load_register(VMReg::R10)); + b.extend(load_memory( + VMReg::Rcx, + VMReg::Rax, + 1, + crypt::HEADER_SIZE as i32, + VMSeg::None, + VMWidth::Lower64, + )); + b.extend(xor(None, None)); + b.extend(register_lcg(engine, None)); + b.extend(store_register(VMReg::R10)); + + b + }, )); - instructions.extend(mul(None, None)); - instructions.extend(load_data(engine, DataDef::VmKeyAddend, VMWidth::Lower64)); - instructions.extend(add(None, None)); + instructions.extend(compute_memory( + VMReg::Rcx, + VMReg::R9, + 1, + crypt::HEADER_SIZE as i32, + VMSeg::None, + )); + instructions.extend(store_register(VMReg::Rcx)); + + instructions.extend(foreach( + engine, + VMReg::Rax, + Bound::Register(VMReg::R8), + 1, + |engine| { + let mut b = Vec::new(); + + b.extend(load_register(VMReg::R10)); + b.extend(load_memory( + VMReg::Rcx, + VMReg::Rax, + 1, + 0, + VMSeg::None, + VMWidth::Lower8, + )); + b.extend(xor(None, None)); + b.extend(register_lcg(engine, None)); + b.extend(store_register(VMReg::R10)); + + b + }, + )); + + instructions.extend(load_register(VMReg::Vp0)); + instructions.extend(load_register(VMReg::R10)); + instructions.extend(xor(None, None)); + instructions.extend(store_register(VMReg::Vp0)); instructions } -fn register_lcg_inverse(engine: &mut Engine, register: Option) -> Vec> { +fn register_lcg(engine: &mut Engine, register: Option) -> Vec> { let mut instructions = Vec::>::new(); if let Some(register) = register { instructions.extend(load_register(register)); } - instructions.extend(load_data(engine, DataDef::VmKeyAddend, VMWidth::Lower64)); - instructions.extend(sub(None, None)); - instructions.extend(load_data( engine, - DataDef::VmKeyMultiplierInverse, + DataDef::VmKeyMultiplier, VMWidth::Lower64, )); instructions.extend(mul(None, None)); + instructions.extend(load_data(engine, DataDef::VmKeyAddend, VMWidth::Lower64)); + instructions.extend(add(None, None)); + instructions } @@ -302,34 +336,8 @@ fn apply_lcg(engine: &Engine, value: u64) -> u64 { .wrapping_add(engine.rt.keys.addend) } -fn combine_operation(operation: Operation, a: u64, b: u64) -> u64 { - let mut result = a; - apply_operation(operation, b, &mut result); - result -} - -fn apply_operation(operation: Operation, value: u64, expected: &mut u64) { - match operation { - Operation::Add => *expected = expected.wrapping_add(value), - Operation::Sub => *expected = expected.wrapping_sub(value), - Operation::Xor => *expected ^= value, - } -} - -fn register_operation( - operation: Operation, - a: Option, - b: Option, -) -> Vec> { - match operation { - Operation::Add => add(a, b), - Operation::Sub => sub(a, b), - Operation::Xor => xor(a, b), - } -} - -fn accumulate( - rng: &mut R, +fn accumulate( + engine: &mut Engine, accumulator: VMReg, source: Vec>, value: u64, @@ -337,24 +345,19 @@ fn accumulate( ) -> Vec> { let mut instructions = Vec::>::new(); - let operation = Operation::random(rng); - - let mix = rng.gen::(); - - instructions.extend(load_register(accumulator)); instructions.extend(source); - instructions.extend(immediate(mix)); + instructions.extend(load_register(accumulator)); instructions.extend(xor(None, None)); - instructions.extend(register_operation(operation, None, None)); + instructions.extend(register_lcg(engine, None)); instructions.extend(store_register(accumulator)); - apply_operation(operation, value ^ mix, expected); + *expected = apply_lcg(engine, value ^ *expected); instructions } -pub fn accumulate_immediate( - rng: &mut R, +pub fn accumulate_immediate( + engine: &mut Engine, accumulator: VMReg, source: Option, value: u64, @@ -364,11 +367,11 @@ pub fn accumulate_immediate( Some(register) => load_register(register), None => Vec::new(), }; - accumulate(rng, accumulator, source, value, expected) + accumulate(engine, accumulator, source, value, expected) } -pub fn accumulate_memory( - rng: &mut R, +pub fn accumulate_memory( + engine: &mut Engine, accumulator: VMReg, base: VMReg, displacement: i32, @@ -377,11 +380,11 @@ pub fn accumulate_memory( expected: &mut u64, ) -> Vec> { let source = load_memory(base, VMReg::None, 1, displacement, VMSeg::None, width); - accumulate(rng, accumulator, source, value, expected) + accumulate(engine, accumulator, source, value, expected) } -fn accumulate_byte( - rng: &mut R, +fn accumulate_byte( + engine: &mut Engine, accumulator: VMReg, base: VMReg, displacement: i32, @@ -389,7 +392,7 @@ fn accumulate_byte( expected: &mut u64, ) -> Vec> { accumulate_memory( - rng, + engine, accumulator, base, displacement, @@ -399,8 +402,8 @@ fn accumulate_byte( ) } -fn accumulate_prologue( - rng: &mut R, +fn accumulate_prologue( + engine: &mut Engine, accumulator: VMReg, base: VMReg, prologue: &[u8; 3], @@ -410,7 +413,7 @@ fn accumulate_prologue( for (offset, byte) in prologue.iter().enumerate() { instructions.extend(accumulate_byte( - rng, + engine, accumulator, base, offset as i32, diff --git a/obfuscator/src/protections/virtualization/crypt.rs b/obfuscator/src/protections/virtualization/crypt.rs index a5afda06..699f9c37 100644 --- a/obfuscator/src/protections/virtualization/crypt.rs +++ b/obfuscator/src/protections/virtualization/crypt.rs @@ -94,11 +94,23 @@ pub fn derive_hash(bytes: &[u8], multiplier: u64, addend: u64) -> u64 { let start = HEADER_SIZE; let end = bytes.len() - TRAILER_SIZE; let payload = &bytes[start..end]; - payload.chunks_exact(8).fold(0, |hash, chunk| { - (hash ^ u64::from_le_bytes(chunk.try_into().unwrap())) + + let mut chunks = payload.chunks_exact(size_of::()); + let mut hash = 0u64; + + for chunk in &mut chunks { + hash = (hash ^ u64::from_le_bytes(chunk.try_into().unwrap())) .wrapping_mul(multiplier) - .wrapping_add(addend) - }) + .wrapping_add(addend); + } + + for &byte in chunks.remainder() { + hash = (hash ^ byte as u64) + .wrapping_mul(multiplier) + .wrapping_add(addend); + } + + hash } pub fn derive_key(bytes: &[u8]) -> u64 { diff --git a/obfuscator/src/protections/virtualization/language.rs b/obfuscator/src/protections/virtualization/language.rs index dbcc0acf..dac93239 100644 --- a/obfuscator/src/protections/virtualization/language.rs +++ b/obfuscator/src/protections/virtualization/language.rs @@ -4,8 +4,9 @@ use runtime::vm::bytecode::{Flag, VMCondition, VMLogic, VMMem, VMReg, VMSeg, VMW use runtime::vm::encoders::add::Add; use runtime::vm::encoders::and::And; use runtime::vm::encoders::block::{Block, Jump, Target}; +use runtime::vm::encoders::branch::Branch; +use runtime::vm::encoders::cpuid::Cpuid; use runtime::vm::encoders::discard::Discard; -use runtime::vm::encoders::jcc::Jcc; use runtime::vm::encoders::label::Label; use runtime::vm::encoders::load_address::LoadAddress; use runtime::vm::encoders::load_immediate::LoadImmediate; @@ -108,7 +109,7 @@ pub fn foreach Vec>>( width: VMWidth::SLower16, source: vec![0, 0], })); - operations.push(Box::new(Jcc { + operations.push(Box::new(Branch { logic: VMLogic::SAND, conditions: vec![VMCondition::cmp(Flag::Carry, 1)], })); @@ -130,6 +131,39 @@ pub fn foreach Vec>>( } } +pub fn forever(body: Vec>) -> Vec> { + let destination = Label::destination(); + let source = Label::source(); + + let mut operations = Vec::>::new(); + + operations.push(Box::new(destination)); + operations.extend(body); + + operations.extend(immediate(0)); + operations.extend(immediate(1)); + operations.extend(sub(None, None)); + operations.push(Box::new(Discard::new())); + + operations.push(Box::new(source)); + operations.push(Box::new(LoadImmediate { + width: VMWidth::SLower16, + source: vec![0, 0], + })); + operations.push(Box::new(Branch { + logic: VMLogic::SAND, + conditions: vec![VMCondition::cmp(Flag::Carry, 1)], + })); + + vec![Box::new(Block::new( + operations, + vec![Jump { + source, + destination: Target::Label(destination), + }], + ))] +} + pub fn compute_data(engine: &mut Engine, def: DataDef) -> Vec> { let displacement = engine.rt.lookup(engine.rt.data_labels[&def]) as i32; compute_memory(VMReg::VImage, VMReg::None, 1, displacement, VMSeg::None) @@ -147,6 +181,39 @@ pub fn load_data(engine: &mut Engine, def: DataDef, width: VMWidth) -> Vec Vec> { + let displacement = engine.rt.lookup(engine.rt.data_labels[&def]) as i32 + offset; + load_memory( + VMReg::VImage, + VMReg::None, + 1, + displacement, + VMSeg::None, + width, + ) +} + +pub fn store_data_at(engine: &mut Engine, def: DataDef, offset: i32) -> Vec> { + let displacement = engine.rt.lookup(engine.rt.data_labels[&def]) as i32 + offset; + let mut instructions = Vec::>::new(); + instructions.extend(compute_memory( + VMReg::VImage, + VMReg::None, + 1, + displacement, + VMSeg::None, + )); + instructions.push(Box::new(StoreMemory { + width: VMWidth::Lower64, + })); + instructions +} + pub fn load_absolute(engine: &mut Engine, def: DataDef, register: VMReg) -> Vec> { let mut operations = Vec::>::new(); @@ -184,6 +251,14 @@ pub fn timestamp() -> Vec> { ] } +pub fn cpuid(leaf: u32, subleaf: u32) -> Vec> { + let mut instructions = Vec::>::new(); + instructions.extend(immediate(leaf as u64)); + instructions.extend(immediate(subleaf as u64)); + instructions.push(Box::new(Cpuid::new())); + instructions +} + pub fn set_register(register: VMReg, value: u64) -> Vec> { vec![ Box::new(LoadImmediate { @@ -197,19 +272,6 @@ pub fn set_register(register: VMReg, value: u64) -> Vec> { ] } -pub fn copy(source: VMReg, destination: VMReg) -> Vec> { - vec![ - Box::new(LoadRegister { - width: VMWidth::Lower64, - source: source, - }), - Box::new(StoreRegister { - width: VMWidth::Lower64, - destination: destination, - }), - ] -} - pub fn increment(register: VMReg, amount: u64) -> Vec> { vec![ Box::new(LoadRegister { @@ -276,7 +338,7 @@ pub fn invoke(target: VMReg) -> Vec> { width: VMWidth::Lower64, source: target, }), - Box::new(Jcc::call()), + Box::new(Branch::call()), ] } @@ -299,7 +361,7 @@ pub fn call(engine: &mut Engine, def: FnDef) -> Vec> { segment: VMSeg::None, }, }), - Box::new(Jcc::call()), + Box::new(Branch::call()), ] } @@ -424,6 +486,48 @@ pub fn xor(a: Option, b: Option) -> Vec> { instructions } +pub fn and(a: Option, b: Option) -> Vec> { + let mut instructions = Vec::>::new(); + + if let Some(reg) = a { + instructions.push(Box::new(LoadRegister { + width: VMWidth::Lower64, + source: reg, + })); + } + if let Some(reg) = b { + instructions.push(Box::new(LoadRegister { + width: VMWidth::Lower64, + source: reg, + })); + } + instructions.push(Box::new(And { + width: VMWidth::Lower64, + })); + instructions +} + +pub fn or(a: Option, b: Option) -> Vec> { + let mut instructions = Vec::>::new(); + + if let Some(reg) = a { + instructions.push(Box::new(LoadRegister { + width: VMWidth::Lower64, + source: reg, + })); + } + if let Some(reg) = b { + instructions.push(Box::new(LoadRegister { + width: VMWidth::Lower64, + source: reg, + })); + } + instructions.push(Box::new(Or { + width: VMWidth::Lower64, + })); + instructions +} + pub fn shr(a: Option, b: Option) -> Vec> { let mut instructions = Vec::>::new(); diff --git a/obfuscator/src/protections/virtualization/mod.rs b/obfuscator/src/protections/virtualization/mod.rs index d8b72b06..7bddec44 100644 --- a/obfuscator/src/protections/virtualization/mod.rs +++ b/obfuscator/src/protections/virtualization/mod.rs @@ -14,6 +14,7 @@ use logger::{debug, info}; use rand::Rng; use runtime::runtime::{DataDef, FnDef}; use runtime::vm::bytecode::{self}; +use runtime::vm::encoders::Encode; use runtime::{VM_DISPATCH_SIZE, VM_REDIRECT_SIZE, VM_TRAMPOLINE_SIZE}; mod attestation; @@ -53,9 +54,9 @@ fn resolve(engine: &Engine, label: DataDef) -> (u32, usize) { (rva, offset) } -fn write_displacement(engine: &mut Engine, label: DataDef, target: u32) { +fn write_displacement(engine: &mut Engine, label: DataDef, value: u32) { let (rva, offset) = resolve(engine, label); - let displacement = (target as i64 - rva as i64) as i32; + let displacement = (value as i64 - rva as i64) as i32; engine .pe .write(offset, &displacement.to_le_bytes()) @@ -91,60 +92,56 @@ pub struct Virtualization { } impl Virtualization { - fn attestation(&self, engine: &mut Engine, base: u64) -> Vec { - let mut code = Vec::new(); - - let mut log = Vec::new(); - - let blocks = attestation::generate(engine, engine.rt.keys.secret); - - let cipher = Cipher::new(engine.rt.keys.multiplier, engine.rt.keys.addend); - - for (index, operations) in blocks.into_iter().enumerate() { - let mut rng = rand::thread_rng(); - - let offset = base + code.len() as u64; + fn assemble( + &self, + engine: &mut Engine, + operations: Vec>, + offset: u64, + register: bool, + ) -> Vec { + let mut rng = rand::thread_rng(); + + let mut operations = operations; + bytecode::fuse(&mut engine.rt, &mut operations, register); + + let transformed = if engine.args.verbose { + let (transformed, snapshots) = bytecode::transform_with_snapshots( + &mut engine.rt.mapper, + operations, + offset, + |ready| rng.gen_range(0..ready.len()), + ); - let transformed = if engine.args.verbose { - let (transformed, snapshots) = bytecode::transform_with_snapshots( - &mut engine.rt.mapper, - operations, - offset, - |ready| rng.gen_range(0..ready.len()), - ); + if !register { + debug!("ATTESTATION @ 0x{:08X}:\n{}", offset, snapshots); + } - log.push(format!("{}BLOCK {}:\n{}", " ".repeat(4), index, snapshots)); + transformed + } else { + bytecode::transform(&mut engine.rt.mapper, operations, offset, |ready| { + rng.gen_range(0..ready.len()) + }) + }; - transformed - } else { - bytecode::transform(&mut engine.rt.mapper, operations, offset, |ready| { - rng.gen_range(0..ready.len()) - }) - }; + let mut bytes = bytecode::assemble(&mut engine.rt.mapper, &transformed); - let mut bytes = bytecode::assemble(&mut engine.rt.mapper, &transformed); + let cipher = Cipher::new(engine.rt.keys.multiplier, engine.rt.keys.addend); + cipher.encrypt_block(&mut bytes, 0, 0); + cipher.decrypt_payload(&mut bytes, 0, 0); - let key = if code.is_empty() { - engine.rt.keys.initializer - } else { - crypt::derive_key(&code) - }; + bytes + } - cipher.encrypt_block(&mut bytes, key, 0); - cipher.decrypt_payload(&mut bytes, key, 0); + fn attestation(&self, engine: &mut Engine, base: u64, register: bool) -> (Vec, Vec) { + let mut expected = 0; - code.extend_from_slice(&bytes); - } + let service = attestation::service(engine, &mut expected); + let program = attestation::program(engine, engine.rt.keys.secret, expected); - if engine.args.verbose { - debug!( - "ATTESTATION @ 0x{:016X}:\n{}", - engine.rt.keys.secret, - log.join("\n") - ); - } + let program = self.assemble(engine, program, base, register); + let service = self.assemble(engine, service, base + program.len() as u64, register); - code + (program, service) } } @@ -160,6 +157,8 @@ impl Protection for Virtualization { let cipher = Cipher::new(engine.rt.keys.multiplier, engine.rt.keys.addend); + let mut operations = Vec::new(); + 'outer: for block in &mut engine.blocks { if block.size < VM_TRAMPOLINE_SIZE { continue; @@ -192,45 +191,50 @@ impl Protection for Virtualization { let hash = hasher.finish(); if lookup.get(&hash).is_none() { - let mut rng = rand::thread_rng(); + let index = operations.len(); + operations.push(lifted); + self.groups.push(vec![block.rva]); + lookup.insert(hash, index); + } else { + self.duplicates += 1; + let index = lookup[&hash]; + self.groups[index].push(block.rva); + } + } - let offset = code.len() as u64; + let mut rng = rand::thread_rng(); - let transformed = if engine.args.verbose { - let (transformed, snapshots) = bytecode::transform_with_snapshots( - &mut engine.rt.mapper, - lifted, - offset, - |ready| rng.gen_range(0..ready.len()), - ); + for (index, operations) in operations.into_iter().enumerate() { + let offset = code.len() as u64; - log.push((block.rva, format!("{}", snapshots))); + let mut operations = operations; + bytecode::fuse(&mut engine.rt, &mut operations, true); - transformed - } else { - bytecode::transform(&mut engine.rt.mapper, lifted, offset, |ready| { - rng.gen_range(0..ready.len()) - }) - }; + let transformed = if engine.args.verbose { + let (transformed, snapshots) = bytecode::transform_with_snapshots( + &mut engine.rt.mapper, + operations, + offset, + |ready| rng.gen_range(0..ready.len()), + ); - let mut bytes = bytecode::assemble(&mut engine.rt.mapper, &transformed); + log.push((self.groups[index][0], format!("{}", snapshots))); - cipher.encrypt_block(&mut bytes, 0, 0); - cipher.decrypt_payload(&mut bytes, 0, 0); + transformed + } else { + bytecode::transform(&mut engine.rt.mapper, operations, offset, |ready| { + rng.gen_range(0..ready.len()) + }) + }; - code.extend_from_slice(&bytes); + let mut bytes = bytecode::assemble(&mut engine.rt.mapper, &transformed); - let index = self.programs.len(); - self.programs.push(bytes); + cipher.encrypt_block(&mut bytes, 0, 0); + cipher.decrypt_payload(&mut bytes, 0, 0); - self.groups.push(vec![block.rva]); + code.extend_from_slice(&bytes); - lookup.insert(hash, index); - } else { - self.duplicates += 1; - let index = lookup[&hash]; - self.groups[index].push(block.rva); - } + self.programs.push(bytes); } for (_, group) in self.programs.iter().zip(&self.groups) { @@ -244,7 +248,7 @@ impl Protection for Virtualization { } } - // Reserve a trampoline slot for each block too small for an inline stub + // Reserve a trampoline slot for each block too small for an inline stub: for block in &engine.blocks { if self.virtualized.contains_key(&block.rva) && block.size < VM_DISPATCH_SIZE { self.redirects.insert(block.rva, self.redirects.len()); @@ -266,7 +270,12 @@ impl Protection for Virtualization { engine.rt.define_data_dword(DataDef::VmCodeStart, 0); engine.rt.define_data_dword(DataDef::VmCodeEnd, 0); - engine.rt.define_data_dword(DataDef::VmAttestation, 0); + engine + .rt + .define_data_dword(DataDef::VmAttestationProgram, 0); + engine + .rt + .define_data_dword(DataDef::VmAttestationService, 0); engine .rt @@ -277,6 +286,8 @@ impl Protection for Virtualization { engine .rt .define_data_qword(DataDef::VmKeyAddend, engine.rt.keys.addend); + + self.attestation(engine, 0, true); } fn apply(&self, engine: &mut Engine) { @@ -292,17 +303,17 @@ impl Protection for Virtualization { } } - let attestation = self.attestation(engine, code.len() as u64); + let attestation = code.len(); + + let (program, service) = self.attestation(engine, attestation as u64, false); let cipher = Cipher::new(engine.rt.keys.multiplier, engine.rt.keys.addend); - let secret = engine.rt.keys.secret; + let region = [program.as_slice(), service.as_slice()].concat(); + let hash = crypt::derive_hash(®ion, engine.rt.keys.multiplier, engine.rt.keys.addend); - let mut key = crypt::derive_hash( - &attestation, - engine.rt.keys.multiplier, - engine.rt.keys.addend, - ); + let secret = engine.rt.keys.secret ^ hash; + let mut key = engine.rt.keys.initializer; let mut position = 0; @@ -316,7 +327,8 @@ impl Protection for Virtualization { position += bytes.len(); } - code.extend_from_slice(&attestation); + code.extend_from_slice(&program); + code.extend_from_slice(&service); let section = engine.create_section( Some("☠️"), @@ -331,8 +343,13 @@ impl Protection for Virtualization { write_displacement(engine, DataDef::VmCodeEnd, base + code.len() as u32); write_displacement( engine, - DataDef::VmAttestation, - base + (code.len() - attestation.len()) as u32, + DataDef::VmAttestationProgram, + base + attestation as u32, + ); + write_displacement( + engine, + DataDef::VmAttestationService, + base + (attestation + program.len()) as u32, ); let entry_rva = engine.rt.lookup(engine.rt.function_labels[&FnDef::VmEntry]); @@ -370,7 +387,7 @@ impl Protection for Virtualization { asm.reset(); - // Stub has to be assembled twice so that the runtime return address can be calculated + // Stub has to be assembled twice so that the runtime return address can be calculated: let return_address = rva as i32 + first.len() as i32; asm.push(token ^ return_address).unwrap(); diff --git a/runtime/src/runtime.rs b/runtime/src/runtime.rs index 57d383a6..948d93ef 100644 --- a/runtime/src/runtime.rs +++ b/runtime/src/runtime.rs @@ -11,7 +11,8 @@ use crate::{ mapper::{mapped, Mappable, Mapper}, vm::{ self, - bytecode::{VMReg, VMVec}, + bytecode::{VMCode, VMReg, VMVec}, + handlers::semantic, }, }; @@ -29,6 +30,7 @@ mapped! { VmInvoke, VmLookup, VmCleanup, + VmService, VmRegistersCapture, VmRegistersCaptureVolatile, VmRegistersCaptureNonvolatile, @@ -39,8 +41,8 @@ mapped! { VmVectorsRestore, VmVectorsCopy, /* VM HANDLERS */ - VmHandlerJcc, - VmHandlerRet, + VmHandlerBranch, + VmHandlersBack, VmHandlerLoadImmediate, VmHandlerLoadRegister, VmHandlerLoadMemory, @@ -88,7 +90,8 @@ mapped! { VmHandlerVectorMul, VmHandlerVectorDiv, VmHandlerTimestamp, - VmHandlerDispatch, + VmHandlerCpuid, + VmHandlerCompound, /* VM VEH */ VmVehInitialize, VmVehHandler, @@ -117,7 +120,9 @@ mapped! { VmTable, VmCodeStart, VmCodeEnd, - VmAttestation, + VmAttestationProgram, + VmAttestationService, + VmServiceBox, VmTrampolines, VmKeyInitializer, VmKeyMultiplier, @@ -165,6 +170,9 @@ mapped! { NtQueryInformationProcess, NtSetInformationThread, NtQueryInformationThread, + NtGetContextThread, + CreateThread, + NtDelayExecution, MessageBoxA, NtTerminateProcess, #[cfg(debug_assertions)] @@ -188,6 +196,9 @@ mapped! { NtQueryInformationProcess, NtSetInformationThread, NtQueryInformationThread, + NtGetContextThread, + CreateThread, + NtDelayExecution, MessageBoxA, NtTerminateProcess, #[cfg(debug_assertions)] @@ -222,6 +233,9 @@ impl ImportDef { ImportDef::NtQueryInformationThread { .. } => { (HashDef::Ntdll, HashDef::NtQueryInformationThread) } + ImportDef::NtGetContextThread { .. } => (HashDef::Ntdll, HashDef::NtGetContextThread), + ImportDef::CreateThread { .. } => (HashDef::Kernel32, HashDef::CreateThread), + ImportDef::NtDelayExecution { .. } => (HashDef::Ntdll, HashDef::NtDelayExecution), ImportDef::MessageBoxA { .. } => (HashDef::User32, HashDef::MessageBoxA), ImportDef::NtTerminateProcess { .. } => (HashDef::Ntdll, HashDef::NtTerminateProcess), #[cfg(debug_assertions)] @@ -241,6 +255,7 @@ enum EmissionTask { Hash(HashDef), DispatchTable(usize), DispatchStub(usize, usize), + Compound(usize), } pub type Handler = Box; @@ -316,6 +331,9 @@ pub struct Runtime { addresses: HashMap, sizes: HashMap, + pub compounds: Vec>, + pub compound_labels: Vec, + pub mapper: Mapper, } @@ -390,10 +408,29 @@ impl Runtime { addresses: HashMap::new(), sizes: HashMap::new(), + compounds: Vec::new(), + compound_labels: Vec::new(), + mapper: Mapper::new(), } } + pub fn compound(&mut self, operations: Vec) -> u8 { + if let Some(index) = self + .compounds + .iter() + .position(|existing| *existing == operations) + { + return index as u8; + } + + let index = self.compounds.len(); + + self.compounds.push(operations); + + index as u8 + } + fn set_function_label(&mut self, def: FnDef) { let label = self.function_labels.get_mut(&def).unwrap(); self.asm.set_label(label).unwrap(); @@ -420,11 +457,11 @@ impl Runtime { } pub fn lookup(&self, label: CodeLabel) -> u64 { - self.addresses[&label] + self.addresses.get(&label).copied().unwrap_or(0) } pub fn size(&self, label: CodeLabel) -> u64 { - self.sizes[&label] + self.sizes.get(&label).copied().unwrap_or(0) } fn hash(&self, value: &str) -> u64 { @@ -595,10 +632,18 @@ impl Runtime { self.asm.set_label(&mut dispatch.table).unwrap(); + self.asm.zero_bytes().unwrap(); + for _ in 0..dispatch.slots() { self.asm.dq(&[0u64]).unwrap(); } } + EmissionTask::Compound(index) => { + let members = self.compounds[index].clone(); + let mut label = self.compound_labels[index]; + self.asm.set_label(&mut label).unwrap(); + semantic::compiler::compile_compound(self, &members); + } EmissionTask::DispatchStub(table, entry) => { let (index, stub, target) = self.dispatches[table].stubs.get_mut(entry).unwrap(); @@ -633,6 +678,7 @@ impl Runtime { (FnDef::VmInvoke, vm::functions::invoke::build), (FnDef::VmLookup, vm::functions::lookup::build), (FnDef::VmCleanup, vm::functions::cleanup::build), + (FnDef::VmService, vm::functions::service::build), (FnDef::VmRegistersCapture, vm::functions::registers::capture), ( FnDef::VmRegistersCaptureVolatile, @@ -648,8 +694,8 @@ impl Runtime { (FnDef::VmVectorsCapture, vm::functions::vectors::capture), (FnDef::VmVectorsRestore, vm::functions::vectors::restore), (FnDef::VmVectorsCopy, vm::functions::vectors::copy), - (FnDef::VmHandlerJcc, vm::handlers::jcc::build), - (FnDef::VmHandlerRet, vm::handlers::ret::build), + (FnDef::VmHandlerBranch, vm::handlers::branch::build), + (FnDef::VmHandlersBack, vm::handlers::back::build), ( FnDef::VmHandlerLoadImmediate, vm::handlers::load_immediate::build, @@ -745,7 +791,8 @@ impl Runtime { (FnDef::VmHandlerVectorMul, vm::handlers::vector_mul::build), (FnDef::VmHandlerVectorDiv, vm::handlers::vector_div::build), (FnDef::VmHandlerTimestamp, vm::handlers::timestamp::build), - (FnDef::VmHandlerDispatch, vm::handlers::dispatch::build), + (FnDef::VmHandlerCompound, vm::handlers::compound::build), + (FnDef::VmHandlerCpuid, vm::handlers::cpuid::build), (FnDef::VmVehInitialize, vm::functions::veh::initialize), (FnDef::Hash, functions::hash::build), (FnDef::Resolve, functions::resolve::build), @@ -774,6 +821,9 @@ impl Runtime { self.define_data_bytes(DataDef::Functions, &vec![0u8; FnDef::COUNT * 8]); + // [ tick ][ locked vp0 ][ locked vp1 ] + self.define_data_bytes(DataDef::VmServiceBox, &[0u8; 16]); + self.define_data_qword(DataDef::VmKeyInitializer, self.keys.initializer); self.define_data_qword(DataDef::VmKeyAddend, self.keys.addend); self.define_data_qword(DataDef::VmKeyMultiplier, self.keys.multiplier); @@ -822,6 +872,9 @@ impl Runtime { HashDef::NtQueryInformationThread, "NtQueryInformationThread", ); + self.define_hash(HashDef::NtGetContextThread, "NtGetContextThread"); + self.define_hash(HashDef::CreateThread, "CreateThread"); + self.define_hash(HashDef::NtDelayExecution, "NtDelayExecution"); self.define_hash(HashDef::MessageBoxA, "MessageBoxA"); self.define_hash(HashDef::NtTerminateProcess, "NtTerminateProcess"); #[cfg(debug_assertions)] @@ -831,6 +884,10 @@ impl Runtime { let mut rng = rand::thread_rng(); + self.compound_labels = (0..self.compounds.len()) + .map(|_| self.asm.create_label()) + .collect(); + let mut data_tasks = Vec::new(); for def in DataDef::VARIANTS { @@ -876,6 +933,10 @@ impl Runtime { phase_one.push(EmissionTask::Function(def, builder)); } + for index in 0..self.compounds.len() { + phase_one.push(EmissionTask::Compound(index)); + } + phase_one.extend(data_phase_one.iter().cloned()); phase_one.shuffle(&mut rng); @@ -885,8 +946,6 @@ impl Runtime { phase_two.extend(data_phase_two.iter().cloned()); - // A case handler may register further dispatches (nested width/precision - // dispatch), so drain in shuffled waves until no new work remains. let mut dispatched = 0; loop { diff --git a/runtime/src/vm/bytecode.rs b/runtime/src/vm/bytecode.rs index 56fde05d..d9d5b528 100644 --- a/runtime/src/vm/bytecode.rs +++ b/runtime/src/vm/bytecode.rs @@ -1,17 +1,17 @@ use crate::mapper::{mapped, Mapper}; +use crate::runtime::Runtime; use crate::vm::encoders::Encode; use crate::vm::lifters::{ - arithmetic, branch, bsr, bswap, bt, cmov, cmpxchg, div, extend, integer, lea, multiply, + arithmetic, branch, bsr, bswap, bt, cmov, cmpxchg, cpuid, div, extend, integer, lea, multiply, pcmpeqb, pmovskb, rdtsc, scalar, set, stack, transfer, tzcnt, xadd, xchg, }; use crate::vm::snapshot::Snapshots; use crate::vm::transform::encrypt::Encrypt; -use crate::vm::transform::indirect::Indirect; use crate::vm::transform::mutation::Mutation; use crate::vm::transform::peephole::Peephole; use crate::vm::transform::permute::Permute; use crate::vm::transform::scramble::Scramble; -use crate::vm::transform::Transform; +use crate::vm::transform::{compound, Transform}; use core::panic; use iced_x86::{Instruction, Mnemonic, Register}; use std::any::Any; @@ -19,9 +19,9 @@ use std::cell::RefCell; use strum_macros::EnumIter; mapped! { - VMOp { - Jcc, - Ret, + VMCode { + Branch, + Back, // Load LoadImmediate, LoadRegister, @@ -76,7 +76,8 @@ mapped! { VectorDiv, // Special Timestamp, - Dispatch + Cpuid, + Compound } } @@ -346,7 +347,7 @@ impl Encode for VMMem { self } - fn op(&self) -> Option { + fn code(&self) -> Option { None } @@ -447,7 +448,7 @@ impl Encode for VMCondition { self } - fn op(&self) -> Option { + fn code(&self) -> Option { None } @@ -464,7 +465,6 @@ pub enum Phase { Scramble, Encrypt, Peephole, - Indirect, } impl Phase { @@ -476,7 +476,6 @@ impl Phase { Self::Scramble => "scramble", Self::Encrypt => "encrypt", Self::Peephole => "peephole", - Self::Indirect => "indirect", } } } @@ -626,6 +625,7 @@ pub fn lift(instructions: &[Instruction]) -> Option>> { | Mnemonic::Setp | Mnemonic::Sets => set::encode(instruction)?, Mnemonic::Rdtsc => rdtsc::encode(instruction)?, + Mnemonic::Cpuid => cpuid::encode(instruction)?, Mnemonic::Nop | Mnemonic::Int | Mnemonic::Int3 | Mnemonic::Ud2 | Mnemonic::Pause => { continue } @@ -642,7 +642,7 @@ pub fn assemble(mapper: &mut Mapper, operations: &[Box]) -> Vec let mut bytes = Vec::new(); for operation in operations { - if let Some(op) = operation.op() { + if let Some(op) = operation.code() { bytes.push(mapper.index(op)); } bytes.extend(operation.encode(mapper)); @@ -659,13 +659,16 @@ fn transforms<'a>( Box::new(Permute { picker }), Box::new(Scramble), Box::new(Mutation), - Box::new(Indirect), Box::new(Encrypt { offset }), Box::new(Permute { picker }), Box::new(Peephole), ] } +pub fn fuse(rt: &mut Runtime, operations: &mut Vec>, register: bool) { + compound::fuse(rt, operations, register); +} + pub fn transform( mapper: &mut Mapper, mut operations: Vec>, diff --git a/runtime/src/vm/encoders/adc.rs b/runtime/src/vm/encoders/adc.rs index f73bea43..d0cd5493 100644 --- a/runtime/src/vm/encoders/adc.rs +++ b/runtime/src/vm/encoders/adc.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Adc { self } - fn op(&self) -> Option { - Some(VMOp::Adc) + fn code(&self) -> Option { + Some(VMCode::Adc) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/add.rs b/runtime/src/vm/encoders/add.rs index 55c4fa5b..bc1ba944 100644 --- a/runtime/src/vm/encoders/add.rs +++ b/runtime/src/vm/encoders/add.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Add { self } - fn op(&self) -> Option { - Some(VMOp::Add) + fn code(&self) -> Option { + Some(VMCode::Add) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/and.rs b/runtime/src/vm/encoders/and.rs index 22aeec32..958b6dfd 100644 --- a/runtime/src/vm/encoders/and.rs +++ b/runtime/src/vm/encoders/and.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for And { self } - fn op(&self) -> Option { - Some(VMOp::And) + fn code(&self) -> Option { + Some(VMCode::And) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/ret.rs b/runtime/src/vm/encoders/back.rs similarity index 82% rename from runtime/src/vm/encoders/ret.rs rename to runtime/src/vm/encoders/back.rs index 8d20f80b..7530a1fe 100644 --- a/runtime/src/vm/encoders/ret.rs +++ b/runtime/src/vm/encoders/back.rs @@ -1,12 +1,12 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg}; +use crate::vm::bytecode::{VMCode, VMReg}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; #[derive(Debug)] -pub struct Ret; +pub struct Back; -impl Encode for Ret { +impl Encode for Back { fn as_any(&self) -> &dyn Any { self } @@ -15,8 +15,8 @@ impl Encode for Ret { self } - fn op(&self) -> Option { - Some(VMOp::Ret) + fn code(&self) -> Option { + Some(VMCode::Back) } fn encode(&self, _mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/bit_scan_reverse.rs b/runtime/src/vm/encoders/bit_scan_reverse.rs index 665cb5a8..1a4ca97a 100644 --- a/runtime/src/vm/encoders/bit_scan_reverse.rs +++ b/runtime/src/vm/encoders/bit_scan_reverse.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for BitScanReverse { self } - fn op(&self) -> Option { - Some(VMOp::BitScanReverse) + fn code(&self) -> Option { + Some(VMCode::BitScanReverse) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/bit_test.rs b/runtime/src/vm/encoders/bit_test.rs index e632f689..99f69064 100644 --- a/runtime/src/vm/encoders/bit_test.rs +++ b/runtime/src/vm/encoders/bit_test.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for BitTest { self } - fn op(&self) -> Option { - Some(VMOp::BitTest) + fn code(&self) -> Option { + Some(VMCode::BitTest) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/bit_test_complement.rs b/runtime/src/vm/encoders/bit_test_complement.rs index ff7a3c3d..4af1b635 100644 --- a/runtime/src/vm/encoders/bit_test_complement.rs +++ b/runtime/src/vm/encoders/bit_test_complement.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for BitTestComplement { self } - fn op(&self) -> Option { - Some(VMOp::BitTestComplement) + fn code(&self) -> Option { + Some(VMCode::BitTestComplement) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/bit_test_reset.rs b/runtime/src/vm/encoders/bit_test_reset.rs index d7fbf278..4a4ea981 100644 --- a/runtime/src/vm/encoders/bit_test_reset.rs +++ b/runtime/src/vm/encoders/bit_test_reset.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for BitTestReset { self } - fn op(&self) -> Option { - Some(VMOp::BitTestReset) + fn code(&self) -> Option { + Some(VMCode::BitTestReset) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/bit_test_set.rs b/runtime/src/vm/encoders/bit_test_set.rs index f232b724..501c024f 100644 --- a/runtime/src/vm/encoders/bit_test_set.rs +++ b/runtime/src/vm/encoders/bit_test_set.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for BitTestSet { self } - fn op(&self) -> Option { - Some(VMOp::BitTestSet) + fn code(&self) -> Option { + Some(VMCode::BitTestSet) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/block.rs b/runtime/src/vm/encoders/block.rs index 27e76c64..c108f13a 100644 --- a/runtime/src/vm/encoders/block.rs +++ b/runtime/src/vm/encoders/block.rs @@ -1,8 +1,8 @@ use std::any::Any; use crate::mapper::Mapper; -use crate::vm::bytecode::{self, VMCondition, VMLogic, VMOp, VMWidth}; -use crate::vm::encoders::jcc::Jcc; +use crate::vm::bytecode::{self, VMCode, VMCondition, VMLogic, VMWidth}; +use crate::vm::encoders::branch::Branch; use crate::vm::encoders::label::Label; use crate::vm::encoders::load_immediate::LoadImmediate; use crate::vm::encoders::{Effect, Encode}; @@ -45,7 +45,7 @@ impl Block { source: vec![0], }), ); - body.insert(2, Box::new(Jcc { logic, conditions })); + body.insert(2, Box::new(Branch { logic, conditions })); let jumps = vec![Jump { source, @@ -91,7 +91,7 @@ impl Block { let consumes = operation.consumes() as usize; - if operation.as_any().downcast_ref::().is_some() { + if operation.as_any().downcast_ref::().is_some() { return Some((stack[stack.len() - consumes], i)); } @@ -117,7 +117,7 @@ impl Encode for Block { self } - fn op(&self) -> Option { + fn code(&self) -> Option { None } diff --git a/runtime/src/vm/encoders/jcc.rs b/runtime/src/vm/encoders/branch.rs similarity index 78% rename from runtime/src/vm/encoders/jcc.rs rename to runtime/src/vm/encoders/branch.rs index d0d31c46..f284bce0 100644 --- a/runtime/src/vm/encoders/jcc.rs +++ b/runtime/src/vm/encoders/branch.rs @@ -1,17 +1,18 @@ use std::any::Any; use std::fmt::Debug; +use std::slice; use crate::mapper::Mapper; -use crate::vm::bytecode::{Flag, VMCondition, VMLogic, VMOp, VMReg}; +use crate::vm::bytecode::{Flag, VMCondition, VMLogic, VMCode, VMReg}; use crate::vm::encoders::{Effect, Encode}; #[derive(Debug)] -pub struct Jcc { +pub struct Branch { pub logic: VMLogic, pub conditions: Vec, } -impl Jcc { +impl Branch { pub fn jump() -> Self { Self::always(VMLogic::JAND) } @@ -43,7 +44,7 @@ impl Jcc { } } -impl Encode for Jcc { +impl Encode for Branch { fn as_any(&self) -> &dyn Any { self } @@ -52,8 +53,8 @@ impl Encode for Jcc { self } - fn op(&self) -> Option { - Some(VMOp::Jcc) + fn code(&self) -> Option { + Some(VMCode::Branch) } fn encode(&self, mapper: &mut Mapper) -> Vec { @@ -91,4 +92,11 @@ impl Encode for Jcc { fn is_branch(&self) -> bool { true } + + fn seal(&mut self, _mapper: &mut Mapper, transform: &mut dyn FnMut(&mut [u8], usize)) { + for condition in &mut self.conditions { + transform(slice::from_mut(&mut condition.lhs), 0); + transform(slice::from_mut(&mut condition.rhs), 0); + } + } } diff --git a/runtime/src/vm/encoders/byte_swap.rs b/runtime/src/vm/encoders/byte_swap.rs index e772c8dd..c4b0b0fc 100644 --- a/runtime/src/vm/encoders/byte_swap.rs +++ b/runtime/src/vm/encoders/byte_swap.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for ByteSwap { self } - fn op(&self) -> Option { - Some(VMOp::ByteSwap) + fn code(&self) -> Option { + Some(VMCode::ByteSwap) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/compare_exchange.rs b/runtime/src/vm/encoders/compare_exchange.rs index 852cf8f8..15106005 100644 --- a/runtime/src/vm/encoders/compare_exchange.rs +++ b/runtime/src/vm/encoders/compare_exchange.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for CompareExchange { self } - fn op(&self) -> Option { - Some(VMOp::CompareExchange) + fn code(&self) -> Option { + Some(VMCode::CompareExchange) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/compound.rs b/runtime/src/vm/encoders/compound.rs new file mode 100644 index 00000000..c2cee8aa --- /dev/null +++ b/runtime/src/vm/encoders/compound.rs @@ -0,0 +1,79 @@ +use crate::mapper::Mapper; +use crate::vm::bytecode::VMCode; +use crate::vm::encoders::{Effect, Encode}; +use std::any::Any; + +#[derive(Debug)] +pub struct Compound { + pub index: u8, + pub members: Vec>, +} + +impl Compound { + fn simulate(&self) -> (i32, i32) { + let mut depth = 0; + let mut low = 0; + + for operation in &self.members { + depth -= operation.consumes(); + low = low.min(depth); + depth += operation.produces(); + } + + (depth, low) + } +} + +impl Encode for Compound { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn code(&self) -> Option { + Some(VMCode::Compound) + } + + fn encode(&self, mapper: &mut Mapper) -> Vec { + let mut bytes = vec![self.index]; + + for member in &self.members { + bytes.extend(member.encode(mapper)); + } + + bytes + } + + fn reads(&self) -> Vec { + self.members + .iter() + .flat_map(|member| member.reads()) + .collect() + } + + fn writes(&self) -> Vec { + self.members + .iter() + .flat_map(|member| member.writes()) + .collect() + } + + fn consumes(&self) -> i32 { + let (_, low) = self.simulate(); + -low + } + + fn produces(&self) -> i32 { + let (depth, low) = self.simulate(); + depth - low + } + + fn seal(&mut self, mapper: &mut Mapper, transform: &mut dyn FnMut(&mut [u8], usize)) { + for member in &mut self.members { + member.seal(mapper, transform); + } + } +} diff --git a/runtime/src/vm/encoders/cpuid.rs b/runtime/src/vm/encoders/cpuid.rs new file mode 100644 index 00000000..434e2db6 --- /dev/null +++ b/runtime/src/vm/encoders/cpuid.rs @@ -0,0 +1,48 @@ +use crate::mapper::Mapper; +use crate::vm::bytecode::VMCode; +use crate::vm::encoders::Encode; +use std::any::Any; +use std::fmt::{Debug, Formatter, Result}; + +pub struct Cpuid { + _marker: u8, +} + +impl Cpuid { + pub fn new() -> Self { + Self { _marker: 0 } + } +} + +impl Debug for Cpuid { + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.debug_struct(self.name()).finish() + } +} + +impl Encode for Cpuid { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn code(&self) -> Option { + Some(VMCode::Cpuid) + } + + fn encode(&self, _mapper: &mut Mapper) -> Vec { + vec![] + } + + fn consumes(&self) -> i32 { + 2 + } + + fn produces(&self) -> i32 { + 4 + } +} diff --git a/runtime/src/vm/encoders/discard.rs b/runtime/src/vm/encoders/discard.rs index c1a01f47..81cc45c0 100644 --- a/runtime/src/vm/encoders/discard.rs +++ b/runtime/src/vm/encoders/discard.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::VMOp; +use crate::vm::bytecode::VMCode; use crate::vm::encoders::Encode; use std::any::Any; use std::fmt::{Debug, Formatter, Result}; @@ -30,8 +30,8 @@ impl Encode for Discard { self } - fn op(&self) -> Option { - Some(VMOp::Discard) + fn code(&self) -> Option { + Some(VMCode::Discard) } fn encode(&self, _mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/dispatch.rs b/runtime/src/vm/encoders/dispatch.rs deleted file mode 100644 index ab3ec6db..00000000 --- a/runtime/src/vm/encoders/dispatch.rs +++ /dev/null @@ -1,71 +0,0 @@ -use crate::mapper::Mapper; -use crate::vm::bytecode::VMOp; -use crate::vm::encoders::{Effect, Encode}; -use std::any::Any; - -#[derive(Debug)] -pub struct Dispatch { - pub operation: Box, -} - -impl Encode for Dispatch { - fn as_any(&self) -> &dyn Any { - self.operation.as_any() - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self.operation.as_any_mut() - } - - fn op(&self) -> Option { - Some(VMOp::Dispatch) - } - - fn encode(&self, mapper: &mut Mapper) -> Vec { - self.operation.encode(mapper) - } - - fn size(&self, mapper: &mut Mapper) -> usize { - self.operation.size(mapper) - } - - fn reads(&self) -> Vec { - self.operation.reads() - } - - fn writes(&self) -> Vec { - self.operation.writes() - } - - fn consumes(&self) -> i32 { - 1 + self.operation.consumes() - } - - fn produces(&self) -> i32 { - self.operation.produces() - } - - fn is_source(&self) -> bool { - self.operation.is_source() - } - - fn is_destination(&self) -> bool { - self.operation.is_destination() - } - - fn is_branch(&self) -> bool { - self.operation.is_branch() - } - - fn children_ref(&self) -> Option<&[Box]> { - self.operation.children_ref() - } - - fn children_mut(&mut self) -> Option<&mut Vec>> { - self.operation.children_mut() - } - - fn seal(&mut self, mapper: &mut Mapper, transform: &mut dyn FnMut(&mut [u8], usize)) { - self.operation.seal(mapper, transform); - } -} diff --git a/runtime/src/vm/encoders/div.rs b/runtime/src/vm/encoders/div.rs index 731625cf..3a39b6f0 100644 --- a/runtime/src/vm/encoders/div.rs +++ b/runtime/src/vm/encoders/div.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Div { self } - fn op(&self) -> Option { - Some(VMOp::Div) + fn code(&self) -> Option { + Some(VMCode::Div) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/exchange.rs b/runtime/src/vm/encoders/exchange.rs index 0755490a..edf4999c 100644 --- a/runtime/src/vm/encoders/exchange.rs +++ b/runtime/src/vm/encoders/exchange.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Exchange { self } - fn op(&self) -> Option { - Some(VMOp::Exchange) + fn code(&self) -> Option { + Some(VMCode::Exchange) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/exchange_add.rs b/runtime/src/vm/encoders/exchange_add.rs index 38cf9023..0a4ac141 100644 --- a/runtime/src/vm/encoders/exchange_add.rs +++ b/runtime/src/vm/encoders/exchange_add.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for ExchangeAdd { self } - fn op(&self) -> Option { - Some(VMOp::ExchangeAdd) + fn code(&self) -> Option { + Some(VMCode::ExchangeAdd) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/label.rs b/runtime/src/vm/encoders/label.rs index a382d3c4..789347e4 100644 --- a/runtime/src/vm/encoders/label.rs +++ b/runtime/src/vm/encoders/label.rs @@ -1,6 +1,6 @@ use crate::{ mapper::Mapper, - vm::{bytecode::VMOp, encoders::Encode}, + vm::{bytecode::VMCode, encoders::Encode}, }; use std::{ any::Any, @@ -50,7 +50,7 @@ impl Encode for Label { self } - fn op(&self) -> Option { + fn code(&self) -> Option { None } diff --git a/runtime/src/vm/encoders/load_address.rs b/runtime/src/vm/encoders/load_address.rs index 39c9ea3c..0b1bd929 100644 --- a/runtime/src/vm/encoders/load_address.rs +++ b/runtime/src/vm/encoders/load_address.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMMem, VMOp, VMReg}; +use crate::vm::bytecode::{VMMem, VMCode, VMReg}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for LoadAddress { self } - fn op(&self) -> Option { - Some(VMOp::LoadAddress) + fn code(&self) -> Option { + Some(VMCode::LoadAddress) } fn encode(&self, mapper: &mut Mapper) -> Vec { @@ -41,4 +41,10 @@ impl Encode for LoadAddress { fn produces(&self) -> i32 { 1 } + + fn seal(&mut self, _mapper: &mut Mapper, transform: &mut dyn FnMut(&mut [u8], usize)) { + let mut displacement = self.source.displacement.to_le_bytes(); + transform(&mut displacement, 0); + self.source.displacement = i32::from_le_bytes(displacement); + } } diff --git a/runtime/src/vm/encoders/load_immediate.rs b/runtime/src/vm/encoders/load_immediate.rs index a86ebde3..76370783 100644 --- a/runtime/src/vm/encoders/load_immediate.rs +++ b/runtime/src/vm/encoders/load_immediate.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -18,8 +18,8 @@ impl Encode for LoadImmediate { self } - fn op(&self) -> Option { - Some(VMOp::LoadImmediate) + fn code(&self) -> Option { + Some(VMCode::LoadImmediate) } fn encode(&self, mapper: &mut Mapper) -> Vec { @@ -42,4 +42,8 @@ impl Encode for LoadImmediate { fn produces(&self) -> i32 { 1 } + + fn seal(&mut self, _mapper: &mut Mapper, transform: &mut dyn FnMut(&mut [u8], usize)) { + transform(&mut self.source, 0); + } } diff --git a/runtime/src/vm/encoders/load_memory.rs b/runtime/src/vm/encoders/load_memory.rs index c27c9997..038b9ad6 100644 --- a/runtime/src/vm/encoders/load_memory.rs +++ b/runtime/src/vm/encoders/load_memory.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for LoadMemory { self } - fn op(&self) -> Option { - Some(VMOp::LoadMemory) + fn code(&self) -> Option { + Some(VMCode::LoadMemory) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/load_register.rs b/runtime/src/vm/encoders/load_register.rs index 12b89b06..80f47409 100644 --- a/runtime/src/vm/encoders/load_register.rs +++ b/runtime/src/vm/encoders/load_register.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -18,8 +18,8 @@ impl Encode for LoadRegister { self } - fn op(&self) -> Option { - Some(VMOp::LoadRegister) + fn code(&self) -> Option { + Some(VMCode::LoadRegister) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/load_vector.rs b/runtime/src/vm/encoders/load_vector.rs index 42195f87..1a5982fb 100644 --- a/runtime/src/vm/encoders/load_vector.rs +++ b/runtime/src/vm/encoders/load_vector.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMVec, VMWidth}; +use crate::vm::bytecode::{VMCode, VMVec, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -18,8 +18,8 @@ impl Encode for LoadVector { self } - fn op(&self) -> Option { - Some(VMOp::LoadVector) + fn code(&self) -> Option { + Some(VMCode::LoadVector) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/mod.rs b/runtime/src/vm/encoders/mod.rs index 1acb6ab4..0abd8c1d 100644 --- a/runtime/src/vm/encoders/mod.rs +++ b/runtime/src/vm/encoders/mod.rs @@ -2,25 +2,27 @@ use std::any::{type_name, Any}; use std::fmt::{self, Debug}; use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMVec}; +use crate::vm::bytecode::{VMCode, VMReg, VMVec}; pub mod adc; pub mod add; pub mod and; +pub mod back; pub mod bit_scan_reverse; pub mod bit_test; pub mod bit_test_complement; pub mod bit_test_reset; pub mod bit_test_set; pub mod block; +pub mod branch; pub mod byte_swap; pub mod compare_exchange; +pub mod compound; +pub mod cpuid; pub mod discard; -pub mod dispatch; pub mod div; pub mod exchange; pub mod exchange_add; -pub mod jcc; pub mod label; pub mod load_address; pub mod load_immediate; @@ -33,7 +35,6 @@ pub mod packed_byte_equal; pub mod packed_byte_mask; pub mod pop; pub mod push; -pub mod ret; pub mod rol; pub mod ror; pub mod sar; @@ -86,12 +87,12 @@ pub trait Encode: Debug + Any { type_name::().rsplit("::").next().unwrap() } - fn op(&self) -> Option; + fn code(&self) -> Option; fn encode(&self, mapper: &mut Mapper) -> Vec; fn size(&self, mapper: &mut Mapper) -> usize { - self.op().map_or(0, |_| 1) + self.encode(mapper).len() + self.code().map_or(0, |_| 1) + self.encode(mapper).len() } fn reads(&self) -> Vec { diff --git a/runtime/src/vm/encoders/mul.rs b/runtime/src/vm/encoders/mul.rs index dac49edf..d7c35adf 100644 --- a/runtime/src/vm/encoders/mul.rs +++ b/runtime/src/vm/encoders/mul.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Mul { self } - fn op(&self) -> Option { - Some(VMOp::Mul) + fn code(&self) -> Option { + Some(VMCode::Mul) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/or.rs b/runtime/src/vm/encoders/or.rs index 8d59154c..69485357 100644 --- a/runtime/src/vm/encoders/or.rs +++ b/runtime/src/vm/encoders/or.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Or { self } - fn op(&self) -> Option { - Some(VMOp::Or) + fn code(&self) -> Option { + Some(VMCode::Or) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/packed_byte_equal.rs b/runtime/src/vm/encoders/packed_byte_equal.rs index e3e3baab..684f161b 100644 --- a/runtime/src/vm/encoders/packed_byte_equal.rs +++ b/runtime/src/vm/encoders/packed_byte_equal.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for PackedByteEqual { self } - fn op(&self) -> Option { - Some(VMOp::PackedByteEqual) + fn code(&self) -> Option { + Some(VMCode::PackedByteEqual) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/packed_byte_mask.rs b/runtime/src/vm/encoders/packed_byte_mask.rs index d338cb11..48d66e84 100644 --- a/runtime/src/vm/encoders/packed_byte_mask.rs +++ b/runtime/src/vm/encoders/packed_byte_mask.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for PackedByteMask { self } - fn op(&self) -> Option { - Some(VMOp::PackedByteMask) + fn code(&self) -> Option { + Some(VMCode::PackedByteMask) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/pop.rs b/runtime/src/vm/encoders/pop.rs index 668db529..46edee6c 100644 --- a/runtime/src/vm/encoders/pop.rs +++ b/runtime/src/vm/encoders/pop.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg}; +use crate::vm::bytecode::{VMCode, VMReg}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; use std::fmt::{Debug, Formatter, Result}; @@ -30,8 +30,8 @@ impl Encode for Pop { self } - fn op(&self) -> Option { - Some(VMOp::Pop) + fn code(&self) -> Option { + Some(VMCode::Pop) } fn encode(&self, _mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/push.rs b/runtime/src/vm/encoders/push.rs index b1a7dfcf..28b0e4f3 100644 --- a/runtime/src/vm/encoders/push.rs +++ b/runtime/src/vm/encoders/push.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg}; +use crate::vm::bytecode::{VMCode, VMReg}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; use std::fmt::{Debug, Formatter, Result}; @@ -30,8 +30,8 @@ impl Encode for Push { self } - fn op(&self) -> Option { - Some(VMOp::Push) + fn code(&self) -> Option { + Some(VMCode::Push) } fn encode(&self, _mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/rol.rs b/runtime/src/vm/encoders/rol.rs index bb9a57c3..3c9008b6 100644 --- a/runtime/src/vm/encoders/rol.rs +++ b/runtime/src/vm/encoders/rol.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Rol { self } - fn op(&self) -> Option { - Some(VMOp::Rol) + fn code(&self) -> Option { + Some(VMCode::Rol) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/ror.rs b/runtime/src/vm/encoders/ror.rs index aa942895..3ce4b17e 100644 --- a/runtime/src/vm/encoders/ror.rs +++ b/runtime/src/vm/encoders/ror.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Ror { self } - fn op(&self) -> Option { - Some(VMOp::Ror) + fn code(&self) -> Option { + Some(VMCode::Ror) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/sar.rs b/runtime/src/vm/encoders/sar.rs index 1b781101..5c4a7b60 100644 --- a/runtime/src/vm/encoders/sar.rs +++ b/runtime/src/vm/encoders/sar.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Sar { self } - fn op(&self) -> Option { - Some(VMOp::Sar) + fn code(&self) -> Option { + Some(VMCode::Sar) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/sbb.rs b/runtime/src/vm/encoders/sbb.rs index 6490e974..23b538cc 100644 --- a/runtime/src/vm/encoders/sbb.rs +++ b/runtime/src/vm/encoders/sbb.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Sbb { self } - fn op(&self) -> Option { - Some(VMOp::Sbb) + fn code(&self) -> Option { + Some(VMCode::Sbb) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/shl.rs b/runtime/src/vm/encoders/shl.rs index 7858b0b2..5b4e5b20 100644 --- a/runtime/src/vm/encoders/shl.rs +++ b/runtime/src/vm/encoders/shl.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Shl { self } - fn op(&self) -> Option { - Some(VMOp::Shl) + fn code(&self) -> Option { + Some(VMCode::Shl) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/shr.rs b/runtime/src/vm/encoders/shr.rs index 376899a6..d382f1ab 100644 --- a/runtime/src/vm/encoders/shr.rs +++ b/runtime/src/vm/encoders/shr.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Shr { self } - fn op(&self) -> Option { - Some(VMOp::Shr) + fn code(&self) -> Option { + Some(VMCode::Shr) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/store_extend.rs b/runtime/src/vm/encoders/store_extend.rs index dccce633..c1e38c14 100644 --- a/runtime/src/vm/encoders/store_extend.rs +++ b/runtime/src/vm/encoders/store_extend.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMVec, VMWidth}; +use crate::vm::bytecode::{VMCode, VMVec, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -18,8 +18,8 @@ impl Encode for StoreExtend { self } - fn op(&self) -> Option { - Some(VMOp::StoreExtend) + fn code(&self) -> Option { + Some(VMCode::StoreExtend) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/store_memory.rs b/runtime/src/vm/encoders/store_memory.rs index 84050f3f..c3eea738 100644 --- a/runtime/src/vm/encoders/store_memory.rs +++ b/runtime/src/vm/encoders/store_memory.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for StoreMemory { self } - fn op(&self) -> Option { - Some(VMOp::StoreMemory) + fn code(&self) -> Option { + Some(VMCode::StoreMemory) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/store_merge.rs b/runtime/src/vm/encoders/store_merge.rs index 2ee89c61..bf44afee 100644 --- a/runtime/src/vm/encoders/store_merge.rs +++ b/runtime/src/vm/encoders/store_merge.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMVec, VMWidth}; +use crate::vm::bytecode::{VMCode, VMVec, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -18,8 +18,8 @@ impl Encode for StoreMerge { self } - fn op(&self) -> Option { - Some(VMOp::StoreMerge) + fn code(&self) -> Option { + Some(VMCode::StoreMerge) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/store_register.rs b/runtime/src/vm/encoders/store_register.rs index 8e60b989..a13fa003 100644 --- a/runtime/src/vm/encoders/store_register.rs +++ b/runtime/src/vm/encoders/store_register.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -18,8 +18,8 @@ impl Encode for StoreRegister { self } - fn op(&self) -> Option { - Some(VMOp::StoreRegister) + fn code(&self) -> Option { + Some(VMCode::StoreRegister) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/sub.rs b/runtime/src/vm/encoders/sub.rs index 4c289f66..2ef67887 100644 --- a/runtime/src/vm/encoders/sub.rs +++ b/runtime/src/vm/encoders/sub.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Sub { self } - fn op(&self) -> Option { - Some(VMOp::Sub) + fn code(&self) -> Option { + Some(VMCode::Sub) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/timestamp.rs b/runtime/src/vm/encoders/timestamp.rs index a256b96e..562d70bb 100644 --- a/runtime/src/vm/encoders/timestamp.rs +++ b/runtime/src/vm/encoders/timestamp.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::VMOp; +use crate::vm::bytecode::VMCode; use crate::vm::encoders::Encode; use std::any::Any; use std::fmt::{Debug, Formatter, Result}; @@ -30,8 +30,8 @@ impl Encode for Timestamp { self } - fn op(&self) -> Option { - Some(VMOp::Timestamp) + fn code(&self) -> Option { + Some(VMCode::Timestamp) } fn encode(&self, _mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/trailing_zeros.rs b/runtime/src/vm/encoders/trailing_zeros.rs index 9dc6a5f7..f216a23b 100644 --- a/runtime/src/vm/encoders/trailing_zeros.rs +++ b/runtime/src/vm/encoders/trailing_zeros.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for TrailingZeros { self } - fn op(&self) -> Option { - Some(VMOp::TrailingZeros) + fn code(&self) -> Option { + Some(VMCode::TrailingZeros) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/vector_add.rs b/runtime/src/vm/encoders/vector_add.rs index d705ca74..a1d430e0 100644 --- a/runtime/src/vm/encoders/vector_add.rs +++ b/runtime/src/vm/encoders/vector_add.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMPrecision, VMWidth}; +use crate::vm::bytecode::{VMCode, VMPrecision, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -19,8 +19,8 @@ impl Encode for VectorAdd { self } - fn op(&self) -> Option { - Some(VMOp::VectorAdd) + fn code(&self) -> Option { + Some(VMCode::VectorAdd) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/vector_and.rs b/runtime/src/vm/encoders/vector_and.rs index 67ff5ba2..fd5e9330 100644 --- a/runtime/src/vm/encoders/vector_and.rs +++ b/runtime/src/vm/encoders/vector_and.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for VectorAnd { self } - fn op(&self) -> Option { - Some(VMOp::VectorAnd) + fn code(&self) -> Option { + Some(VMCode::VectorAnd) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/vector_and_not.rs b/runtime/src/vm/encoders/vector_and_not.rs index 4ea2a697..ada0271d 100644 --- a/runtime/src/vm/encoders/vector_and_not.rs +++ b/runtime/src/vm/encoders/vector_and_not.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for VectorAndNot { self } - fn op(&self) -> Option { - Some(VMOp::VectorAndNot) + fn code(&self) -> Option { + Some(VMCode::VectorAndNot) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/vector_div.rs b/runtime/src/vm/encoders/vector_div.rs index 20f5d530..aab1609c 100644 --- a/runtime/src/vm/encoders/vector_div.rs +++ b/runtime/src/vm/encoders/vector_div.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -18,8 +18,8 @@ impl Encode for VectorDiv { self } - fn op(&self) -> Option { - Some(VMOp::VectorDiv) + fn code(&self) -> Option { + Some(VMCode::VectorDiv) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/vector_mul.rs b/runtime/src/vm/encoders/vector_mul.rs index 24880a80..b9a6239a 100644 --- a/runtime/src/vm/encoders/vector_mul.rs +++ b/runtime/src/vm/encoders/vector_mul.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMPrecision, VMWidth}; +use crate::vm::bytecode::{VMCode, VMPrecision, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -19,8 +19,8 @@ impl Encode for VectorMul { self } - fn op(&self) -> Option { - Some(VMOp::VectorMul) + fn code(&self) -> Option { + Some(VMCode::VectorMul) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/vector_or.rs b/runtime/src/vm/encoders/vector_or.rs index b8b16a2c..9c09f223 100644 --- a/runtime/src/vm/encoders/vector_or.rs +++ b/runtime/src/vm/encoders/vector_or.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for VectorOr { self } - fn op(&self) -> Option { - Some(VMOp::VectorOr) + fn code(&self) -> Option { + Some(VMCode::VectorOr) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/vector_sub.rs b/runtime/src/vm/encoders/vector_sub.rs index c5172ebb..54a54be8 100644 --- a/runtime/src/vm/encoders/vector_sub.rs +++ b/runtime/src/vm/encoders/vector_sub.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMPrecision, VMWidth}; +use crate::vm::bytecode::{VMCode, VMPrecision, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -19,8 +19,8 @@ impl Encode for VectorSub { self } - fn op(&self) -> Option { - Some(VMOp::VectorSub) + fn code(&self) -> Option { + Some(VMCode::VectorSub) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/vector_xor.rs b/runtime/src/vm/encoders/vector_xor.rs index bad28bfc..5b36ac22 100644 --- a/runtime/src/vm/encoders/vector_xor.rs +++ b/runtime/src/vm/encoders/vector_xor.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMWidth}; +use crate::vm::bytecode::{VMCode, VMWidth}; use crate::vm::encoders::Encode; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for VectorXor { self } - fn op(&self) -> Option { - Some(VMOp::VectorXor) + fn code(&self) -> Option { + Some(VMCode::VectorXor) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/encoders/xor.rs b/runtime/src/vm/encoders/xor.rs index 1a4434aa..b661d1ed 100644 --- a/runtime/src/vm/encoders/xor.rs +++ b/runtime/src/vm/encoders/xor.rs @@ -1,5 +1,5 @@ use crate::mapper::Mapper; -use crate::vm::bytecode::{VMOp, VMReg, VMWidth}; +use crate::vm::bytecode::{VMCode, VMReg, VMWidth}; use crate::vm::encoders::{Effect, Encode}; use std::any::Any; @@ -17,8 +17,8 @@ impl Encode for Xor { self } - fn op(&self) -> Option { - Some(VMOp::Xor) + fn code(&self) -> Option { + Some(VMCode::Xor) } fn encode(&self, mapper: &mut Mapper) -> Vec { diff --git a/runtime/src/vm/functions/cleanup.rs b/runtime/src/vm/functions/cleanup.rs index 4fa1339d..17a16e1b 100644 --- a/runtime/src/vm/functions/cleanup.rs +++ b/runtime/src/vm/functions/cleanup.rs @@ -19,7 +19,7 @@ pub fn build(rt: &mut Runtime) { rt.asm.mov(r12, ptr(0x1480 + r12 * 8).gs()).unwrap(); // mov rcx, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VShadow, rcx); + utils::register::load(rt, r12, rcx, VMReg::VShadow); // test rcx, rcx rt.asm.test(rcx, rcx).unwrap(); // jz ... diff --git a/runtime/src/vm/functions/context.rs b/runtime/src/vm/functions/context.rs index 035ee39d..72129164 100644 --- a/runtime/src/vm/functions/context.rs +++ b/runtime/src/vm/functions/context.rs @@ -5,7 +5,7 @@ use crate::{ runtime::{ImportDef, Runtime}, vm::{ bytecode::{VMReg, VMVec}, - utils, + utils::register, }, VM_SCRATCH_SIZE, VM_STACK_SIZE, }; @@ -53,7 +53,7 @@ pub fn create(rt: &mut Runtime) { // call r13 rt.asm.call(r13).unwrap(); // mov [r14 + ...], rax - utils::vreg::store_reg(rt, r14, rax, VMReg::VVector); + register::store(rt, r14, VMReg::VVector, rax); // mov rcx, r12 rt.asm.mov(rcx, r12).unwrap(); @@ -66,7 +66,7 @@ pub fn create(rt: &mut Runtime) { // add rax, ... rt.asm.add(rax, VM_STACK_SIZE as i32).unwrap(); // mov [r14 + ...], rax - utils::vreg::store_reg(rt, r14, rax, VMReg::VStack); + register::store(rt, r14, VMReg::VStack, rax); // mov rcx, r12 rt.asm.mov(rcx, r12).unwrap(); @@ -79,14 +79,14 @@ pub fn create(rt: &mut Runtime) { // add rax, ... rt.asm.add(rax, VM_SCRATCH_SIZE as i32).unwrap(); // mov [r14 + ...], rax - utils::vreg::store_reg(rt, r14, rax, VMReg::VScratch); + register::store(rt, r14, VMReg::VScratch, rax); // mov rax, gs:[0x60] -> PEB *TEB->ProcessEnvironmentBlock rt.asm.mov(rax, ptr(0x60).gs()).unwrap(); // mov rax, [rax + 0x10] -> PVOID PEB->ImageBaseAddress rt.asm.mov(rax, ptr(rax + 0x10)).unwrap(); // mov [r14 + ...], rax - utils::vreg::store_reg(rt, r14, rax, VMReg::VImage); + register::store(rt, r14, VMReg::VImage, rax); // mov rax, r14 rt.asm.mov(rax, r14).unwrap(); @@ -135,7 +135,7 @@ pub fn delete(rt: &mut Runtime) { // xor rdx, rdx rt.asm.xor(rdx, rdx).unwrap(); // mov r8, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VStack, r8); + register::load(rt, r12, r8, VMReg::VStack); // sub r8, ... rt.asm.sub(r8, VM_STACK_SIZE as i32).unwrap(); // call r14 @@ -146,7 +146,7 @@ pub fn delete(rt: &mut Runtime) { // xor rdx, rdx rt.asm.xor(rdx, rdx).unwrap(); // mov r8, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VScratch, r8); + register::load(rt, r12, r8, VMReg::VScratch); // sub r8, ... rt.asm.sub(r8, VM_SCRATCH_SIZE as i32).unwrap(); // call r14 @@ -157,7 +157,7 @@ pub fn delete(rt: &mut Runtime) { // xor rdx, rdx rt.asm.xor(rdx, rdx).unwrap(); // mov r8, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VVector, r8); + register::load(rt, r12, r8, VMReg::VVector); // call r14 rt.asm.call(r14).unwrap(); diff --git a/runtime/src/vm/functions/crypt.rs b/runtime/src/vm/functions/crypt.rs index 4898cfae..4c60e47c 100644 --- a/runtime/src/vm/functions/crypt.rs +++ b/runtime/src/vm/functions/crypt.rs @@ -49,9 +49,9 @@ pub fn build(rt: &mut Runtime) { rt.asm.mov(r13, rcx).unwrap(); // mov r14, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::BPointer, r14); + utils::register::load(rt, r12, r14, VMReg::BPointer); // mov r15, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::BLength, r15); + utils::register::load(rt, r12, r15, VMReg::BLength); // lea rbx, [r14 + 0x2] rt.asm.lea(rbx, ptr(r14 + 0x2)).unwrap(); @@ -216,7 +216,7 @@ pub fn build(rt: &mut Runtime) { { // lea rcx, [...] rt.asm - .lea(rcx, ptr(rt.data_labels[&DataDef::VmAttestation])) + .lea(rcx, ptr(rt.data_labels[&DataDef::VmAttestationProgram])) .unwrap(); // movsxd rax, [rcx] rt.asm.movsxd(rax, ptr(rcx)).unwrap(); @@ -247,7 +247,7 @@ pub fn build(rt: &mut Runtime) { { // lea rcx, [...] rt.asm - .lea(rcx, ptr(rt.data_labels[&DataDef::VmAttestation])) + .lea(rcx, ptr(rt.data_labels[&DataDef::VmAttestationProgram])) .unwrap(); // movsxd rax, [rcx] rt.asm.movsxd(rax, ptr(rcx)).unwrap(); diff --git a/runtime/src/vm/functions/dispatch.rs b/runtime/src/vm/functions/dispatch.rs index e532d6e9..3f0314b8 100644 --- a/runtime/src/vm/functions/dispatch.rs +++ b/runtime/src/vm/functions/dispatch.rs @@ -7,8 +7,9 @@ use crate::{ mapper::Mappable, runtime::{DataDef, FnDef, ImportDef, Runtime, StringDef}, vm::{ - bytecode::{VMOp, VMReg}, - utils::{self, lock}, + bytecode::{VMCode, VMReg}, + handlers, + utils::{bytecode, lock, register}, }, VM_DISPATCH_SIZE, VM_INTEGRITY_QWORD, VM_REDIRECT_SIZE, VM_TRAMPOLINE_SIZE, }; @@ -16,59 +17,6 @@ use crate::{ #[cfg(feature = "profile")] use crate::debug::{start_profiling, stop_profiling}; -pub const HANDLERS: [(VMOp, FnDef); VMOp::COUNT] = [ - (VMOp::Jcc, FnDef::VmHandlerJcc), - (VMOp::Ret, FnDef::VmHandlerRet), - (VMOp::LoadImmediate, FnDef::VmHandlerLoadImmediate), - (VMOp::LoadRegister, FnDef::VmHandlerLoadRegister), - (VMOp::LoadMemory, FnDef::VmHandlerLoadMemory), - (VMOp::LoadAddress, FnDef::VmHandlerLoadAddress), - (VMOp::StoreRegister, FnDef::VmHandlerStoreRegister), - (VMOp::StoreMemory, FnDef::VmHandlerStoreMemory), - (VMOp::LoadVector, FnDef::VmHandlerLoadVector), - (VMOp::StoreMerge, FnDef::VmHandlerStoreMerge), - (VMOp::StoreExtend, FnDef::VmHandlerStoreExtend), - (VMOp::Add, FnDef::VmHandlerAdd), - (VMOp::Sub, FnDef::VmHandlerSub), - (VMOp::Adc, FnDef::VmHandlerAdc), - (VMOp::Sbb, FnDef::VmHandlerSbb), - (VMOp::Exchange, FnDef::VmHandlerExchange), - (VMOp::ExchangeAdd, FnDef::VmHandlerExchangeAdd), - (VMOp::CompareExchange, FnDef::VmHandlerCompareExchange), - (VMOp::And, FnDef::VmHandlerAnd), - (VMOp::Or, FnDef::VmHandlerOr), - (VMOp::Xor, FnDef::VmHandlerXor), - (VMOp::Rol, FnDef::VmHandlerRol), - (VMOp::Ror, FnDef::VmHandlerRor), - (VMOp::Shl, FnDef::VmHandlerShl), - (VMOp::Shr, FnDef::VmHandlerShr), - (VMOp::Sar, FnDef::VmHandlerSar), - (VMOp::Mul, FnDef::VmHandlerMul), - (VMOp::Div, FnDef::VmHandlerDiv), - (VMOp::TrailingZeros, FnDef::VmHandlerTrailingZeros), - (VMOp::BitScanReverse, FnDef::VmHandlerBitScanReverse), - (VMOp::ByteSwap, FnDef::VmHandlerByteSwap), - (VMOp::BitTest, FnDef::VmHandlerBitTest), - (VMOp::BitTestSet, FnDef::VmHandlerBitTestSet), - (VMOp::BitTestReset, FnDef::VmHandlerBitTestReset), - (VMOp::BitTestComplement, FnDef::VmHandlerBitTestComplement), - (VMOp::Push, FnDef::VmHandlerPush), - (VMOp::Pop, FnDef::VmHandlerPop), - (VMOp::Discard, FnDef::VmHandlerDiscard), - (VMOp::PackedByteMask, FnDef::VmHandlerPackedByteMask), - (VMOp::PackedByteEqual, FnDef::VmHandlerPackedByteEqual), - (VMOp::VectorAnd, FnDef::VmHandlerVectorAnd), - (VMOp::VectorAndNot, FnDef::VmHandlerVectorAndNot), - (VMOp::VectorOr, FnDef::VmHandlerVectorOr), - (VMOp::VectorXor, FnDef::VmHandlerVectorXor), - (VMOp::VectorAdd, FnDef::VmHandlerVectorAdd), - (VMOp::VectorSub, FnDef::VmHandlerVectorSub), - (VMOp::VectorMul, FnDef::VmHandlerVectorMul), - (VMOp::VectorDiv, FnDef::VmHandlerVectorDiv), - (VMOp::Timestamp, FnDef::VmHandlerTimestamp), - (VMOp::Dispatch, FnDef::VmHandlerDispatch), -]; - pub fn build(rt: &mut Runtime) { let mut setup_block = rt.asm.create_label(); let mut resume_block = rt.asm.create_label(); @@ -97,11 +45,11 @@ pub fn build(rt: &mut Runtime) { { // Initialize block pointer and block length: // mov r13, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::BPointer, r13); + register::load(rt, r12, r13, VMReg::BPointer); // eax = length - utils::bytecode::read_word_zx(rt, r13, eax); + bytecode::read_word_zx(rt, r13, eax); // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::BLength); + register::store(rt, r12, VMReg::BLength, rax); // Store the end of the block: // lea r14, [r13 + rax] @@ -109,7 +57,7 @@ pub fn build(rt: &mut Runtime) { // Check if this is a fresh execution: // cmp [r12 + ...], 0x0 - utils::vreg::cmp_imm(rt, r12, VMReg::BResume, 0x0); + register::cmp_with_native(rt, r12, VMReg::BResume, 0x0); // je ... rt.asm.je(decrypt_block).unwrap(); } @@ -117,12 +65,12 @@ pub fn build(rt: &mut Runtime) { rt.asm.set_label(&mut resume_block).unwrap(); { // mov r13, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::BResume, r13); + register::load(rt, r12, r13, VMReg::BResume); // mov [r12 + ...], 0x0 - utils::vreg::store_imm(rt, r12, 0x0, VMReg::NBranch); + register::store(rt, r12, VMReg::NBranch, 0x0); // mov [r12 + ...], 0x0 - utils::vreg::store_imm(rt, r12, 0x0, VMReg::BResume); + register::store(rt, r12, VMReg::BResume, 0x0); // jmp ... rt.asm.jmp(execute_loop).unwrap(); @@ -153,7 +101,7 @@ pub fn build(rt: &mut Runtime) { rt.asm.set_label(&mut start_block).unwrap(); { // mov [r12 + ...], 0x0 - utils::vreg::store_imm(rt, r12, 0x0, VMReg::NBranch); + register::store(rt, r12, VMReg::NBranch, 0x0); // lea rax, [...] rt.asm @@ -170,11 +118,11 @@ pub fn build(rt: &mut Runtime) { // sub rcx, rax rt.asm.sub(rcx, rax).unwrap(); // mov [r12 + ...], rcx - utils::vreg::store_reg(rt, r12, rcx, VMReg::VImmAdd); + register::store(rt, r12, VMReg::VImmAdd, rcx); // or rcx, 0x1 rt.asm.or(rcx, 0x1).unwrap(); // mov [r12 + ...], rcx - utils::vreg::store_reg(rt, r12, rcx, VMReg::VImmMul); + register::store(rt, r12, VMReg::VImmMul, rcx); } rt.asm.set_label(&mut execute_loop).unwrap(); @@ -185,12 +133,12 @@ pub fn build(rt: &mut Runtime) { rt.asm.je(check_loop).unwrap(); // cmp [r12 + ...], 0x0 - utils::vreg::cmp_imm(rt, r12, VMReg::NBranch, 0x0); + register::cmp_with_native(rt, r12, VMReg::NBranch, 0x0); // jne ... rt.asm.jne(check_suspend).unwrap(); // r8d -> operation - utils::bytecode::read_byte_zx(rt, r13, r8d); + bytecode::read_byte_zx(rt, r13, r8d); #[cfg(feature = "profile")] { @@ -200,13 +148,13 @@ pub fn build(rt: &mut Runtime) { let mut cases = Vec::new(); - for op in VMOp::VARIANTS { + for op in VMCode::VARIANTS { cases.push((rt.mapper.index(*op), rt.asm.create_label())); } rt.jumps(r8, cases.clone()); - for (op, (_, mut label)) in VMOp::VARIANTS.iter().zip(cases) { + for (op, (_, mut label)) in VMCode::VARIANTS.iter().zip(cases) { rt.asm.set_label(&mut label).unwrap(); print_thread_message(rt, &format!("{:?}", op), None, None); @@ -220,9 +168,12 @@ pub fn build(rt: &mut Runtime) { // mov rcx, r13 rt.asm.mov(rcx, r13).unwrap(); - let cases = HANDLERS + let cases = VMCode::VARIANTS .iter() - .map(|&(op, def)| (rt.mapper.index(op), rt.function_labels[&def])) + .map(|&op| { + let label = rt.function_labels[&handlers::handler(op)]; + (rt.mapper.index(op), label) + }) .collect::>(); rt.calls(r8, cases); @@ -238,25 +189,25 @@ pub fn build(rt: &mut Runtime) { { // Skip if the native branch is zero: // cmp [r12 + ...], 0x0 - utils::vreg::cmp_imm(rt, r12, VMReg::NBranch, 0x0); + register::cmp_with_native(rt, r12, VMReg::NBranch, 0x0); // je ... rt.asm.je(check_exit).unwrap(); // Skip if the native entry is not equal to the native branch: // mov rax, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::NEntry, rax); + register::load(rt, r12, rax, VMReg::NEntry); // cmp [r12 + ...], - utils::vreg::cmp_reg(rt, r12, VMReg::NBranch, rax); + register::cmp_with_native(rt, r12, VMReg::NBranch, rax); // jne ... rt.asm.jne(check_exit).unwrap(); // Native branch points to the native entry so re-execute the block: // mov r13, [...] - utils::vreg::load_reg(rt, r12, VMReg::BPointer, r13); + register::load(rt, r12, r13, VMReg::BPointer); // eax = length - utils::bytecode::read_word_zx(rt, r13, eax); + bytecode::read_word_zx(rt, r13, eax); // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::BLength); + register::store(rt, r12, VMReg::BLength, rax); // jmp ... rt.asm.jmp(start_block).unwrap(); } @@ -269,7 +220,7 @@ pub fn build(rt: &mut Runtime) { rt.asm.je(check_exit).unwrap(); // mov [r12 + ...], r13 - utils::vreg::store_reg(rt, r12, r13, VMReg::BResume); + register::store(rt, r12, VMReg::BResume, r13); // jmp ... rt.asm.jmp(epilogue).unwrap(); } @@ -290,9 +241,9 @@ pub fn build(rt: &mut Runtime) { // Compute the address where execution will continue: // mov rax, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::NExit, rax); + register::load(rt, r12, rax, VMReg::NExit); // mov rcx, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::NBranch, rcx); + register::load(rt, r12, rcx, VMReg::NBranch); // test rcx, rcx rt.asm.test(rcx, rcx).unwrap(); // cmovnz rax, rcx @@ -349,7 +300,7 @@ pub fn build(rt: &mut Runtime) { // call ... rt.asm.call(rt.function_labels[&FnDef::VmLookup]).unwrap(); // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::BPointer); + register::store(rt, r12, VMReg::BPointer, rax); // jmp ... rt.asm.jmp(setup_block).unwrap(); diff --git a/runtime/src/vm/functions/entry.rs b/runtime/src/vm/functions/entry.rs index 6ab6857c..ec2a95ab 100644 --- a/runtime/src/vm/functions/entry.rs +++ b/runtime/src/vm/functions/entry.rs @@ -106,7 +106,7 @@ pub fn build(rt: &mut Runtime) { .lea(rcx, ptr(rt.data_labels[&DataDef::VmGlobalVectors])) .unwrap(); // mov rdx, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VVector, rdx); + utils::register::load(rt, r12, rdx, VMReg::VVector); // call ... rt.asm .call(rt.function_labels[&FnDef::VmVectorsCopy]) @@ -124,7 +124,7 @@ pub fn build(rt: &mut Runtime) { .unwrap(); // mov rcx, [...] - utils::vreg::load_reg(rt, r12, VMReg::VVector, rcx); + utils::register::load(rt, r12, rcx, VMReg::VVector); // call ... rt.asm .call(rt.function_labels[&FnDef::VmVectorsCapture]) @@ -136,12 +136,12 @@ pub fn build(rt: &mut Runtime) { // pop rax rt.asm.pop(rax).unwrap(); // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::R12); + utils::register::store(rt, r12, VMReg::R12, rax); // pop rax rt.asm.pop(rax).unwrap(); // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::Flags); + utils::register::store(rt, r12, VMReg::Flags, rax); // Pop the return address from the stack: // pop rcx @@ -155,14 +155,14 @@ pub fn build(rt: &mut Runtime) { // call ... rt.asm.call(rt.function_labels[&FnDef::VmLookup]).unwrap(); // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::BPointer); + utils::register::store(rt, r12, VMReg::BPointer, rax); // Stack now points to where it was before the caller stub: // mov [r12 + ...], rsp - utils::vreg::store_reg(rt, r12, rsp, VMReg::Rsp); + utils::register::store(rt, r12, VMReg::Rsp, rsp); // mov rsp, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VStack, rsp); + utils::register::load(rt, r12, rsp, VMReg::VStack); } #[cfg(feature = "profile")] diff --git a/runtime/src/vm/functions/exit.rs b/runtime/src/vm/functions/exit.rs index 05df8243..e0c241e3 100644 --- a/runtime/src/vm/functions/exit.rs +++ b/runtime/src/vm/functions/exit.rs @@ -10,7 +10,7 @@ pub fn build(rt: &mut Runtime) { let mut epilogue = rt.asm.create_label(); // mov rsp, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::Rsp, rsp); + utils::register::load(rt, r12, rsp, VMReg::Rsp); // call ... rt.asm @@ -22,30 +22,30 @@ pub fn build(rt: &mut Runtime) { .unwrap(); // cmp [r12 + ...], 0x0 - utils::vreg::cmp_imm(rt, r12, VMReg::NBranch, 0x0); + utils::register::cmp_with_native(rt, r12, VMReg::NBranch, 0x0); // je ... rt.asm.je(no_branch).unwrap(); // push [r12 + ...] - utils::vreg::push(rt, r12, VMReg::NBranch); + utils::register::push(rt, r12, VMReg::NBranch); // jmp ... rt.asm.jmp(epilogue).unwrap(); rt.asm.set_label(&mut no_branch).unwrap(); { // push [r12 + ...] - utils::vreg::push(rt, r12, VMReg::NExit); + utils::register::push(rt, r12, VMReg::NExit); } rt.asm.set_label(&mut epilogue).unwrap(); { // push [r12 + ...] - utils::vreg::push(rt, r12, VMReg::Flags); + utils::register::push(rt, r12, VMReg::Flags); // popfq rt.asm.popfq().unwrap(); // mov r12, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::R12, r12); + utils::register::load(rt, r12, r12, VMReg::R12); // ret rt.asm.ret().unwrap(); diff --git a/runtime/src/vm/functions/ginit.rs b/runtime/src/vm/functions/ginit.rs index 89b30fae..d7c9bc4e 100644 --- a/runtime/src/vm/functions/ginit.rs +++ b/runtime/src/vm/functions/ginit.rs @@ -1,13 +1,15 @@ -use iced_x86::code_asm::{eax, ptr, r13, rax, rcx, rdx, rsp}; +use iced_x86::code_asm::{eax, ptr, qword_ptr, r13, r8, r9, rax, rcx, rdx, rsp}; use crate::runtime::{DataDef, FnDef, ImportDef, Runtime}; pub fn build(rt: &mut Runtime) { + let mut spin = rt.asm.create_label(); + // push r13 rt.asm.push(r13).unwrap(); - // sub rsp, 0x20 - rt.asm.sub(rsp, 0x20).unwrap(); + // sub rsp, 0x30 + rt.asm.sub(rsp, 0x30).unwrap(); // mov rcx, [...]; call ... rt.resolve(ImportDef::TlsAlloc); @@ -55,8 +57,41 @@ pub fn build(rt: &mut Runtime) { .call(rt.function_labels[&FnDef::VmVehInitialize]) .unwrap(); - // add rsp, 0x20 - rt.asm.add(rsp, 0x20).unwrap(); + // Spawn the attestation service thread: + // mov rcx, [...]; call ... + rt.resolve(ImportDef::CreateThread); + // xor rcx, rcx + rt.asm.xor(rcx, rcx).unwrap(); + // xor rdx, rdx + rt.asm.xor(rdx, rdx).unwrap(); + // lea r8, [...] + rt.asm + .lea(r8, ptr(rt.function_labels[&FnDef::VmService])) + .unwrap(); + // xor r9, r9 + rt.asm.xor(r9, r9).unwrap(); + // mov qword [rsp + 0x20], 0x0 + rt.asm.mov(qword_ptr(rsp + 0x20), 0x0).unwrap(); + // mov qword [rsp + 0x28], 0x0 + rt.asm.mov(qword_ptr(rsp + 0x28), 0x0).unwrap(); + // call rax + rt.asm.call(rax).unwrap(); + + // Wait for the service to run once: + rt.asm.set_label(&mut spin).unwrap(); + { + // cmp qword [...], 0x0 + rt.asm + .cmp(qword_ptr(rt.data_labels[&DataDef::VmServiceBox]), 0x0) + .unwrap(); + // pause + rt.asm.pause().unwrap(); + // je ... + rt.asm.je(spin).unwrap(); + } + + // add rsp, 0x30 + rt.asm.add(rsp, 0x30).unwrap(); // pop r13 rt.asm.pop(r13).unwrap(); diff --git a/runtime/src/vm/functions/invoke.rs b/runtime/src/vm/functions/invoke.rs index 091ca761..c85d0102 100644 --- a/runtime/src/vm/functions/invoke.rs +++ b/runtime/src/vm/functions/invoke.rs @@ -39,7 +39,7 @@ pub fn build(rt: &mut Runtime) { rt.asm.mov(r15, rdx).unwrap(); // mov r13, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VShadow, r13); + utils::register::load(rt, r12, r13, VMReg::VShadow); // test r13, r13 rt.asm.test(r13, r13).unwrap(); // jnz ... @@ -53,7 +53,7 @@ pub fn build(rt: &mut Runtime) { rt.asm.mov(r13, rax).unwrap(); // mov [r12 + ...], r13 - utils::vreg::store_reg(rt, r12, r13, VMReg::VShadow); + utils::register::store(rt, r12, VMReg::VShadow, r13); rt.asm.set_label(&mut initialized).unwrap(); @@ -61,22 +61,22 @@ pub fn build(rt: &mut Runtime) { rt.asm.mov(r12, r13).unwrap(); // mov [r12 + ...], r12 - utils::vreg::store_reg(rt, r12, r12, VMReg::R12); + utils::register::store(rt, r12, VMReg::R12, r12); // mov [r12 + ...], r14 - utils::vreg::store_reg(rt, r12, r14, VMReg::BPointer); + utils::register::store(rt, r12, VMReg::BPointer, r14); // mov [r12 + ...], r15 - utils::vreg::store_reg(rt, r12, r15, VMReg::Vg0); + utils::register::store(rt, r12, VMReg::Vg0, r15); // lea rax, [...] rt.asm.lea(rax, ptr(execute_continue)).unwrap(); // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::NExit); + utils::register::store(rt, r12, VMReg::NExit, rax); // push [r12 + ...] - utils::vreg::push(rt, r12, VMReg::VStack); + utils::register::push(rt, r12, VMReg::VStack); // pop [r12 + ...] - utils::vreg::pop(rt, r12, VMReg::Rsp); + utils::register::pop(rt, r12, VMReg::Rsp); rt.asm.set_label(&mut execute_loop).unwrap(); { @@ -104,7 +104,7 @@ pub fn build(rt: &mut Runtime) { .unwrap(); // mov [r12 + ...], rsp - utils::vreg::store_reg(rt, r12, rsp, VMReg::Rsp); + utils::register::store(rt, r12, VMReg::Rsp, rsp); // mov r13d, [...] rt.asm @@ -117,7 +117,7 @@ pub fn build(rt: &mut Runtime) { scratch::load(rt, r13, rsp); // cmp [r12 + ...], 0x0 - utils::vreg::cmp_imm(rt, r12, VMReg::BResume, 0x0); + utils::register::cmp_with_native(rt, r12, VMReg::BResume, 0x0); // jne ... rt.asm.jne(execute_loop).unwrap(); } @@ -125,7 +125,7 @@ pub fn build(rt: &mut Runtime) { rt.asm.set_label(&mut epilogue).unwrap(); { // mov rax, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::Vg0, rax); + utils::register::load(rt, r12, rax, VMReg::Vg0); // pop r15 rt.asm.pop(r15).unwrap(); diff --git a/runtime/src/vm/functions/lookup.rs b/runtime/src/vm/functions/lookup.rs index b570c810..6e580201 100644 --- a/runtime/src/vm/functions/lookup.rs +++ b/runtime/src/vm/functions/lookup.rs @@ -14,7 +14,7 @@ pub fn build(rt: &mut Runtime) { // mov r8, rcx rt.asm.mov(r8, rcx).unwrap(); // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImage, r8); + utils::register::sub_from_native(rt, r12, r8, VMReg::VImage); // Resolve the table entry using the index: // xor edx, r8d @@ -49,7 +49,7 @@ pub fn build(rt: &mut Runtime) { // add rax, rcx rt.asm.add(rax, rcx).unwrap(); // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::NExit); + utils::register::store(rt, r12, VMReg::NExit, rax); // Apply the entry displacement of the caller stub to the return address: // movsxd rax, [r8 + 0x4] @@ -57,7 +57,7 @@ pub fn build(rt: &mut Runtime) { // add rax, rcx rt.asm.add(rax, rcx).unwrap(); // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::NEntry); + utils::register::store(rt, r12, VMReg::NEntry, rax); // Read the offset into bytecode from the table: // mov edx, [r8 + 0x8] diff --git a/runtime/src/vm/functions/mod.rs b/runtime/src/vm/functions/mod.rs index 45e2b41d..e0bd6569 100644 --- a/runtime/src/vm/functions/mod.rs +++ b/runtime/src/vm/functions/mod.rs @@ -8,6 +8,7 @@ pub mod ginit; pub mod invoke; pub mod lookup; pub mod registers; +pub mod service; pub mod tinit; pub mod vectors; pub mod veh; diff --git a/runtime/src/vm/functions/registers.rs b/runtime/src/vm/functions/registers.rs index c8671b1e..129b662a 100644 --- a/runtime/src/vm/functions/registers.rs +++ b/runtime/src/vm/functions/registers.rs @@ -10,7 +10,7 @@ use crate::{ pub fn capture(rt: &mut Runtime) { for (dst, src) in REGISTERS_TO_NATIVE { // mov [r12 + ...], ... - utils::vreg::store_reg(rt, r12, src, dst); + utils::register::store(rt, r12, dst, src); } // ret rt.asm.ret().unwrap(); @@ -19,7 +19,7 @@ pub fn capture(rt: &mut Runtime) { pub fn capture_volatile(rt: &mut Runtime) { for &(dst, src) in REGISTERS_TO_NATIVE_VOLATILE { // mov [r12 + ...], ... - utils::vreg::store_reg(rt, r12, src, dst); + utils::register::store(rt, r12, dst, src); } // ret rt.asm.ret().unwrap(); @@ -28,7 +28,7 @@ pub fn capture_volatile(rt: &mut Runtime) { pub fn capture_nonvolatile(rt: &mut Runtime) { for &(dst, src) in REGISTERS_TO_NATIVE_NONVOLATILE { // mov [r12 + ...], ... - utils::vreg::store_reg(rt, r12, src, dst); + utils::register::store(rt, r12, dst, src); } // ret rt.asm.ret().unwrap(); @@ -37,7 +37,7 @@ pub fn capture_nonvolatile(rt: &mut Runtime) { pub fn restore(rt: &mut Runtime) { for (src, dst) in REGISTERS_TO_NATIVE { // mov ..., [r12 + ...] - utils::vreg::load_reg(rt, r12, src, dst); + utils::register::load(rt, r12, dst, src); } // ret rt.asm.ret().unwrap(); @@ -46,9 +46,9 @@ pub fn restore(rt: &mut Runtime) { pub fn copy(rt: &mut Runtime) { for (reg, _) in REGISTERS_TO_NATIVE { // mov rax, [rcx + ...] - utils::vreg::load_reg(rt, rcx, reg, rax); + utils::register::load(rt, rcx, rax, reg); // mov [rdx + ...], rax - utils::vreg::store_reg(rt, rdx, rax, reg); + utils::register::store(rt, rdx, reg, rax); } // ret rt.asm.ret().unwrap(); diff --git a/runtime/src/vm/functions/service.rs b/runtime/src/vm/functions/service.rs new file mode 100644 index 00000000..e9d19ee3 --- /dev/null +++ b/runtime/src/vm/functions/service.rs @@ -0,0 +1,41 @@ +use iced_x86::code_asm::{eax, ptr, r12, r12d, rax, rcx, rdx, rsp}; + +use crate::runtime::{DataDef, FnDef, Runtime}; + +// DWORD (LPVOID) +pub fn build(rt: &mut Runtime) { + // sub rsp, 0x28 + rt.asm.sub(rsp, 0x28).unwrap(); + + // call ... + rt.asm.call(rt.function_labels[&FnDef::VmTInit]).unwrap(); + + // mov r12d, [...] + rt.asm + .mov(r12d, ptr(rt.data_labels[&DataDef::VmRegistersTlsIndex])) + .unwrap(); + // mov r12, gs:[0x1480 + r12*8] + rt.asm.mov(r12, ptr(0x1480 + r12 * 8).gs()).unwrap(); + + // lea rcx, [...] + rt.asm + .lea(rcx, ptr(rt.data_labels[&DataDef::VmAttestationService])) + .unwrap(); + // movsxd rax, [rcx] + rt.asm.movsxd(rax, ptr(rcx)).unwrap(); + // add rcx, rax + rt.asm.add(rcx, rax).unwrap(); + + // xor rdx, rdx + rt.asm.xor(rdx, rdx).unwrap(); + + // call ... + rt.asm.call(rt.function_labels[&FnDef::VmInvoke]).unwrap(); + + // xor eax, eax + rt.asm.xor(eax, eax).unwrap(); + // add rsp, 0x28 + rt.asm.add(rsp, 0x28).unwrap(); + // ret + rt.asm.ret().unwrap(); +} diff --git a/runtime/src/vm/functions/vectors.rs b/runtime/src/vm/functions/vectors.rs index 917fd5ee..bb4ad3fc 100644 --- a/runtime/src/vm/functions/vectors.rs +++ b/runtime/src/vm/functions/vectors.rs @@ -104,7 +104,7 @@ pub fn capture(rt: &mut Runtime) { for (vec, ymm, _) in VECTORS_TO_NATIVE { // vmovups [rax + ...], ... - utils::vvec::store_256(rt, r13, *ymm, *vec); + utils::vector::store_256(rt, r13, *ymm, *vec); } // pop r13 rt.asm.pop(r13).unwrap(); @@ -115,7 +115,7 @@ pub fn capture(rt: &mut Runtime) { { for (vec, _, xmm) in VECTORS_TO_NATIVE { // movups [rax + ...], ... - utils::vvec::store_128(rt, r13, *xmm, *vec); + utils::vector::store_128(rt, r13, *xmm, *vec); } // pop r13 rt.asm.pop(r13).unwrap(); @@ -137,11 +137,11 @@ pub fn restore(rt: &mut Runtime) { rt.asm.jz(sse).unwrap(); // mov rax, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VVector, rax); + utils::register::load(rt, r12, rax, VMReg::VVector); for (src, dst, _) in VECTORS_TO_NATIVE { // vmovups ..., [rax + ...] - utils::vvec::load_256(rt, rax, *src, *dst); + utils::vector::load_256(rt, rax, *src, *dst); } // ret rt.asm.ret().unwrap(); @@ -149,11 +149,11 @@ pub fn restore(rt: &mut Runtime) { rt.asm.set_label(&mut sse).unwrap(); { // mov rax, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VVector, rax); + utils::register::load(rt, r12, rax, VMReg::VVector); for (src, _, dst) in VECTORS_TO_NATIVE { // movups ..., [rax + ...] - utils::vvec::load_128(rt, rax, *src, *dst); + utils::vector::load_128(rt, rax, *src, *dst); } // ret rt.asm.ret().unwrap(); @@ -183,9 +183,9 @@ pub fn copy(rt: &mut Runtime) { for (vec, ymm, _) in VECTORS_TO_NATIVE { // vmovups ymm0, [r13 + ...] - utils::vvec::load_256(rt, r13, *vec, ymm0); + utils::vector::load_256(rt, r13, *vec, ymm0); // vmovups [r14 + ...], ymm0 - utils::vvec::store_256(rt, r14, *ymm, *vec); + utils::vector::store_256(rt, r14, *ymm, *vec); } // pop r14 rt.asm.pop(r14).unwrap(); @@ -198,9 +198,9 @@ pub fn copy(rt: &mut Runtime) { { for (vec, _, xmm) in VECTORS_TO_NATIVE { // movups xmm0, [r13 + ...] - utils::vvec::load_128(rt, r13, *vec, xmm0); + utils::vector::load_128(rt, r13, *vec, xmm0); // movups [r14 + ...], xmm0 - utils::vvec::store_128(rt, r14, *xmm, *vec); + utils::vector::store_128(rt, r14, *xmm, *vec); } // pop r14 rt.asm.pop(r14).unwrap(); diff --git a/runtime/src/vm/functions/veh.rs b/runtime/src/vm/functions/veh.rs index 478d6525..363bb79c 100644 --- a/runtime/src/vm/functions/veh.rs +++ b/runtime/src/vm/functions/veh.rs @@ -167,7 +167,7 @@ pub fn handler(rt: &mut Runtime) { for (register, offset) in VM_TO_CONTEXT { // mov rax, [rax + ...] - utils::vreg::load_reg(rt, r12, *register, rax); + utils::register::load(rt, r12, rax, *register); if *register == VMReg::Flags { // mov [r15 + ...], eax diff --git a/runtime/src/vm/handlers/adc.rs b/runtime/src/vm/handlers/adc.rs index 11ede6ef..97450a95 100644 --- a/runtime/src/vm/handlers/adc.rs +++ b/runtime/src/vm/handlers/adc.rs @@ -2,101 +2,104 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Add( - Expression::Operand(Operand::Input(0)), - Expression::Sub( - Box::new(Expression::Sub( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::BitNot(Box::new(Expression::Flag(Flag::Carry)))), - )), - Box::new(Expression::Constant(1)), - ), - )], - flags: Flags::Always(vec![ - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitOr( - Box::new(Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Input(1))), - )), - Box::new(Expression::BitAnd( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Input(1))), - )), - Box::new(Expression::BitNot(Box::new(Expression::Operand( - Operand::Output(0), - )))), - )), - ), - Expression::SignBit, - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitAnd( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - ), - Expression::SignBit, - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ( - Flag::Auxiliary, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitXor( +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Add( + Expression::Operand(Operand::Input(0)), + Expression::Sub( + Box::new(Expression::Sub( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::BitNot(Box::new(Expression::Flag(Flag::Carry)))), + )), + Box::new(Expression::Immediate(Immediate::Fixed(1))), + ), + )], + flags: Flags::Always(vec![ + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitOr( + Box::new(Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Input(1))), + )), + Box::new(Expression::BitAnd( Box::new(Expression::BitXor( Box::new(Expression::Operand(Operand::Input(0))), Box::new(Expression::Operand(Operand::Input(1))), )), + Box::new(Expression::BitNot(Box::new(Expression::Operand( + Operand::Output(0), + )))), + )), + ), + Expression::SignBit, + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitAnd( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), Box::new(Expression::Operand(Operand::Output(0))), - ), - Expression::Constant(4), - ))), - ), - ]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - ], - }, - ); + )), + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::Operand(Operand::Output(0))), + )), + ), + Expression::SignBit, + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), + ( + Flag::Auxiliary, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitXor( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Input(1))), + )), + Box::new(Expression::Operand(Operand::Output(0))), + ), + Expression::Immediate(Immediate::Fixed(4)), + ))), + ), + ]), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/add.rs b/runtime/src/vm/handlers/add.rs index 9e762533..8e800b00 100644 --- a/runtime/src/vm/handlers/add.rs +++ b/runtime/src/vm/handlers/add.rs @@ -2,81 +2,84 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Add( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::Always(vec![ - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::LessThan( - Expression::Operand(Operand::Output(0)), - Expression::Operand(Operand::Input(0)), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitAnd( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - ), - Expression::SignBit, - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ( - Flag::Auxiliary, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitXor( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Input(1))), - )), +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Add( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::Always(vec![ + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::LessThan( + Expression::Operand(Operand::Output(0)), + Expression::Operand(Operand::Input(0)), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitAnd( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), Box::new(Expression::Operand(Operand::Output(0))), - ), - Expression::Constant(4), - ))), - ), - ]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - ], - }, - ); + )), + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::Operand(Operand::Output(0))), + )), + ), + Expression::SignBit, + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), + ( + Flag::Auxiliary, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitXor( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Input(1))), + )), + Box::new(Expression::Operand(Operand::Output(0))), + ), + Expression::Immediate(Immediate::Fixed(4)), + ))), + ), + ]), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/and.rs b/runtime/src/vm/handlers/and.rs index d37ea58c..f763e437 100644 --- a/runtime/src/vm/handlers/and.rs +++ b/runtime/src/vm/handlers/and.rs @@ -2,59 +2,62 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::And( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::Always(vec![ + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::Equal( + Expression::Immediate(Immediate::Fixed(1)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::Equal( + Expression::Immediate(Immediate::Fixed(1)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), + ]), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::And( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::Always(vec![ - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::Equal( - Expression::Constant(1), - Expression::Constant(0), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::Equal( - Expression::Constant(1), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - ], - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/back.rs b/runtime/src/vm/handlers/back.rs new file mode 100644 index 00000000..62035852 --- /dev/null +++ b/runtime/src/vm/handlers/back.rs @@ -0,0 +1,37 @@ +use crate::{ + runtime::Runtime, + vm::{ + bytecode::VMReg, + handlers::semantic::{ + self, Effect, Expression, Flags, Immediate, Operand, Operation, Register, + }, + }, +}; + +pub fn operation() -> Operation { + Operation { + effects: vec![ + Effect::Register( + Register::Fixed(VMReg::NBranch), + Expression::Memory(Box::new(Expression::Register(Register::Fixed(VMReg::Rsp)))), + ), + Effect::Register( + Register::Fixed(VMReg::Rsp), + Expression::Add( + Box::new(Expression::Register(Register::Fixed(VMReg::Rsp))), + Box::new(Expression::Add( + Box::new(Expression::Immediate(Immediate::Fixed(8))), + Box::new(Expression::Operand(Operand::Input(0))), + )), + ), + ), + ], + flags: Flags::Never, + stores: None, + widths: &[], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/bit_scan_reverse.rs b/runtime/src/vm/handlers/bit_scan_reverse.rs index 5b8ecd62..9fbeae8b 100644 --- a/runtime/src/vm/handlers/bit_scan_reverse.rs +++ b/runtime/src/vm/handlers/bit_scan_reverse.rs @@ -2,27 +2,30 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; +pub fn operation() -> Operation { + Operation { + effects: vec![ + Effect::Push(Expression::Operand(Operand::Input(0))), + Effect::Bsr(Expression::Operand(Operand::Input(1))), + ], + flags: Flags::Always(vec![( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Input(1)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + )]), + stores: None, + widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], + } +} + pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![ - Effect::Assign(Expression::Operand(Operand::Input(0))), - Effect::Bsr(Expression::Operand(Operand::Input(1))), - ], - flags: Flags::Always(vec![( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Input(1)), - Expression::Constant(0), - ))), - )]), - stores: None, - widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/bit_test.rs b/runtime/src/vm/handlers/bit_test.rs index d220eed4..b84a977f 100644 --- a/runtime/src/vm/handlers/bit_test.rs +++ b/runtime/src/vm/handlers/bit_test.rs @@ -6,23 +6,24 @@ use crate::{ }, }; +pub fn operation() -> Operation { + Operation { + effects: vec![], + flags: Flags::Always(vec![( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Input(0)), + Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::SignBit), + ), + ))), + )]), + stores: Some(vec![Expression::Operand(Operand::Input(0))]), + widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], + } +} + pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![], - flags: Flags::Always(vec![( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Input(0)), - Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::SignBit), - ), - ))), - )]), - stores: Some(vec![Expression::Operand(Operand::Input(0))]), - widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/bit_test_complement.rs b/runtime/src/vm/handlers/bit_test_complement.rs index c1c88eef..7fe418f2 100644 --- a/runtime/src/vm/handlers/bit_test_complement.rs +++ b/runtime/src/vm/handlers/bit_test_complement.rs @@ -2,36 +2,39 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Xor( +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Xor( + Expression::Operand(Operand::Input(0)), + Expression::BitShl( + Box::new(Expression::Immediate(Immediate::Fixed(1))), + Box::new(Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::SignBit), + )), + ), + )], + flags: Flags::Always(vec![( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( Expression::Operand(Operand::Input(0)), - Expression::BitShl( - Box::new(Expression::Constant(1)), - Box::new(Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::SignBit), - )), + Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::SignBit), ), - )], - flags: Flags::Always(vec![( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Input(0)), - Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::SignBit), - ), - ))), - )]), - stores: None, - widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], - }, - ); + ))), + )]), + stores: None, + widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/bit_test_reset.rs b/runtime/src/vm/handlers/bit_test_reset.rs index 56009a05..7051b2b7 100644 --- a/runtime/src/vm/handlers/bit_test_reset.rs +++ b/runtime/src/vm/handlers/bit_test_reset.rs @@ -2,36 +2,39 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::And( +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::And( + Expression::Operand(Operand::Input(0)), + Expression::BitNot(Box::new(Expression::BitShl( + Box::new(Expression::Immediate(Immediate::Fixed(1))), + Box::new(Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::SignBit), + )), + ))), + )], + flags: Flags::Always(vec![( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( Expression::Operand(Operand::Input(0)), - Expression::BitNot(Box::new(Expression::BitShl( - Box::new(Expression::Constant(1)), - Box::new(Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::SignBit), - )), - ))), - )], - flags: Flags::Always(vec![( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Input(0)), - Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::SignBit), - ), - ))), - )]), - stores: None, - widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], - }, - ); + Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::SignBit), + ), + ))), + )]), + stores: None, + widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/bit_test_set.rs b/runtime/src/vm/handlers/bit_test_set.rs index c8513b0e..dbfab494 100644 --- a/runtime/src/vm/handlers/bit_test_set.rs +++ b/runtime/src/vm/handlers/bit_test_set.rs @@ -2,36 +2,39 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Or( +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Or( + Expression::Operand(Operand::Input(0)), + Expression::BitShl( + Box::new(Expression::Immediate(Immediate::Fixed(1))), + Box::new(Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::SignBit), + )), + ), + )], + flags: Flags::Always(vec![( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( Expression::Operand(Operand::Input(0)), - Expression::BitShl( - Box::new(Expression::Constant(1)), - Box::new(Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::SignBit), - )), + Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::SignBit), ), - )], - flags: Flags::Always(vec![( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Input(0)), - Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::SignBit), - ), - ))), - )]), - stores: None, - widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], - }, - ); + ))), + )]), + stores: None, + widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/branch.rs b/runtime/src/vm/handlers/branch.rs new file mode 100644 index 00000000..7798b2c3 --- /dev/null +++ b/runtime/src/vm/handlers/branch.rs @@ -0,0 +1,120 @@ +use crate::{ + mapper::Mappable, + runtime::Runtime, + vm::{ + bytecode::{VMLogic, VMReg, VMTest, VMWidth}, + handlers::semantic::{ + self, + builder::{self, Builder, Value}, + Operation, + }, + }, +}; + +fn keys(rt: &mut Runtime, variants: &[T]) -> Vec { + variants + .iter() + .map(|variant| rt.mapper.index(*variant) as u64) + .collect() +} + +pub fn build(rt: &mut Runtime) { + let operation = operation(rt); + semantic::compiler::compile(rt, &operation); +} + +pub fn operation(rt: &mut Runtime) -> Operation { + let all = keys(rt, &[VMLogic::JAND, VMLogic::CAND, VMLogic::SAND]); + let any = keys(rt, &[VMLogic::JOR, VMLogic::COR, VMLogic::SOR]); + let parity = keys(rt, &[VMLogic::JXOR, VMLogic::CXOR, VMLogic::SXOR]); + + let jump = keys(rt, &[VMLogic::JAND, VMLogic::JOR, VMLogic::JXOR]); + let call = keys(rt, &[VMLogic::CAND, VMLogic::COR, VMLogic::CXOR]); + let skip = keys(rt, &[VMLogic::SAND, VMLogic::SOR, VMLogic::SXOR]); + + let compare = keys(rt, &[VMTest::CMP]); + let equal = keys(rt, &[VMTest::EQ]); + let unequal = keys(rt, &[VMTest::NEQ]); + + builder::build(|b| { + let logic = b.read(VMWidth::Lower8); + let accumulator = b.variable(); + + b.dispatch(logic, |s| { + s.on(all.clone(), |b| { + let value = b.constant(1); + b.set(accumulator, value); + }); + s.on([any.clone(), parity.clone()].concat(), |b| { + let value = b.constant(0); + b.set(accumulator, value); + }); + }); + + b.repeat(|b| { + let test = b.read(VMWidth::Lower8); + let lhs = b.read(VMWidth::Lower8); + let lhs = b.decrypt(lhs); + let rhs = b.read(VMWidth::Lower8); + let rhs = b.decrypt(rhs); + + let condition = b.select(test, |s| { + s.on(compare, |b| { + let lhs = b.flag(lhs); + b.equal(lhs, rhs) + }); + s.on(equal, |b| { + let lhs = b.flag(lhs); + let rhs = b.flag(rhs); + b.equal(lhs, rhs) + }); + s.on(unequal, |b| { + let lhs = b.flag(lhs); + let rhs = b.flag(rhs); + b.unequal(lhs, rhs) + }); + }); + + let fold = |b: &mut Builder, folded: Value| b.set(accumulator, folded); + + b.dispatch(logic, |s| { + s.on(all.clone(), |b| { + let acc = b.get(accumulator); + let folded = b.and(acc, condition); + fold(b, folded); + }); + s.on(any.clone(), |b| { + let acc = b.get(accumulator); + let folded = b.or(acc, condition); + fold(b, folded); + }); + s.on(parity.clone(), |b| { + let acc = b.get(accumulator); + let folded = b.xor(acc, condition); + fold(b, folded); + }); + }); + }); + + let taken = b.get(accumulator); + + b.when(taken, |b| { + b.dispatch(logic, |s| { + s.on(jump, |b| { + let target = b.input(0); + b.store(VMReg::NBranch, target); + }); + s.on(call, |b| { + let target = b.input(0); + b.store(VMReg::NBranch, target); + let exit = b.register(VMReg::NExit); + b.push(exit); + }); + s.on(skip, |b| { + let distance = b.input(0); + b.advance(distance); + }); + }); + }); + }) +} diff --git a/runtime/src/vm/handlers/byte_swap.rs b/runtime/src/vm/handlers/byte_swap.rs index a966e126..121b8629 100644 --- a/runtime/src/vm/handlers/byte_swap.rs +++ b/runtime/src/vm/handlers/byte_swap.rs @@ -2,120 +2,121 @@ use crate::{ runtime::Runtime, vm::{ bytecode::VMWidth, - handlers::semantic::{self, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{self, Effect, Expression, Flags, Immediate, Operand, Operation}, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![ - Effect::Assign(Expression::BitAnd( +pub fn operation() -> Operation { + Operation { + effects: vec![ + Effect::Push(Expression::BitAnd( + Box::new(Expression::BitShr( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Sub( + Box::new(Expression::BitSize), + Box::new(Expression::Immediate(Immediate::Fixed(8))), + )), + )), + Box::new(Expression::Immediate(Immediate::Fixed(0xFF))), + )), + Effect::Or( + Expression::Operand(Operand::Output(0)), + Expression::BitAnd( Box::new(Expression::BitShr( Box::new(Expression::Operand(Operand::Input(0))), Box::new(Expression::Sub( Box::new(Expression::BitSize), - Box::new(Expression::Constant(8)), + Box::new(Expression::Immediate(Immediate::Fixed(24))), )), )), - Box::new(Expression::Constant(0xFF)), - )), - Effect::Or( - Expression::Operand(Operand::Output(0)), - Expression::BitAnd( - Box::new(Expression::BitShr( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Sub( - Box::new(Expression::BitSize), - Box::new(Expression::Constant(24)), - )), - )), - Box::new(Expression::Constant(0xFF00)), - ), + Box::new(Expression::Immediate(Immediate::Fixed(0xFF00))), ), - Effect::Or( - Expression::Operand(Operand::Output(0)), - Expression::BitAnd( - Box::new(Expression::BitShr( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Sub( - Box::new(Expression::BitSize), - Box::new(Expression::Constant(40)), - )), + ), + Effect::Or( + Expression::Operand(Operand::Output(0)), + Expression::BitAnd( + Box::new(Expression::BitShr( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Sub( + Box::new(Expression::BitSize), + Box::new(Expression::Immediate(Immediate::Fixed(40))), )), - Box::new(Expression::Constant(0xFF_0000)), - ), + )), + Box::new(Expression::Immediate(Immediate::Fixed(0xFF_0000))), ), - Effect::Or( - Expression::Operand(Operand::Output(0)), - Expression::BitAnd( - Box::new(Expression::BitShr( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Sub( - Box::new(Expression::BitSize), - Box::new(Expression::Constant(56)), - )), + ), + Effect::Or( + Expression::Operand(Operand::Output(0)), + Expression::BitAnd( + Box::new(Expression::BitShr( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Sub( + Box::new(Expression::BitSize), + Box::new(Expression::Immediate(Immediate::Fixed(56))), )), - Box::new(Expression::Constant(0xFF_000000)), - ), + )), + Box::new(Expression::Immediate(Immediate::Fixed(0xFF_000000))), ), - Effect::Or( - Expression::Operand(Operand::Output(0)), - Expression::BitAnd( - Box::new(Expression::BitShl( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Sub( - Box::new(Expression::BitSize), - Box::new(Expression::Constant(56)), - )), + ), + Effect::Or( + Expression::Operand(Operand::Output(0)), + Expression::BitAnd( + Box::new(Expression::BitShl( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Sub( + Box::new(Expression::BitSize), + Box::new(Expression::Immediate(Immediate::Fixed(56))), )), - Box::new(Expression::ByteMask(3)), - ), + )), + Box::new(Expression::ByteMask(3)), ), - Effect::Or( - Expression::Operand(Operand::Output(0)), - Expression::BitAnd( - Box::new(Expression::BitShl( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Sub( - Box::new(Expression::BitSize), - Box::new(Expression::Constant(40)), - )), + ), + Effect::Or( + Expression::Operand(Operand::Output(0)), + Expression::BitAnd( + Box::new(Expression::BitShl( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Sub( + Box::new(Expression::BitSize), + Box::new(Expression::Immediate(Immediate::Fixed(40))), )), - Box::new(Expression::ByteMask(2)), - ), + )), + Box::new(Expression::ByteMask(2)), ), - Effect::Or( - Expression::Operand(Operand::Output(0)), - Expression::BitAnd( - Box::new(Expression::BitShl( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Sub( - Box::new(Expression::BitSize), - Box::new(Expression::Constant(24)), - )), + ), + Effect::Or( + Expression::Operand(Operand::Output(0)), + Expression::BitAnd( + Box::new(Expression::BitShl( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Sub( + Box::new(Expression::BitSize), + Box::new(Expression::Immediate(Immediate::Fixed(24))), )), - Box::new(Expression::ByteMask(1)), - ), + )), + Box::new(Expression::ByteMask(1)), ), - Effect::Or( - Expression::Operand(Operand::Output(0)), - Expression::BitAnd( - Box::new(Expression::BitShl( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Sub( - Box::new(Expression::BitSize), - Box::new(Expression::Constant(8)), - )), + ), + Effect::Or( + Expression::Operand(Operand::Output(0)), + Expression::BitAnd( + Box::new(Expression::BitShl( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Sub( + Box::new(Expression::BitSize), + Box::new(Expression::Immediate(Immediate::Fixed(8))), )), - Box::new(Expression::ByteMask(0)), - ), + )), + Box::new(Expression::ByteMask(0)), ), - ], - flags: Flags::Always(vec![]), - stores: None, - widths: &[VMWidth::Lower64, VMWidth::Lower32], - }, - ); + ), + ], + flags: Flags::Never, + stores: None, + widths: &[VMWidth::Lower64, VMWidth::Lower32], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/compare_exchange.rs b/runtime/src/vm/handlers/compare_exchange.rs index 76e4b467..2992f883 100644 --- a/runtime/src/vm/handlers/compare_exchange.rs +++ b/runtime/src/vm/handlers/compare_exchange.rs @@ -2,97 +2,100 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::CompareExchange( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - Expression::Operand(Operand::Input(2)), - )], - flags: Flags::Always(vec![ - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Sub( +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::CompareExchange( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + Expression::Operand(Operand::Input(2)), + )], + flags: Flags::Always(vec![ + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Sub( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Output(0))), + ), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Sub( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Output(0))), + ), + Expression::SignBit, + ))), + ), + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::LessThan( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Output(0)), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitAnd( + Box::new(Expression::BitXor( Box::new(Expression::Operand(Operand::Input(0))), Box::new(Expression::Operand(Operand::Output(0))), - ), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Sub( + )), + Box::new(Expression::BitXor( Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(0))), - ), - Expression::SignBit, - ))), - ), - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::LessThan( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Output(0)), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitAnd( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Sub( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - )), - ), - Expression::SignBit, - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Sub( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(0))), - ))), - ), - ( - Flag::Auxiliary, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitXor( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(0))), - )), Box::new(Expression::Sub( Box::new(Expression::Operand(Operand::Input(0))), Box::new(Expression::Operand(Operand::Output(0))), )), - ), - Expression::Constant(4), - ))), - ), - ]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - ], - }, - ); + )), + ), + Expression::SignBit, + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Sub( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Output(0))), + ))), + ), + ( + Flag::Auxiliary, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitXor( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Output(0))), + )), + Box::new(Expression::Sub( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Output(0))), + )), + ), + Expression::Immediate(Immediate::Fixed(4)), + ))), + ), + ]), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/compound.rs b/runtime/src/vm/handlers/compound.rs new file mode 100644 index 00000000..5b7e21bd --- /dev/null +++ b/runtime/src/vm/handlers/compound.rs @@ -0,0 +1,20 @@ +use iced_x86::code_asm::{r8, r8d, rcx, CodeLabel}; + +use crate::{runtime::Runtime, vm::utils}; + +pub fn build(rt: &mut Runtime) { + let cases = rt + .compound_labels + .iter() + .enumerate() + .map(|(index, &label)| (index as u8, label)) + .collect::>(); + + // r8d -> index + utils::bytecode::read_byte_zx(rt, rcx, r8d); + + rt.calls(r8, cases); + + // ret + rt.asm.ret().unwrap(); +} diff --git a/runtime/src/vm/handlers/cpuid.rs b/runtime/src/vm/handlers/cpuid.rs new file mode 100644 index 00000000..4c1774bc --- /dev/null +++ b/runtime/src/vm/handlers/cpuid.rs @@ -0,0 +1,17 @@ +use crate::{ + runtime::Runtime, + vm::handlers::semantic::{self, Effect, Flags, Operation}, +}; + +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Cpuid], + flags: Flags::Never, + stores: None, + widths: &[], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/discard.rs b/runtime/src/vm/handlers/discard.rs index 9c41f51a..70bcdf55 100644 --- a/runtime/src/vm/handlers/discard.rs +++ b/runtime/src/vm/handlers/discard.rs @@ -1,17 +1,17 @@ -use iced_x86::code_asm::{r12, rax, rcx}; - use crate::{ runtime::Runtime, - vm::{bytecode::VMReg, utils::vreg}, + vm::handlers::semantic::{self, Effect, Expression, Flags, Operand, Operation}, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - // add [r12 + ...], 0x8 - vreg::add_imm(rt, r12, 0x8, VMReg::VScratch); +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Drop(Expression::Operand(Operand::Input(0)))], + flags: Flags::Never, + stores: None, + widths: &[], + } +} - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/dispatch.rs b/runtime/src/vm/handlers/dispatch.rs deleted file mode 100644 index ed83032b..00000000 --- a/runtime/src/vm/handlers/dispatch.rs +++ /dev/null @@ -1,48 +0,0 @@ -use iced_x86::code_asm::{r12, r8, CodeLabel}; - -use crate::{ - runtime::Runtime, - vm::{functions::dispatch::HANDLERS, utils::scratch}, -}; - -pub fn build(rt: &mut Runtime) { - // load r8 - scratch::load(rt, r12, r8); - - #[cfg(feature = "profile")] - { - use crate::debug::print_thread_message; - use crate::mapper::Mappable; - use crate::vm::bytecode::VMOp; - - let mut epilogue = rt.asm.create_label(); - - let mut cases = Vec::new(); - - for op in VMOp::VARIANTS { - cases.push((rt.mapper.index(*op), rt.asm.create_label())); - } - - rt.jumps(r8, cases.clone()); - - for (op, (_, mut label)) in VMOp::VARIANTS.iter().zip(cases) { - rt.asm.set_label(&mut label).unwrap(); - - print_thread_message(rt, &format!("{:?}", op), None, None); - - rt.asm.jmp(epilogue).unwrap(); - } - - rt.asm.set_label(&mut epilogue).unwrap(); - } - - let cases = HANDLERS - .iter() - .map(|&(op, def)| (rt.mapper.index(op), rt.function_labels[&def])) - .collect::>(); - - rt.calls(r8, cases); - - // ret - rt.asm.ret().unwrap(); -} diff --git a/runtime/src/vm/handlers/div.rs b/runtime/src/vm/handlers/div.rs index 63874f54..6dc441ef 100644 --- a/runtime/src/vm/handlers/div.rs +++ b/runtime/src/vm/handlers/div.rs @@ -6,27 +6,28 @@ use crate::{ }, }; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Div( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + Expression::Operand(Operand::Input(2)), + )], + flags: Flags::Never, + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + VMWidth::SLower64, + VMWidth::SLower32, + VMWidth::SLower16, + VMWidth::SLower8, + ], + } +} + pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Div( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - Expression::Operand(Operand::Input(2)), - )], - flags: Flags::Always(vec![]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - VMWidth::SLower64, - VMWidth::SLower32, - VMWidth::SLower16, - VMWidth::SLower8, - ], - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/exchange.rs b/runtime/src/vm/handlers/exchange.rs index 94ebe025..bf424abb 100644 --- a/runtime/src/vm/handlers/exchange.rs +++ b/runtime/src/vm/handlers/exchange.rs @@ -6,22 +6,23 @@ use crate::{ }, }; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Exchange( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::Never, + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Exchange( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::Always(vec![]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - ], - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/exchange_add.rs b/runtime/src/vm/handlers/exchange_add.rs index fb5761cf..114a57f5 100644 --- a/runtime/src/vm/handlers/exchange_add.rs +++ b/runtime/src/vm/handlers/exchange_add.rs @@ -2,81 +2,84 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::ExchangeAdd( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::Always(vec![ - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::LessThan( - Expression::Operand(Operand::Output(0)), - Expression::Operand(Operand::Input(0)), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitAnd( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Output(1))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - ), - Expression::SignBit, - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ( - Flag::Auxiliary, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitXor( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(1))), - )), +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::ExchangeAdd( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::Always(vec![ + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::LessThan( + Expression::Operand(Operand::Output(0)), + Expression::Operand(Operand::Input(0)), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitAnd( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), Box::new(Expression::Operand(Operand::Output(0))), - ), - Expression::Constant(4), - ))), - ), - ]), - stores: Some(vec![Expression::Operand(Operand::Output(1))]), - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - ], - }, - ); + )), + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Output(1))), + Box::new(Expression::Operand(Operand::Output(0))), + )), + ), + Expression::SignBit, + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), + ( + Flag::Auxiliary, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitXor( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Output(1))), + )), + Box::new(Expression::Operand(Operand::Output(0))), + ), + Expression::Immediate(Immediate::Fixed(4)), + ))), + ), + ]), + stores: Some(vec![Expression::Operand(Operand::Output(1))]), + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/jcc.rs b/runtime/src/vm/handlers/jcc.rs deleted file mode 100644 index 04106cab..00000000 --- a/runtime/src/vm/handlers/jcc.rs +++ /dev/null @@ -1,554 +0,0 @@ -use crate::vm::bytecode::{VMLogic, VMTest}; -use crate::vm::utils::{self}; -use crate::{runtime::Runtime, vm::bytecode::VMReg}; -use iced_x86::code_asm::{ - eax, r12, r13, r13d, r14, r14d, r15, r15b, r8, r8b, r8d, r9, r9b, r9d, rax, rcx, -}; - -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut or_entry = rt.asm.create_label(); - let mut or_loop = rt.asm.create_label(); - let mut or_cmp = rt.asm.create_label(); - let mut or_eq = rt.asm.create_label(); - let mut or_neq = rt.asm.create_label(); - let mut or_fold = rt.asm.create_label(); - - let mut and_entry = rt.asm.create_label(); - let mut and_loop = rt.asm.create_label(); - let mut and_cmp = rt.asm.create_label(); - let mut and_eq = rt.asm.create_label(); - let mut and_neq = rt.asm.create_label(); - let mut and_fold = rt.asm.create_label(); - - let mut xor_entry = rt.asm.create_label(); - let mut xor_loop = rt.asm.create_label(); - let mut xor_cmp = rt.asm.create_label(); - let mut xor_eq = rt.asm.create_label(); - let mut xor_neq = rt.asm.create_label(); - let mut xor_fold = rt.asm.create_label(); - - let mut validate = rt.asm.create_label(); - - let mut handle_jump = rt.asm.create_label(); - let mut handle_call = rt.asm.create_label(); - let mut handle_skip = rt.asm.create_label(); - - let mut epilogue = rt.asm.create_label(); - - // push r13 - rt.asm.push(r13).unwrap(); - // push r14 - rt.asm.push(r14).unwrap(); - // push r15 - rt.asm.push(r15).unwrap(); - - // mov eax, [r12 + ...] - utils::vreg::load_reg32(rt, r12, VMReg::Flags, eax); - - // r13d -> logic - utils::bytecode::read_byte_zx(rt, rcx, r13d); - - // r14d -> conditions - utils::bytecode::read_byte_zx(rt, rcx, r14d); - - let cases = vec![ - (rt.mapper.index(VMLogic::JAND) as u8, and_entry), - (rt.mapper.index(VMLogic::CAND) as u8, and_entry), - (rt.mapper.index(VMLogic::SAND) as u8, and_entry), - (rt.mapper.index(VMLogic::JXOR) as u8, xor_entry), - (rt.mapper.index(VMLogic::CXOR) as u8, xor_entry), - (rt.mapper.index(VMLogic::SXOR) as u8, xor_entry), - (rt.mapper.index(VMLogic::JOR) as u8, or_entry), - (rt.mapper.index(VMLogic::COR) as u8, or_entry), - (rt.mapper.index(VMLogic::SOR) as u8, or_entry), - ]; - - rt.jumps(r13, cases); - - rt.asm.set_label(&mut and_entry).unwrap(); - // mov r15b, 0x1 - rt.asm.mov(r15b, 1i32).unwrap(); - // jmp ... - rt.asm.jmp(and_loop).unwrap(); - - rt.asm.set_label(&mut or_entry).unwrap(); - // xor r15b, r15b - rt.asm.xor(r15b, r15b).unwrap(); - // jmp ... - rt.asm.jmp(or_loop).unwrap(); - - rt.asm.set_label(&mut xor_entry).unwrap(); - // xor r15b, r15b - rt.asm.xor(r15b, r15b).unwrap(); - // jmp ... - rt.asm.jmp(xor_loop).unwrap(); - - // Iterates through conditions accumulating their results into the accumulator via OR - rt.asm.set_label(&mut or_loop).unwrap(); - { - // test r14d, r14d - rt.asm.test(r14d, r14d).unwrap(); - // jz ... - rt.asm.jz(validate).unwrap(); - - // r8b -> test - utils::bytecode::read_byte(rt, rcx, r8b); - - // cmp r8b, ... - rt.asm - .cmp(r8b, rt.mapper.index(VMTest::CMP) as i32) - .unwrap(); - // jz ... - rt.asm.jz(or_cmp).unwrap(); - // cmp r8b, ... - rt.asm.cmp(r8b, rt.mapper.index(VMTest::EQ) as i32).unwrap(); - // je ... - rt.asm.je(or_eq).unwrap(); - // jmp ... - rt.asm.jmp(or_neq).unwrap(); - } - - // Compares the bit in flags specified by the flag bit (lhs) with the set state (rhs) - rt.asm.set_label(&mut or_cmp).unwrap(); - { - // r8d -> lhs - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> rhs - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - - // imul r9, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r9); - // sub r9, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r9); - - // bt eax, r8d - rt.asm.bt(eax, r8d).unwrap(); - // setc r8b - rt.asm.setc(r8b).unwrap(); - // cmp r8b, r9b - rt.asm.cmp(r8b, r9b).unwrap(); - // sete r8b - rt.asm.sete(r8b).unwrap(); - // jmp ... - rt.asm.jmp(or_fold).unwrap(); - } - - // Checks if the bit in flags specified by the first flag bit (lhs) == the bit in flags specified by the second flag bit (rhs) - rt.asm.set_label(&mut or_eq).unwrap(); - { - // r8d -> lhs - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> rhs - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - - // imul r9, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r9); - // sub r9, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r9); - - // bt eax, r8d - rt.asm.bt(eax, r8d).unwrap(); - // setc r8b - rt.asm.setc(r8b).unwrap(); - // bt eax, r9d - rt.asm.bt(eax, r9d).unwrap(); - // setc r9b - rt.asm.setc(r9b).unwrap(); - // cmp r8b, r9b - rt.asm.cmp(r8b, r9b).unwrap(); - // sete r8b - rt.asm.sete(r8b).unwrap(); - // jmp ... - rt.asm.jmp(or_fold).unwrap(); - } - - // Checks if the bit in flags specified by the first flag bit (lhs) != the bit in flags specified by the second flag bit (rhs) - rt.asm.set_label(&mut or_neq).unwrap(); - { - // r8d -> lhs - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> rhs - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - - // imul r9, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r9); - // sub r9, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r9); - - // bt eax, r8d - rt.asm.bt(eax, r8d).unwrap(); - // setc r8b - rt.asm.setc(r8b).unwrap(); - // bt eax, r9d - rt.asm.bt(eax, r9d).unwrap(); - // setc r9b - rt.asm.setc(r9b).unwrap(); - // cmp r8b, r9b - rt.asm.cmp(r8b, r9b).unwrap(); - // setne r8b - rt.asm.setne(r8b).unwrap(); - - rt.asm.jmp(or_fold).unwrap(); - } - - // Folds the current condition's result into the accumulator via OR and loops back - rt.asm.set_label(&mut or_fold).unwrap(); - { - // or r15b, r8b - rt.asm.or(r15b, r8b).unwrap(); - // dec r14d - rt.asm.dec(r14d).unwrap(); - // jmp ... - rt.asm.jmp(or_loop).unwrap(); - } - - // Iterates through conditions accumulating their results into the accumulator via AND - rt.asm.set_label(&mut and_loop).unwrap(); - { - // test r14d, r14d - rt.asm.test(r14d, r14d).unwrap(); - // jz ... - rt.asm.jz(validate).unwrap(); - - // r8b -> test - utils::bytecode::read_byte(rt, rcx, r8b); - - // cmp r8b, ... - rt.asm - .cmp(r8b, rt.mapper.index(VMTest::CMP) as i32) - .unwrap(); - // jz ... - rt.asm.jz(and_cmp).unwrap(); - // cmp r8b, ... - rt.asm.cmp(r8b, rt.mapper.index(VMTest::EQ) as i32).unwrap(); - // je ... - rt.asm.je(and_eq).unwrap(); - // jmp ... - rt.asm.jmp(and_neq).unwrap(); - } - - // Compares the bit in flags specified by the flag bit (lhs) with the set state (rhs) - rt.asm.set_label(&mut and_cmp).unwrap(); - { - // r8d -> lhs - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> rhs - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - - // imul r9, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r9); - // sub r9, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r9); - - // bt eax, r8d - rt.asm.bt(eax, r8d).unwrap(); - // setc r8b - rt.asm.setc(r8b).unwrap(); - // cmp r8b, r9b - rt.asm.cmp(r8b, r9b).unwrap(); - // sete r8b - rt.asm.sete(r8b).unwrap(); - // jmp ... - rt.asm.jmp(and_fold).unwrap(); - } - - // Checks if the bit in flags specified by the first flag bit (lhs) == the bit in flags specified by the second flag bit (rhs) - rt.asm.set_label(&mut and_eq).unwrap(); - { - // r8d -> lhs - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> rhs - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - - // imul r9, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r9); - // sub r9, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r9); - - // bt eax, r8d - rt.asm.bt(eax, r8d).unwrap(); - // setc r8b - rt.asm.setc(r8b).unwrap(); - // bt eax, r9d - rt.asm.bt(eax, r9d).unwrap(); - // setc r9b - rt.asm.setc(r9b).unwrap(); - // cmp r8b, r9b - rt.asm.cmp(r8b, r9b).unwrap(); - // sete r8b - rt.asm.sete(r8b).unwrap(); - // jmp ... - rt.asm.jmp(and_fold).unwrap(); - } - - // Checks if the bit in flags specified by the first flag bit (lhs) != the bit in flags specified by the second flag bit (rhs) - rt.asm.set_label(&mut and_neq).unwrap(); - { - // r8d -> lhs - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> rhs - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - - // imul r9, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r9); - // sub r9, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r9); - - // bt eax, r8d - rt.asm.bt(eax, r8d).unwrap(); - // setc r8b - rt.asm.setc(r8b).unwrap(); - // bt eax, r9d - rt.asm.bt(eax, r9d).unwrap(); - // setc r9b - rt.asm.setc(r9b).unwrap(); - // cmp r8b, r9b - rt.asm.cmp(r8b, r9b).unwrap(); - // setne r8b - rt.asm.setne(r8b).unwrap(); - } - - // Folds the current condition's result into the accumulator via AND and loops back - rt.asm.set_label(&mut and_fold).unwrap(); - { - // and r15b, r8b - rt.asm.and(r15b, r8b).unwrap(); - // dec r14d - rt.asm.dec(r14d).unwrap(); - // jmp ... - rt.asm.jmp(and_loop).unwrap(); - } - - // Iterates through conditions accumulating their results into the accumulator via XOR - rt.asm.set_label(&mut xor_loop).unwrap(); - { - // test r14d, r14d - rt.asm.test(r14d, r14d).unwrap(); - // jz ... - rt.asm.jz(validate).unwrap(); - - // r8b -> test - utils::bytecode::read_byte(rt, rcx, r8b); - - // cmp r8b, ... - rt.asm - .cmp(r8b, rt.mapper.index(VMTest::CMP) as i32) - .unwrap(); - // jz ... - rt.asm.jz(xor_cmp).unwrap(); - // cmp r8b, ... - rt.asm.cmp(r8b, rt.mapper.index(VMTest::EQ) as i32).unwrap(); - // je ... - rt.asm.je(xor_eq).unwrap(); - // jmp ... - rt.asm.jmp(xor_neq).unwrap(); - } - - // Compares the bit in flags specified by the flag bit (lhs) with the set state (rhs) - rt.asm.set_label(&mut xor_cmp).unwrap(); - { - // r8d -> lhs - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> rhs - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - - // imul r9, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r9); - // sub r9, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r9); - - // bt eax, r8d - rt.asm.bt(eax, r8d).unwrap(); - // setc r8b - rt.asm.setc(r8b).unwrap(); - // cmp r8b, r9b - rt.asm.cmp(r8b, r9b).unwrap(); - // sete r8b - rt.asm.sete(r8b).unwrap(); - // jmp ... - rt.asm.jmp(xor_fold).unwrap(); - } - - // Checks if the bit in flags specified by the first flag bit (lhs) == the bit in flags specified by the second flag bit (rhs) - rt.asm.set_label(&mut xor_eq).unwrap(); - { - // r8d -> lhs - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> rhs - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - - // imul r9, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r9); - // sub r9, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r9); - - // bt eax, r8d - rt.asm.bt(eax, r8d).unwrap(); - // setc r8b - rt.asm.setc(r8b).unwrap(); - // bt eax, r9d - rt.asm.bt(eax, r9d).unwrap(); - // setc r9b - rt.asm.setc(r9b).unwrap(); - // cmp r8b, r9b - rt.asm.cmp(r8b, r9b).unwrap(); - // sete r8b - rt.asm.sete(r8b).unwrap(); - // jmp ... - rt.asm.jmp(xor_fold).unwrap(); - } - - // Checks if the bit in flags specified by the first flag bit (lhs) != the bit in flags specified by the second flag bit (rhs) - rt.asm.set_label(&mut xor_neq).unwrap(); - { - // r8d -> lhs - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> rhs - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - - // imul r9, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r9); - // sub r9, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r9); - - // bt eax, r8d - rt.asm.bt(eax, r8d).unwrap(); - // setc r8b - rt.asm.setc(r8b).unwrap(); - // bt eax, r9d - rt.asm.bt(eax, r9d).unwrap(); - // setc r9b - rt.asm.setc(r9b).unwrap(); - // cmp r8b, r9b - rt.asm.cmp(r8b, r9b).unwrap(); - // setne r8b - rt.asm.setne(r8b).unwrap(); - } - - // Folds the current condition's result into the accumulator via XOR and loops back - rt.asm.set_label(&mut xor_fold).unwrap(); - { - // xor r15b, r8b - rt.asm.xor(r15b, r8b).unwrap(); - // dec r14d - rt.asm.dec(r14d).unwrap(); - // jmp ... - rt.asm.jmp(xor_loop).unwrap(); - } - - rt.asm.set_label(&mut validate).unwrap(); - { - // load rax - utils::scratch::load(rt, r12, rax); - - // test r15b, r15b - rt.asm.test(r15b, r15b).unwrap(); - // jz ... - rt.asm.jz(epilogue).unwrap(); - - let cases = vec![ - (rt.mapper.index(VMLogic::SAND) as u8, handle_skip), - (rt.mapper.index(VMLogic::SOR) as u8, handle_skip), - (rt.mapper.index(VMLogic::SXOR) as u8, handle_skip), - (rt.mapper.index(VMLogic::CAND) as u8, handle_call), - (rt.mapper.index(VMLogic::COR) as u8, handle_call), - (rt.mapper.index(VMLogic::CXOR) as u8, handle_call), - (rt.mapper.index(VMLogic::JAND) as u8, handle_jump), - (rt.mapper.index(VMLogic::JOR) as u8, handle_jump), - (rt.mapper.index(VMLogic::JXOR) as u8, handle_jump), - ]; - - rt.jumps(r13, cases); - } - - rt.asm.set_label(&mut handle_jump).unwrap(); - { - // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::NBranch); - // jmp ... - rt.asm.jmp(epilogue).unwrap(); - } - - rt.asm.set_label(&mut handle_call).unwrap(); - { - // mov [r12 + ...], rax - utils::vreg::store_reg(rt, r12, rax, VMReg::NBranch); - - // sub [r12 + ...], 0x8 - utils::vreg::sub_imm(rt, r12, 0x8, VMReg::Rsp); - // mov r8, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::NExit, r8); - // mov rax, [r12 + ...]; mov [rax], r8 - utils::vreg::store_mem(rt, r12, VMReg::Rsp, rax, r8); - - // jmp ... - rt.asm.jmp(epilogue).unwrap(); - } - - rt.asm.set_label(&mut handle_skip).unwrap(); - { - // add rcx, rax - rt.asm.add(rcx, rax).unwrap(); - } - - rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - - // pop r15 - rt.asm.pop(r15).unwrap(); - // pop r14 - rt.asm.pop(r14).unwrap(); - // pop r13 - rt.asm.pop(r13).unwrap(); - // ret - rt.asm.ret().unwrap(); - } -} diff --git a/runtime/src/vm/handlers/load_address.rs b/runtime/src/vm/handlers/load_address.rs index d888707b..88bac19a 100644 --- a/runtime/src/vm/handlers/load_address.rs +++ b/runtime/src/vm/handlers/load_address.rs @@ -1,93 +1,37 @@ -use iced_x86::code_asm::{ptr, r12, r8, r8d, r9, r9d, rax, rcx}; - use crate::{ runtime::Runtime, vm::{ - bytecode::{VMReg, VMSeg}, - utils::{self, scratch}, + bytecode::{VMSeg, VMWidth}, + handlers::semantic::{self, builder, Operation}, }, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut add_base = rt.asm.create_label(); - let mut check_index = rt.asm.create_label(); - let mut add_displacement = rt.asm.create_label(); - let mut add_segment = rt.asm.create_label(); - let mut epilogue = rt.asm.create_label(); - - // xor rax, rax - rt.asm.xor(rax, rax).unwrap(); - - // r8d -> base - utils::bytecode::read_byte_zx(rt, rcx, r8d); - - // cmp r8, ... - rt.asm.cmp(r8, rt.mapper.index(VMReg::None) as i32).unwrap(); - // je ... - rt.asm.je(check_index).unwrap(); - - rt.asm.set_label(&mut add_base).unwrap(); - { - // add rax, [r12 + r8*8] - rt.asm.add(rax, ptr(r12 + r8 * 8)).unwrap(); - } - - rt.asm.set_label(&mut check_index).unwrap(); - { - // r8d -> index - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> scale - utils::bytecode::read_byte_zx(rt, rcx, r9d); - // cmp r8, ... - rt.asm.cmp(r8, rt.mapper.index(VMReg::None) as i32).unwrap(); - // je ... - rt.asm.je(add_displacement).unwrap(); - } - - // mov r8, [r12 + r8*8] - rt.asm.mov(r8, ptr(r12 + r8 * 8)).unwrap(); - // imul r8, r9 - rt.asm.imul_2(r8, r9).unwrap(); - // add rax, r8 - rt.asm.add(rax, r8).unwrap(); - - rt.asm.set_label(&mut add_displacement).unwrap(); - { - // r8d -> displacement - utils::bytecode::read_dword(rt, rcx, r8d); - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - // movsxd r8, r8d - rt.asm.movsxd(r8, r8d).unwrap(); - // add rax, r8 - rt.asm.add(rax, r8).unwrap(); - } - - // r8d -> segment - utils::bytecode::read_byte_zx(rt, rcx, r8d); - - // cmp r8, ... - rt.asm.cmp(r8, rt.mapper.index(VMSeg::None) as i32).unwrap(); - // je ... - rt.asm.je(epilogue).unwrap(); - - rt.asm.set_label(&mut add_segment).unwrap(); - { - // add rax, gs:[0x30] - rt.asm.add(rax, ptr(0x30).gs()).unwrap(); - } - - rt.asm.set_label(&mut epilogue).unwrap(); - { - // store rax - scratch::store(rt, r12, rax); +pub fn operation(rt: &mut Runtime) -> Operation { + let none = vec![rt.mapper.index(VMSeg::None) as u64]; + let gs = vec![rt.mapper.index(VMSeg::Gs) as u64]; + + builder::build(|b| { + let base = b.register_operand(); + let index = b.register_operand(); + let scale = b.read(VMWidth::Lower8); + let displacement = b.immediate(VMWidth::SLower32); + + let selector = b.read(VMWidth::Lower8); + let segment = b.select(selector, |s| { + s.on(none, |b| b.constant(0)); + s.on(gs, |b| b.segment()); + }); + + let scaled = b.mul(index, scale); + let address = b.add(base, scaled); + let address = b.add(address, displacement); + let address = b.add(address, segment); + + b.produce(address); + }) +} - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); - } +pub fn build(rt: &mut Runtime) { + let operation = operation(rt); + semantic::compiler::compile(rt, &operation); } diff --git a/runtime/src/vm/handlers/load_immediate.rs b/runtime/src/vm/handlers/load_immediate.rs index f3bda00f..a647904b 100644 --- a/runtime/src/vm/handlers/load_immediate.rs +++ b/runtime/src/vm/handlers/load_immediate.rs @@ -1,110 +1,39 @@ -use iced_x86::code_asm::{eax, r12, r8, r8b, r8d, r8w, rax, rcx}; - use crate::{ runtime::Runtime, vm::{ - bytecode::VMReg, - utils::{self, scratch}, + bytecode::VMWidth, + handlers::semantic::{self, builder, Operation}, }, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut epilogue = rt.asm.create_label(); +const WIDTHS: [VMWidth; 8] = [ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + VMWidth::SLower64, + VMWidth::SLower32, + VMWidth::SLower16, + VMWidth::SLower8, +]; - // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); +pub fn operation(rt: &mut Runtime) -> Operation { + let keys = WIDTHS.map(|width| rt.mapper.index(width) as u64); - utils::width::dispatch( - rt, - rax, - &mut epilogue, - Some(Box::new(|rt| { - // r8 -> source - utils::bytecode::read_qword(rt, rcx, r8); - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - })), - Some(Box::new(|rt| { - // r8d -> source - utils::bytecode::read_dword(rt, rcx, r8d); - // imul r8d, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8d); - // sub r8d, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8d); - })), - None, - Some(Box::new(|rt| { - // r8w -> source - utils::bytecode::read_word_zx(rt, rcx, r8d); - // imul r8w, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8w); - // sub r8w, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8w); - })), - None, - Some(Box::new(|rt| { - // r8b -> source - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // imul r8w, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8w); - // sub r8b, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8b); - // movzx r8w, r8b - rt.asm.movzx(r8w, r8b).unwrap(); - })), - Some(Box::new(|rt| { - // r8 -> source - utils::bytecode::read_qword(rt, rcx, r8); - // imul r8, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8); - // sub r8, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8); - })), - Some(Box::new(|rt| { - // r8d -> source - utils::bytecode::read_dword(rt, rcx, r8d); - // imul r8d, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8d); - // sub r8d, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8d); - // movsxd r8, r8d - rt.asm.movsxd(r8, r8d).unwrap(); - })), - Some(Box::new(|rt| { - // r8w -> source - utils::bytecode::read_word_zx(rt, rcx, r8d); - // imul r8w, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8w); - // sub r8w, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8w); - // movsx r8, r8w - rt.asm.movsx(r8, r8w).unwrap(); - })), - Some(Box::new(|rt| { - // r8b -> source - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // imul r8w, [r12 + ...] - utils::vreg::reg_imul(rt, r12, VMReg::VImmMul, r8w); - // sub r8b, [r12 + ...] - utils::vreg::reg_sub(rt, r12, VMReg::VImmAdd, r8b); - // movsx r8, r8b - rt.asm.movsx(r8, r8b).unwrap(); - })), - None, - None, - ); + builder::build(|b| { + let selector = b.read(VMWidth::Lower8); - rt.asm.set_label(&mut epilogue).unwrap(); - { - // store r8 - scratch::store(rt, r12, r8); + let value = b.select(selector, |s| { + for (width, key) in WIDTHS.into_iter().zip(keys) { + s.on(vec![key], move |b| b.immediate(width)); + } + }); - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); - } + b.produce(value); + }) +} + +pub fn build(rt: &mut Runtime) { + let operation = operation(rt); + semantic::compiler::compile(rt, &operation); } diff --git a/runtime/src/vm/handlers/load_memory.rs b/runtime/src/vm/handlers/load_memory.rs index 1868645a..bbe0d69e 100644 --- a/runtime/src/vm/handlers/load_memory.rs +++ b/runtime/src/vm/handlers/load_memory.rs @@ -1,100 +1,17 @@ -use iced_x86::code_asm::{ - byte_ptr, dword_ptr, eax, ptr, r12, r8, r9, r9d, rax, rcx, word_ptr, xmm0, ymm0, -}; - use crate::{ runtime::Runtime, - vm::utils::{self, scratch}, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut epilogue = rt.asm.create_label(); - - // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); - - // load r8 - scratch::load(rt, r12, r8); - - utils::width::dispatch( - rt, - rax, - &mut epilogue, - Some(Box::new(|rt| { - // mov r9, [r8] - rt.asm.mov(r9, ptr(r8)).unwrap(); - // store r9 - scratch::store(rt, r12, r9); - })), - Some(Box::new(|rt| { - // mov r9d, [r8] - rt.asm.mov(r9d, ptr(r8)).unwrap(); - // store r9 - scratch::store(rt, r12, r9); - })), - None, - Some(Box::new(|rt| { - // movzx r9, [r8] - rt.asm.movzx(r9, word_ptr(r8)).unwrap(); - // store r9 - scratch::store(rt, r12, r9); - })), - Some(Box::new(|rt| { - // movzx r9, [r8] - rt.asm.movzx(r9, byte_ptr(r8)).unwrap(); - // store r9 - scratch::store(rt, r12, r9); - })), - Some(Box::new(|rt| { - // movzx r9, [r8] - rt.asm.movzx(r9, byte_ptr(r8)).unwrap(); - // store r9 - scratch::store(rt, r12, r9); - })), - Some(Box::new(|rt| { - // mov r9, [r8] - rt.asm.mov(r9, ptr(r8)).unwrap(); - // store r9 - scratch::store(rt, r12, r9); - })), - Some(Box::new(|rt| { - // movsxd r9, [r8] - rt.asm.movsxd(r9, dword_ptr(r8)).unwrap(); - // store r9 - scratch::store(rt, r12, r9); - })), - Some(Box::new(|rt| { - // movsx r9, [r8] - rt.asm.movsx(r9, word_ptr(r8)).unwrap(); - // store r9 - scratch::store(rt, r12, r9); - })), - Some(Box::new(|rt| { - // movsx r9, [r8] - rt.asm.movsx(r9, byte_ptr(r8)).unwrap(); - // store r9 - scratch::store(rt, r12, r9); - })), - Some(Box::new(|rt| { - // movups xmm0, [r8] - rt.asm.movups(xmm0, ptr(r8)).unwrap(); - // store xmm0 - scratch::store_128(rt, r12, xmm0); - })), - Some(Box::new(|rt| { - // movups ymm0, [r8] - rt.asm.vmovups(ymm0, ptr(r8)).unwrap(); - // store ymm0 - scratch::store_256(rt, r12, ymm0); - })), - ); - - rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::LoadMemory)], + flags: Flags::Never, + stores: None, + widths: &[], } } + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/load_register.rs b/runtime/src/vm/handlers/load_register.rs index c82aad00..09e9b781 100644 --- a/runtime/src/vm/handlers/load_register.rs +++ b/runtime/src/vm/handlers/load_register.rs @@ -1,75 +1,30 @@ -use iced_x86::code_asm::{ - byte_ptr, dword_ptr, eax, ptr, r12, r8, r8d, r9, r9d, rax, rcx, word_ptr, -}; - use crate::{ runtime::Runtime, - vm::utils::{self, scratch}, + vm::{ + bytecode::VMWidth, + handlers::semantic::{self, Effect, Expression, Flags, Operation, Register}, + }, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut epilogue = rt.asm.create_label(); - - // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); - - // r8d -> source - utils::bytecode::read_byte_zx(rt, rcx, r8d); - - utils::width::dispatch( - rt, - rax, - &mut epilogue, - Some(Box::new(|rt| { - // mov r9, [r12 + r8*8] - rt.asm.mov(r9, ptr(r12 + r8 * 8)).unwrap(); - })), - Some(Box::new(|rt| { - // mov r9d, [r12 + r8*8] - rt.asm.mov(r9d, ptr(r12 + r8 * 8)).unwrap(); - })), - None, - Some(Box::new(|rt| { - // movzx r9, [r12 + r8*8] - rt.asm.movzx(r9, word_ptr(r12 + r8 * 8)).unwrap(); - })), - Some(Box::new(|rt| { - // movzx r9, [r12 + r8*8 + 0x1] - rt.asm.movzx(r9, byte_ptr(r12 + r8 * 8 + 0x1)).unwrap(); - })), - Some(Box::new(|rt| { - // movzx r9, [r12 + r8*8] - rt.asm.movzx(r9, byte_ptr(r12 + r8 * 8)).unwrap(); - })), - Some(Box::new(|rt| { - // mov r9, [r12 + r8*8] - rt.asm.mov(r9, ptr(r12 + r8 * 8)).unwrap(); - })), - Some(Box::new(|rt| { - // movsxd r9, [r12 + r8*8] - rt.asm.movsxd(r9, dword_ptr(r12 + r8 * 8)).unwrap(); - })), - Some(Box::new(|rt| { - // movsx r9, [r12 + r8*8] - rt.asm.movsx(r9, word_ptr(r12 + r8 * 8)).unwrap(); - })), - Some(Box::new(|rt| { - // movsx r9, [r12 + r8*8] - rt.asm.movsx(r9, byte_ptr(r12 + r8 * 8)).unwrap(); - })), - None, - None, - ); - - rt.asm.set_label(&mut epilogue).unwrap(); - { - // store r9 - scratch::store(rt, r12, r9); - - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Push(Expression::Register(Register::Operand))], + flags: Flags::Never, + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Higher8, + VMWidth::Lower8, + VMWidth::SLower64, + VMWidth::SLower32, + VMWidth::SLower16, + VMWidth::SLower8, + ], } } + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/load_vector.rs b/runtime/src/vm/handlers/load_vector.rs index 0b60005e..b1a90b1e 100644 --- a/runtime/src/vm/handlers/load_vector.rs +++ b/runtime/src/vm/handlers/load_vector.rs @@ -1,71 +1,17 @@ -use iced_x86::code_asm::{eax, ptr, r12, r8, r8d, r9, r9d, rax, rcx, xmm0, ymm0}; - use crate::{ runtime::Runtime, - vm::{ - bytecode::VMReg, - utils::{self, scratch}, - }, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut epilogue = rt.asm.create_label(); - - // r8b -> width - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> source - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // shl r9, 0x5 - rt.asm.shl(r9, 0x5).unwrap(); - - // mov rax, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VVector, rax); - - utils::width::dispatch( - rt, - r8, - &mut epilogue, - Some(Box::new(|rt| { - // mov rax, [rax + r9] - rt.asm.mov(rax, ptr(rax + r9)).unwrap(); - // store rax - scratch::store(rt, r12, rax); - })), - Some(Box::new(|rt| { - // mov eax, [rax + r9] - rt.asm.mov(eax, ptr(rax + r9)).unwrap(); - // store rax - scratch::store(rt, r12, rax); - })), - None, - None, - None, - None, - None, - None, - None, - None, - Some(Box::new(|rt| { - // movups xmm0, [rax + r9] - rt.asm.movups(xmm0, ptr(rax + r9)).unwrap(); - // store xmm0 - scratch::store_128(rt, r12, xmm0); - })), - Some(Box::new(|rt| { - // vmovups ymm0, [rax + r9] - rt.asm.vmovups(ymm0, ptr(rax + r9)).unwrap(); - // store ymm0 - scratch::store_256(rt, r12, ymm0); - })), - ); - - rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::LoadVector)], + flags: Flags::Never, + stores: None, + widths: &[], } } + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/mod.rs b/runtime/src/vm/handlers/mod.rs index 77b3c5a1..d1cd53b6 100644 --- a/runtime/src/vm/handlers/mod.rs +++ b/runtime/src/vm/handlers/mod.rs @@ -1,19 +1,21 @@ pub mod adc; pub mod add; pub mod and; +pub mod back; pub mod bit_scan_reverse; pub mod bit_test; pub mod bit_test_complement; pub mod bit_test_reset; pub mod bit_test_set; +pub mod branch; pub mod byte_swap; pub mod compare_exchange; +pub mod compound; +pub mod cpuid; pub mod discard; -pub mod dispatch; pub mod div; pub mod exchange; pub mod exchange_add; -pub mod jcc; pub mod load_address; pub mod load_immediate; pub mod load_memory; @@ -25,7 +27,6 @@ pub mod packed_byte_equal; pub mod packed_byte_mask; pub mod pop; pub mod push; -pub mod ret; pub mod rol; pub mod ror; pub mod sar; @@ -50,3 +51,119 @@ pub mod vector_or; pub mod vector_sub; pub mod vector_xor; pub mod xor; + +use crate::runtime::{FnDef, Runtime}; +use crate::vm::bytecode::VMCode; +use crate::vm::handlers::semantic::Operation; + +pub fn handler(op: VMCode) -> FnDef { + match op { + VMCode::Branch => FnDef::VmHandlerBranch, + VMCode::Back => FnDef::VmHandlersBack, + VMCode::LoadImmediate => FnDef::VmHandlerLoadImmediate, + VMCode::LoadRegister => FnDef::VmHandlerLoadRegister, + VMCode::LoadMemory => FnDef::VmHandlerLoadMemory, + VMCode::LoadAddress => FnDef::VmHandlerLoadAddress, + VMCode::LoadVector => FnDef::VmHandlerLoadVector, + VMCode::StoreRegister => FnDef::VmHandlerStoreRegister, + VMCode::StoreMemory => FnDef::VmHandlerStoreMemory, + VMCode::StoreMerge => FnDef::VmHandlerStoreMerge, + VMCode::StoreExtend => FnDef::VmHandlerStoreExtend, + VMCode::Add => FnDef::VmHandlerAdd, + VMCode::Sub => FnDef::VmHandlerSub, + VMCode::Adc => FnDef::VmHandlerAdc, + VMCode::Sbb => FnDef::VmHandlerSbb, + VMCode::And => FnDef::VmHandlerAnd, + VMCode::Or => FnDef::VmHandlerOr, + VMCode::Xor => FnDef::VmHandlerXor, + VMCode::Rol => FnDef::VmHandlerRol, + VMCode::Ror => FnDef::VmHandlerRor, + VMCode::Shl => FnDef::VmHandlerShl, + VMCode::Shr => FnDef::VmHandlerShr, + VMCode::Sar => FnDef::VmHandlerSar, + VMCode::Mul => FnDef::VmHandlerMul, + VMCode::Div => FnDef::VmHandlerDiv, + VMCode::TrailingZeros => FnDef::VmHandlerTrailingZeros, + VMCode::BitScanReverse => FnDef::VmHandlerBitScanReverse, + VMCode::ByteSwap => FnDef::VmHandlerByteSwap, + VMCode::BitTest => FnDef::VmHandlerBitTest, + VMCode::BitTestSet => FnDef::VmHandlerBitTestSet, + VMCode::BitTestReset => FnDef::VmHandlerBitTestReset, + VMCode::BitTestComplement => FnDef::VmHandlerBitTestComplement, + VMCode::Push => FnDef::VmHandlerPush, + VMCode::Pop => FnDef::VmHandlerPop, + VMCode::Discard => FnDef::VmHandlerDiscard, + VMCode::Exchange => FnDef::VmHandlerExchange, + VMCode::ExchangeAdd => FnDef::VmHandlerExchangeAdd, + VMCode::CompareExchange => FnDef::VmHandlerCompareExchange, + VMCode::PackedByteMask => FnDef::VmHandlerPackedByteMask, + VMCode::PackedByteEqual => FnDef::VmHandlerPackedByteEqual, + VMCode::VectorAnd => FnDef::VmHandlerVectorAnd, + VMCode::VectorAndNot => FnDef::VmHandlerVectorAndNot, + VMCode::VectorOr => FnDef::VmHandlerVectorOr, + VMCode::VectorXor => FnDef::VmHandlerVectorXor, + VMCode::VectorAdd => FnDef::VmHandlerVectorAdd, + VMCode::VectorSub => FnDef::VmHandlerVectorSub, + VMCode::VectorMul => FnDef::VmHandlerVectorMul, + VMCode::VectorDiv => FnDef::VmHandlerVectorDiv, + VMCode::Timestamp => FnDef::VmHandlerTimestamp, + VMCode::Cpuid => FnDef::VmHandlerCpuid, + VMCode::Compound => FnDef::VmHandlerCompound, + } +} + +pub fn operation(rt: &mut Runtime, op: VMCode) -> Option { + Some(match op { + VMCode::Branch => branch::operation(rt), + VMCode::Back => back::operation(), + VMCode::LoadImmediate => load_immediate::operation(rt), + VMCode::LoadRegister => load_register::operation(), + VMCode::LoadMemory => load_memory::operation(), + VMCode::LoadAddress => load_address::operation(rt), + VMCode::LoadVector => load_vector::operation(), + VMCode::StoreRegister => store_register::operation(), + VMCode::StoreMemory => store_memory::operation(), + VMCode::StoreMerge => store_merge::operation(), + VMCode::StoreExtend => store_extend::operation(), + VMCode::Add => add::operation(), + VMCode::Sub => sub::operation(), + VMCode::Adc => adc::operation(), + VMCode::Sbb => sbb::operation(), + VMCode::And => and::operation(), + VMCode::Or => or::operation(), + VMCode::Xor => xor::operation(), + VMCode::Rol => rol::operation(), + VMCode::Ror => ror::operation(), + VMCode::Shl => shl::operation(), + VMCode::Shr => shr::operation(), + VMCode::Sar => sar::operation(), + VMCode::Mul => mul::operation(), + VMCode::Div => div::operation(), + VMCode::TrailingZeros => trailing_zeros::operation(), + VMCode::BitScanReverse => bit_scan_reverse::operation(), + VMCode::ByteSwap => byte_swap::operation(), + VMCode::BitTest => bit_test::operation(), + VMCode::BitTestSet => bit_test_set::operation(), + VMCode::BitTestReset => bit_test_reset::operation(), + VMCode::BitTestComplement => bit_test_complement::operation(), + VMCode::Push => push::operation(), + VMCode::Pop => pop::operation(), + VMCode::Discard => discard::operation(), + VMCode::Exchange => exchange::operation(), + VMCode::ExchangeAdd => exchange_add::operation(), + VMCode::CompareExchange => compare_exchange::operation(), + VMCode::PackedByteMask => packed_byte_mask::operation(), + VMCode::PackedByteEqual => packed_byte_equal::operation(), + VMCode::VectorAnd => vector_and::operation(), + VMCode::VectorAndNot => vector_and_not::operation(), + VMCode::VectorOr => vector_or::operation(), + VMCode::VectorXor => vector_xor::operation(), + VMCode::VectorAdd => vector_add::operation(), + VMCode::VectorSub => vector_sub::operation(), + VMCode::VectorMul => vector_mul::operation(), + VMCode::VectorDiv => vector_div::operation(), + VMCode::Timestamp => timestamp::operation(), + VMCode::Cpuid => cpuid::operation(), + VMCode::Compound => return None, + }) +} diff --git a/runtime/src/vm/handlers/mul.rs b/runtime/src/vm/handlers/mul.rs index 4afcd7d0..121fb991 100644 --- a/runtime/src/vm/handlers/mul.rs +++ b/runtime/src/vm/handlers/mul.rs @@ -2,45 +2,48 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Mul( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::Always(vec![ + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::GreaterThan( + Expression::Operand(Operand::Output(1)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::GreaterThan( + Expression::Operand(Operand::Output(1)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ]), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + VMWidth::SLower64, + VMWidth::SLower32, + VMWidth::SLower16, + VMWidth::SLower8, + ], + } +} + pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Mul( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::Always(vec![ - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::GreaterThan( - Expression::Operand(Operand::Output(1)), - Expression::Constant(0), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::GreaterThan( - Expression::Operand(Operand::Output(1)), - Expression::Constant(0), - ))), - ), - ]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - VMWidth::SLower64, - VMWidth::SLower32, - VMWidth::SLower16, - VMWidth::SLower8, - ], - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/or.rs b/runtime/src/vm/handlers/or.rs index 19d34320..8dbbaf99 100644 --- a/runtime/src/vm/handlers/or.rs +++ b/runtime/src/vm/handlers/or.rs @@ -2,59 +2,62 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Or( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::Always(vec![ + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::Equal( + Expression::Immediate(Immediate::Fixed(1)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::Equal( + Expression::Immediate(Immediate::Fixed(1)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), + ]), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Or( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::Always(vec![ - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::Equal( - Expression::Constant(1), - Expression::Constant(0), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::Equal( - Expression::Constant(1), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - ], - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/packed_byte_equal.rs b/runtime/src/vm/handlers/packed_byte_equal.rs index 89ae22a0..5b6d7401 100644 --- a/runtime/src/vm/handlers/packed_byte_equal.rs +++ b/runtime/src/vm/handlers/packed_byte_equal.rs @@ -1,58 +1,17 @@ -use iced_x86::code_asm::{eax, r12, rax, rcx, xmm0, xmm1, ymm0, ymm1}; - use crate::{ runtime::Runtime, - vm::utils::{self, scratch}, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut epilogue = rt.asm.create_label(); - - // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); - - utils::width::dispatch( - rt, - rax, - &mut epilogue, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - Some(Box::new(|rt| { - // load xmm1 - scratch::load_128(rt, r12, xmm1); - // load xmm0 - scratch::load_128(rt, r12, xmm0); - // pcmpeqb xmm0, xmm1 - rt.asm.pcmpeqb(xmm0, xmm1).unwrap(); - // store xmm0 - scratch::store_128(rt, r12, xmm0); - })), - Some(Box::new(|rt| { - // load ymm1 - scratch::load_256(rt, r12, ymm1); - // load ymm0 - scratch::load_256(rt, r12, ymm0); - // vpcmpeqb ymm0, ymm0, ymm1 - rt.asm.vpcmpeqb(ymm0, ymm0, ymm1).unwrap(); - // store ymm0 - scratch::store_256(rt, r12, ymm0); - })), - ); - - rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::ByteEqual)], + flags: Flags::Never, + stores: None, + widths: &[], } } + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/packed_byte_mask.rs b/runtime/src/vm/handlers/packed_byte_mask.rs index f485a075..65889e74 100644 --- a/runtime/src/vm/handlers/packed_byte_mask.rs +++ b/runtime/src/vm/handlers/packed_byte_mask.rs @@ -1,54 +1,17 @@ -use iced_x86::code_asm::{eax, r12, r8, r8d, rax, rcx, xmm0, ymm0}; - use crate::{ runtime::Runtime, - vm::utils::{self, scratch}, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, }; -// unsigned char* (unsigned long*, unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut epilogue = rt.asm.create_label(); - - // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); - - utils::width::dispatch( - rt, - rax, - &mut epilogue, - None, - None, - None, - None, - None, - None, - None, - None, - None, - None, - Some(Box::new(|rt| { - // load xmm0 - scratch::load_128(rt, r12, xmm0); - // pmovmskb r8d, xmm0 - rt.asm.pmovmskb(r8d, xmm0).unwrap(); - // store r8 - scratch::store(rt, r12, r8); - })), - Some(Box::new(|rt| { - // load ymm0 - scratch::load_256(rt, r12, ymm0); - // vpmovmskb r8d, ymm0 - rt.asm.vpmovmskb(r8d, ymm0).unwrap(); - // store r8 - scratch::store(rt, r12, r8); - })), - ); - - rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::ByteMask)], + flags: Flags::Never, + stores: None, + widths: &[], } } + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/pop.rs b/runtime/src/vm/handlers/pop.rs index 75fbeb3e..da27f013 100644 --- a/runtime/src/vm/handlers/pop.rs +++ b/runtime/src/vm/handlers/pop.rs @@ -1,23 +1,31 @@ -use iced_x86::code_asm::{r12, r8, r9, rax, rcx}; - use crate::{ runtime::Runtime, - vm::bytecode::VMReg, - vm::utils::{self, scratch}, + vm::{ + bytecode::VMReg, + handlers::semantic::{self, Effect, Expression, Flags, Immediate, Operation, Register}, + }, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - // mov r8, [r12 + ...]; mov r9, [r8] - utils::vreg::load_mem(rt, r12, VMReg::Rsp, r8, r9); - // add [r12 + ...], 0x8 - utils::vreg::add_imm(rt, r12, 0x8, VMReg::Rsp); - - // store r9 - scratch::store(rt, r12, r9); +pub fn operation() -> Operation { + Operation { + effects: vec![ + Effect::Push(Expression::Memory(Box::new(Expression::Register( + Register::Fixed(VMReg::Rsp), + )))), + Effect::Register( + Register::Fixed(VMReg::Rsp), + Expression::Add( + Box::new(Expression::Register(Register::Fixed(VMReg::Rsp))), + Box::new(Expression::Immediate(Immediate::Fixed(8))), + ), + ), + ], + flags: Flags::Never, + stores: None, + widths: &[], + } +} - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/push.rs b/runtime/src/vm/handlers/push.rs index eca14286..849aac11 100644 --- a/runtime/src/vm/handlers/push.rs +++ b/runtime/src/vm/handlers/push.rs @@ -1,23 +1,34 @@ -use iced_x86::code_asm::{r12, r8, r9, rax, rcx}; - use crate::{ runtime::Runtime, - vm::bytecode::VMReg, - vm::utils::{self, scratch}, + vm::{ + bytecode::VMReg, + handlers::semantic::{ + self, Effect, Expression, Flags, Immediate, Operand, Operation, Register, + }, + }, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - // load r9 - scratch::load(rt, r12, r9); - - // sub [r12 + ...], 0x8 - utils::vreg::sub_imm(rt, r12, 0x8, VMReg::Rsp); - // mov r8, [r12 + ...]; mov [r8], r9 - utils::vreg::store_mem(rt, r12, VMReg::Rsp, r8, r9); +pub fn operation() -> Operation { + Operation { + effects: vec![ + Effect::Register( + Register::Fixed(VMReg::Rsp), + Expression::Sub( + Box::new(Expression::Register(Register::Fixed(VMReg::Rsp))), + Box::new(Expression::Immediate(Immediate::Fixed(8))), + ), + ), + Effect::Memory( + Expression::Register(Register::Fixed(VMReg::Rsp)), + Expression::Operand(Operand::Input(0)), + ), + ], + flags: Flags::Never, + stores: None, + widths: &[], + } +} - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/ret.rs b/runtime/src/vm/handlers/ret.rs deleted file mode 100644 index 62885e18..00000000 --- a/runtime/src/vm/handlers/ret.rs +++ /dev/null @@ -1,28 +0,0 @@ -use iced_x86::code_asm::{r12, r8, r9, rax, rcx}; - -use crate::{ - runtime::Runtime, - vm::{ - bytecode::VMReg, - utils::{scratch, vreg}, - }, -}; - -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - // load r8 - scratch::load(rt, r12, r8); - // mov rax, [r12 + ...]; mov r9, [rax] - vreg::load_mem(rt, r12, VMReg::Rsp, rax, r9); - // mov [r12 + ...], r9 - vreg::store_reg(rt, r12, r9, VMReg::NBranch); - // add [r12 + ...], 0x8 - vreg::add_imm(rt, r12, 0x8, VMReg::Rsp); - // add [r12 + ...], r8 - vreg::add_reg(rt, r12, r8, VMReg::Rsp); - - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); -} diff --git a/runtime/src/vm/handlers/rol.rs b/runtime/src/vm/handlers/rol.rs index 123bdad2..0cae80a6 100644 --- a/runtime/src/vm/handlers/rol.rs +++ b/runtime/src/vm/handlers/rol.rs @@ -2,59 +2,62 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Rol( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::When( - Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::BitOr( - Box::new(Expression::SignBit), - Box::new(Expression::Constant(0x1f)), - )), - ), - vec![ - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::GreaterThan( - Expression::BitXor( - Box::new(Expression::BitShr( - Box::new(Expression::Operand(Operand::Output(0))), - Box::new(Expression::SignBit), - )), - Box::new(Expression::BitAnd( - Box::new(Expression::Operand(Operand::Output(0))), - Box::new(Expression::Constant(1)), - )), - ), - Expression::Constant(0), - ))), - ), - ], +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Rol( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::When( + Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::BitOr( + Box::new(Expression::SignBit), + Box::new(Expression::Immediate(Immediate::Fixed(0x1f))), + )), ), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, + vec![ + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::GreaterThan( + Expression::BitXor( + Box::new(Expression::BitShr( + Box::new(Expression::Operand(Operand::Output(0))), + Box::new(Expression::SignBit), + )), + Box::new(Expression::BitAnd( + Box::new(Expression::Operand(Operand::Output(0))), + Box::new(Expression::Immediate(Immediate::Fixed(1))), + )), + ), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), ], - }, - ); + ), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/ror.rs b/runtime/src/vm/handlers/ror.rs index 7e3ed88d..5020216e 100644 --- a/runtime/src/vm/handlers/ror.rs +++ b/runtime/src/vm/handlers/ror.rs @@ -2,65 +2,68 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Ror( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::When( - Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::BitOr( - Box::new(Expression::SignBit), - Box::new(Expression::Constant(0x1f)), - )), +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Ror( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::When( + Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::BitOr( + Box::new(Expression::SignBit), + Box::new(Expression::Immediate(Immediate::Fixed(0x1f))), + )), + ), + vec![ + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), ), - vec![ - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::GreaterThan( - Expression::BitXor( + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::GreaterThan( + Expression::BitXor( + Box::new(Expression::BitShr( + Box::new(Expression::Operand(Operand::Output(0))), + Box::new(Expression::SignBit), + )), + Box::new(Expression::BitAnd( Box::new(Expression::BitShr( Box::new(Expression::Operand(Operand::Output(0))), - Box::new(Expression::SignBit), - )), - Box::new(Expression::BitAnd( - Box::new(Expression::BitShr( - Box::new(Expression::Operand(Operand::Output(0))), - Box::new(Expression::Sub( - Box::new(Expression::SignBit), - Box::new(Expression::Constant(1)), - )), + Box::new(Expression::Sub( + Box::new(Expression::SignBit), + Box::new(Expression::Immediate(Immediate::Fixed(1))), )), - Box::new(Expression::Constant(1)), )), - ), - Expression::Constant(0), - ))), - ), - ], - ), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, + Box::new(Expression::Immediate(Immediate::Fixed(1))), + )), + ), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), ], - }, - ); + ), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/sar.rs b/runtime/src/vm/handlers/sar.rs index aba44ef4..3076004c 100644 --- a/runtime/src/vm/handlers/sar.rs +++ b/runtime/src/vm/handlers/sar.rs @@ -2,97 +2,102 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Sar( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::When( - Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::BitOr( - Box::new(Expression::SignBit), - Box::new(Expression::Constant(0x1f)), - )), - ), - vec![ - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Input(0)), - Expression::Sub( - Box::new(Expression::SignBit), - Box::new(Expression::BitAnd( +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Sar( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::When( + Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::BitOr( + Box::new(Expression::SignBit), + Box::new(Expression::Immediate(Immediate::Fixed(0x1f))), + )), + ), + vec![ + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Input(0)), + Expression::Sub( + Box::new(Expression::SignBit), + Box::new(Expression::BitAnd( + Box::new(Expression::Sub( + Box::new(Expression::BitSize), + Box::new(Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::BitOr( + Box::new(Expression::SignBit), + Box::new(Expression::Immediate(Immediate::Fixed(0x1f))), + )), + )), + )), + Box::new(Expression::BitShr( + Box::new(Expression::BitNot(Box::new(Expression::Immediate( + Immediate::Fixed(0), + )))), Box::new(Expression::Sub( - Box::new(Expression::BitSize), Box::new(Expression::BitAnd( Box::new(Expression::Operand(Operand::Input(1))), Box::new(Expression::BitOr( Box::new(Expression::SignBit), - Box::new(Expression::Constant(0x1f)), - )), - )), - )), - Box::new(Expression::BitShr( - Box::new(Expression::BitNot(Box::new( - Expression::Constant(0), - ))), - Box::new(Expression::Sub( - Box::new(Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::BitOr( - Box::new(Expression::SignBit), - Box::new(Expression::Constant(0x1f)), - )), + Box::new(Expression::Immediate(Immediate::Fixed( + 0x1f, + ))), )), - Box::new(Expression::Constant(1)), )), + Box::new(Expression::Immediate(Immediate::Fixed(1))), )), )), - ), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::Equal( - Expression::Constant(1), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ], - ), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, + )), + ), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::Equal( + Expression::Immediate(Immediate::Fixed(1)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), ], - }, - ); + ), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/sbb.rs b/runtime/src/vm/handlers/sbb.rs index 21c61e27..69c1fd6c 100644 --- a/runtime/src/vm/handlers/sbb.rs +++ b/runtime/src/vm/handlers/sbb.rs @@ -2,101 +2,104 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Sub( - Expression::Operand(Operand::Input(0)), - Expression::Sub( - Box::new(Expression::Sub( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::BitNot(Box::new(Expression::Flag(Flag::Carry)))), - )), - Box::new(Expression::Constant(1)), - ), - )], - flags: Flags::Always(vec![ - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitOr( - Box::new(Expression::BitAnd( - Box::new(Expression::BitNot(Box::new(Expression::Operand( - Operand::Input(0), - )))), - Box::new(Expression::Operand(Operand::Input(1))), - )), - Box::new(Expression::BitAnd( - Box::new(Expression::BitNot(Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Input(1))), - )))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - ), - Expression::SignBit, - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitAnd( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Input(1))), - )), - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - ), - Expression::SignBit, - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ( - Flag::Auxiliary, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitXor( - Box::new(Expression::BitXor( +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Sub( + Expression::Operand(Operand::Input(0)), + Expression::Sub( + Box::new(Expression::Sub( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::BitNot(Box::new(Expression::Flag(Flag::Carry)))), + )), + Box::new(Expression::Immediate(Immediate::Fixed(1))), + ), + )], + flags: Flags::Always(vec![ + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitOr( + Box::new(Expression::BitAnd( + Box::new(Expression::BitNot(Box::new(Expression::Operand( + Operand::Input(0), + )))), + Box::new(Expression::Operand(Operand::Input(1))), + )), + Box::new(Expression::BitAnd( + Box::new(Expression::BitNot(Box::new(Expression::BitXor( Box::new(Expression::Operand(Operand::Input(0))), Box::new(Expression::Operand(Operand::Input(1))), - )), + )))), Box::new(Expression::Operand(Operand::Output(0))), - ), - Expression::Constant(4), - ))), - ), - ]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - ], - }, - ); + )), + ), + Expression::SignBit, + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitAnd( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Input(1))), + )), + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Output(0))), + )), + ), + Expression::SignBit, + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), + ( + Flag::Auxiliary, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitXor( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Input(1))), + )), + Box::new(Expression::Operand(Operand::Output(0))), + ), + Expression::Immediate(Immediate::Fixed(4)), + ))), + ), + ]), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/semantic/allocator.rs b/runtime/src/vm/handlers/semantic/allocator.rs index de308768..bdf2b67f 100644 --- a/runtime/src/vm/handlers/semantic/allocator.rs +++ b/runtime/src/vm/handlers/semantic/allocator.rs @@ -14,19 +14,21 @@ pub struct Allocator { temporary: usize, inputs: usize, outputs: usize, + locals: usize, flags: bool, } impl Allocator { const REGISTERS: [AsmRegister64; 5] = [rax, rcx, rdx, r8, r9]; - pub fn new(inputs: usize, outputs: usize, flags: bool) -> Self { + pub fn new(inputs: usize, outputs: usize, locals: usize, flags: bool) -> Self { Self { tracked: Vec::new(), dirty: HashSet::new(), temporary: 0, inputs, outputs, + locals, flags, } } @@ -82,7 +84,8 @@ impl Allocator { Value::Input(index) => index, Value::Output(index) => self.inputs + index, Value::Flags => self.inputs + self.outputs, - Value::Temporary(index) => self.inputs + self.outputs + flags + index, + Value::Local(index) => self.inputs + self.outputs + flags + index, + Value::Temporary(index) => self.inputs + self.outputs + flags + self.locals + index, }; (slot as i32 + 1) * 8 } diff --git a/runtime/src/vm/handlers/semantic/builder.rs b/runtime/src/vm/handlers/semantic/builder.rs new file mode 100644 index 00000000..661e2232 --- /dev/null +++ b/runtime/src/vm/handlers/semantic/builder.rs @@ -0,0 +1,294 @@ +use crate::vm::{ + bytecode::{VMReg, VMWidth}, + handlers::semantic::{ + Compare, Effect, Expression, Flags, Immediate, Operand, Operation, Register, + }, +}; + +#[derive(Clone, Copy)] +pub struct Value(usize); + +#[derive(Clone, Copy)] +pub struct Variable(usize); + +pub struct Builder { + effects: Vec, + values: Vec, + locals: usize, +} + +pub struct Select<'a> { + builder: &'a mut Builder, + result: usize, + arms: Vec<(Vec, Vec)>, +} + +pub struct Dispatch<'a> { + builder: &'a mut Builder, + arms: Vec<(Vec, Vec)>, +} + +pub fn build(program: impl FnOnce(&mut Builder)) -> Operation { + let mut builder = Builder { + effects: Vec::new(), + values: Vec::new(), + locals: 0, + }; + + program(&mut builder); + + Operation { + effects: builder.effects, + flags: Flags::Never, + stores: None, + widths: &[], + } +} + +impl Builder { + fn local(&mut self) -> usize { + let index = self.locals; + self.locals += 1; + index + } + + fn define(&mut self, expression: Expression) -> Value { + let value = Value(self.values.len()); + self.values.push(expression); + value + } + + fn expression(&self, value: Value) -> Expression { + self.values[value.0].clone() + } + + fn block(&mut self, body: impl FnOnce(&mut Self)) -> Vec { + let outer = std::mem::take(&mut self.effects); + body(self); + std::mem::replace(&mut self.effects, outer) + } + + fn bind(&mut self, expression: Expression) -> Value { + let local = self.local(); + self.effects.push(Effect::Assign(local, expression)); + self.define(Expression::Local(local)) + } + + pub fn read(&mut self, width: VMWidth) -> Value { + let local = self.local(); + self.effects.push(Effect::Read(local, width)); + self.define(Expression::Local(local)) + } + + pub fn register_operand(&mut self) -> Value { + self.bind(Expression::Register(Register::Operand)) + } + + pub fn segment(&mut self) -> Value { + self.define(Expression::Segment) + } + + pub fn add(&mut self, first: Value, second: Value) -> Value { + let first = self.expression(first); + let second = self.expression(second); + self.define(Expression::Add(Box::new(first), Box::new(second))) + } + + pub fn sub(&mut self, first: Value, second: Value) -> Value { + let first = self.expression(first); + let second = self.expression(second); + self.define(Expression::Sub(Box::new(first), Box::new(second))) + } + + pub fn mul(&mut self, first: Value, second: Value) -> Value { + let first = self.expression(first); + let second = self.expression(second); + self.define(Expression::Mul(Box::new(first), Box::new(second))) + } + + pub fn extend(&mut self, value: Value, width: VMWidth) -> Value { + let value = self.expression(value); + self.define(Expression::Extend(Box::new(value), width)) + } + + pub fn produce(&mut self, value: Value) { + let value = self.expression(value); + self.effects.push(Effect::Push(value)); + } + + pub fn input(&mut self, index: usize) -> Value { + self.define(Expression::Operand(Operand::Input(index))) + } + + pub fn register(&mut self, register: VMReg) -> Value { + self.define(Expression::Register(Register::Fixed(register))) + } + + pub fn decrypt(&mut self, cipher: Value) -> Value { + let cipher = self.expression(cipher); + self.bind(Expression::LowByte(Box::new(Expression::Sub( + Box::new(Expression::Mul( + Box::new(cipher), + Box::new(Expression::Register(Register::Fixed(VMReg::VImmMul))), + )), + Box::new(Expression::Register(Register::Fixed(VMReg::VImmAdd))), + )))) + } + + pub fn flag(&mut self, index: Value) -> Value { + let index = self.expression(index); + self.define(Expression::Compare(Box::new(Compare::BitSet( + Expression::Register(Register::Fixed(VMReg::Flags)), + index, + )))) + } + + pub fn equal(&mut self, first: Value, second: Value) -> Value { + let first = self.expression(first); + let second = self.expression(second); + self.define(Expression::Compare(Box::new(Compare::Equal(first, second)))) + } + + pub fn unequal(&mut self, first: Value, second: Value) -> Value { + let first = self.expression(first); + let second = self.expression(second); + self.define(Expression::BitXor(Box::new(first), Box::new(second))) + } + + pub fn constant(&mut self, value: u64) -> Value { + self.define(Expression::Immediate(Immediate::Fixed(value))) + } + + pub fn immediate(&mut self, width: VMWidth) -> Value { + let cipher = self.read(width); + + let multiplier = self.register(VMReg::VImmMul); + let product = self.mul(cipher, multiplier); + let addend = self.register(VMReg::VImmAdd); + let decrypted = self.sub(product, addend); + + self.extend(decrypted, width) + } + + pub fn and(&mut self, first: Value, second: Value) -> Value { + let first = self.expression(first); + let second = self.expression(second); + self.define(Expression::BitAnd(Box::new(first), Box::new(second))) + } + + pub fn or(&mut self, first: Value, second: Value) -> Value { + let first = self.expression(first); + let second = self.expression(second); + self.define(Expression::BitOr(Box::new(first), Box::new(second))) + } + + pub fn xor(&mut self, first: Value, second: Value) -> Value { + let first = self.expression(first); + let second = self.expression(second); + self.define(Expression::BitXor(Box::new(first), Box::new(second))) + } + + pub fn variable(&mut self) -> Variable { + Variable(self.local()) + } + + pub fn set(&mut self, variable: Variable, value: Value) { + let value = self.expression(value); + self.effects.push(Effect::Assign(variable.0, value)); + } + + pub fn get(&mut self, variable: Variable) -> Value { + self.define(Expression::Local(variable.0)) + } + + pub fn store(&mut self, register: VMReg, value: Value) { + let value = self.expression(value); + self.effects + .push(Effect::Register(Register::Fixed(register), value)); + } + + pub fn push(&mut self, value: Value) { + let value = self.expression(value); + self.effects.push(Effect::Register( + Register::Fixed(VMReg::Rsp), + Expression::Sub( + Box::new(Expression::Register(Register::Fixed(VMReg::Rsp))), + Box::new(Expression::Immediate(Immediate::Fixed(8))), + ), + )); + self.effects.push(Effect::Memory( + Expression::Register(Register::Fixed(VMReg::Rsp)), + value, + )); + } + + pub fn advance(&mut self, value: Value) { + let value = self.expression(value); + self.effects.push(Effect::Advance(value)); + } + + pub fn select(&mut self, selector: Value, build: impl FnOnce(&mut Select)) -> Value { + let result = self.local(); + let selector = self.expression(selector); + + let arms = { + let mut select = Select { + builder: self, + result, + arms: Vec::new(), + }; + build(&mut select); + select.arms + }; + + self.effects.push(Effect::Select(selector, arms)); + self.define(Expression::Local(result)) + } + + pub fn dispatch(&mut self, selector: Value, build: impl FnOnce(&mut Dispatch)) { + let selector = self.expression(selector); + + let arms = { + let mut dispatch = Dispatch { + builder: self, + arms: Vec::new(), + }; + build(&mut dispatch); + dispatch.arms + }; + + self.effects.push(Effect::Select(selector, arms)); + } + + pub fn when(&mut self, condition: Value, body: impl FnOnce(&mut Self)) { + let condition = self.expression(condition); + let body = self.block(body); + self.effects.push(Effect::When(condition, body)); + } + + pub fn repeat(&mut self, body: impl FnOnce(&mut Self)) { + let counter = self.local(); + self.effects.push(Effect::Read(counter, VMWidth::Lower8)); + let body = self.block(body); + self.effects.push(Effect::Loop(counter, body)); + } +} + +impl Select<'_> { + pub fn on(&mut self, keys: Vec, body: impl FnOnce(&mut Builder) -> Value) { + let result = self.result; + let effects = self.builder.block(|builder| { + let value = body(builder); + let value = builder.expression(value); + builder.effects.push(Effect::Assign(result, value)); + }); + self.arms.push((keys, effects)); + } +} + +impl Dispatch<'_> { + pub fn on(&mut self, keys: Vec, body: impl FnOnce(&mut Builder)) { + let effects = self.builder.block(body); + self.arms.push((keys, effects)); + } +} diff --git a/runtime/src/vm/handlers/semantic/compiler.rs b/runtime/src/vm/handlers/semantic/compiler.rs index d5664df0..d478118a 100644 --- a/runtime/src/vm/handlers/semantic/compiler.rs +++ b/runtime/src/vm/handlers/semantic/compiler.rs @@ -1,30 +1,55 @@ use iced_x86::code_asm::{ - ah, ax, cl, dl, dword_ptr, dx, get_gpr16, get_gpr32, get_gpr8, ptr, qword_ptr, r12, r13, r14, - r14d, rax, rbp, rcx, rdx, rsp, AsmRegister16, AsmRegister32, AsmRegister64, AsmRegister8, - CodeAssembler, CodeLabel, + ah, ax, byte_ptr, cl, dl, dword_ptr, dx, get_gpr16, get_gpr32, get_gpr8, ptr, qword_ptr, r12, + r13, r14, r14d, rax, rbp, rbx, rcx, rdx, rsp, word_ptr, xmm0, xmm1, ymm0, ymm1, AsmRegister16, + AsmRegister32, AsmRegister64, AsmRegister8, CodeAssembler, CodeLabel, }; +use rand::Rng; use crate::{ runtime::Runtime, utils::register_of_size, vm::{ - bytecode::{VMReg, VMWidth}, - handlers::semantic::{ - allocator::Allocator, Compare, Effect, Expression, Flags, Operand, Operation, - Reference, Value, + bytecode::{VMCode, VMReg, VMWidth}, + handlers::{ + self, + semantic::{ + allocator::Allocator, Compare, Effect, Expression, Flags, Immediate, Operand, + Operation, Reference, Register, Value, Vector, + }, + vector, }, - utils::{bytecode, scratch, vreg}, + utils::{bytecode, register, scratch}, }, }; -const BUDGET: u32 = 2; - pub fn compile(rt: &mut Runtime, operation: &Operation) { + let operation = obfuscate(operation); + compile_scalar(rt, &operation); + rt.asm.ret().unwrap(); +} + +pub fn compile_fragment(rt: &mut Runtime, operation: &Operation) { + compile_scalar(rt, &obfuscate(operation)); +} + +pub fn compile_compound(rt: &mut Runtime, members: &[VMCode]) { + for (index, member) in members.iter().enumerate() { + if index > 0 { + rt.asm.mov(rcx, rax).unwrap(); + } + + let operation = handlers::operation(rt, *member).unwrap(); + compile_fragment(rt, &operation); + } + rt.asm.ret().unwrap(); +} + +fn obfuscate(operation: &Operation) -> Operation { let mut rng = rand::thread_rng(); - let mut budget = BUDGET; + let mut budget = rng.gen_range(1..4); - let operation = Operation { + Operation { effects: operation .effects .iter() @@ -34,17 +59,19 @@ pub fn compile(rt: &mut Runtime, operation: &Operation) { flags: operation.flags.clone(), stores: operation.stores.clone(), widths: operation.widths, - }; - let operation = &operation; + } +} +fn compile_scalar(rt: &mut Runtime, operation: &Operation) { let mut epilogue = rt.asm.create_label(); let operands = operation.operands(); let outputs = operation.outputs(); let flags = !operation.flags.is_empty(); + let locals = operation.locals(); let temporaries = operation.temporaries(); - let slots = operands + outputs + flags as usize + temporaries; + let slots = operands + outputs + flags as usize + locals + temporaries; let size = ((slots as i32 * 8) + 15) & !15; - let allocator = Allocator::new(operands, outputs, flags); + let allocator = Allocator::new(operands, outputs, locals, flags); rt.asm.push(r13).unwrap(); rt.asm.push(r14).unwrap(); @@ -54,7 +81,9 @@ pub fn compile(rt: &mut Runtime, operation: &Operation) { rt.asm.mov(r13, rcx).unwrap(); - bytecode::read_byte_zx(rt, r13, r14d); + if !operation.widths.is_empty() { + bytecode::read_byte_zx(rt, r13, r14d); + } for index in (0..operands).rev() { scratch::load(rt, r12, rax); @@ -64,72 +93,67 @@ pub fn compile(rt: &mut Runtime, operation: &Operation) { .unwrap(); } - let handlers = operation - .widths - .iter() - .map(|&width| { - let actions = operation.effects.clone(); - let rules = operation.flags.clone(); - - ( - width, - Box::new(move |rt: &mut Runtime, allocator: &mut Allocator| { - compile_effects(rt, allocator, &actions, width); - - for index in 0..outputs { - let output = Value::Output(index); - let register = allocator.mutable(rt, output, &[]); - let mask = allocator.acquire(rt, &[output], &[register]); - - rt.asm.mov(mask, width.mask() as i64).unwrap(); - rt.asm.and(register, mask).unwrap(); - - allocator.spill(rt, mask); - allocator.dirty(output); - } - - if !rules.is_empty() { - compile_flags(rt, allocator, &rules, width); - } - }) as Box, - ) - }) - .collect::)>>(); + if operation.widths.is_empty() { + let mut local = Allocator::new(operands, outputs, locals, flags); - let cases = handlers - .iter() - .map( - |(width, _function): &(VMWidth, Box)| { - (rt.mapper.index(*width) as u8, rt.asm.create_label()) - }, - ) - .collect::>(); + compile_effects(rt, &mut local, &operation.effects, VMWidth::Lower64); + + if flags { + compile_flags(rt, &mut local, &operation.flags, VMWidth::Lower64); + } - rt.jumps( - r14, - cases + local.dump(rt); + } else { + let handlers = operation + .widths .iter() - .map(|(key, label): &(u8, CodeLabel)| (*key, *label)) - .collect::>(), - ); + .map(|&width| { + let actions = operation.effects.clone(); + let rules = operation.flags.clone(); + ( + width, + Box::new(move |rt: &mut Runtime, allocator: &mut Allocator| { + compile_effects(rt, allocator, &actions, width); + + if !rules.is_empty() { + compile_flags(rt, allocator, &rules, width); + } + }) as Box, + ) + }) + .collect::)>>(); - for ((_key, mut label), (_width, handler)) in cases.into_iter().zip(handlers.into_iter()) { - rt.asm.set_label(&mut label).unwrap(); + let cases = handlers + .iter() + .map(|(width, _function)| (rt.mapper.index(*width) as u8, rt.asm.create_label())) + .collect::>(); - let mut local = Allocator::new(operands, outputs, flags); + rt.jumps( + r14, + cases + .iter() + .map(|(key, label): &(u8, CodeLabel)| (*key, *label)) + .collect::>(), + ); - handler(rt, &mut local); + for ((_key, mut label), (_width, handler)) in cases.into_iter().zip(handlers.into_iter()) { + rt.asm.set_label(&mut label).unwrap(); - local.dump(rt); + let mut local = Allocator::new(operands, outputs, locals, flags); + + handler(rt, &mut local); - rt.asm.jmp(epilogue).unwrap(); + local.dump(rt); + + rt.asm.jmp(epilogue).unwrap(); + } } rt.asm.set_label(&mut epilogue).unwrap(); match &operation.stores { Some(stores) => { - let mut allocator = Allocator::new(operands, outputs, flags); + let mut allocator = Allocator::new(operands, outputs, locals, flags); for expression in stores { let src = compile_expression(rt, &mut allocator, expression, VMWidth::Lower64); @@ -145,7 +169,7 @@ pub fn compile(rt: &mut Runtime, operation: &Operation) { } } None => { - let mut allocator = Allocator::new(operands, outputs, flags); + let mut allocator = Allocator::new(operands, outputs, locals, flags); for index in (0..outputs).rev() { let dst = allocator.acquire(rt, &[], &[]); @@ -162,7 +186,100 @@ pub fn compile(rt: &mut Runtime, operation: &Operation) { rt.asm.pop(rbp).unwrap(); rt.asm.pop(r14).unwrap(); rt.asm.pop(r13).unwrap(); - rt.asm.ret().unwrap(); +} + +fn compile_vector(rt: &mut Runtime, operation: Vector) { + match operation { + Vector::And => vector::with_width( + rt, + |rt| rt.asm.pand(xmm0, xmm1).unwrap(), + |rt| rt.asm.vpand(ymm0, ymm0, ymm1).unwrap(), + ), + Vector::Or => vector::with_width( + rt, + |rt| rt.asm.por(xmm0, xmm1).unwrap(), + |rt| rt.asm.vpor(ymm0, ymm0, ymm1).unwrap(), + ), + Vector::Xor => vector::with_width( + rt, + |rt| rt.asm.pxor(xmm0, xmm1).unwrap(), + |rt| rt.asm.vpxor(ymm0, ymm0, ymm1).unwrap(), + ), + Vector::AndNot => vector::with_width( + rt, + |rt| rt.asm.pandn(xmm0, xmm1).unwrap(), + |rt| rt.asm.vpandn(ymm0, ymm0, ymm1).unwrap(), + ), + Vector::Div => vector::with_stride( + rt, + |rt| rt.asm.divps(xmm0, xmm1).unwrap(), + |rt| rt.asm.divpd(xmm0, xmm1).unwrap(), + |rt| rt.asm.vdivps(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vdivpd(ymm0, ymm0, ymm1).unwrap(), + ), + Vector::Mul => vector::with_extension( + rt, + |rt| rt.asm.mulpd(xmm0, xmm1).unwrap(), + |rt| rt.asm.pmulld(xmm0, xmm1).unwrap(), + |rt| rt.asm.mulps(xmm0, xmm1).unwrap(), + |rt| rt.asm.pmulhw(xmm0, xmm1).unwrap(), + |rt| rt.asm.pmullw(xmm0, xmm1).unwrap(), + |rt| rt.asm.vmulpd(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vpmulld(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vmulps(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vpmulhw(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vpmullw(ymm0, ymm0, ymm1).unwrap(), + ), + Vector::Add => vector::with_precision( + rt, + |rt| rt.asm.paddb(xmm0, xmm1).unwrap(), + |rt| rt.asm.paddw(xmm0, xmm1).unwrap(), + |rt| rt.asm.paddd(xmm0, xmm1).unwrap(), + |rt| rt.asm.paddq(xmm0, xmm1).unwrap(), + |rt| rt.asm.addps(xmm0, xmm1).unwrap(), + |rt| rt.asm.addps(xmm0, xmm1).unwrap(), + |rt| rt.asm.addps(xmm0, xmm1).unwrap(), + |rt| rt.asm.addpd(xmm0, xmm1).unwrap(), + |rt| rt.asm.vpaddb(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vpaddw(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vpaddd(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vpaddq(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vaddps(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vaddps(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vaddps(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vaddpd(ymm0, ymm0, ymm1).unwrap(), + ), + Vector::Sub => vector::with_precision( + rt, + |rt| rt.asm.psubb(xmm0, xmm1).unwrap(), + |rt| rt.asm.psubw(xmm0, xmm1).unwrap(), + |rt| rt.asm.psubd(xmm0, xmm1).unwrap(), + |rt| rt.asm.psubq(xmm0, xmm1).unwrap(), + |rt| rt.asm.subps(xmm0, xmm1).unwrap(), + |rt| rt.asm.subps(xmm0, xmm1).unwrap(), + |rt| rt.asm.subps(xmm0, xmm1).unwrap(), + |rt| rt.asm.subpd(xmm0, xmm1).unwrap(), + |rt| rt.asm.vpsubb(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vpsubw(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vpsubd(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vpsubq(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vsubps(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vsubps(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vsubps(ymm0, ymm0, ymm1).unwrap(), + |rt| rt.asm.vsubpd(ymm0, ymm0, ymm1).unwrap(), + ), + Vector::ByteEqual => vector::with_width( + rt, + |rt| rt.asm.pcmpeqb(xmm0, xmm1).unwrap(), + |rt| rt.asm.vpcmpeqb(ymm0, ymm0, ymm1).unwrap(), + ), + Vector::ByteMask => vector::byte_mask(rt), + Vector::LoadVector => vector::load_vector(rt), + Vector::StoreMerge => vector::store_merge(rt), + Vector::StoreExtend => vector::store_extend(rt), + Vector::LoadMemory => vector::load_memory(rt), + Vector::StoreMemory => vector::store_memory(rt), + } } fn compile_effects( @@ -787,7 +904,7 @@ fn compile_effect(rt: &mut Runtime, allocator: &mut Allocator, effect: &Effect, asm.sar(qword, cl).unwrap(); }, ), - Effect::Assign(expression) => { + Effect::Push(expression) => { let src = compile_expression(rt, allocator, expression, width); let dst = allocator.acquire(rt, &[], &[]); allocator.copy(rt, src, dst); @@ -820,6 +937,240 @@ fn compile_effect(rt: &mut Runtime, allocator: &mut Allocator, effect: &Effect, Effect::CompareExchange(first, second, third) => { compile_compare_exchange(rt, allocator, first, second, third, width) } + Effect::Register(register, expression) => { + let value = compile_expression(rt, allocator, expression, width); + + let pinned = match value { + Reference::Value(value) => vec![value], + Reference::Immediate(_) => vec![], + }; + + let index = allocator.acquire(rt, &pinned, &[]); + let slot = get_gpr32(register_of_size(index.into(), 4).unwrap()).unwrap(); + + match register { + Register::Operand => bytecode::read_byte_zx(rt, r13, slot), + Register::Fixed(register) => { + rt.asm.mov(slot, rt.mapper.index(*register) as i32).unwrap() + } + } + + let src = allocator.acquire(rt, &pinned, &[index]); + allocator.copy(rt, value, src); + + match width { + VMWidth::Lower64 | VMWidth::SLower64 => { + rt.asm.mov(ptr(r12 + index * 8), src).unwrap(); + } + VMWidth::Lower32 => { + let source = get_gpr32(register_of_size(src.into(), 4).unwrap()).unwrap(); + rt.asm.mov(source, source).unwrap(); + rt.asm.mov(ptr(r12 + index * 8), src).unwrap(); + } + VMWidth::Lower16 => { + let source = get_gpr16(register_of_size(src.into(), 2).unwrap()).unwrap(); + rt.asm.mov(ptr(r12 + index * 8), source).unwrap(); + } + VMWidth::Higher8 => { + let source = get_gpr8(register_of_size(src.into(), 1).unwrap()).unwrap(); + rt.asm.mov(ptr(r12 + index * 8 + 0x1), source).unwrap(); + } + VMWidth::Lower8 => { + let source = get_gpr8(register_of_size(src.into(), 1).unwrap()).unwrap(); + rt.asm.mov(ptr(r12 + index * 8), source).unwrap(); + } + _ => unreachable!(), + } + + allocator.consume(value); + } + Effect::Memory(address, expression) => { + let pointer = compile_expression(rt, allocator, address, VMWidth::Lower64); + let value = compile_expression(rt, allocator, expression, width); + + let pinned = [pointer, value] + .into_iter() + .filter_map(|reference| match reference { + Reference::Value(value) => Some(value), + Reference::Immediate(_) => None, + }) + .collect::>(); + + let base = allocator.acquire(rt, &pinned, &[]); + allocator.copy(rt, pointer, base); + + let src = allocator.acquire(rt, &pinned, &[base]); + allocator.copy(rt, value, src); + + match width { + VMWidth::Lower64 | VMWidth::SLower64 => { + rt.asm.mov(ptr(base), src).unwrap(); + } + VMWidth::Lower32 => { + let source = get_gpr32(register_of_size(src.into(), 4).unwrap()).unwrap(); + rt.asm.mov(ptr(base), source).unwrap(); + } + VMWidth::Lower16 => { + let source = get_gpr16(register_of_size(src.into(), 2).unwrap()).unwrap(); + rt.asm.mov(ptr(base), source).unwrap(); + } + VMWidth::Higher8 | VMWidth::Lower8 => { + let source = get_gpr8(register_of_size(src.into(), 1).unwrap()).unwrap(); + rt.asm.mov(ptr(base), source).unwrap(); + } + _ => unreachable!(), + } + + allocator.consume(pointer); + allocator.consume(value); + } + Effect::Assign(index, expression) => { + let value = compile_expression(rt, allocator, expression, width); + + let pinned = match value { + Reference::Value(value) => vec![value], + Reference::Immediate(_) => vec![], + }; + + let dst = allocator.acquire(rt, &pinned, &[]); + allocator.copy(rt, value, dst); + allocator.consume(value); + + rt.asm + .mov(qword_ptr(rbp - allocator.offset(Value::Local(*index))), dst) + .unwrap(); + } + Effect::Read(index, width) => { + let dst = allocator.acquire(rt, &[], &[]); + let register = get_gpr32(register_of_size(dst.into(), 4).unwrap()).unwrap(); + + match width.size() { + 1 => bytecode::read_byte_zx(rt, r13, register), + 2 => bytecode::read_word_zx(rt, r13, register), + 4 => bytecode::read_dword(rt, r13, register), + 8 => bytecode::read_qword(rt, r13, dst), + _ => unreachable!(), + } + + rt.asm + .mov(qword_ptr(rbp - allocator.offset(Value::Local(*index))), dst) + .unwrap(); + } + Effect::Advance(expression) => { + let value = compile_expression(rt, allocator, expression, width); + + let pinned = match value { + Reference::Value(value) => vec![value], + Reference::Immediate(_) => vec![], + }; + + let register = allocator.acquire(rt, &pinned, &[]); + allocator.copy(rt, value, register); + allocator.consume(value); + + rt.asm.add(r13, register).unwrap(); + } + Effect::Drop(expression) => { + let value = compile_expression(rt, allocator, expression, width); + allocator.consume(value); + } + Effect::Loop(counter, body) => { + let counter = Value::Local(*counter); + let mut repeat = rt.asm.create_label(); + let mut done = rt.asm.create_label(); + + rt.asm.set_label(&mut repeat).unwrap(); + rt.asm.zero_bytes().unwrap(); + + let register = allocator.acquire(rt, &[], &[]); + rt.asm + .mov(register, qword_ptr(rbp - allocator.offset(counter))) + .unwrap(); + rt.asm.test(register, register).unwrap(); + rt.asm.jz(done).unwrap(); + + compile_effects(rt, allocator, body, width); + + let register = allocator.acquire(rt, &[], &[]); + rt.asm + .mov(register, qword_ptr(rbp - allocator.offset(counter))) + .unwrap(); + rt.asm.sub(register, 1).unwrap(); + rt.asm + .mov(qword_ptr(rbp - allocator.offset(counter)), register) + .unwrap(); + rt.asm.jmp(repeat).unwrap(); + + rt.asm.set_label(&mut done).unwrap(); + rt.asm.zero_bytes().unwrap(); + } + Effect::Select(selector, arms) => { + let value = compile_expression(rt, allocator, selector, width); + let register = allocator.acquire(rt, &[], &[]); + allocator.copy(rt, value, register); + allocator.consume(value); + + let mut merge = rt.asm.create_label(); + let labels = arms + .iter() + .map(|_| rt.asm.create_label()) + .collect::>(); + + let cases = arms + .iter() + .zip(&labels) + .flat_map(|((keys, _), label)| keys.iter().map(move |key| (*key as u8, *label))) + .collect::>(); + + rt.jumps(register, cases); + + for ((_, body), mut label) in arms.iter().zip(labels) { + rt.asm.set_label(&mut label).unwrap(); + rt.asm.zero_bytes().unwrap(); + compile_effects(rt, allocator, body, width); + rt.asm.jmp(merge).unwrap(); + } + + rt.asm.set_label(&mut merge).unwrap(); + rt.asm.zero_bytes().unwrap(); + } + Effect::When(condition, body) => { + let value = compile_expression(rt, allocator, condition, width); + let register = allocator.acquire(rt, &[], &[]); + allocator.copy(rt, value, register); + allocator.consume(value); + rt.asm.test(register, register).unwrap(); + + let mut skip = rt.asm.create_label(); + rt.asm.jz(skip).unwrap(); + + compile_effects(rt, allocator, body, width); + + rt.asm.set_label(&mut skip).unwrap(); + rt.asm.zero_bytes().unwrap(); + } + Effect::Cpuid => { + rt.asm.push(rbx).unwrap(); + + scratch::load(rt, r12, rcx); + scratch::load(rt, r12, rax); + rt.asm.cpuid().unwrap(); + scratch::store(rt, r12, rax); + scratch::store(rt, r12, rbx); + scratch::store(rt, r12, rcx); + scratch::store(rt, r12, rdx); + + rt.asm.pop(rbx).unwrap(); + } + Effect::Timestamp => { + rt.asm.rdtsc().unwrap(); + scratch::store(rt, r12, rax); + scratch::store(rt, r12, rdx); + } + Effect::Vector(vector) => { + compile_vector(rt, *vector); + rt.asm.zero_bytes().unwrap(); + } } } @@ -880,11 +1231,142 @@ fn compile_expression( match expression { Expression::Operand(Operand::Input(index)) => Reference::Value(Value::Input(*index)), Expression::Operand(Operand::Output(index)) => Reference::Value(Value::Output(*index)), - Expression::Constant(value) => Reference::Immediate(*value as i64), + Expression::Register(register) => { + let index = allocator.acquire(rt, &[], &[]); + let slot = get_gpr32(register_of_size(index.into(), 4).unwrap()).unwrap(); + + match register { + Register::Operand => bytecode::read_byte_zx(rt, r13, slot), + Register::Fixed(register) => { + rt.asm.mov(slot, rt.mapper.index(*register) as i32).unwrap() + } + } + + let dst = allocator.acquire(rt, &[], &[index]); + + match width { + VMWidth::Lower64 | VMWidth::SLower64 => { + rt.asm.mov(dst, ptr(r12 + index * 8)).unwrap(); + } + VMWidth::Lower32 => { + let destination = get_gpr32(register_of_size(dst.into(), 4).unwrap()).unwrap(); + rt.asm.mov(destination, ptr(r12 + index * 8)).unwrap(); + } + VMWidth::Lower16 => { + rt.asm.movzx(dst, word_ptr(r12 + index * 8)).unwrap(); + } + VMWidth::Higher8 => { + rt.asm.movzx(dst, byte_ptr(r12 + index * 8 + 0x1)).unwrap(); + } + VMWidth::Lower8 => { + rt.asm.movzx(dst, byte_ptr(r12 + index * 8)).unwrap(); + } + VMWidth::SLower32 => { + rt.asm.movsxd(dst, dword_ptr(r12 + index * 8)).unwrap(); + } + VMWidth::SLower16 => { + rt.asm.movsx(dst, word_ptr(r12 + index * 8)).unwrap(); + } + VMWidth::SLower8 => { + rt.asm.movsx(dst, byte_ptr(r12 + index * 8)).unwrap(); + } + _ => unreachable!(), + } + + let tmp = allocator.temporary(); + allocator.replace(dst, tmp, true); + + Reference::Value(tmp) + } + Expression::Extend(inner, extend) => { + let src = compile_expression(rt, allocator, inner, *extend); + let dst = allocator.acquire(rt, &[], &[]); + allocator.copy(rt, src, dst); + allocator.consume(src); + + let dword = get_gpr32(register_of_size(dst.into(), 4).unwrap()).unwrap(); + let word = get_gpr16(register_of_size(dst.into(), 2).unwrap()).unwrap(); + let byte = get_gpr8(register_of_size(dst.into(), 1).unwrap()).unwrap(); + + match (extend.size(), *extend == extend.signed()) { + (8, _) => {} + (4, false) => rt.asm.mov(dword, dword).unwrap(), + (4, true) => rt.asm.movsxd(dst, dword).unwrap(), + (2, false) => rt.asm.movzx(dst, word).unwrap(), + (2, true) => rt.asm.movsx(dst, word).unwrap(), + (1, false) => rt.asm.movzx(dst, byte).unwrap(), + (1, true) => rt.asm.movsx(dst, byte).unwrap(), + _ => unreachable!(), + } + + let tmp = allocator.temporary(); + allocator.replace(dst, tmp, true); + + Reference::Value(tmp) + } + Expression::Memory(address) => { + let pointer = compile_expression(rt, allocator, address, VMWidth::Lower64); + + let pinned = match pointer { + Reference::Value(value) => vec![value], + Reference::Immediate(_) => vec![], + }; + + let base = allocator.acquire(rt, &pinned, &[]); + allocator.copy(rt, pointer, base); + + let dst = allocator.acquire(rt, &[], &[base]); + + match width { + VMWidth::Lower64 | VMWidth::SLower64 => { + rt.asm.mov(dst, ptr(base)).unwrap(); + } + VMWidth::Lower32 => { + let destination = get_gpr32(register_of_size(dst.into(), 4).unwrap()).unwrap(); + rt.asm.mov(destination, ptr(base)).unwrap(); + } + VMWidth::Lower16 => { + rt.asm.movzx(dst, word_ptr(base)).unwrap(); + } + VMWidth::Higher8 | VMWidth::Lower8 => { + rt.asm.movzx(dst, byte_ptr(base)).unwrap(); + } + VMWidth::SLower32 => { + rt.asm.movsxd(dst, dword_ptr(base)).unwrap(); + } + VMWidth::SLower16 => { + rt.asm.movsx(dst, word_ptr(base)).unwrap(); + } + VMWidth::SLower8 => { + rt.asm.movsx(dst, byte_ptr(base)).unwrap(); + } + _ => unreachable!(), + } + + allocator.consume(pointer); + + let tmp = allocator.temporary(); + allocator.replace(dst, tmp, true); + + Reference::Value(tmp) + } + Expression::Immediate(Immediate::Fixed(value)) => Reference::Immediate(*value as i64), + Expression::Local(index) => { + let dst = allocator.acquire(rt, &[], &[]); + + rt.asm + .mov(dst, qword_ptr(rbp - allocator.offset(Value::Local(*index)))) + .unwrap(); + + let tmp = allocator.temporary(); + allocator.replace(dst, tmp, true); + + Reference::Value(tmp) + } Expression::Flag(flag) => { let dst = allocator.acquire(rt, &[], &[]); - vreg::load_reg(rt, r12, VMReg::Flags, dst); + register::load(rt, r12, dst, VMReg::Flags); let bit = flag.bit32().trailing_zeros() as i32; @@ -902,6 +1384,16 @@ fn compile_expression( } Expression::Compare(compare) => compile_compare(rt, allocator, compare, width), Expression::Parity(node) => compile_parity(rt, allocator, node, width), + Expression::Segment => { + let dst = allocator.acquire(rt, &[], &[]); + + rt.asm.mov(dst, qword_ptr(0x30).gs()).unwrap(); + + let tmp = allocator.temporary(); + allocator.replace(dst, tmp, true); + + Reference::Value(tmp) + } Expression::SignBit => Reference::Immediate(width.mask().ilog2() as i64), Expression::BitSize => Reference::Immediate((width.size() * 8) as i64), Expression::ByteMask(n) => { @@ -1019,7 +1511,7 @@ fn compile_expression( fn compile_flags(rt: &mut Runtime, allocator: &mut Allocator, flags: &Flags, width: VMWidth) { let register = allocator.acquire(rt, &[], &[]); - vreg::load_reg(rt, r12, VMReg::Flags, register); + register::load(rt, r12, register, VMReg::Flags); rt.asm .mov(qword_ptr(rbp - allocator.offset(Value::Flags)), register) @@ -1061,7 +1553,7 @@ fn compile_flags(rt: &mut Runtime, allocator: &mut Allocator, flags: &Flags, wid .mov(register, qword_ptr(rbp - allocator.offset(Value::Flags))) .unwrap(); - vreg::store_reg(rt, r12, register, VMReg::Flags); + register::store(rt, r12, VMReg::Flags, register); allocator.untrack(register); } diff --git a/runtime/src/vm/handlers/semantic/mod.rs b/runtime/src/vm/handlers/semantic/mod.rs index 78a2ac87..e7390ef8 100644 --- a/runtime/src/vm/handlers/semantic/mod.rs +++ b/runtime/src/vm/handlers/semantic/mod.rs @@ -1,8 +1,9 @@ use rand::Rng; -use crate::vm::bytecode::{Flag, VMWidth}; +use crate::vm::bytecode::{Flag, VMReg, VMWidth}; mod allocator; +pub mod builder; pub mod compiler; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -11,10 +12,43 @@ pub enum Operand { Output(usize), } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Register { + Fixed(VMReg), + Operand, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Immediate { + Fixed(u64), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Vector { + Add, + Sub, + Mul, + Div, + And, + Or, + Xor, + AndNot, + ByteEqual, + ByteMask, + LoadVector, + StoreMerge, + StoreExtend, + LoadMemory, + StoreMemory, +} + #[derive(Debug, Clone)] pub enum Expression { Operand(Operand), - Constant(u64), + Register(Register), + Immediate(Immediate), + Local(usize), + Memory(Box), BitAnd(Box, Box), BitOr(Box, Box), BitXor(Box, Box), @@ -31,6 +65,8 @@ pub enum Expression { SignBit, BitSize, ByteMask(usize), + Segment, + Extend(Box, VMWidth), } #[derive(Debug, Clone)] @@ -46,13 +82,25 @@ pub enum Effect { Rol(Expression, Expression), Mul(Expression, Expression), Div(Expression, Expression, Expression), - Assign(Expression), + Push(Expression), Sar(Expression, Expression), Bsr(Expression), Tzcnt(Expression), Exchange(Expression, Expression), ExchangeAdd(Expression, Expression), CompareExchange(Expression, Expression, Expression), + Register(Register, Expression), + Memory(Expression, Expression), + Assign(usize, Expression), + Read(usize, VMWidth), + Advance(Expression), + Drop(Expression), + Vector(Vector), + Cpuid, + Timestamp, + Loop(usize, Vec), + Select(Expression, Vec<(Vec, Vec)>), + When(Expression, Vec), } #[derive(Debug, Clone)] @@ -65,6 +113,7 @@ pub enum Compare { #[derive(Debug, Clone)] pub enum Flags { + Never, Always(Vec<(Flag, Expression)>), When(Expression, Vec<(Flag, Expression)>), } @@ -82,6 +131,7 @@ enum Value { Input(usize), Output(usize), Flags, + Local(usize), Temporary(usize), } @@ -91,6 +141,38 @@ enum Reference { Immediate(i64), } +fn not(a: Box) -> Box { + Box::new(Expression::BitNot(a)) +} + +fn and(a: Box, b: Box) -> Box { + Box::new(Expression::BitAnd(a, b)) +} + +fn or(a: Box, b: Box) -> Box { + Box::new(Expression::BitOr(a, b)) +} + +fn xor(a: Box, b: Box) -> Box { + Box::new(Expression::BitXor(a, b)) +} + +fn add(a: Box, b: Box) -> Box { + Box::new(Expression::Add(a, b)) +} + +fn sub(a: Box, b: Box) -> Box { + Box::new(Expression::Sub(a, b)) +} + +fn shl(a: Box, b: Box) -> Box { + Box::new(Expression::BitShl(a, b)) +} + +fn imm(value: u64) -> Box { + Box::new(Expression::Immediate(Immediate::Fixed(value))) +} + impl Expression { fn obfuscate(self, rng: &mut impl Rng, budget: &mut u32) -> Expression { let expression = match self { @@ -127,6 +209,10 @@ impl Expression { Box::new(b.obfuscate(rng, budget)), ), Expression::BitNot(a) => Expression::BitNot(Box::new(a.obfuscate(rng, budget))), + Expression::Extend(a, width) => { + Expression::Extend(Box::new(a.obfuscate(rng, budget)), width) + } + Expression::Memory(a) => Expression::Memory(Box::new(a.obfuscate(rng, budget))), Expression::LowByte(a) => Expression::LowByte(Box::new(a.obfuscate(rng, budget))), Expression::Parity(a) => Expression::Parity(Box::new(a.obfuscate(rng, budget))), Expression::Compare(compare) => { @@ -135,61 +221,92 @@ impl Expression { leaf => leaf, }; - if *budget == 0 || rng.gen() { + if *budget == 0 { return expression; } match expression { - // a ^ b = (a | b) - (a & b) Expression::BitXor(a, b) => { *budget -= 1; - Expression::Sub( - Box::new(Expression::BitOr(a.clone(), b.clone())), - Box::new(Expression::BitAnd(a, b)), - ) + match rng.gen_range(0..4) { + // (a | b) - (a & b) + 0 => Expression::Sub(or(a.clone(), b.clone()), and(a, b)), + // (a | b) & ~(a & b) + 1 => Expression::BitAnd(or(a.clone(), b.clone()), not(and(a, b))), + // (a & ~b) | (~a & b) + 2 => Expression::BitOr(and(a.clone(), not(b.clone())), and(not(a), b)), + // (a + b) - ((a & b) << 1) + _ => Expression::Sub(add(a.clone(), b.clone()), shl(and(a, b), imm(1))), + } } - // a | b = ~(~a & ~b) Expression::BitOr(a, b) => { *budget -= 1; - Expression::BitNot(Box::new(Expression::BitAnd( - Box::new(Expression::BitNot(a)), - Box::new(Expression::BitNot(b)), - ))) + match rng.gen_range(0..4) { + // ~(~a & ~b) + 0 => Expression::BitNot(and(not(a), not(b))), + // (a & b) + (a ^ b) + 1 => Expression::Add(and(a.clone(), b.clone()), xor(a, b)), + // a + (b & ~a) + 2 => Expression::Add(a.clone(), and(b, not(a))), + // (a + b) - (a & b) + _ => Expression::Sub(add(a.clone(), b.clone()), and(a, b)), + } } - // a & b = ~(~a | ~b) Expression::BitAnd(a, b) => { *budget -= 1; - Expression::BitNot(Box::new(Expression::BitOr( - Box::new(Expression::BitNot(a)), - Box::new(Expression::BitNot(b)), - ))) + match rng.gen_range(0..4) { + // ~(~a | ~b) + 0 => Expression::BitNot(or(not(a), not(b))), + // (a | b) - (a ^ b) + 1 => Expression::Sub(or(a.clone(), b.clone()), xor(a, b)), + // a - (a & ~b) + 2 => Expression::Sub(a.clone(), and(a, not(b))), + // (a + b) - (a | b) + _ => Expression::Sub(add(a.clone(), b.clone()), or(a, b)), + } } - // ~a = -a - 1 Expression::BitNot(a) => { *budget -= 1; - Expression::Sub( - Box::new(Expression::Sub(Box::new(Expression::Constant(0)), a)), - Box::new(Expression::Constant(1)), - ) + match rng.gen_range(0..2) { + // -a - 1 + 0 => Expression::Sub(sub(imm(0), a), imm(1)), + // a ^ -1 + _ => Expression::BitXor(a, imm(u64::MAX)), + } } - // a + b = (a ^ b) + ((a & b) << 1) Expression::Add(a, b) => { *budget -= 1; - Expression::Add( - Box::new(Expression::BitXor(a.clone(), b.clone())), - Box::new(Expression::BitShl( - Box::new(Expression::BitAnd(a, b)), - Box::new(Expression::Constant(1)), - )), - ) - } - // a - b = a + ~b + 1 + match rng.gen_range(0..3) { + // (a ^ b) + ((a & b) << 1) + 0 => Expression::Add(xor(a.clone(), b.clone()), shl(and(a, b), imm(1))), + // (a | b) + (a & b) + 1 => Expression::Add(or(a.clone(), b.clone()), and(a, b)), + // (a - ~b) - 1 + _ => Expression::Sub(sub(a, not(b)), imm(1)), + } + } Expression::Sub(a, b) => { *budget -= 1; - Expression::Add( - Box::new(Expression::Add(a, Box::new(Expression::BitNot(b)))), - Box::new(Expression::Constant(1)), - ) + match rng.gen_range(0..3) { + // (a + ~b) + 1 + 0 => Expression::Add(add(a, not(b)), imm(1)), + // a + (0 - b) + 1 => Expression::Add(a, sub(imm(0), b)), + // (a ^ b) - ((~a & b) << 1) + _ => Expression::Sub(xor(a.clone(), b.clone()), shl(and(not(a), b), imm(1))), + } + } + Expression::Immediate(Immediate::Fixed(value)) => { + *budget -= 1; + let key = rng.gen::(); + match rng.gen_range(0..3) { + // (value ^ key) ^ key + 0 => Expression::BitXor(imm(value ^ key), imm(key)), + // (value + key) - key + 1 => Expression::Sub(imm(value.wrapping_add(key)), imm(key)), + // (value - key) + key + _ => Expression::Add(imm(value.wrapping_sub(key)), imm(key)), + } } other => other, } @@ -233,7 +350,7 @@ impl Effect { b.obfuscate(rng, budget), c.obfuscate(rng, budget), ), - Effect::Assign(a) => Effect::Assign(a.obfuscate(rng, budget)), + Effect::Push(a) => Effect::Push(a.obfuscate(rng, budget)), Effect::Sar(a, b) => Effect::Sar(a.obfuscate(rng, budget), b.obfuscate(rng, budget)), Effect::Bsr(a) => Effect::Bsr(a.obfuscate(rng, budget)), Effect::Tzcnt(a) => Effect::Tzcnt(a.obfuscate(rng, budget)), @@ -248,10 +365,39 @@ impl Effect { b.obfuscate(rng, budget), c.obfuscate(rng, budget), ), + Effect::Register(register, a) => Effect::Register(register, a.obfuscate(rng, budget)), + Effect::Memory(a, b) => { + Effect::Memory(a.obfuscate(rng, budget), b.obfuscate(rng, budget)) + } + Effect::Assign(local, a) => Effect::Assign(local, a.obfuscate(rng, budget)), + Effect::Read(local, width) => Effect::Read(local, width), + Effect::Advance(a) => Effect::Advance(a.obfuscate(rng, budget)), + Effect::Drop(a) => Effect::Drop(a.obfuscate(rng, budget)), + Effect::Vector(vector) => Effect::Vector(vector), + Effect::Cpuid => Effect::Cpuid, + Effect::Timestamp => Effect::Timestamp, + Effect::Loop(counter, body) => Effect::Loop(counter, obfuscate(body, rng, budget)), + Effect::Select(selector, arms) => Effect::Select( + selector.obfuscate(rng, budget), + arms.into_iter() + .map(|(keys, body)| (keys, obfuscate(body, rng, budget))) + .collect(), + ), + Effect::When(condition, body) => Effect::When( + condition.obfuscate(rng, budget), + obfuscate(body, rng, budget), + ), } } } +fn obfuscate(effects: Vec, rng: &mut impl Rng, budget: &mut u32) -> Vec { + effects + .into_iter() + .map(|effect| effect.obfuscate(rng, budget)) + .collect() +} + impl Operation { fn operands(&self) -> usize { let mut value = 0; @@ -285,6 +431,24 @@ impl Operation { value } + fn locals(&self) -> usize { + let mut value = 0; + + for effect in &self.effects { + effect.locals(&mut value); + } + + self.flags.locals(&mut value); + + if let Some(stores) = &self.stores { + for store in stores { + store.locals(&mut value); + } + } + + value + } + fn temporaries(&self) -> usize { let effects = self.effects.iter().map(Effect::temporary).sum::(); let flags = self.flags.temporary(); @@ -301,13 +465,14 @@ impl Operation { impl Flags { fn values(&self) -> &[(Flag, Expression)] { match self { + Flags::Never => &[], Flags::Always(values) | Flags::When(_, values) => values, } } fn condition(&self) -> Option<&Expression> { match self { - Flags::Always(_) => None, + Flags::Never | Flags::Always(_) => None, Flags::When(condition, _) => Some(condition), } } @@ -336,6 +501,16 @@ impl Flags { condition + values } + + fn locals(&self, value: &mut usize) { + if let Some(condition) = self.condition() { + condition.locals(value); + } + + for (_, expression) in self.values() { + expression.locals(value); + } + } } impl Expression { @@ -345,11 +520,14 @@ impl Expression { *value = (*value).max(*index + 1); } Expression::Operand(Operand::Output(_)) - | Expression::Constant(_) + | Expression::Register(_) + | Expression::Immediate(_) + | Expression::Local(_) | Expression::Flag(_) | Expression::SignBit | Expression::BitSize - | Expression::ByteMask(_) => {} + | Expression::ByteMask(_) + | Expression::Segment => {} Expression::BitAnd(first, second) | Expression::BitOr(first, second) | Expression::BitXor(first, second) @@ -361,7 +539,11 @@ impl Expression { first.operands(value); second.operands(value); } - Expression::BitNot(inner) | Expression::LowByte(inner) | Expression::Parity(inner) => { + Expression::BitNot(inner) + | Expression::LowByte(inner) + | Expression::Parity(inner) + | Expression::Extend(inner, _) + | Expression::Memory(inner) => { inner.operands(value); } Expression::Compare(compare) => compare.operands(value), @@ -371,11 +553,14 @@ impl Expression { fn temporary(&self) -> usize { match self { Expression::Operand(_) - | Expression::Constant(_) + | Expression::Immediate(Immediate::Fixed(_)) | Expression::SignBit | Expression::BitSize | Expression::ByteMask(_) => 0, - Expression::Flag(_) => 1, + Expression::Register(_) + | Expression::Local(_) + | Expression::Flag(_) + | Expression::Segment => 1, Expression::BitAnd(first, second) | Expression::BitOr(first, second) | Expression::BitXor(first, second) @@ -384,12 +569,49 @@ impl Expression { | Expression::Add(first, second) | Expression::Sub(first, second) | Expression::Mul(first, second) => 1 + first.temporary() + second.temporary(), - Expression::BitNot(inner) | Expression::LowByte(inner) | Expression::Parity(inner) => { - 1 + inner.temporary() - } + Expression::BitNot(inner) + | Expression::LowByte(inner) + | Expression::Parity(inner) + | Expression::Extend(inner, _) + | Expression::Memory(inner) => 1 + inner.temporary(), Expression::Compare(compare) => 1 + compare.temporary(), } } + + fn locals(&self, value: &mut usize) { + match self { + Expression::Local(index) => { + *value = (*value).max(*index + 1); + } + Expression::Operand(_) + | Expression::Register(_) + | Expression::Immediate(_) + | Expression::Flag(_) + | Expression::SignBit + | Expression::BitSize + | Expression::ByteMask(_) + | Expression::Segment => {} + Expression::BitAnd(first, second) + | Expression::BitOr(first, second) + | Expression::BitXor(first, second) + | Expression::BitShr(first, second) + | Expression::BitShl(first, second) + | Expression::Add(first, second) + | Expression::Sub(first, second) + | Expression::Mul(first, second) => { + first.locals(value); + second.locals(value); + } + Expression::BitNot(inner) + | Expression::LowByte(inner) + | Expression::Parity(inner) + | Expression::Extend(inner, _) + | Expression::Memory(inner) => { + inner.locals(value); + } + Expression::Compare(compare) => compare.locals(value), + } + } } impl Effect { @@ -421,9 +643,102 @@ impl Effect { second.operands(value); third.operands(value); } - Effect::Assign(expression) | Effect::Bsr(expression) | Effect::Tzcnt(expression) => { + Effect::Memory(first, second) => { + first.operands(value); + second.operands(value); + } + Effect::Push(expression) + | Effect::Bsr(expression) + | Effect::Tzcnt(expression) + | Effect::Register(_, expression) + | Effect::Assign(_, expression) + | Effect::Advance(expression) + | Effect::Drop(expression) => { expression.operands(value); } + Effect::Select(selector, arms) => { + selector.operands(value); + for (_, body) in arms { + for effect in body { + effect.operands(value); + } + } + } + Effect::When(condition, body) => { + condition.operands(value); + for effect in body { + effect.operands(value); + } + } + Effect::Loop(_, body) => { + for effect in body { + effect.operands(value); + } + } + Effect::Read(..) | Effect::Vector(_) | Effect::Cpuid | Effect::Timestamp => {} + } + } + + fn locals(&self, value: &mut usize) { + match self { + Effect::Assign(index, expression) => { + *value = (*value).max(*index + 1); + expression.locals(value); + } + Effect::Read(index, _) => { + *value = (*value).max(*index + 1); + } + Effect::Loop(counter, body) => { + *value = (*value).max(*counter + 1); + for effect in body { + effect.locals(value); + } + } + Effect::Add(first, second) + | Effect::Sub(first, second) + | Effect::And(first, second) + | Effect::Or(first, second) + | Effect::Xor(first, second) + | Effect::Shr(first, second) + | Effect::Shl(first, second) + | Effect::Ror(first, second) + | Effect::Rol(first, second) + | Effect::Mul(first, second) + | Effect::Sar(first, second) + | Effect::Exchange(first, second) + | Effect::ExchangeAdd(first, second) + | Effect::Memory(first, second) => { + first.locals(value); + second.locals(value); + } + Effect::Div(first, second, third) | Effect::CompareExchange(first, second, third) => { + first.locals(value); + second.locals(value); + third.locals(value); + } + Effect::Push(expression) + | Effect::Bsr(expression) + | Effect::Tzcnt(expression) + | Effect::Register(_, expression) + | Effect::Advance(expression) + | Effect::Drop(expression) => { + expression.locals(value); + } + Effect::Select(selector, arms) => { + selector.locals(value); + for (_, body) in arms { + for effect in body { + effect.locals(value); + } + } + } + Effect::When(condition, body) => { + condition.locals(value); + for effect in body { + effect.locals(value); + } + } + Effect::Vector(_) | Effect::Cpuid | Effect::Timestamp => {} } } @@ -439,7 +754,7 @@ impl Effect { | Effect::Ror(..) | Effect::Rol(..) | Effect::Sar(..) - | Effect::Assign(..) + | Effect::Push(..) | Effect::Bsr(..) | Effect::Tzcnt(..) | Effect::Exchange(..) @@ -449,6 +764,27 @@ impl Effect { Effect::Mul(..) | Effect::Div(..) | Effect::ExchangeAdd(..) => { *value = (*value).max(2); } + Effect::Select(_, arms) => { + for (_, body) in arms { + for effect in body { + effect.outputs(value); + } + } + } + Effect::When(_, body) | Effect::Loop(_, body) => { + for effect in body { + effect.outputs(value); + } + } + Effect::Register(..) + | Effect::Memory(..) + | Effect::Assign(..) + | Effect::Read(..) + | Effect::Advance(..) + | Effect::Drop(..) + | Effect::Vector(..) + | Effect::Cpuid + | Effect::Timestamp => {} } } @@ -473,9 +809,27 @@ impl Effect { Effect::CompareExchange(first, second, third) => { first.temporary() + second.temporary() + third.temporary() } - Effect::Assign(expression) | Effect::Bsr(expression) | Effect::Tzcnt(expression) => { - expression.temporary() + Effect::Memory(first, second) => first.temporary() + second.temporary(), + Effect::Push(expression) + | Effect::Bsr(expression) + | Effect::Tzcnt(expression) + | Effect::Register(_, expression) + | Effect::Assign(_, expression) + | Effect::Advance(expression) + | Effect::Drop(expression) => expression.temporary(), + Effect::Select(selector, arms) => { + selector.temporary() + + arms + .iter() + .flat_map(|(_, body)| body) + .map(Effect::temporary) + .sum::() + } + Effect::When(condition, body) => { + condition.temporary() + body.iter().map(Effect::temporary).sum::() } + Effect::Loop(_, body) => body.iter().map(Effect::temporary).sum::(), + Effect::Read(..) | Effect::Vector(_) | Effect::Cpuid | Effect::Timestamp => 0, } } } @@ -501,4 +855,16 @@ impl Compare { | Compare::BitSet(first, second) => first.temporary() + second.temporary(), } } + + fn locals(&self, value: &mut usize) { + match self { + Compare::Equal(first, second) + | Compare::LessThan(first, second) + | Compare::GreaterThan(first, second) + | Compare::BitSet(first, second) => { + first.locals(value); + second.locals(value); + } + } + } } diff --git a/runtime/src/vm/handlers/shl.rs b/runtime/src/vm/handlers/shl.rs index c5589c01..b25ed50d 100644 --- a/runtime/src/vm/handlers/shl.rs +++ b/runtime/src/vm/handlers/shl.rs @@ -2,86 +2,89 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Shl( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::When( - Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::BitOr( - Box::new(Expression::SignBit), - Box::new(Expression::Constant(0x1f)), - )), - ), - vec![ - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Input(0)), - Expression::Sub( - Box::new(Expression::BitSize), - Box::new(Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::BitOr( - Box::new(Expression::SignBit), - Box::new(Expression::Constant(0x1f)), - )), - )), - ), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::GreaterThan( - Expression::BitXor( - Box::new(Expression::BitShr( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::SignBit), - )), - Box::new(Expression::BitShr( - Box::new(Expression::Operand(Operand::Output(0))), +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Shl( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::When( + Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::BitOr( + Box::new(Expression::SignBit), + Box::new(Expression::Immediate(Immediate::Fixed(0x1f))), + )), + ), + vec![ + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Input(0)), + Expression::Sub( + Box::new(Expression::BitSize), + Box::new(Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::BitOr( Box::new(Expression::SignBit), + Box::new(Expression::Immediate(Immediate::Fixed(0x1f))), )), - ), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ], - ), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, + )), + ), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::GreaterThan( + Expression::BitXor( + Box::new(Expression::BitShr( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::SignBit), + )), + Box::new(Expression::BitShr( + Box::new(Expression::Operand(Operand::Output(0))), + Box::new(Expression::SignBit), + )), + ), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), ], - }, - ); + ), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/shr.rs b/runtime/src/vm/handlers/shr.rs index b4a8ebbc..e4af93f2 100644 --- a/runtime/src/vm/handlers/shr.rs +++ b/runtime/src/vm/handlers/shr.rs @@ -2,77 +2,80 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Shr( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::When( - Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::BitOr( - Box::new(Expression::SignBit), - Box::new(Expression::Constant(0x1f)), - )), - ), - vec![ - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Input(0)), - Expression::Sub( - Box::new(Expression::BitAnd( - Box::new(Expression::Operand(Operand::Input(1))), - Box::new(Expression::BitOr( - Box::new(Expression::SignBit), - Box::new(Expression::Constant(0x1f)), - )), - )), - Box::new(Expression::Constant(1)), - ), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Input(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ], +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Shr( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::When( + Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::BitOr( + Box::new(Expression::SignBit), + Box::new(Expression::Immediate(Immediate::Fixed(0x1f))), + )), ), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, + vec![ + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Input(0)), + Expression::Sub( + Box::new(Expression::BitAnd( + Box::new(Expression::Operand(Operand::Input(1))), + Box::new(Expression::BitOr( + Box::new(Expression::SignBit), + Box::new(Expression::Immediate(Immediate::Fixed(0x1f))), + )), + )), + Box::new(Expression::Immediate(Immediate::Fixed(1))), + ), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Input(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), ], - }, - ); + ), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/store_extend.rs b/runtime/src/vm/handlers/store_extend.rs index 24ad8865..bdc126d6 100644 --- a/runtime/src/vm/handlers/store_extend.rs +++ b/runtime/src/vm/handlers/store_extend.rs @@ -1,81 +1,17 @@ -use iced_x86::code_asm::{ptr, r12, r8, r8d, r9, r9d, rax, rcx, xmm0, ymm0}; - use crate::{ runtime::Runtime, - vm::{ - bytecode::VMReg, - utils::{self, scratch}, - }, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut epilogue = rt.asm.create_label(); - - // r8d -> width - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> destination - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // shl r9, 0x5 - rt.asm.shl(r9, 0x5).unwrap(); - - // mov rax, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VVector, rax); - - utils::width::dispatch( - rt, - r8, - &mut epilogue, - Some(Box::new(|rt| { - // load ymm0 - rt.asm.vmovups(ymm0, ptr(rax + r9)).unwrap(); - // load r8 - scratch::load(rt, r12, r8); - // movq xmm0, r8 - rt.asm.movq(xmm0, r8).unwrap(); - // vmovups [rax + r9], ymm0 - rt.asm.vmovups(ptr(rax + r9), ymm0).unwrap(); - })), - Some(Box::new(|rt| { - // load ymm0 - rt.asm.vmovups(ymm0, ptr(rax + r9)).unwrap(); - // load r8 - scratch::load(rt, r12, r8); - // movd xmm0, r8d - rt.asm.movd(xmm0, r8d).unwrap(); - // vmovups [rax + r9], ymm0 - rt.asm.vmovups(ptr(rax + r9), ymm0).unwrap(); - })), - None, - None, - None, - None, - None, - None, - None, - None, - Some(Box::new(|rt| { - // load xmm0 - scratch::load_128(rt, r12, xmm0); - // vmovaps xmm0, xmm0 - rt.asm.vmovaps(xmm0, xmm0).unwrap(); - // vmovups [rax + r9], ymm0 - rt.asm.vmovups(ptr(rax + r9), ymm0).unwrap(); - })), - Some(Box::new(|rt| { - // load ymm0 - scratch::load_256(rt, r12, ymm0); - // vmovups [rax + r9], ymm0 - rt.asm.vmovups(ptr(rax + r9), ymm0).unwrap(); - })), - ); - - rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::StoreExtend)], + flags: Flags::Never, + stores: None, + widths: &[], } } + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/store_memory.rs b/runtime/src/vm/handlers/store_memory.rs index f38013ef..ac1b9b59 100644 --- a/runtime/src/vm/handlers/store_memory.rs +++ b/runtime/src/vm/handlers/store_memory.rs @@ -1,72 +1,17 @@ -use iced_x86::code_asm::{eax, ptr, r12, r8, r9, r9b, r9d, r9w, rax, rcx, xmm0, ymm0}; - use crate::{ runtime::Runtime, - vm::utils::{self, scratch}, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut epilogue = rt.asm.create_label(); - - // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); - - // load r8 - scratch::load(rt, r12, r8); - - utils::width::dispatch( - rt, - rax, - &mut epilogue, - Some(Box::new(|rt| { - // load r9 - scratch::load(rt, r12, r9); - // mov [r8], r9 - rt.asm.mov(ptr(r8), r9).unwrap(); - })), - Some(Box::new(|rt| { - // load r9 - scratch::load(rt, r12, r9); - // mov [r8], r9d - rt.asm.mov(ptr(r8), r9d).unwrap(); - })), - None, - Some(Box::new(|rt| { - // load r9 - scratch::load(rt, r12, r9); - // mov [r8], r9w - rt.asm.mov(ptr(r8), r9w).unwrap(); - })), - None, - Some(Box::new(|rt| { - // load r9 - scratch::load(rt, r12, r9); - // mov [r8], r9b - rt.asm.mov(ptr(r8), r9b).unwrap(); - })), - None, - None, - None, - None, - Some(Box::new(|rt| { - // load xmm0 - scratch::load_128(rt, r12, xmm0); - // movups [r8], xmm0 - rt.asm.movups(ptr(r8), xmm0).unwrap(); - })), - Some(Box::new(|rt| { - // load ymm0 - scratch::load_256(rt, r12, ymm0); - // vmovups [r8], ymm0 - rt.asm.vmovups(ptr(r8), ymm0).unwrap(); - })), - ); - rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::StoreMemory)], + flags: Flags::Never, + stores: None, + widths: &[], } } + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/store_merge.rs b/runtime/src/vm/handlers/store_merge.rs index 505c73d2..fc2d881f 100644 --- a/runtime/src/vm/handlers/store_merge.rs +++ b/runtime/src/vm/handlers/store_merge.rs @@ -1,71 +1,17 @@ -use iced_x86::code_asm::{ptr, r12, r8, r8d, r9, r9d, rax, rcx, xmm0, ymm0}; - use crate::{ runtime::Runtime, - vm::{ - bytecode::VMReg, - utils::{self, scratch}, - }, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut epilogue = rt.asm.create_label(); - - // r8d -> width - utils::bytecode::read_byte_zx(rt, rcx, r8d); - // r9d -> destination - utils::bytecode::read_byte_zx(rt, rcx, r9d); - - // shl r9, 0x5 - rt.asm.shl(r9, 0x5).unwrap(); - - // mov rax, [r12 + ...] - utils::vreg::load_reg(rt, r12, VMReg::VVector, rax); - - utils::width::dispatch( - rt, - r8, - &mut epilogue, - Some(Box::new(|rt| { - // load r8 - scratch::load(rt, r12, r8); - // mov [rax + r9], r8 - rt.asm.mov(ptr(rax + r9), r8).unwrap(); - })), - Some(Box::new(|rt| { - // load r8 - scratch::load(rt, r12, r8); - // mov [rax + r9], r8d - rt.asm.mov(ptr(rax + r9), r8d).unwrap(); - })), - None, - None, - None, - None, - None, - None, - None, - None, - Some(Box::new(|rt| { - // load xmm0 - scratch::load_128(rt, r12, xmm0); - // movups [rax + r9], xmm0 - rt.asm.movups(ptr(rax + r9), xmm0).unwrap(); - })), - Some(Box::new(|rt| { - // load ymm0 - scratch::load_256(rt, r12, ymm0); - // vmovups [rax + r9], ymm0 - rt.asm.vmovups(ptr(rax + r9), ymm0).unwrap(); - })), - ); - - rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::StoreMerge)], + flags: Flags::Never, + stores: None, + widths: &[], } } + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/store_register.rs b/runtime/src/vm/handlers/store_register.rs index 57df52f6..18d87db9 100644 --- a/runtime/src/vm/handlers/store_register.rs +++ b/runtime/src/vm/handlers/store_register.rs @@ -1,68 +1,29 @@ -use iced_x86::code_asm::{eax, ptr, r12, r8, r8d, r9, r9b, r9d, r9w, rax, rcx}; - use crate::{ runtime::Runtime, - vm::utils::{self, scratch}, + vm::{ + bytecode::VMWidth, + handlers::semantic::{self, Effect, Expression, Flags, Operand, Operation, Register}, + }, }; -// unsigned char* (unsigned char*) -pub fn build(rt: &mut Runtime) { - let mut epilogue = rt.asm.create_label(); - - // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); - - // r8d -> destination - utils::bytecode::read_byte_zx(rt, rcx, r8d); - - utils::width::dispatch( - rt, - rax, - &mut epilogue, - Some(Box::new(|rt| { - // load r9 - scratch::load(rt, r12, r9); - // mov [r12 + r8*8], r9 - rt.asm.mov(ptr(r12 + r8 * 8), r9).unwrap(); - })), - Some(Box::new(|rt| { - // load r9d - scratch::load_32(rt, r12, r9d); - // mov [r12 + r8*8], r9 - rt.asm.mov(ptr(r12 + r8 * 8), r9).unwrap(); - })), - None, - Some(Box::new(|rt| { - // load r9 - scratch::load(rt, r12, r9); - // mov [r12 + r8*8], r9w - rt.asm.mov(ptr(r12 + r8 * 8), r9w).unwrap(); - })), - Some(Box::new(|rt| { - // load r9 - scratch::load(rt, r12, r9); - // mov [r12 + r8*8 + 0x1], r9b - rt.asm.mov(ptr(r12 + r8 * 8 + 0x1), r9b).unwrap(); - })), - Some(Box::new(|rt| { - // load r9 - scratch::load(rt, r12, r9); - // mov [r12 + r8*8], r9b - rt.asm.mov(ptr(r12 + r8 * 8), r9b).unwrap(); - })), - None, - None, - None, - None, - None, - None, - ); - - rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Register( + Register::Operand, + Expression::Operand(Operand::Input(0)), + )], + flags: Flags::Never, + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Higher8, + VMWidth::Lower8, + ], } } + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); +} diff --git a/runtime/src/vm/handlers/sub.rs b/runtime/src/vm/handlers/sub.rs index 43d080ff..abc1ac0d 100644 --- a/runtime/src/vm/handlers/sub.rs +++ b/runtime/src/vm/handlers/sub.rs @@ -2,81 +2,84 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; -pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Sub( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::Always(vec![ - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::LessThan( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitAnd( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Input(1))), - )), - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Output(0))), - )), - ), - Expression::SignBit, - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ( - Flag::Auxiliary, - Expression::Compare(Box::new(Compare::BitSet( - Expression::BitXor( - Box::new(Expression::BitXor( - Box::new(Expression::Operand(Operand::Input(0))), - Box::new(Expression::Operand(Operand::Input(1))), - )), +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Sub( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::Always(vec![ + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::LessThan( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitAnd( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Input(1))), + )), + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), Box::new(Expression::Operand(Operand::Output(0))), - ), - Expression::Constant(4), - ))), - ), - ]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - ], - }, - ); + )), + ), + Expression::SignBit, + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), + ( + Flag::Auxiliary, + Expression::Compare(Box::new(Compare::BitSet( + Expression::BitXor( + Box::new(Expression::BitXor( + Box::new(Expression::Operand(Operand::Input(0))), + Box::new(Expression::Operand(Operand::Input(1))), + )), + Box::new(Expression::Operand(Operand::Output(0))), + ), + Expression::Immediate(Immediate::Fixed(4)), + ))), + ), + ]), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + +pub fn build(rt: &mut Runtime) { + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/timestamp.rs b/runtime/src/vm/handlers/timestamp.rs index cef91c66..cdbed067 100644 --- a/runtime/src/vm/handlers/timestamp.rs +++ b/runtime/src/vm/handlers/timestamp.rs @@ -1,17 +1,17 @@ -use crate::runtime::Runtime; -use crate::vm::utils::scratch; -use iced_x86::code_asm::*; +use crate::{ + runtime::Runtime, + vm::handlers::semantic::{self, Effect, Flags, Operation}, +}; + +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Timestamp], + flags: Flags::Never, + stores: None, + widths: &[], + } +} -// unsigned char* (unsigned char*) pub fn build(rt: &mut Runtime) { - // rdtsc - rt.asm.rdtsc().unwrap(); - // store rax - scratch::store(rt, r12, rax); - // store rdx - scratch::store(rt, r12, rdx); - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/trailing_zeros.rs b/runtime/src/vm/handlers/trailing_zeros.rs index 495a6b85..3d554098 100644 --- a/runtime/src/vm/handlers/trailing_zeros.rs +++ b/runtime/src/vm/handlers/trailing_zeros.rs @@ -2,33 +2,36 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Tzcnt(Expression::Operand(Operand::Input(0)))], + flags: Flags::Always(vec![ + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Input(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ]), + stores: None, + widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], + } +} + pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Tzcnt(Expression::Operand(Operand::Input(0)))], - flags: Flags::Always(vec![ - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Input(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ]), - stores: None, - widths: &[VMWidth::Lower64, VMWidth::Lower32, VMWidth::Lower16], - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/vector.rs b/runtime/src/vm/handlers/vector.rs index 77120be8..803e0114 100644 --- a/runtime/src/vm/handlers/vector.rs +++ b/runtime/src/vm/handlers/vector.rs @@ -1,8 +1,14 @@ -use iced_x86::code_asm::{eax, r12, r8, r8d, r9, r9d, rax, rcx, xmm0, xmm1, ymm0, ymm1}; +use iced_x86::code_asm::{ + byte_ptr, dword_ptr, eax, ptr, r12, r13, r8, r8d, r9, r9b, r9d, r9w, rax, word_ptr, xmm0, xmm1, + ymm0, ymm1, +}; use crate::{ runtime::Runtime, - vm::utils::{self, scratch}, + vm::{ + bytecode::VMReg, + utils::{self, scratch}, + }, }; pub fn with_width( @@ -13,7 +19,7 @@ pub fn with_width( let mut epilogue = rt.asm.create_label(); // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); + utils::bytecode::read_byte_zx(rt, r13, eax); utils::width::dispatch( rt, @@ -50,12 +56,6 @@ pub fn with_width( ); rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); - } } pub fn with_stride( @@ -68,7 +68,7 @@ pub fn with_stride( let mut epilogue = rt.asm.create_label(); // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); + utils::bytecode::read_byte_zx(rt, r13, eax); utils::width::dispatch( rt, @@ -88,7 +88,7 @@ pub fn with_stride( let mut stride_epilogue = rt.asm.create_label(); // r8d -> stride - utils::bytecode::read_byte_zx(rt, rcx, r8d); + utils::bytecode::read_byte_zx(rt, r13, r8d); // load xmm1 scratch::load_128(rt, r12, xmm1); @@ -126,7 +126,7 @@ pub fn with_stride( let mut stride_epilogue = rt.asm.create_label(); // r8d -> stride - utils::bytecode::read_byte_zx(rt, rcx, r8d); + utils::bytecode::read_byte_zx(rt, r13, r8d); // load ymm1 scratch::load_256(rt, r12, ymm1); @@ -163,12 +163,6 @@ pub fn with_stride( ); rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); - } } pub fn with_precision( @@ -193,7 +187,7 @@ pub fn with_precision( let mut epilogue = rt.asm.create_label(); // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); + utils::bytecode::read_byte_zx(rt, r13, eax); utils::width::dispatch( rt, @@ -214,10 +208,10 @@ pub fn with_precision( let mut precision_epilogue = rt.asm.create_label(); // r8d -> stride - utils::bytecode::read_byte_zx(rt, rcx, r8d); + utils::bytecode::read_byte_zx(rt, r13, r8d); // r9d -> precision - utils::bytecode::read_byte_zx(rt, rcx, r9d); + utils::bytecode::read_byte_zx(rt, r13, r9d); // load xmm1 scratch::load_128(rt, r12, xmm1); @@ -302,10 +296,10 @@ pub fn with_precision( let mut precision_epilogue = rt.asm.create_label(); // r8d -> stride - utils::bytecode::read_byte_zx(rt, rcx, r8d); + utils::bytecode::read_byte_zx(rt, r13, r8d); // r9d -> precision - utils::bytecode::read_byte_zx(rt, rcx, r9d); + utils::bytecode::read_byte_zx(rt, r13, r9d); // load ymm1 scratch::load_256(rt, r12, ymm1); @@ -388,12 +382,6 @@ pub fn with_precision( ); rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); - } } pub fn with_extension( @@ -412,7 +400,7 @@ pub fn with_extension( let mut epilogue = rt.asm.create_label(); // eax -> width - utils::bytecode::read_byte_zx(rt, rcx, eax); + utils::bytecode::read_byte_zx(rt, r13, eax); utils::width::dispatch( rt, @@ -433,10 +421,10 @@ pub fn with_extension( let mut precision_epilogue = rt.asm.create_label(); // r8d -> stride - utils::bytecode::read_byte_zx(rt, rcx, r8d); + utils::bytecode::read_byte_zx(rt, r13, r8d); // r9d -> precision - utils::bytecode::read_byte_zx(rt, rcx, r9d); + utils::bytecode::read_byte_zx(rt, r13, r9d); // load xmm1 scratch::load_128(rt, r12, xmm1); @@ -515,10 +503,10 @@ pub fn with_extension( let mut precision_epilogue = rt.asm.create_label(); // r8d -> stride - utils::bytecode::read_byte_zx(rt, rcx, r8d); + utils::bytecode::read_byte_zx(rt, r13, r8d); // r9d -> precision - utils::bytecode::read_byte_zx(rt, rcx, r9d); + utils::bytecode::read_byte_zx(rt, r13, r9d); // load ymm1 scratch::load_256(rt, r12, ymm1); @@ -595,10 +583,279 @@ pub fn with_extension( ); rt.asm.set_label(&mut epilogue).unwrap(); - { - // mov rax, rcx - rt.asm.mov(rax, rcx).unwrap(); - // ret - rt.asm.ret().unwrap(); - } +} + +pub fn byte_mask(rt: &mut Runtime) { + let mut epilogue = rt.asm.create_label(); + + utils::bytecode::read_byte_zx(rt, r13, eax); + + utils::width::dispatch( + rt, + rax, + &mut epilogue, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + Some(Box::new(|rt| { + scratch::load_128(rt, r12, xmm0); + rt.asm.pmovmskb(r8d, xmm0).unwrap(); + scratch::store(rt, r12, r8); + })), + Some(Box::new(|rt| { + scratch::load_256(rt, r12, ymm0); + rt.asm.vpmovmskb(r8d, ymm0).unwrap(); + scratch::store(rt, r12, r8); + })), + ); + + rt.asm.set_label(&mut epilogue).unwrap(); +} + +pub fn load_vector(rt: &mut Runtime) { + let mut epilogue = rt.asm.create_label(); + + utils::bytecode::read_byte_zx(rt, r13, r8d); + utils::bytecode::read_byte_zx(rt, r13, r9d); + + rt.asm.shl(r9, 0x5).unwrap(); + + utils::register::load(rt, r12, rax, VMReg::VVector); + + utils::width::dispatch( + rt, + r8, + &mut epilogue, + Some(Box::new(|rt| { + rt.asm.mov(rax, ptr(rax + r9)).unwrap(); + scratch::store(rt, r12, rax); + })), + Some(Box::new(|rt| { + rt.asm.mov(eax, ptr(rax + r9)).unwrap(); + scratch::store(rt, r12, rax); + })), + None, + None, + None, + None, + None, + None, + None, + None, + Some(Box::new(|rt| { + rt.asm.movups(xmm0, ptr(rax + r9)).unwrap(); + scratch::store_128(rt, r12, xmm0); + })), + Some(Box::new(|rt| { + rt.asm.vmovups(ymm0, ptr(rax + r9)).unwrap(); + scratch::store_256(rt, r12, ymm0); + })), + ); + + rt.asm.set_label(&mut epilogue).unwrap(); +} + +pub fn store_merge(rt: &mut Runtime) { + let mut epilogue = rt.asm.create_label(); + + utils::bytecode::read_byte_zx(rt, r13, r8d); + utils::bytecode::read_byte_zx(rt, r13, r9d); + + rt.asm.shl(r9, 0x5).unwrap(); + + utils::register::load(rt, r12, rax, VMReg::VVector); + + utils::width::dispatch( + rt, + r8, + &mut epilogue, + Some(Box::new(|rt| { + scratch::load(rt, r12, r8); + rt.asm.mov(ptr(rax + r9), r8).unwrap(); + })), + Some(Box::new(|rt| { + scratch::load(rt, r12, r8); + rt.asm.mov(ptr(rax + r9), r8d).unwrap(); + })), + None, + None, + None, + None, + None, + None, + None, + None, + Some(Box::new(|rt| { + scratch::load_128(rt, r12, xmm0); + rt.asm.movups(ptr(rax + r9), xmm0).unwrap(); + })), + Some(Box::new(|rt| { + scratch::load_256(rt, r12, ymm0); + rt.asm.vmovups(ptr(rax + r9), ymm0).unwrap(); + })), + ); + + rt.asm.set_label(&mut epilogue).unwrap(); +} + +pub fn store_extend(rt: &mut Runtime) { + let mut epilogue = rt.asm.create_label(); + + utils::bytecode::read_byte_zx(rt, r13, r8d); + utils::bytecode::read_byte_zx(rt, r13, r9d); + + rt.asm.shl(r9, 0x5).unwrap(); + + utils::register::load(rt, r12, rax, VMReg::VVector); + + utils::width::dispatch( + rt, + r8, + &mut epilogue, + Some(Box::new(|rt| { + rt.asm.vmovups(ymm0, ptr(rax + r9)).unwrap(); + scratch::load(rt, r12, r8); + rt.asm.movq(xmm0, r8).unwrap(); + rt.asm.vmovups(ptr(rax + r9), ymm0).unwrap(); + })), + Some(Box::new(|rt| { + rt.asm.vmovups(ymm0, ptr(rax + r9)).unwrap(); + scratch::load(rt, r12, r8); + rt.asm.movd(xmm0, r8d).unwrap(); + rt.asm.vmovups(ptr(rax + r9), ymm0).unwrap(); + })), + None, + None, + None, + None, + None, + None, + None, + None, + Some(Box::new(|rt| { + scratch::load_128(rt, r12, xmm0); + rt.asm.vmovaps(xmm0, xmm0).unwrap(); + rt.asm.vmovups(ptr(rax + r9), ymm0).unwrap(); + })), + Some(Box::new(|rt| { + scratch::load_256(rt, r12, ymm0); + rt.asm.vmovups(ptr(rax + r9), ymm0).unwrap(); + })), + ); + + rt.asm.set_label(&mut epilogue).unwrap(); +} + +pub fn load_memory(rt: &mut Runtime) { + let mut epilogue = rt.asm.create_label(); + + utils::bytecode::read_byte_zx(rt, r13, eax); + + scratch::load(rt, r12, r8); + + utils::width::dispatch( + rt, + rax, + &mut epilogue, + Some(Box::new(|rt| { + rt.asm.mov(r9, ptr(r8)).unwrap(); + scratch::store(rt, r12, r9); + })), + Some(Box::new(|rt| { + rt.asm.mov(r9d, ptr(r8)).unwrap(); + scratch::store(rt, r12, r9); + })), + None, + Some(Box::new(|rt| { + rt.asm.movzx(r9, word_ptr(r8)).unwrap(); + scratch::store(rt, r12, r9); + })), + Some(Box::new(|rt| { + rt.asm.movzx(r9, byte_ptr(r8)).unwrap(); + scratch::store(rt, r12, r9); + })), + Some(Box::new(|rt| { + rt.asm.movzx(r9, byte_ptr(r8)).unwrap(); + scratch::store(rt, r12, r9); + })), + Some(Box::new(|rt| { + rt.asm.mov(r9, ptr(r8)).unwrap(); + scratch::store(rt, r12, r9); + })), + Some(Box::new(|rt| { + rt.asm.movsxd(r9, dword_ptr(r8)).unwrap(); + scratch::store(rt, r12, r9); + })), + Some(Box::new(|rt| { + rt.asm.movsx(r9, word_ptr(r8)).unwrap(); + scratch::store(rt, r12, r9); + })), + Some(Box::new(|rt| { + rt.asm.movsx(r9, byte_ptr(r8)).unwrap(); + scratch::store(rt, r12, r9); + })), + Some(Box::new(|rt| { + rt.asm.movups(xmm0, ptr(r8)).unwrap(); + scratch::store_128(rt, r12, xmm0); + })), + Some(Box::new(|rt| { + rt.asm.vmovups(ymm0, ptr(r8)).unwrap(); + scratch::store_256(rt, r12, ymm0); + })), + ); + + rt.asm.set_label(&mut epilogue).unwrap(); +} + +pub fn store_memory(rt: &mut Runtime) { + let mut epilogue = rt.asm.create_label(); + + utils::bytecode::read_byte_zx(rt, r13, eax); + + scratch::load(rt, r12, r8); + + utils::width::dispatch( + rt, + rax, + &mut epilogue, + Some(Box::new(|rt| { + scratch::load(rt, r12, r9); + rt.asm.mov(ptr(r8), r9).unwrap(); + })), + Some(Box::new(|rt| { + scratch::load(rt, r12, r9); + rt.asm.mov(ptr(r8), r9d).unwrap(); + })), + None, + Some(Box::new(|rt| { + scratch::load(rt, r12, r9); + rt.asm.mov(ptr(r8), r9w).unwrap(); + })), + None, + Some(Box::new(|rt| { + scratch::load(rt, r12, r9); + rt.asm.mov(ptr(r8), r9b).unwrap(); + })), + None, + None, + None, + None, + Some(Box::new(|rt| { + scratch::load_128(rt, r12, xmm0); + rt.asm.movups(ptr(r8), xmm0).unwrap(); + })), + Some(Box::new(|rt| { + scratch::load_256(rt, r12, ymm0); + rt.asm.vmovups(ptr(r8), ymm0).unwrap(); + })), + ); + + rt.asm.set_label(&mut epilogue).unwrap(); } diff --git a/runtime/src/vm/handlers/vector_add.rs b/runtime/src/vm/handlers/vector_add.rs index 40e45184..63a47cf5 100644 --- a/runtime/src/vm/handlers/vector_add.rs +++ b/runtime/src/vm/handlers/vector_add.rs @@ -1,74 +1,17 @@ -use crate::{runtime::Runtime, vm::handlers::vector}; -use iced_x86::code_asm::{xmm0, xmm1, ymm0, ymm1}; +use crate::{ + runtime::Runtime, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, +}; + +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::Add)], + flags: Flags::Never, + stores: None, + widths: &[], + } +} -// unsigned char* (unsigned char*) pub fn build(rt: &mut Runtime) { - vector::with_precision( - rt, - |rt| { - // paddb xmm0, xmm1 - rt.asm.paddb(xmm0, xmm1).unwrap(); - }, - |rt| { - // paddw xmm0, xmm1 - rt.asm.paddw(xmm0, xmm1).unwrap(); - }, - |rt| { - // paddd xmm0, xmm1 - rt.asm.paddd(xmm0, xmm1).unwrap(); - }, - |rt| { - // paddq xmm0, xmm1 - rt.asm.paddq(xmm0, xmm1).unwrap(); - }, - |rt| { - // addps xmm0, xmm1 - rt.asm.addps(xmm0, xmm1).unwrap(); - }, - |rt| { - // addps xmm0, xmm1 - rt.asm.addps(xmm0, xmm1).unwrap(); - }, - |rt| { - // addps xmm0, xmm1 - rt.asm.addps(xmm0, xmm1).unwrap(); - }, - |rt| { - // addpd xmm0, xmm1 - rt.asm.addpd(xmm0, xmm1).unwrap(); - }, - // avx_int - |rt| { - // vpaddb ymm0, ymm0, ymm1 - rt.asm.vpaddb(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vpaddw ymm0, ymm0, ymm1 - rt.asm.vpaddw(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vpaddd ymm0, ymm0, ymm1 - rt.asm.vpaddd(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vpaddq ymm0, ymm0, ymm1 - rt.asm.vpaddq(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vaddps ymm0, ymm0, ymm1 - rt.asm.vaddps(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vaddps ymm0, ymm0, ymm1 - rt.asm.vaddps(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vaddps ymm0, ymm0, ymm1 - rt.asm.vaddps(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vaddpd ymm0, ymm0, ymm1 - rt.asm.vaddpd(ymm0, ymm0, ymm1).unwrap(); - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/vector_and.rs b/runtime/src/vm/handlers/vector_and.rs index bf286da1..070325c6 100644 --- a/runtime/src/vm/handlers/vector_and.rs +++ b/runtime/src/vm/handlers/vector_and.rs @@ -1,18 +1,17 @@ -use iced_x86::code_asm::{xmm0, xmm1, ymm0, ymm1}; +use crate::{ + runtime::Runtime, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, +}; -use crate::{runtime::Runtime, vm::handlers::vector}; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::And)], + flags: Flags::Never, + stores: None, + widths: &[], + } +} -// unsigned char* (unsigned char*) pub fn build(rt: &mut Runtime) { - vector::with_width( - rt, - |rt| { - // pand xmm0, xmm1 - rt.asm.pand(xmm0, xmm1).unwrap(); - }, - |rt| { - // vpand ymm0, ymm0, ymm1 - rt.asm.vpand(ymm0, ymm0, ymm1).unwrap(); - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/vector_and_not.rs b/runtime/src/vm/handlers/vector_and_not.rs index 85531f3d..15a17b7c 100644 --- a/runtime/src/vm/handlers/vector_and_not.rs +++ b/runtime/src/vm/handlers/vector_and_not.rs @@ -1,18 +1,17 @@ -use iced_x86::code_asm::{xmm0, xmm1, ymm0, ymm1}; +use crate::{ + runtime::Runtime, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, +}; -use crate::{runtime::Runtime, vm::handlers::vector}; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::AndNot)], + flags: Flags::Never, + stores: None, + widths: &[], + } +} -// unsigned char* (unsigned char*) pub fn build(rt: &mut Runtime) { - vector::with_width( - rt, - |rt| { - // pandn xmm0, xmm1 - rt.asm.pandn(xmm0, xmm1).unwrap(); - }, - |rt| { - // vpandn ymm0, ymm0, ymm1 - rt.asm.vpandn(ymm0, ymm0, ymm1).unwrap(); - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/vector_div.rs b/runtime/src/vm/handlers/vector_div.rs index 61a0106b..7446f07b 100644 --- a/runtime/src/vm/handlers/vector_div.rs +++ b/runtime/src/vm/handlers/vector_div.rs @@ -1,26 +1,17 @@ -use iced_x86::code_asm::{xmm0, xmm1, ymm0, ymm1}; +use crate::{ + runtime::Runtime, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, +}; -use crate::{runtime::Runtime, vm::handlers::vector}; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::Div)], + flags: Flags::Never, + stores: None, + widths: &[], + } +} -// unsigned char* (unsigned char*) pub fn build(rt: &mut Runtime) { - vector::with_stride( - rt, - |rt| { - // divps xmm0, xmm1 - rt.asm.divps(xmm0, xmm1).unwrap(); - }, - |rt| { - // divpd xmm0, xmm1 - rt.asm.divpd(xmm0, xmm1).unwrap(); - }, - |rt| { - // vdivps ymm0, ymm0, ymm1 - rt.asm.vdivps(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vdivpd ymm0, ymm0, ymm1 - rt.asm.vdivpd(ymm0, ymm0, ymm1).unwrap(); - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/vector_mul.rs b/runtime/src/vm/handlers/vector_mul.rs index d4cb4882..e5fc90f0 100644 --- a/runtime/src/vm/handlers/vector_mul.rs +++ b/runtime/src/vm/handlers/vector_mul.rs @@ -1,50 +1,17 @@ -use iced_x86::code_asm::{xmm0, xmm1, ymm0, ymm1}; +use crate::{ + runtime::Runtime, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, +}; -use crate::{runtime::Runtime, vm::handlers::vector}; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::Mul)], + flags: Flags::Never, + stores: None, + widths: &[], + } +} -// unsigned char* (unsigned char*) pub fn build(rt: &mut Runtime) { - vector::with_extension( - rt, - |rt| { - // mulpd xmm0, xmm1 - rt.asm.mulpd(xmm0, xmm1).unwrap(); - }, - |rt| { - // pmulld xmm0, xmm1 - rt.asm.pmulld(xmm0, xmm1).unwrap(); - }, - |rt| { - // mulps xmm0, xmm1 - rt.asm.mulps(xmm0, xmm1).unwrap(); - }, - |rt| { - // pmulhw xmm0, xmm1 - rt.asm.pmulhw(xmm0, xmm1).unwrap(); - }, - |rt| { - // pmullw xmm0, xmm1 - rt.asm.pmullw(xmm0, xmm1).unwrap(); - }, - |rt| { - // vmulpd ymm0, ymm0, ymm1 - rt.asm.vmulpd(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vpmulld ymm0, ymm0, ymm1 - rt.asm.vpmulld(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vmulps ymm0, ymm0, ymm1 - rt.asm.vmulps(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vpmulhw ymm0, ymm0, ymm1 - rt.asm.vpmulhw(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vpmullw ymm0, ymm0, ymm1 - rt.asm.vpmullw(ymm0, ymm0, ymm1).unwrap(); - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/vector_or.rs b/runtime/src/vm/handlers/vector_or.rs index 9577821c..75a47f58 100644 --- a/runtime/src/vm/handlers/vector_or.rs +++ b/runtime/src/vm/handlers/vector_or.rs @@ -1,18 +1,17 @@ -use iced_x86::code_asm::{xmm0, xmm1, ymm0, ymm1}; +use crate::{ + runtime::Runtime, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, +}; -use crate::{runtime::Runtime, vm::handlers::vector}; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::Or)], + flags: Flags::Never, + stores: None, + widths: &[], + } +} -// unsigned char* (unsigned char*) pub fn build(rt: &mut Runtime) { - vector::with_width( - rt, - |rt| { - // por xmm0, xmm1 - rt.asm.por(xmm0, xmm1).unwrap(); - }, - |rt| { - // vpor ymm0, ymm0, ymm1 - rt.asm.vpor(ymm0, ymm0, ymm1).unwrap(); - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/vector_sub.rs b/runtime/src/vm/handlers/vector_sub.rs index a82af39c..f6ebaba6 100644 --- a/runtime/src/vm/handlers/vector_sub.rs +++ b/runtime/src/vm/handlers/vector_sub.rs @@ -1,73 +1,17 @@ -use crate::{runtime::Runtime, vm::handlers::vector}; -use iced_x86::code_asm::{xmm0, xmm1, ymm0, ymm1}; +use crate::{ + runtime::Runtime, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, +}; + +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::Sub)], + flags: Flags::Never, + stores: None, + widths: &[], + } +} pub fn build(rt: &mut Runtime) { - vector::with_precision( - rt, - |rt| { - // psubb xmm0, xmm1 - rt.asm.psubb(xmm0, xmm1).unwrap(); - }, - |rt| { - // psubw xmm0, xmm1 - rt.asm.psubw(xmm0, xmm1).unwrap(); - }, - |rt| { - // psubd xmm0, xmm1 - rt.asm.psubd(xmm0, xmm1).unwrap(); - }, - |rt| { - // psubq xmm0, xmm1 - rt.asm.psubq(xmm0, xmm1).unwrap(); - }, - |rt| { - // subps xmm0, xmm1 - rt.asm.subps(xmm0, xmm1).unwrap(); - }, - |rt| { - // subps xmm0, xmm1 - rt.asm.subps(xmm0, xmm1).unwrap(); - }, - |rt| { - // subps xmm0, xmm1 - rt.asm.subps(xmm0, xmm1).unwrap(); - }, - |rt| { - // subpd xmm0, xmm1 - rt.asm.subpd(xmm0, xmm1).unwrap(); - }, - // avx_int - |rt| { - // vpsubb ymm0, ymm0, ymm1 - rt.asm.vpsubb(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vpsubw ymm0, ymm0, ymm1 - rt.asm.vpsubw(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vpsubd ymm0, ymm0, ymm1 - rt.asm.vpsubd(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vpsubq ymm0, ymm0, ymm1 - rt.asm.vpsubq(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vsubps ymm0, ymm0, ymm1 - rt.asm.vsubps(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vsubps ymm0, ymm0, ymm1 - rt.asm.vsubps(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vsubps ymm0, ymm0, ymm1 - rt.asm.vsubps(ymm0, ymm0, ymm1).unwrap(); - }, - |rt| { - // vsubpd ymm0, ymm0, ymm1 - rt.asm.vsubpd(ymm0, ymm0, ymm1).unwrap(); - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/vector_xor.rs b/runtime/src/vm/handlers/vector_xor.rs index 6ae59f27..53ad6e7b 100644 --- a/runtime/src/vm/handlers/vector_xor.rs +++ b/runtime/src/vm/handlers/vector_xor.rs @@ -1,18 +1,17 @@ -use iced_x86::code_asm::{xmm0, xmm1, ymm0, ymm1}; +use crate::{ + runtime::Runtime, + vm::handlers::semantic::{self, Effect, Flags, Operation, Vector}, +}; -use crate::{runtime::Runtime, vm::handlers::vector}; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Vector(Vector::Xor)], + flags: Flags::Never, + stores: None, + widths: &[], + } +} -// unsigned char* (unsigned char*) pub fn build(rt: &mut Runtime) { - vector::with_width( - rt, - |rt| { - // pxor xmm0, xmm1 - rt.asm.pxor(xmm0, xmm1).unwrap(); - }, - |rt| { - // vpxor ymm0, ymm0, ymm1 - rt.asm.vpxor(ymm0, ymm0, ymm1).unwrap(); - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/handlers/xor.rs b/runtime/src/vm/handlers/xor.rs index 50ba21cc..4bda5fdf 100644 --- a/runtime/src/vm/handlers/xor.rs +++ b/runtime/src/vm/handlers/xor.rs @@ -2,59 +2,62 @@ use crate::{ runtime::Runtime, vm::{ bytecode::{Flag, VMWidth}, - handlers::semantic::{self, Compare, Effect, Expression, Flags, Operand, Operation}, + handlers::semantic::{ + self, Compare, Effect, Expression, Flags, Immediate, Operand, Operation, + }, }, }; +pub fn operation() -> Operation { + Operation { + effects: vec![Effect::Xor( + Expression::Operand(Operand::Input(0)), + Expression::Operand(Operand::Input(1)), + )], + flags: Flags::Always(vec![ + ( + Flag::Carry, + Expression::Compare(Box::new(Compare::Equal( + Expression::Immediate(Immediate::Fixed(1)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Overflow, + Expression::Compare(Box::new(Compare::Equal( + Expression::Immediate(Immediate::Fixed(1)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Sign, + Expression::Compare(Box::new(Compare::BitSet( + Expression::Operand(Operand::Output(0)), + Expression::SignBit, + ))), + ), + ( + Flag::Zero, + Expression::Compare(Box::new(Compare::Equal( + Expression::Operand(Operand::Output(0)), + Expression::Immediate(Immediate::Fixed(0)), + ))), + ), + ( + Flag::Parity, + Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), + ), + ]), + stores: None, + widths: &[ + VMWidth::Lower64, + VMWidth::Lower32, + VMWidth::Lower16, + VMWidth::Lower8, + ], + } +} + pub fn build(rt: &mut Runtime) { - semantic::compiler::compile( - rt, - &Operation { - effects: vec![Effect::Xor( - Expression::Operand(Operand::Input(0)), - Expression::Operand(Operand::Input(1)), - )], - flags: Flags::Always(vec![ - ( - Flag::Carry, - Expression::Compare(Box::new(Compare::Equal( - Expression::Constant(1), - Expression::Constant(0), - ))), - ), - ( - Flag::Overflow, - Expression::Compare(Box::new(Compare::Equal( - Expression::Constant(1), - Expression::Constant(0), - ))), - ), - ( - Flag::Sign, - Expression::Compare(Box::new(Compare::BitSet( - Expression::Operand(Operand::Output(0)), - Expression::SignBit, - ))), - ), - ( - Flag::Zero, - Expression::Compare(Box::new(Compare::Equal( - Expression::Operand(Operand::Output(0)), - Expression::Constant(0), - ))), - ), - ( - Flag::Parity, - Expression::Parity(Box::new(Expression::Operand(Operand::Output(0)))), - ), - ]), - stores: None, - widths: &[ - VMWidth::Lower64, - VMWidth::Lower32, - VMWidth::Lower16, - VMWidth::Lower8, - ], - }, - ); + semantic::compiler::compile(rt, &operation()); } diff --git a/runtime/src/vm/lifters/branch.rs b/runtime/src/vm/lifters/branch.rs index 9efa7036..374f04dc 100644 --- a/runtime/src/vm/lifters/branch.rs +++ b/runtime/src/vm/lifters/branch.rs @@ -1,12 +1,12 @@ use iced_x86::{Code, Instruction, OpKind}; use crate::vm::bytecode::{Flag, VMCondition, VMLogic, VMMem, VMReg, VMSeg, VMWidth}; +use crate::vm::encoders::back::Back; use crate::vm::encoders::load_address::LoadAddress; use crate::vm::encoders::load_immediate::LoadImmediate; use crate::vm::encoders::load_memory::LoadMemory; use crate::vm::encoders::load_register::LoadRegister; -use crate::vm::encoders::ret::Ret; -use crate::vm::encoders::{jcc::Jcc, Encode}; +use crate::vm::encoders::{branch::Branch, Encode}; use crate::vm::lifters::operation_width; pub fn encode(instruction: &Instruction) -> Option>> { @@ -21,7 +21,7 @@ pub fn encode(instruction: &Instruction) -> Option>> { width: VMWidth::Lower64, source: source_register, }), - Box::new(Jcc::jump()), + Box::new(Branch::jump()), ]) } OpKind::Memory => Some(vec![ @@ -31,7 +31,7 @@ pub fn encode(instruction: &Instruction) -> Option>> { Box::new(LoadMemory { width: VMWidth::Lower64, }), - Box::new(Jcc::jump()), + Box::new(Branch::jump()), ]), _ => unreachable!(), }, @@ -49,7 +49,7 @@ pub fn encode(instruction: &Instruction) -> Option>> { segment: VMSeg::None, }, }), - Box::new(Jcc::jump()), + Box::new(Branch::jump()), ]) } @@ -66,7 +66,7 @@ pub fn encode(instruction: &Instruction) -> Option>> { segment: VMSeg::None, }, }), - Box::new(Jcc::call()), + Box::new(Branch::call()), ]) } @@ -76,17 +76,19 @@ pub fn encode(instruction: &Instruction) -> Option>> { } else { VMWidth::Lower8 }; + let immediate_source = if instruction.op_count() > 0 { instruction.immediate16() } else { 0 }; + Some(vec![ Box::new(LoadImmediate { width: immediate_width, source: immediate_source.to_le_bytes()[..immediate_width.size()].to_vec(), }), - Box::new(Ret), + Box::new(Back), ]) } @@ -98,7 +100,7 @@ pub fn encode(instruction: &Instruction) -> Option>> { width: VMWidth::Lower64, source: source_register, }), - Box::new(Jcc::call()), + Box::new(Branch::call()), ]) } OpKind::Memory => Some(vec![ @@ -108,7 +110,7 @@ pub fn encode(instruction: &Instruction) -> Option>> { Box::new(LoadMemory { width: VMWidth::Lower64, }), - Box::new(Jcc::call()), + Box::new(Branch::call()), ]), _ => unreachable!(), }, @@ -212,7 +214,7 @@ pub fn encode(instruction: &Instruction) -> Option>> { segment: VMSeg::None, }, }), - Box::new(Jcc { logic, conditions }), + Box::new(Branch { logic, conditions }), ]) } } diff --git a/runtime/src/vm/lifters/cpuid.rs b/runtime/src/vm/lifters/cpuid.rs new file mode 100644 index 00000000..a90140ea --- /dev/null +++ b/runtime/src/vm/lifters/cpuid.rs @@ -0,0 +1,35 @@ +use crate::vm::bytecode::{VMReg, VMWidth}; +use crate::vm::encoders::{ + cpuid::Cpuid, load_register::LoadRegister, store_register::StoreRegister, Encode, +}; +use iced_x86::Instruction; + +pub fn encode(_instruction: &Instruction) -> Option>> { + Some(vec![ + Box::new(LoadRegister { + width: VMWidth::Lower32, + source: VMReg::Rax, + }), + Box::new(LoadRegister { + width: VMWidth::Lower32, + source: VMReg::Rcx, + }), + Box::new(Cpuid::new()), + Box::new(StoreRegister { + width: VMWidth::Lower32, + destination: VMReg::Rdx, + }), + Box::new(StoreRegister { + width: VMWidth::Lower32, + destination: VMReg::Rcx, + }), + Box::new(StoreRegister { + width: VMWidth::Lower32, + destination: VMReg::Rbx, + }), + Box::new(StoreRegister { + width: VMWidth::Lower32, + destination: VMReg::Rax, + }), + ]) +} diff --git a/runtime/src/vm/lifters/mod.rs b/runtime/src/vm/lifters/mod.rs index ec900e15..610cb7d5 100644 --- a/runtime/src/vm/lifters/mod.rs +++ b/runtime/src/vm/lifters/mod.rs @@ -15,6 +15,7 @@ pub mod bswap; pub mod bt; pub mod cmov; pub mod cmpxchg; +pub mod cpuid; pub mod div; pub mod extend; pub mod integer; diff --git a/runtime/src/vm/transform/compound.rs b/runtime/src/vm/transform/compound.rs new file mode 100644 index 00000000..8c6ec6b9 --- /dev/null +++ b/runtime/src/vm/transform/compound.rs @@ -0,0 +1,93 @@ +use std::mem; + +use rand::Rng; + +use crate::runtime::Runtime; +use crate::vm::bytecode::VMCode; +use crate::vm::encoders::compound::Compound; +use crate::vm::encoders::Encode; +use crate::vm::transform::descend; + +const LIMIT: usize = u8::MAX as usize + 1; + +pub fn fuse(rt: &mut Runtime, operations: &mut Vec>, register: bool) { + let mut rng = rand::thread_rng(); + + descend(operations, |operations| { + let fusible = operations + .iter() + .map(|operation| { + !operation.is_branch() + && operation + .code() + .is_some_and(|code| !matches!(code, VMCode::Compound)) + }) + .collect::>(); + + let codes = operations + .iter() + .map(|operation| operation.code()) + .collect::>>(); + + let mut planned = Vec::<(usize, Option)>::new(); + + let mut cursor = 0; + + while cursor < codes.len() { + let mut chosen = None; + + let window = rng.gen_range(2..=6); + + for length in (2..=window).rev() { + if cursor + length > codes.len() { + continue; + } + + if !fusible[cursor..cursor + length] + .iter() + .all(|&fusible| fusible) + { + continue; + } + + let members = codes[cursor..cursor + length] + .iter() + .map(|code| code.unwrap()) + .collect::>(); + + if let Some(index) = rt.compounds.iter().position(|entry| *entry == members) { + chosen = Some((length, index as u8)); + break; + } + + if register && rt.compounds.len() < LIMIT { + chosen = Some((length, rt.compound(members))); + break; + } + } + + match chosen { + Some((length, index)) => { + planned.push((length, Some(index))); + cursor += length; + } + None => { + planned.push((1, None)); + cursor += 1; + } + } + } + + let mut source = mem::take(operations).into_iter(); + + for (length, index) in planned { + match index { + Some(index) => { + let members = (0..length).map(|_| source.next().unwrap()).collect(); + operations.push(Box::new(Compound { index, members })); + } + None => operations.push(source.next().unwrap()), + } + } + }); +} diff --git a/runtime/src/vm/transform/encrypt.rs b/runtime/src/vm/transform/encrypt.rs index db8d80b5..be3dee04 100644 --- a/runtime/src/vm/transform/encrypt.rs +++ b/runtime/src/vm/transform/encrypt.rs @@ -1,12 +1,12 @@ -use std::{matches, slice}; +use std::matches; use rand::Rng; use crate::mapper::Mapper; use crate::utils::invert_multiplier; use crate::vm::bytecode::{VMReg, VMWidth}; +use crate::vm::encoders::branch::Branch; use crate::vm::encoders::discard::Discard; -use crate::vm::encoders::jcc::Jcc; use crate::vm::encoders::load_address::LoadAddress; use crate::vm::encoders::load_immediate::LoadImmediate; use crate::vm::encoders::load_register::LoadRegister; @@ -196,7 +196,7 @@ fn walk( } } - if leaf(&mut operations[i], *addend, *multiplier) { + if leaf(&mut operations[i], mapper, *addend, *multiplier) { skip -= 1; if !operations[i].is_branch() { @@ -223,29 +223,18 @@ fn walk( trace } -/// Encrypts the leaf in place when it matches [`LoadImmediate`] or [`LoadAddress`], returning whether a match was found. -fn leaf(operation: &mut Box, addend: u64, multiplier: u64) -> bool { - if let Some(load) = operation.as_any_mut().downcast_mut::() { - encrypt(&mut load.source, addend, multiplier); - return true; - } - - if let Some(load) = operation.as_any_mut().downcast_mut::() { - let mut displacement = load.source.displacement.to_le_bytes(); - encrypt(&mut displacement, addend, multiplier); - load.source.displacement = i32::from_le_bytes(displacement); - return true; - } - - if let Some(jcc) = operation.as_any_mut().downcast_mut::() { - for condition in &mut jcc.conditions { - encrypt(slice::from_mut(&mut condition.lhs), addend, multiplier); - encrypt(slice::from_mut(&mut condition.rhs), addend, multiplier); - } - return true; - } +/// Seals the operation against the current keys, returning whether it rolls the keystream afterwards. +fn leaf( + operation: &mut Box, + mapper: &mut Mapper, + addend: u64, + multiplier: u64, +) -> bool { + operation.seal(mapper, &mut |source, _| encrypt(source, addend, multiplier)); - false + operation.as_any().downcast_ref::().is_some() + || operation.as_any().downcast_ref::().is_some() + || operation.as_any().downcast_ref::().is_some() } /// Encrypts `source` against `addend` and `multiplier`. diff --git a/runtime/src/vm/transform/indirect.rs b/runtime/src/vm/transform/indirect.rs deleted file mode 100644 index 85e16c9e..00000000 --- a/runtime/src/vm/transform/indirect.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::mem; - -use crate::{ - mapper::Mapper, - vm::{ - bytecode::{Phase, VMWidth}, - encoders::{dispatch::Dispatch, load_immediate::LoadImmediate, Encode}, - transform::Transform, - }, -}; - -pub struct Indirect; - -impl Transform for Indirect { - fn phase(&self) -> Phase { - Phase::Indirect - } - - fn run( - &self, - mapper: &mut Mapper, - mut operations: Vec>, - ) -> Vec> { - indirect(mapper, &mut operations); - operations - } -} - -/// Redirects operations to use an indirect dispatch via [`Dispatch`]. -fn indirect(mapper: &mut Mapper, operations: &mut Vec>) { - let mut index = 0; - - while index < operations.len() { - if let Some(children) = operations[index].children_mut() { - indirect(mapper, children); - } - - let Some(op) = operations[index].op() else { - index += 1; - continue; - }; - - let operation = mem::replace( - &mut operations[index], - Box::new(LoadImmediate { - width: VMWidth::Lower8, - source: mapper.index(op).to_le_bytes().to_vec(), - }), - ); - - index += 1; - - operations.insert(index, Box::new(Dispatch { operation })); - - index += 1; - } -} diff --git a/runtime/src/vm/transform/mod.rs b/runtime/src/vm/transform/mod.rs index 4f28a5f1..6bb71c6e 100644 --- a/runtime/src/vm/transform/mod.rs +++ b/runtime/src/vm/transform/mod.rs @@ -10,8 +10,8 @@ use crate::vm::{ encoders::{Effect, Encode}, }; +pub mod compound; pub mod encrypt; -pub mod indirect; pub mod mutation; pub mod peephole; pub mod permute; diff --git a/runtime/src/vm/transform/mutation/jcc.rs b/runtime/src/vm/transform/mutation/branch.rs similarity index 66% rename from runtime/src/vm/transform/mutation/jcc.rs rename to runtime/src/vm/transform/mutation/branch.rs index c7b06d0c..c3e56886 100644 --- a/runtime/src/vm/transform/mutation/jcc.rs +++ b/runtime/src/vm/transform/mutation/branch.rs @@ -1,20 +1,20 @@ use crate::vm::bytecode::{Flag, VMCondition, VMLogic}; -use crate::vm::encoders::jcc::Jcc; +use crate::vm::encoders::branch::Branch; use crate::vm::encoders::Encode; use crate::vm::transform::descend; use rand::seq::SliceRandom; use rand::Rng; use strum::IntoEnumIterator; -/// Rewrites each [`Jcc`] in place via randomized, semantics-preserving conditions. +/// Rewrites each [`Branch`] in place via randomized, semantics-preserving conditions. pub fn mutate(operations: &mut Vec>, rng: &mut R) { descend(operations, |operations| { for i in 0..operations.len() { - let Some(jcc) = operations[i].as_any_mut().downcast_mut::() else { + let Some(branch) = operations[i].as_any_mut().downcast_mut::() else { continue; }; - let (and, or, xor) = match jcc.logic { + let (and, or, xor) = match branch.logic { VMLogic::JAND | VMLogic::JOR | VMLogic::JXOR => { (VMLogic::JAND, VMLogic::JOR, VMLogic::JXOR) } @@ -28,14 +28,14 @@ pub fn mutate(operations: &mut Vec>, rng: &mut R) { let flags = Flag::iter().collect::>(); - let is_always_true = jcc.conditions.len() == 1 + let is_always_true = branch.conditions.len() == 1 && flags .iter() - .any(|&f| jcc.conditions[0] == VMCondition::eq(f, f)); - let is_always_false = jcc.conditions.len() == 1 + .any(|&f| branch.conditions[0] == VMCondition::eq(f, f)); + let is_always_false = branch.conditions.len() == 1 && flags .iter() - .any(|&f| jcc.conditions[0] == VMCondition::neq(f, f)); + .any(|&f| branch.conditions[0] == VMCondition::neq(f, f)); if is_always_true { let lhs = *flags.choose(rng).unwrap(); @@ -47,43 +47,43 @@ pub fn mutate(operations: &mut Vec>, rng: &mut R) { match rng.gen_range(0..3) { 0 => { // X XOR !X == 1. - jcc.logic = xor; - jcc.conditions = vec![x, not_x]; + branch.logic = xor; + branch.conditions = vec![x, not_x]; let remaining = rng.gen_range(0..=1); if remaining == 1 { let y = random(&flags, rng); - jcc.conditions.push(y); - jcc.conditions.push(y); + branch.conditions.push(y); + branch.conditions.push(y); } } 1 => { // X OR !X == 1. - jcc.logic = or; - jcc.conditions = vec![x, not_x]; + branch.logic = or; + branch.conditions = vec![x, not_x]; let count = rng.gen_range(0..=2); for _ in 0..count { - jcc.conditions.push(random(&flags, rng)); + branch.conditions.push(random(&flags, rng)); } } _ => { // X AND 1 == X. - jcc.logic = and; - jcc.conditions = vec![VMCondition::eq(lhs, lhs)]; + branch.logic = and; + branch.conditions = vec![VMCondition::eq(lhs, lhs)]; let count = rng.gen_range(0..=3); for _ in 0..count { let flag = *flags.choose(rng).unwrap(); - jcc.conditions.push(VMCondition::eq(flag, flag)); + branch.conditions.push(VMCondition::eq(flag, flag)); } } } - jcc.conditions.shuffle(rng); + branch.conditions.shuffle(rng); continue; } @@ -94,34 +94,34 @@ pub fn mutate(operations: &mut Vec>, rng: &mut R) { let x = VMCondition::eq(lhs, rhs); let not_x = VMCondition::neq(lhs, rhs); - jcc.logic = and; - jcc.conditions = vec![x, not_x]; + branch.logic = and; + branch.conditions = vec![x, not_x]; let count = rng.gen_range(0..=2); for _ in 0..count { let flag = *flags.choose(rng).unwrap(); - jcc.conditions.push(VMCondition::eq(flag, flag)); + branch.conditions.push(VMCondition::eq(flag, flag)); } - jcc.conditions.shuffle(rng); + branch.conditions.shuffle(rng); continue; } - let remaining = 4usize.saturating_sub(jcc.conditions.len()); + let remaining = 4usize.saturating_sub(branch.conditions.len()); - match jcc.logic { + match branch.logic { VMLogic::JAND | VMLogic::CAND | VMLogic::SAND => { // X AND 1 == X. let count = rng.gen_range(0..=remaining); for _ in 0..count { let flag = *flags.choose(rng).unwrap(); - jcc.conditions.push(VMCondition::eq(flag, flag)); + branch.conditions.push(VMCondition::eq(flag, flag)); } - jcc.logic = and; - jcc.conditions.shuffle(rng); + branch.logic = and; + branch.conditions.shuffle(rng); } VMLogic::JOR | VMLogic::COR | VMLogic::SOR => { // X OR 0 == X. @@ -129,11 +129,11 @@ pub fn mutate(operations: &mut Vec>, rng: &mut R) { for _ in 0..count { let flag = *flags.choose(rng).unwrap(); - jcc.conditions.push(VMCondition::neq(flag, flag)); + branch.conditions.push(VMCondition::neq(flag, flag)); } - jcc.logic = or; - jcc.conditions.shuffle(rng); + branch.logic = or; + branch.conditions.shuffle(rng); } VMLogic::JXOR | VMLogic::CXOR | VMLogic::SXOR => { // X XOR Y XOR Y == X. @@ -141,12 +141,12 @@ pub fn mutate(operations: &mut Vec>, rng: &mut R) { for _ in 0..pairs { let y = random(&flags, rng); - jcc.conditions.push(y); - jcc.conditions.push(y); + branch.conditions.push(y); + branch.conditions.push(y); } - jcc.logic = xor; - jcc.conditions.shuffle(rng); + branch.logic = xor; + branch.conditions.shuffle(rng); } } } diff --git a/runtime/src/vm/transform/mutation/mod.rs b/runtime/src/vm/transform/mutation/mod.rs index 173ef62e..af8fc120 100644 --- a/runtime/src/vm/transform/mutation/mod.rs +++ b/runtime/src/vm/transform/mutation/mod.rs @@ -1,4 +1,4 @@ -mod jcc; +mod branch; use crate::mapper::Mapper; use crate::vm::encoders::Encode; @@ -15,7 +15,7 @@ impl Transform for Mutation { let mut operations = operations; let mut rng = rand::thread_rng(); - jcc::mutate(&mut operations, &mut rng); + branch::mutate(&mut operations, &mut rng); operations } diff --git a/runtime/src/vm/transform/scramble.rs b/runtime/src/vm/transform/scramble.rs index ff4bb71f..aff73058 100644 --- a/runtime/src/vm/transform/scramble.rs +++ b/runtime/src/vm/transform/scramble.rs @@ -6,7 +6,7 @@ use rand::Rng; use crate::mapper::Mapper; use crate::vm::bytecode::VMWidth; use crate::vm::encoders::block::{Block, Jump, Target}; -use crate::vm::encoders::jcc::Jcc; +use crate::vm::encoders::branch::Branch; use crate::vm::encoders::label::Label; use crate::vm::encoders::load_immediate::LoadImmediate; use crate::vm::encoders::Encode; @@ -169,9 +169,9 @@ fn placeholder(fallthrough: bool) -> (Label, Vec>) { source: vec![0], })); procedure.push(Box::new(if fallthrough { - Jcc::fallthrough() + Branch::fallthrough() } else { - Jcc::skip() + Branch::skip() })); (source, procedure) diff --git a/runtime/src/vm/utils/mod.rs b/runtime/src/vm/utils/mod.rs index f90820f1..c217c5ba 100644 --- a/runtime/src/vm/utils/mod.rs +++ b/runtime/src/vm/utils/mod.rs @@ -2,7 +2,7 @@ pub mod bytecode; pub mod lock; pub mod precision; +pub mod register; pub mod scratch; -pub mod vreg; -pub mod vvec; +pub mod vector; pub mod width; diff --git a/runtime/src/vm/utils/register.rs b/runtime/src/vm/utils/register.rs new file mode 100644 index 00000000..9e57ae64 --- /dev/null +++ b/runtime/src/vm/utils/register.rs @@ -0,0 +1,90 @@ +use crate::{runtime::Runtime, vm::bytecode::VMReg}; + +use iced_x86::code_asm::{ + asm_traits::{CodeAsmAdd, CodeAsmCmp, CodeAsmImul2, CodeAsmMov, CodeAsmSub}, + ptr, qword_ptr, AsmMemoryOperand, AsmRegister64, CodeAssembler, +}; + +pub fn load(rt: &mut Runtime, base: AsmRegister64, dst: T, src: VMReg) +where + CodeAssembler: CodeAsmMov, +{ + // mov ..., [...] + rt.asm + .mov(dst, ptr(base + rt.mapper.index(src) as i32 * 8)) + .unwrap(); +} + +pub fn store(rt: &mut Runtime, base: AsmRegister64, dst: VMReg, src: T) +where + CodeAssembler: CodeAsmMov, +{ + // mov [...], ... + rt.asm + .mov(qword_ptr(base + rt.mapper.index(dst) as i32 * 8), src) + .unwrap(); +} + +pub fn add_to_virtual(rt: &mut Runtime, base: AsmRegister64, dst: VMReg, src: T) +where + CodeAssembler: CodeAsmAdd, +{ + // add [...], ... + rt.asm + .add(qword_ptr(base + rt.mapper.index(dst) as i32 * 8), src) + .unwrap(); +} + +pub fn sub_from_virtual(rt: &mut Runtime, base: AsmRegister64, dst: VMReg, src: T) +where + CodeAssembler: CodeAsmSub, +{ + // sub [...], ... + rt.asm + .sub(qword_ptr(base + rt.mapper.index(dst) as i32 * 8), src) + .unwrap(); +} + +pub fn sub_from_native(rt: &mut Runtime, base: AsmRegister64, dst: T, src: VMReg) +where + CodeAssembler: CodeAsmSub, +{ + // sub ..., [...] + rt.asm + .sub(dst, ptr(base + rt.mapper.index(src) as i32 * 8)) + .unwrap(); +} + +pub fn cmp_with_native(rt: &mut Runtime, base: AsmRegister64, dst: VMReg, src: T) +where + CodeAssembler: CodeAsmCmp, +{ + // cmp [...], ... + rt.asm + .cmp(qword_ptr(base + rt.mapper.index(dst) as i32 * 8), src) + .unwrap(); +} + +pub fn imul_with_virtual(rt: &mut Runtime, base: AsmRegister64, dst: T, src: VMReg) +where + CodeAssembler: CodeAsmImul2, +{ + // imul ..., [...] + rt.asm + .imul_2(dst, ptr(base + rt.mapper.index(src) as i32 * 8)) + .unwrap(); +} + +pub fn push(rt: &mut Runtime, base: AsmRegister64, dst: VMReg) { + // push [...] + rt.asm + .push(qword_ptr(base + rt.mapper.index(dst) as i32 * 8)) + .unwrap(); +} + +pub fn pop(rt: &mut Runtime, base: AsmRegister64, dst: VMReg) { + // pop [...] + rt.asm + .pop(qword_ptr(base + rt.mapper.index(dst) as i32 * 8)) + .unwrap(); +} diff --git a/runtime/src/vm/utils/scratch.rs b/runtime/src/vm/utils/scratch.rs index 4a63d7c2..232cf398 100644 --- a/runtime/src/vm/utils/scratch.rs +++ b/runtime/src/vm/utils/scratch.rs @@ -1,68 +1,68 @@ use crate::{ runtime::Runtime, - vm::{bytecode::VMReg, utils::vreg}, + vm::{bytecode::VMReg, utils::register}, }; use iced_x86::code_asm::{ptr, r10, AsmRegister32, AsmRegister64, AsmRegisterXmm, AsmRegisterYmm}; pub fn store(rt: &mut Runtime, base: AsmRegister64, src: AsmRegister64) { // sub [...], 0x8 - vreg::sub_imm(rt, base, 0x8, VMReg::VScratch); + register::sub_from_virtual(rt, base, VMReg::VScratch, 0x8); // mov r10, [...] - vreg::load_reg(rt, base, VMReg::VScratch, r10); + register::load(rt, base, r10, VMReg::VScratch); // mov [r10], ... rt.asm.mov(ptr(r10), src).unwrap(); } pub fn load(rt: &mut Runtime, base: AsmRegister64, dst: AsmRegister64) { // add [...], 0x8 - vreg::add_imm(rt, base, 0x8, VMReg::VScratch); + register::add_to_virtual(rt, base, VMReg::VScratch, 0x8); // mov r10, [...] - vreg::load_reg(rt, base, VMReg::VScratch, r10); + register::load(rt, base, r10, VMReg::VScratch); // mov ..., [r10 - 0x8] rt.asm.mov(dst, ptr(r10 - 0x8)).unwrap(); } pub fn load_32(rt: &mut Runtime, base: AsmRegister64, dst: AsmRegister32) { // add [...], 0x8 - vreg::add_imm(rt, base, 0x8, VMReg::VScratch); + register::add_to_virtual(rt, base, VMReg::VScratch, 0x8); // mov r10, [...] - vreg::load_reg(rt, base, VMReg::VScratch, r10); + register::load(rt, base, r10, VMReg::VScratch); // mov ..., [r10 - 0x8] rt.asm.mov(dst, ptr(r10 - 0x8)).unwrap(); } pub fn store_128(rt: &mut Runtime, base: AsmRegister64, src: AsmRegisterXmm) { // sub [...], 0x10 - vreg::sub_imm(rt, base, 0x10, VMReg::VScratch); + register::sub_from_virtual(rt, base, VMReg::VScratch, 0x10); // mov r10, [...] - vreg::load_reg(rt, base, VMReg::VScratch, r10); + register::load(rt, base, r10, VMReg::VScratch); // movups [r10], ... rt.asm.movups(ptr(r10), src).unwrap(); } pub fn load_128(rt: &mut Runtime, base: AsmRegister64, dst: AsmRegisterXmm) { // add [...], 0x10 - vreg::add_imm(rt, base, 0x10, VMReg::VScratch); + register::add_to_virtual(rt, base, VMReg::VScratch, 0x10); // mov r10, [...] - vreg::load_reg(rt, base, VMReg::VScratch, r10); + register::load(rt, base, r10, VMReg::VScratch); // movups ..., [r10 - 0x10] rt.asm.movups(dst, ptr(r10 - 0x10)).unwrap(); } pub fn store_256(rt: &mut Runtime, base: AsmRegister64, src: AsmRegisterYmm) { // sub [...], 0x20 - vreg::sub_imm(rt, base, 0x20, VMReg::VScratch); + register::sub_from_virtual(rt, base, VMReg::VScratch, 0x20); // mov r10, [...] - vreg::load_reg(rt, base, VMReg::VScratch, r10); + register::load(rt, base, r10, VMReg::VScratch); // vmovups [r10], ... rt.asm.vmovups(ptr(r10), src).unwrap(); } pub fn load_256(rt: &mut Runtime, base: AsmRegister64, dst: AsmRegisterYmm) { // add [...], 0x20 - vreg::add_imm(rt, base, 0x20, VMReg::VScratch); + register::add_to_virtual(rt, base, VMReg::VScratch, 0x20); // mov r10, [...] - vreg::load_reg(rt, base, VMReg::VScratch, r10); + register::load(rt, base, r10, VMReg::VScratch); // vmovups ..., [r10 - 0x20] rt.asm.vmovups(dst, ptr(r10 - 0x20)).unwrap(); } diff --git a/runtime/src/vm/utils/vvec.rs b/runtime/src/vm/utils/vector.rs similarity index 100% rename from runtime/src/vm/utils/vvec.rs rename to runtime/src/vm/utils/vector.rs diff --git a/runtime/src/vm/utils/vreg.rs b/runtime/src/vm/utils/vreg.rs deleted file mode 100644 index c0b783e4..00000000 --- a/runtime/src/vm/utils/vreg.rs +++ /dev/null @@ -1,172 +0,0 @@ -use crate::{runtime::Runtime, vm::bytecode::VMReg}; - -use iced_x86::code_asm::{ - asm_traits::{CodeAsmAdd, CodeAsmCmp, CodeAsmImul2, CodeAsmMov, CodeAsmSub}, - ptr, qword_ptr, AsmMemoryOperand, AsmRegister32, AsmRegister64, CodeAssembler, -}; - -pub fn load_reg(rt: &mut Runtime, base: AsmRegister64, src: VMReg, dst: T) -where - CodeAssembler: CodeAsmMov, -{ - // mov ..., [...] - rt.asm - .mov(dst, ptr(base + rt.mapper.index(src) as i32 * 8)) - .unwrap(); -} - -pub fn load_reg32(rt: &mut Runtime, base: AsmRegister64, src: VMReg, dst: AsmRegister32) { - // mov ..., [...] - rt.asm - .mov(dst, ptr(base + rt.mapper.index(src) as i32 * 8)) - .unwrap(); -} - -pub fn load_mem( - rt: &mut Runtime, - base: AsmRegister64, - src: VMReg, - tmp: AsmRegister64, - dst: AsmRegister64, -) { - // mov ..., [...] - rt.asm - .mov(tmp, ptr(base + rt.mapper.index(src) as i32 * 8)) - .unwrap(); - // mov ..., [...] - rt.asm.mov(dst, ptr(tmp)).unwrap(); -} - -pub fn store_reg(rt: &mut Runtime, base: AsmRegister64, src: T, dst: VMReg) -where - CodeAssembler: CodeAsmMov, -{ - // mov [...], ... - rt.asm - .mov(ptr(base + rt.mapper.index(dst) as i32 * 8), src) - .unwrap(); -} - -pub fn store_reg32(rt: &mut Runtime, base: AsmRegister64, src: AsmRegister32, dst: VMReg) { - // mov [...], ... - rt.asm - .mov(ptr(base + rt.mapper.index(dst) as i32 * 8), src) - .unwrap(); -} - -pub fn store_imm(rt: &mut Runtime, base: AsmRegister64, src: i32, dst: VMReg) { - // mov [...], ... - rt.asm - .mov(qword_ptr(base + rt.mapper.index(dst) as i32 * 8), src) - .unwrap(); -} - -pub fn store_mem( - rt: &mut Runtime, - base: AsmRegister64, - dst: VMReg, - tmp: AsmRegister64, - src: AsmRegister64, -) { - // mov ..., [...] - rt.asm - .mov(tmp, ptr(base + rt.mapper.index(dst) as i32 * 8)) - .unwrap(); - // mov [...], ... - rt.asm.mov(ptr(tmp), src).unwrap(); -} - -pub fn add_reg(rt: &mut Runtime, base: AsmRegister64, src: T, dst: VMReg) -where - CodeAssembler: CodeAsmAdd, -{ - // add [...], ... - rt.asm - .add(ptr(base + rt.mapper.index(dst) as i32 * 8), src) - .unwrap(); -} - -pub fn add_imm(rt: &mut Runtime, base: AsmRegister64, src: i32, dst: VMReg) { - // add [...], ... - rt.asm - .add(qword_ptr(base + rt.mapper.index(dst) as i32 * 8), src) - .unwrap(); -} - -pub fn reg_add(rt: &mut Runtime, base: AsmRegister64, src: VMReg, dst: T) -where - CodeAssembler: CodeAsmAdd, -{ - // add ..., [...] - rt.asm - .add(dst, ptr(base + rt.mapper.index(src) as i32 * 8)) - .unwrap(); -} - -pub fn sub_reg(rt: &mut Runtime, base: AsmRegister64, src: T, dst: VMReg) -where - CodeAssembler: CodeAsmSub, -{ - // sub [...], ... - rt.asm - .sub(ptr(base + rt.mapper.index(dst) as i32 * 8), src) - .unwrap(); -} - -pub fn sub_imm(rt: &mut Runtime, base: AsmRegister64, src: i32, dst: VMReg) { - // sub [...], ... - rt.asm - .sub(qword_ptr(base + rt.mapper.index(dst) as i32 * 8), src) - .unwrap(); -} - -pub fn reg_sub(rt: &mut Runtime, base: AsmRegister64, src: VMReg, dst: T) -where - CodeAssembler: CodeAsmSub, -{ - // sub ..., [...] - rt.asm - .sub(dst, ptr(base + rt.mapper.index(src) as i32 * 8)) - .unwrap(); -} - -pub fn cmp_reg(rt: &mut Runtime, base: AsmRegister64, dst: VMReg, src: T) -where - CodeAssembler: CodeAsmCmp, -{ - // cmp [...], ... - rt.asm - .cmp(ptr(base + rt.mapper.index(dst) as i32 * 8), src) - .unwrap(); -} - -pub fn cmp_imm(rt: &mut Runtime, base: AsmRegister64, dst: VMReg, src: i32) { - // cmp [...], ... - rt.asm - .cmp(qword_ptr(base + rt.mapper.index(dst) as i32 * 8), src) - .unwrap(); -} - -pub fn reg_imul(rt: &mut Runtime, base: AsmRegister64, src: VMReg, dst: T) -where - CodeAssembler: CodeAsmImul2, -{ - // imul ..., [...] - rt.asm - .imul_2(dst, ptr(base + rt.mapper.index(src) as i32 * 8)) - .unwrap(); -} - -pub fn push(rt: &mut Runtime, base: AsmRegister64, src: VMReg) { - // push [...] - rt.asm - .push(qword_ptr(base + rt.mapper.index(src) as i32 * 8)) - .unwrap(); -} - -pub fn pop(rt: &mut Runtime, base: AsmRegister64, dst: VMReg) { - // pop [...] - rt.asm - .pop(qword_ptr(base + rt.mapper.index(dst) as i32 * 8)) - .unwrap(); -} diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 7aee8242..2e88c60d 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -254,7 +254,7 @@ impl Executor { // add rax, size_of::() self.rt.asm.add(rax, size_of::() as i32).unwrap(); // mov [r12 + ...], rax - utils::vreg::store_reg(&mut self.rt, r12, rax, VMReg::BPointer); + utils::register::store(&mut self.rt, r12, VMReg::BPointer, rax); // call ... self.rt