sbpf_assembler/
instruction.rs

1use 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    //
17    pub fn get_size(&self) -> u64 {
18        match self.opcode {
19            Opcode::Lddw => 16,
20            _ => 8,
21        }
22    }
23    //
24    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    //
36    pub fn is_jump(&self) -> bool {
37        match self.opcode {
38            Opcode::Ja | Opcode::JeqImm | Opcode::JgtImm | Opcode::JgeImm   //
39            | Opcode::JltImm | Opcode::JleImm | Opcode::JsetImm             // 
40            | Opcode::JneImm | Opcode::JsgtImm | Opcode::JsgeImm            // 
41            | Opcode::JsltImm | Opcode::JsleImm | Opcode::JeqReg            // 
42            | Opcode::JgtReg | Opcode::JgeReg | Opcode::JltReg              // 
43            | Opcode::JleReg | Opcode::JsetReg | Opcode::JneReg             // 
44            | Opcode::JsgtReg | Opcode::JsgeReg | Opcode::JsltReg           // 
45            | Opcode::JsleReg => true,
46            _ => false,
47        }
48    }
49    //
50    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    //
68    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 =   // 
80                    i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
81                let imm_high =  // 
82                    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            // Arithmetic instructions with immediate values
125            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            // Arithmetic instructions with register operands
140            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            // Unary operations
172            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