diff options
-rw-r--r-- | Cargo.toml | 8 | ||||
-rw-r--r-- | build.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 64 | ||||
-rw-r--r-- | test/bench.rs | 163 |
4 files changed, 207 insertions, 32 deletions
@@ -24,6 +24,14 @@ path = "test/test.rs" name = "bench" path = "test/bench.rs" +[profile.bench] +opt-level = 3 +lto = true + +[profile.release] +opt-level = 3 +lto = true + [features] default = [] diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..c6bc953 --- /dev/null +++ b/build.rs @@ -0,0 +1,4 @@ +fn main() { + println!("cargo:rustc-link-search=/usr/lib/"); + println!("cargo:rustc-link-lib=capstone"); +} @@ -636,10 +636,10 @@ const BITWISE_OPCODE_MAP: [Opcode; 8] = [ Opcode::SAR ]; -fn read_opcode_0f_map<'a, T: Iterator<Item=&'a u8>>(bytes_iter: &mut T, instruction: &mut Instruction, prefixes: Prefixes) -> Result<OperandCode, String> { +fn read_opcode_0f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mut Instruction, prefixes: Prefixes) -> Result<OperandCode, String> { match bytes_iter.next() { Some(b) => { - match *b { + match b { 0x1f => { instruction.prefixes = prefixes; instruction.opcode = Opcode::NOP; @@ -836,7 +836,7 @@ fn read_opcode_0f_map<'a, T: Iterator<Item=&'a u8>>(bytes_iter: &mut T, instruct } } -fn read_opcode<'a, T: Iterator<Item=&'a u8>>(bytes_iter: &mut T, instruction: &mut Instruction) -> Result<OperandCode, String> { +fn read_opcode<T: Iterator<Item=u8>>(bytes_iter: &mut T, instruction: &mut Instruction) -> Result<OperandCode, String> { use std::hint::unreachable_unchecked; // use std::intrinsics::unlikely; let mut reading = true; @@ -845,7 +845,7 @@ fn read_opcode<'a, T: Iterator<Item=&'a u8>>(bytes_iter: &mut T, instruction: &m loop { match bytes_iter.next() { Some(b) => { - match *b { + match b { x if x < 0x40 => { if x % 8 > 5 { // unsafe { unlikely(x % 8 > 5) } { // for x86_32 this is push/pop prefixes and 0x0f escape @@ -1346,7 +1346,7 @@ fn read_opcode<'a, T: Iterator<Item=&'a u8>>(bytes_iter: &mut T, instruction: &m } } -fn read_E<'a, T: Iterator<Item=&'a u8>>(bytes_iter: &mut T, prefixes: &Prefixes, m: u8, modbits: u8, width: u8, result: &mut Operand) -> Result<(), String> { +fn read_E<T: Iterator<Item=u8>>(bytes_iter: &mut T, prefixes: &Prefixes, m: u8, modbits: u8, width: u8, result: &mut Operand) -> Result<(), String> { let addr_width = if prefixes.address_size() { 4 } else { 8 }; if modbits == 0b11 { *result = Operand::Register(RegSpec::gp_from_parts(m, prefixes.rex().b(), width, prefixes.rex().present())) @@ -1357,7 +1357,7 @@ fn read_E<'a, T: Iterator<Item=&'a u8>>(bytes_iter: &mut T, prefixes: &Prefixes, disp as i32 ); } else if m == 4 { - let sibbyte = *bytes_iter.next().unwrap(); + let sibbyte = bytes_iter.next().unwrap(); let (ss, index, base) = octets_of(sibbyte); // println!("scale: {:b}, index: {:b}, base: {:b}", ss, index, base); @@ -1456,7 +1456,7 @@ fn read_E<'a, T: Iterator<Item=&'a u8>>(bytes_iter: &mut T, prefixes: &Prefixes, } #[inline] -fn read_operands<'a, T: Iterator<Item=&'a u8>>( +fn read_operands<T: Iterator<Item=u8>>( bytes_iter: &mut T, instruction: &mut Instruction, operand_code: OperandCode @@ -1512,7 +1512,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = 1; // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1529,7 +1529,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = 1; // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1546,7 +1546,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1563,7 +1563,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = 1; // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1582,7 +1582,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(e_op) => { @@ -1602,7 +1602,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = 1; // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1618,7 +1618,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1633,7 +1633,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( OperandCode::ModRM_0xf6 => { let opwidth = 1; let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { }, Err(reason) => { return Err(reason); } @@ -1675,7 +1675,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( OperandCode::ModRM_0xf7 => { let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { }, Err(reason) => { return Err(reason); } @@ -1719,7 +1719,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = 1; // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1744,7 +1744,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1769,7 +1769,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1783,7 +1783,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = 1; // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1798,7 +1798,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1813,7 +1813,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = 1; // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[1]) { Ok(()) => { @@ -1828,7 +1828,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[1]) { Ok(()) => { @@ -1843,7 +1843,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, 2, &mut instruction.operands[1]) { Ok(()) => { @@ -1859,7 +1859,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); // TODO: ... let modrm = bytes_iter.next().unwrap(); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); // println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[1]) { @@ -1934,7 +1934,7 @@ fn read_operands<'a, T: Iterator<Item=&'a u8>>( let modrm = bytes_iter.next().unwrap(); let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); - let (mod_bits, r, m) = octets_of(*modrm); + let (mod_bits, r, m) = octets_of(modrm); match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { Ok(()) => { @@ -1996,7 +1996,7 @@ fn width_to_gp_reg_bank(width: u8, rex: bool) -> RegisterBank { } } -pub fn decode_one<'a, 'b, T: IntoIterator<Item=&'a u8>>(bytes: T, instr: &'b mut Instruction) -> Option<()> { +pub fn decode_one<'b, T: IntoIterator<Item=u8>>(bytes: T, instr: &'b mut Instruction) -> Option<()> { let mut bytes_iter = bytes.into_iter(); match read_opcode(&mut bytes_iter, instr) { Ok(operand_code) => { @@ -2022,21 +2022,21 @@ pub fn decode_one<'a, 'b, T: IntoIterator<Item=&'a u8>>(bytes: T, instr: &'b mut } #[inline] -fn read_num<'a, T: Iterator<Item=&'a u8>>(bytes: &mut T, width: u8) -> u64 { +fn read_num<T: Iterator<Item=u8>>(bytes: &mut T, width: u8) -> u64 { let mut result = 0u64; let mut idx = 0; loop { if idx == width { return result; } - let byte = *bytes.next().unwrap(); + let byte = bytes.next().unwrap(); result |= (byte as u64) << (idx * 8); idx += 1; } } #[inline] -fn read_imm_ivq<'a, T: Iterator<Item=&'a u8>>(bytes: &mut T, width: u8) -> Result<Operand, String> { +fn read_imm_ivq<T: Iterator<Item=u8>>(bytes: &mut T, width: u8) -> Result<Operand, String> { match width { 2 => { Ok(Operand::ImmediateU16(read_num(bytes, 2) as u16)) @@ -2054,7 +2054,7 @@ fn read_imm_ivq<'a, T: Iterator<Item=&'a u8>>(bytes: &mut T, width: u8) -> Resul } #[inline] -fn read_imm_signed<'a, T: Iterator<Item=&'a u8>>(bytes: &mut T, num_width: u8, extend_to: u8) -> Result<Operand, String> { +fn read_imm_signed<T: Iterator<Item=u8>>(bytes: &mut T, num_width: u8, extend_to: u8) -> Result<Operand, String> { let num = match num_width { 1 => read_num(bytes, 1) as i8 as i64, 2 => read_num(bytes, 2) as i16 as i64, @@ -2073,7 +2073,7 @@ fn read_imm_signed<'a, T: Iterator<Item=&'a u8>>(bytes: &mut T, num_width: u8, e } #[inline] -fn read_imm_unsigned<'a, T: Iterator<Item=&'a u8>>(bytes: &mut T, width: u8) -> Result<Operand, String> { +fn read_imm_unsigned<T: Iterator<Item=u8>>(bytes: &mut T, width: u8) -> Result<Operand, String> { match width { 1 => { Ok(Operand::ImmediateU8(read_num(bytes, 1) as u8)) diff --git a/test/bench.rs b/test/bench.rs new file mode 100644 index 0000000..1d7414d --- /dev/null +++ b/test/bench.rs @@ -0,0 +1,163 @@ +#![feature(test)] + +extern crate test; +extern crate yaxpeax_x86; + +use std::ffi::c_void; + +use std::io::Write; + +use test::Bencher; + +use yaxpeax_x86::{Instruction, Opcode, decode_one}; + +fn decode(bytes: &[u8]) -> Option<Instruction> { + let mut instr = Instruction::invalid(); + match decode_one(bytes, &mut instr) { + Some(()) => Some(instr), + None => None + } +} + +#[bench] +fn bench_102000_instrs(b: &mut Bencher) { + b.iter(|| { + for i in (0..3000) { + test::black_box(do_decode_swathe()); + } + }) +} + +#[cfg(feature = "capstone_bench")] +#[bench] +fn bench_102000_intrs_capstone(b: &mut Bencher) { + let handle = get_cs_handle(); +// panic!("Allocating.."); + let mut instr: *mut c_void = unsafe { cs_malloc(handle) }; +// panic!("Allocated..."); + b.iter(|| { + for i in (0..3000) { + test::black_box(do_capstone_decode_swathe(handle, instr)); + } + }) +} + +const decode_data: [u8; 130] = [ + 0x48, 0xc7, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x89, 0x44, 0x24, 0x08, + 0x48, 0x89, 0x43, 0x18, + 0x48, 0xc7, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x49, 0x89, 0x4e, 0x08, + 0x48, 0x8b, 0x32, + 0x49, 0x89, 0x46, 0x10, + 0x4d, 0x0f, 0x43, 0xec, 0x49, + 0x0f, 0xb6, 0x06, + 0x0f, 0xb7, 0x06, + 0x66, 0x41, 0x50, + 0x66, 0x41, 0x31, 0xc0, + 0x66, 0x41, 0x32, 0xc0, + 0x40, 0x32, 0xc5, + 0x73, 0x31, + 0x72, 0x5a, + 0x0f, 0x86, 0x8b, 0x01, 0x00, 0x00, + 0x74, 0x47, + 0xff, 0x15, 0x7e, 0x72, 0x24, 0x00, + 0xc3, + 0x48, 0x3d, 0x01, 0xf0, 0xff, 0xff, + 0x3d, 0x01, 0xf0, 0xff, 0xff, + 0x48, 0x83, 0xf8, 0xff, + 0x48, 0x39, 0xc6, + 0x48, 0x8d, 0xa4, 0xc7, 0x20, 0x00, 0x00, 0x12, + 0x33, 0xc0, + 0x48, 0x8d, 0x53, 0x08, + 0x31, 0xc9, + 0x48, 0x29, 0xc8, + 0x48, 0x03, 0x0b, + 0x5b, + 0x41, 0x5e, + 0x48, 0x8d, 0x0c, 0x12, + 0xf6, 0xc2, 0x18 +]; + +fn do_decode_swathe() { + let mut buf = [0u8; 128]; + let mut iter = decode_data.iter(); + let mut result = yaxpeax_x86::Instruction::invalid(); + loop { + match yaxpeax_x86::decode_one(&mut iter, &mut result) { + Some(_) => { + #[cfg(feature = "capstone_bench")] + test::black_box(write!(&mut buf[..], "{}", result)); + test::black_box(&result); + }, + None => { + println!("done."); + break; + } + } + } +} + +#[cfg(feature = "capstone_bench")] +extern "C" { + pub fn cs_open(arch: u32, mode: u32, handle: *mut usize) -> usize; +} + +#[cfg(feature = "capstone_bench")] +extern "C" { + pub fn cs_malloc(handle: usize) -> *mut c_void; +} + +#[cfg(feature = "capstone_bench")] +extern "C" { + pub fn cs_disasm_iter( + arch: usize, + code: *mut *const u8, + size: *mut usize, + address: *mut u64, + insn: *mut c_void + ) -> bool; +} + +#[cfg(feature = "capstone_bench")] +fn get_cs_handle() -> usize { + let mut handle: usize = 0; + let res = unsafe { cs_open(3, 4, &mut handle as *mut usize) }; + handle +} + +#[cfg(feature = "capstone_bench")] +fn get_instr(handle: usize) -> *mut c_void { + unsafe { cs_malloc(handle) as *mut c_void } +} + +#[cfg(feature = "capstone_bench")] +fn do_capstone_decode_swathe(cs: usize, instr: *mut c_void) { + unsafe { + let mut code = &decode_data as *const u8; + let mut len = decode_data.len(); + let mut addr = 0u64; + loop { + let result = cs_disasm_iter( + cs, + &mut code as *mut *const u8, + &mut len as *mut usize, + &mut addr as *mut u64, + instr + ); + //panic!("at least one succeeded"); + if result == false { + return; + } + } + } +} + +//#[bench] +//#[ignore] +// VEX prefixes are not supported at the moment, in any form +//fn test_avx() { +// assert_eq!(&format!("{}", decode( +// &[0xc5, 0xf8, 0x10, 0x00] +// ).unwrap()), "vmovups xmm0, xmmword [rax]"); +//} |