sbpf_assembler/
instruction.rs1use crate::opcode::Opcode;
2use crate::lexer::{Token, ImmediateValue};
3use crate::dynsym::RelocationType;
4use crate::syscall::SYSCALLS;
5
6use std::ops::Range;
7
8#[derive(Debug, Clone)]
9pub struct Instruction {
10 pub opcode: Opcode,
11 pub operands: Vec<Token>,
12 pub span: Range<usize>,
13}
14
15impl Instruction {
16 pub fn get_size(&self) -> u64 {
18 match self.opcode {
19 Opcode::Lddw => 16,
20 _ => 8,
21 }
22 }
23 pub fn needs_relocation(&self) -> bool {
25 match self.opcode {
26 Opcode::Call | Opcode::Lddw => {
27 match &self.operands.last() {
28 Some(Token::Identifier(_, _)) => true,
29 _ => false,
30 }
31 },
32 _ => false,
33 }
34 }
35 pub fn is_jump(&self) -> bool {
37 match self.opcode {
38 Opcode::Ja | Opcode::JeqImm | Opcode::JgtImm | Opcode::JgeImm | Opcode::JltImm | Opcode::JleImm | Opcode::JsetImm | Opcode::JneImm | Opcode::JsgtImm | Opcode::JsgeImm | Opcode::JsltImm | Opcode::JsleImm | Opcode::JeqReg | Opcode::JgtReg | Opcode::JgeReg | Opcode::JltReg | Opcode::JleReg | Opcode::JsetReg | Opcode::JneReg | Opcode::JsgtReg | Opcode::JsgeReg | Opcode::JsltReg | Opcode::JsleReg => true,
46 _ => false,
47 }
48 }
49 pub fn get_relocation_info(&self) -> (RelocationType, String) {
51 match self.opcode {
52 Opcode::Lddw => {
53 match &self.operands[1] {
54 Token::Identifier(name, _) => (RelocationType::RSbf64Relative, name.clone()),
55 _ => panic!("Expected label operand"),
56 }
57 },
58 _ => {
59 if let Token::Identifier(name, _) = &self.operands[0] {
60 (RelocationType::RSbfSyscall, name.clone())
61 } else {
62 panic!("Expected label operand")
63 }
64 },
65 }
66 }
67 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
69 let mut operands = Vec::new();
70 let span = 0..bytes.len();
71
72 let opcode = Opcode::from_u8(bytes[0]).unwrap();
73 let reg = bytes[1];
74 let src = reg >> 4;
75 let dst = reg & 0x0f;
76 let off = i16::from_le_bytes([bytes[2], bytes[3]]);
77 let imm = match opcode {
78 Opcode::Lddw => {
79 let imm_low = i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
81 let imm_high = i32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]);
83 let imm64 = ((imm_high as i64) << 32) | (imm_low as u32 as i64);
84 imm64
85 }
86 _ => i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as i64,
87 };
88
89
90 match opcode {
91 Opcode::Lddw => {
92 operands.push(Token::Register(dst, 1..2));
93 operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..12));
94 }
95
96 Opcode::Call => {
97 if let Some(name) = SYSCALLS.get(&(imm as u32)) {
98 operands.push(Token::Identifier(name.to_string(), 4..8));
99 } else {
100 operands.push(Token::ImmediateValue(ImmediateValue::Int(imm as i64), 4..8));
101 }
102 }
103
104 Opcode::Ja => {
105 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
106 }
107
108 Opcode::JeqImm | Opcode::JgtImm | Opcode::JgeImm | Opcode::JltImm |
109 Opcode::JleImm | Opcode::JsetImm | Opcode::JneImm | Opcode::JsgtImm |
110 Opcode::JsgeImm | Opcode::JsltImm | Opcode::JsleImm => {
111 operands.push(Token::Register(dst, 1..2));
112 operands.push(Token::ImmediateValue(ImmediateValue::Int(imm as i64), 4..8));
113 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
114 }
115
116 Opcode::JeqReg | Opcode::JgtReg | Opcode::JgeReg | Opcode::JltReg |
117 Opcode::JleReg | Opcode::JsetReg | Opcode::JneReg | Opcode::JsgtReg |
118 Opcode::JsgeReg | Opcode::JsltReg | Opcode::JsleReg => {
119 operands.push(Token::Register(dst, 1..2));
120 operands.push(Token::Register(src, 1..2));
121 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
122 }
123
124 Opcode::Add32Imm | Opcode::Sub32Imm | Opcode::Mul32Imm | Opcode::Div32Imm |
126 Opcode::Or32Imm | Opcode::And32Imm | Opcode::Lsh32Imm | Opcode::Rsh32Imm |
127 Opcode::Mod32Imm | Opcode::Xor32Imm | Opcode::Mov32Imm | Opcode::Arsh32Imm |
128 Opcode::Lmul32Imm | Opcode::Udiv32Imm | Opcode::Urem32Imm | Opcode::Sdiv32Imm |
129 Opcode::Srem32Imm | Opcode::Add64Imm | Opcode::Sub64Imm | Opcode::Mul64Imm |
130 Opcode::Div64Imm | Opcode::Or64Imm | Opcode::And64Imm | Opcode::Lsh64Imm |
131 Opcode::Rsh64Imm | Opcode::Mod64Imm | Opcode::Xor64Imm | Opcode::Mov64Imm |
132 Opcode::Arsh64Imm | Opcode::Hor64Imm | Opcode::Lmul64Imm | Opcode::Uhmul64Imm |
133 Opcode::Udiv64Imm | Opcode::Urem64Imm | Opcode::Shmul64Imm | Opcode::Sdiv64Imm |
134 Opcode::Srem64Imm => {
135 operands.push(Token::Register(dst, 1..2));
136 operands.push(Token::ImmediateValue(ImmediateValue::Int(imm as i64), 4..8));
137 }
138
139 Opcode::Add32Reg | Opcode::Sub32Reg | Opcode::Mul32Reg | Opcode::Div32Reg |
141 Opcode::Or32Reg | Opcode::And32Reg | Opcode::Lsh32Reg | Opcode::Rsh32Reg |
142 Opcode::Mod32Reg | Opcode::Xor32Reg | Opcode::Mov32Reg | Opcode::Arsh32Reg |
143 Opcode::Lmul32Reg | Opcode::Udiv32Reg | Opcode::Urem32Reg | Opcode::Sdiv32Reg |
144 Opcode::Srem32Reg | Opcode::Add64Reg | Opcode::Sub64Reg | Opcode::Mul64Reg |
145 Opcode::Div64Reg | Opcode::Or64Reg | Opcode::And64Reg | Opcode::Lsh64Reg |
146 Opcode::Rsh64Reg | Opcode::Mod64Reg | Opcode::Xor64Reg | Opcode::Mov64Reg |
147 Opcode::Arsh64Reg | Opcode::Lmul64Reg | Opcode::Uhmul64Reg | Opcode::Udiv64Reg |
148 Opcode::Urem64Reg | Opcode::Shmul64Reg | Opcode::Sdiv64Reg | Opcode::Srem64Reg => {
149 operands.push(Token::Register(dst , 1..2));
150 operands.push(Token::Register(src, 1..2));
151 }
152
153 Opcode::Ldxw | Opcode::Ldxh | Opcode::Ldxb | Opcode::Ldxdw => {
154 operands.push(Token::Register(dst, 1..2));
155 operands.push(Token::Register(src, 1..2));
156 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
157 }
158
159 Opcode::Stw | Opcode::Sth | Opcode::Stb | Opcode::Stdw => {
160 operands.push(Token::Register(dst, 1..2));
161 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
162 operands.push(Token::ImmediateValue(ImmediateValue::Int(imm as i64), 4..8));
163 }
164
165 Opcode::Stxb | Opcode::Stxh | Opcode::Stxw | Opcode::Stxdw => {
166 operands.push(Token::Register(dst, 1..2));
167 operands.push(Token::Register(src, 1..2));
168 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
169 }
170
171 Opcode::Neg32 | Opcode::Neg64 | Opcode::Exit => {
173 operands.push(Token::Register(dst, 1..2));
174 }
175
176 _ => {
177 return None;
178 }
179 }
180
181 Some(Instruction {
182 opcode,
183 operands,
184 span,
185 })
186 }
187}
188