unsafe extern "C" { unsafe fn parse_gpr(src: *mut Source, prefix: u8) -> (u64, u64); unsafe fn parse_reg(src: *mut Source) -> (u64, u64); } struct Source<'a> { iter: core::iter::Peekable>, } impl<'a> From<&'a [u8]> for Source<'a> { fn from(value: &'a [u8]) -> Self { Self { iter: value.iter().peekable(), } } } #[unsafe(no_mangle)] extern "C" fn peekc(src: *mut Source) -> u8 { unsafe { (*src).iter.peek().cloned().unwrap_or(&0).clone() } } #[unsafe(no_mangle)] extern "C" fn getc(src: *mut Source) -> u8 { unsafe { (*src).iter.next().unwrap_or(&0).clone() } } #[test] fn test_parse_reg() { let cases = [ (&b"rax"[..], (0, 8)), (&b"rbx"[..], (1, 8)), (&b"rcx"[..], (2, 8)), (&b"rdx"[..], (3, 8)), (&b"rsp"[..], (4, 8)), (&b"rbp"[..], (5, 8)), (&b"rsi"[..], (6, 8)), (&b"rdi"[..], (7, 8)), (&b"eax"[..], (0, 4)), (&b"ebx"[..], (1, 4)), (&b"ecx"[..], (2, 4)), (&b"edx"[..], (3, 4)), (&b"esp"[..], (4, 4)), (&b"ebp"[..], (5, 4)), (&b"esi"[..], (6, 4)), (&b"edi"[..], (7, 4)), (&b"r8"[..], (8, 8)), (&b"r9"[..], (9, 8)), (&b"r10"[..], (10, 8)), (&b"r11"[..], (11, 8)), (&b"r12"[..], (12, 8)), (&b"r13"[..], (13, 8)), (&b"r14"[..], (14, 8)), (&b"r15"[..], (15, 8)), (&b"r8d"[..], (8, 4)), (&b"r9d"[..], (9, 4)), (&b"r10d"[..], (10, 4)), (&b"r11d"[..], (11, 4)), (&b"r12d"[..], (12, 4)), (&b"r13d"[..], (13, 4)), (&b"r14d"[..], (14, 4)), (&b"r15d"[..], (15, 4)), (&b"r8w"[..], (8, 2)), (&b"r9w"[..], (9, 2)), (&b"r10w"[..], (10, 2)), (&b"r11w"[..], (11, 2)), (&b"r12w"[..], (12, 2)), (&b"r13w"[..], (13, 2)), (&b"r14w"[..], (14, 2)), (&b"r15w"[..], (15, 2)), (&b"r8b"[..], (8, 1)), (&b"r9b"[..], (9, 1)), (&b"r10b"[..], (10, 1)), (&b"r11b"[..], (11, 1)), (&b"r12b"[..], (12, 1)), (&b"r13b"[..], (13, 1)), (&b"r14b"[..], (14, 1)), (&b"r15b"[..], (15, 1)), (&b"ax"[..], (0, 2)), (&b"bx"[..], (1, 2)), (&b"cx"[..], (2, 2)), (&b"dx"[..], (3, 2)), (&b"sp"[..], (4, 2)), (&b"bp"[..], (5, 2)), (&b"si"[..], (6, 2)), (&b"di"[..], (7, 2)), (&b"al"[..], (0, 1)), (&b"bl"[..], (1, 1)), (&b"cl"[..], (2, 1)), (&b"dl"[..], (3, 1)), (&b"ah"[..], (0, 3)), (&b"bh"[..], (1, 3)), (&b"ch"[..], (2, 3)), (&b"dh"[..], (3, 3)), (&b"sil"[..], (6, 1)), (&b"dil"[..], (7, 1)), (&b"asd"[..], (0, 0)), ]; for (text, result) in cases { let mut src = Source::from(text); unsafe { assert_eq!( parse_reg(&mut src), result, "Failed to parse '{}'", std::str::from_utf8(text).unwrap() ); } } } #[test] fn test_parse_gpr() { let cases = [ (&b"ax"[..], (0, 2)), (&b"bx"[..], (1, 2)), (&b"cx"[..], (2, 2)), (&b"dx"[..], (3, 2)), (&b"sp"[..], (4, 2)), (&b"bp"[..], (5, 2)), (&b"si"[..], (6, 2)), (&b"di"[..], (7, 2)), (&b"al"[..], (0, 1)), (&b"bl"[..], (1, 1)), (&b"cl"[..], (2, 1)), (&b"dl"[..], (3, 1)), (&b"ah"[..], (0, 3)), (&b"bh"[..], (1, 3)), (&b"ch"[..], (2, 3)), (&b"dh"[..], (3, 3)), (&b"sil"[..], (6, 1)), (&b"dil"[..], (7, 1)), (&b"asd"[..], (0, 0)), ]; for (text, result) in cases { let mut src = Source::from(text); unsafe { assert_eq!( parse_gpr(&mut src, b'r'), result, "Failed to parse '{}'", std::str::from_utf8(text).unwrap() ); } } } enum Register { A = 0, B, C, D, Src, Dst, Sp, Bp, R8, R9, R10, R11, R12, R13, R14, R15, } enum RegisterSize { Byte = 1, Word = 2, Dword = 4, Qword = 8, HighByte = 3, None = 0, } #[repr(C)] struct PackedRegister(u8); impl From for Option<(Register, RegisterSize)> { fn from(value: PackedRegister) -> Self { let reg_bits = value.0 & 0x00F; let size_bits = (value.0 >> 4) & 0x0F; let size = match size_bits { 1 => RegisterSize::Byte, 2 => RegisterSize::Word, 4 => RegisterSize::Dword, 8 => RegisterSize::Qword, 3 => RegisterSize::HighByte, 0 => return None, _ => panic!("Invalid register size"), }; let reg = match reg_bits { 0 => Register::A, 1 => Register::B, 2 => Register::C, 3 => Register::D, 4 => Register::Sp, 5 => Register::Bp, 6 => Register::Src, 7 => Register::Dst, 8 => Register::R8, 9 => Register::R9, 10 => Register::R10, 11 => Register::R11, 12 => Register::R12, 13 => Register::R13, 14 => Register::R14, 15 => Register::R15, _ => panic!("Invalid register number"), }; Some((reg, size)) } }