Просмотр исходного кода

feat: safe guard unused instruction fields

Claire xyz 1 месяц назад
Родитель
Сommit
7186f74b86
2 измененных файлов с 106 добавлено и 5 удалено
  1. 5 0
      crates/assembler/src/errors.rs
  2. 101 5
      crates/assembler/src/instruction.rs

+ 5 - 0
crates/assembler/src/errors.rs

@@ -87,4 +87,9 @@ define_compile_errors! {
         label = "Label redefined",
         fields = { label: String, span: Range<usize>, original_span: Range<usize> }
     },
+    BytecodeError {
+        error = "Bytecode error: {error}",
+        label = "Bytecode error",
+        fields = { error: String, span: Range<usize> }
+    },
 }

+ 101 - 5
crates/assembler/src/instruction.rs

@@ -1,6 +1,7 @@
 use crate::dynsym::RelocationType;
 use crate::lexer::{ImmediateValue, Token};
 use crate::syscall::SYSCALLS;
+use crate::errors::CompileError;
 use sbpf_common::opcode::Opcode;
 
 use std::ops::Range;
@@ -76,7 +77,7 @@ impl Instruction {
         }
     }
     //
-    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
+    pub fn from_bytes(bytes: &[u8]) -> Result<Self, CompileError> {
         let mut operands = Vec::new();
         let span = 0..bytes.len();
 
@@ -97,24 +98,59 @@ impl Instruction {
 
         match opcode {
             Opcode::Lddw => {
+                if src != 0 || off != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Lddw instruction expects src and off to be 0, but got src: {}, off: {}", src, off),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..12));
             }
 
             Opcode::Call => {
                 if let Some(name) = SYSCALLS.get(&(imm as u32)) {
+                    if reg != 0 || off != 0 {
+                        return Err(CompileError::BytecodeError {
+                            error: format!("Call instruction with syscall expects reg and off to be 0, but got reg: {}, off: {}", reg, off),
+                            span: span.clone(),
+                            custom_label: None,
+                        });
+                    }
                     operands.push(Token::Identifier(name.to_string(), 4..8));
                 } else {
+                    if reg != 16 || off != 0 {
+                        return Err(CompileError::BytecodeError {
+                            error: format!("Call instruction with immediate expects reg to be 16 and off to be 0, but got reg: {}, off: {}", reg, off),
+                            span: span.clone(),
+                            custom_label: None,
+                        });
+                    }
                     operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
                 }
             }
 
             Opcode::Callx => {
-                // callx source register is encoded in the src field
-                operands.push(Token::Register(src, 1..2));
+                if src != 0 || off != 0 || imm != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Callx instruction expects src, off, and imm to be 0, but got src: {}, off: {}, imm: {}", src, off, imm),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
+                // callx destination register is encoded in the dst field
+                operands.push(Token::Register(dst, 1..2));
             }
 
             Opcode::Ja => {
+                if reg != 0 || imm != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Ja instruction expects reg and imm to be 0, but got reg: {}, imm: {}", reg, imm),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
             }
 
@@ -129,6 +165,13 @@ impl Instruction {
             | Opcode::JsgeImm
             | Opcode::JsltImm
             | Opcode::JsleImm => {
+                if src != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Jump instruction with immediate expects src to be 0, but got src: {}", src),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
@@ -145,6 +188,13 @@ impl Instruction {
             | Opcode::JsgeReg
             | Opcode::JsltReg
             | Opcode::JsleReg => {
+                if imm != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Jump instruction with register expects imm to be 0, but got imm: {}", imm),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::Register(src, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
@@ -190,6 +240,13 @@ impl Instruction {
             | Opcode::Srem64Imm
             | Opcode::Be
             | Opcode::Le => {
+                if src != 0 || off != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Arithmetic instruction with immediate expects src and off to be 0, but got src: {}, off: {}", src, off),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
             }
@@ -231,23 +288,51 @@ impl Instruction {
             | Opcode::Shmul64Reg
             | Opcode::Sdiv64Reg
             | Opcode::Srem64Reg => {
+                if off != 0 || imm != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Arithmetic instruction with register expects off and imm to be 0, but got off: {}, imm: {}", off, imm),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::Register(src, 1..2));
             }
 
             Opcode::Ldxw | Opcode::Ldxh | Opcode::Ldxb | Opcode::Ldxdw => {
+                if imm != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Load instruction expects imm to be 0, but got imm: {}", imm),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::Register(src, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
             }
 
             Opcode::Stw | Opcode::Sth | Opcode::Stb | Opcode::Stdw => {
+                if src != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Store instruction expects src to be 0, but got src: {}", src),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
             }
 
             Opcode::Stxb | Opcode::Stxh | Opcode::Stxw | Opcode::Stxdw => {
+                if imm != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Store instruction with register expects imm to be 0, but got imm: {}", imm),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::Register(src, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
@@ -255,15 +340,26 @@ impl Instruction {
 
             // Unary operations
             Opcode::Neg32 | Opcode::Neg64 | Opcode::Exit => {
+                if src != 0 || off != 0 || imm != 0 {
+                    return Err(CompileError::BytecodeError {
+                        error: format!("Unary operation expects src, off, and imm to be 0, but got src: {}, off: {}, imm: {}", src, off, imm),
+                        span: span.clone(),
+                        custom_label: None,
+                    });
+                }
                 operands.push(Token::Register(dst, 1..2));
             }
 
             _ => {
-                return None;
+                return Err(CompileError::BytecodeError {
+                    error: format!("Unsupported opcode: {:?}", opcode),
+                    span: span.clone(),
+                    custom_label: None,
+                });
             }
         }
 
-        Some(Instruction {
+        Ok(Instruction {
             opcode,
             operands,
             span,