sbpf_common/execute/
endian.rs1use {
2 super::{ExecutionResult, Vm, helpers::*},
3 crate::{errors::ExecutionError, instruction::Instruction, opcode::Opcode},
4};
5
6pub fn execute_endian(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
7 let dst = get_dst(inst)?;
8 let imm = get_imm_i64(inst)?;
9
10 if imm != 16 && imm != 32 && imm != 64 {
11 return Err(ExecutionError::InvalidOperand);
12 }
13
14 vm.set_register(
15 dst,
16 match inst.opcode {
17 Opcode::Le => match imm {
18 16 => (vm.get_register(dst) as u16).to_le() as u64,
19 32 => (vm.get_register(dst) as u32).to_le() as u64,
20 64 => vm.get_register(dst).to_le(),
21 _ => unreachable!(),
22 },
23 Opcode::Be => match imm {
24 16 => (vm.get_register(dst) as u16).to_be() as u64,
25 32 => (vm.get_register(dst) as u32).to_be() as u64,
26 64 => vm.get_register(dst).to_be(),
27 _ => unreachable!(),
28 },
29 _ => return Err(ExecutionError::InvalidInstruction),
30 },
31 );
32
33 vm.advance_pc();
34 Ok(())
35}
36
37#[cfg(test)]
38mod tests {
39 use {
40 super::*,
41 crate::{
42 errors::ExecutionError,
43 execute::{MockVm, make_test_instruction},
44 inst_param::{Number, Register},
45 },
46 either::Either,
47 };
48
49 #[test]
50 fn test_le() {
51 let test_cases = [
52 (16, 0xFFFFFFFF_FFFF1234u64, 0x1234u64),
53 (32, 0xFFFFFFFF_12345678u64, 0x12345678u64),
54 (64, 0xFFFFFFFF_12345678u64, 0xFFFFFFFF_12345678u64),
55 ];
56
57 for (imm, input, expected) in test_cases {
58 let inst = make_test_instruction(
59 Opcode::Le,
60 Some(Register { n: 0 }),
61 None,
62 None,
63 Some(Either::Right(Number::Int(imm))),
64 );
65 let mut vm = MockVm::new();
66 vm.registers[0] = input;
67
68 execute_endian(&mut vm, &inst).unwrap();
69
70 assert_eq!(
71 vm.registers[0], expected,
72 "le{} failed: input=0x{:X}, expected=0x{:X}, got=0x{:X}",
73 imm, input, expected, vm.registers[0]
74 );
75 }
76 }
77
78 #[test]
79 fn test_be() {
80 let test_cases = [
81 (16, 0x1234u64, 0x3412u64),
82 (32, 0x12345678u64, 0x78563412u64),
83 (64, 0x0123456789ABCDEFu64, 0xEFCDAB8967452301u64),
84 ];
85
86 for (imm, input, expected) in test_cases {
87 let inst = make_test_instruction(
88 Opcode::Be,
89 Some(Register { n: 0 }),
90 None,
91 None,
92 Some(Either::Right(Number::Int(imm))),
93 );
94 let mut vm = MockVm::new();
95 vm.registers[0] = input;
96
97 execute_endian(&mut vm, &inst).unwrap();
98
99 assert_eq!(
100 vm.registers[0], expected,
101 "be{} failed: input=0x{:X}, expected=0x{:X}, got=0x{:X}",
102 imm, input, expected, vm.registers[0]
103 );
104 }
105 }
106
107 #[test]
108 fn test_invalid_imm() {
109 let inst = make_test_instruction(
110 Opcode::Le,
111 Some(Register { n: 0 }),
112 None,
113 None,
114 Some(Either::Right(Number::Int(8))),
115 );
116 let mut vm = MockVm::new();
117
118 let result = execute_endian(&mut vm, &inst);
119
120 assert!(matches!(result, Err(ExecutionError::InvalidOperand)));
121 }
122}