Преглед на файлове

refactor: share common instruction in linker/assembler/disassembler

Claire xyz преди 3 седмици
родител
ревизия
87f4ebc764

+ 4 - 2
Cargo.toml

@@ -22,6 +22,7 @@ serde = { version = "1.0", features = ["derive"] }
 codespan-reporting = "0.12.0"
 termcolor = "1.4"
 
+
 sbpf-assembler = { workspace = true }
 sbpf-disassembler = { workspace = true }
 
@@ -38,11 +39,12 @@ authors = ["Dean Little <dean@blueshift.gg>", "Claire Fan <claire@blueshift.gg>"
 rust-version = "1.90"
 
 [workspace.dependencies]
+anyhow = "1.0.86"
+either = { version = "1.15.0", features = ["serde"] }
 num-derive = "0.4"
 num-traits = "0.2"
-thiserror = "2.0.12"
-anyhow = "1.0.86"
 object = "0.37.3"
+thiserror = "2.0.12"
 
 sbpf-assembler = { path = "crates/assembler", version = "0.1.5" }
 sbpf-disassembler = { path = "crates/disassembler", version = "0.1.5" }

+ 1 - 0
crates/assembler/Cargo.toml

@@ -15,6 +15,7 @@ crate-type = ["cdylib", "lib"]
 name = "sbpf_assembler"
 
 [dependencies]
+either = { workspace = true }
 num-traits = { workspace = true }
 thiserror = { workspace = true }
 anyhow = { workspace = true }

+ 21 - 27
crates/assembler/src/ast.rs

@@ -2,13 +2,12 @@ use {
     crate::{
         CompileError,
         astnode::{ASTNode, ROData},
-        dynsym::{DynamicSymbolMap, RelDynMap, RelocationType},
-        instruction::Instruction,
-        lexer::{ImmediateValue, Token},
+        dynsym::{DynamicSymbolMap, RelDynMap, RelocationType, get_relocation_info},
         parser::ParseResult,
         section::{CodeSection, DataSection},
     },
-    sbpf_common::opcode::Opcode,
+    either::Either,
+    sbpf_common::{inst_param::Number, instruction::Instruction, opcode::Opcode},
     std::collections::HashMap,
 };
 
@@ -94,7 +93,7 @@ impl AST {
         // 1. resolve labels in the intruction nodes for lddw and jump
         // 2. find relocation information
 
-        let mut program_is_static = true;
+        let program_is_static = !self.nodes.iter_mut().any(|node| matches!(node, ASTNode::Instruction { instruction: inst, .. } if inst.needs_relocation()));
         let mut relocations = RelDynMap::new();
         let mut dynamic_symbols = DynamicSymbolMap::new();
 
@@ -108,53 +107,48 @@ impl AST {
             } = node
             {
                 // For jump/call instructions, replace label with relative offsets
-                if (inst.is_jump() || inst.opcode == Opcode::Call)
-                    && let Some(Token::Identifier(label, span)) = inst.operands.last()
+                if inst.is_jump()
+                    && let Some(Either::Left(label)) = &inst.off
                 {
-                    let label = label.clone();
-                    if let Some(target_offset) = label_offset_map.get(&label) {
+                    if let Some(target_offset) = label_offset_map.get(label) {
                         let rel_offset = (*target_offset as i64 - *offset as i64) / 8 - 1;
-                        let last_idx = inst.operands.len() - 1;
-                        inst.operands[last_idx] =
-                            Token::ImmediateValue(ImmediateValue::Int(rel_offset), span.clone());
-                    } else if inst.is_jump() {
-                        // only error out unresolved jump labels, since call
-                        // labels could exist externally
+                        inst.off = Some(Either::Right(rel_offset as i16));
+                    } else {
                         errors.push(CompileError::UndefinedLabel {
                             label: label.clone(),
-                            span: span.clone(),
+                            span: inst.span.clone(),
                             custom_label: None,
                         });
                     }
+                } else if inst.opcode == Opcode::Call
+                    && let Some(Either::Left(label)) = &inst.imm
+                    && let Some(target_offset) = label_offset_map.get(label)
+                {
+                    let rel_offset = (*target_offset as i64 - *offset as i64) / 8 - 1;
+                    inst.imm = Some(Either::Right(Number::Int(rel_offset)));
                 }
-                // This has to be done before resolving lddw labels since lddw
-                // operand needs to be absolute offset values
+
                 if inst.needs_relocation() {
-                    program_is_static = false;
-                    let (reloc_type, label) = inst.get_relocation_info();
+                    let (reloc_type, label) = get_relocation_info(inst);
                     relocations.add_rel_dyn(*offset, reloc_type, label.clone());
                     if reloc_type == RelocationType::RSbfSyscall {
                         dynamic_symbols.add_call_target(label.clone(), *offset);
                     }
                 }
                 if inst.opcode == Opcode::Lddw
-                    && let Some(Token::Identifier(name, span)) = inst.operands.last()
+                    && let Some(Either::Left(name)) = &inst.imm
                 {
                     let label = name.clone();
                     if let Some(target_offset) = label_offset_map.get(&label) {
-                        // actually lddw with label makes a program dynamic, so
-                        // we should be able to hard code ph_offset
                         let ph_count = if program_is_static { 1 } else { 3 };
                         let ph_offset = 64 + (ph_count as u64 * 56) as i64;
                         let abs_offset = *target_offset as i64 + ph_offset;
                         // Replace label with immediate value
-                        let last_idx = inst.operands.len() - 1;
-                        inst.operands[last_idx] =
-                            Token::ImmediateValue(ImmediateValue::Addr(abs_offset), span.clone());
+                        inst.imm = Some(Either::Right(Number::Addr(abs_offset)));
                     } else {
                         errors.push(CompileError::UndefinedLabel {
                             label: name.clone(),
-                            span: span.clone(),
+                            span: inst.span.clone(),
                             custom_label: None,
                         });
                     }

+ 20 - 197
crates/assembler/src/astnode.rs

@@ -1,17 +1,12 @@
 use {
-    crate::{
-        debuginfo::{DebugInfo, RegisterHint, RegisterType},
-        errors::CompileError,
-        instruction::Instruction,
-        lexer::{ImmediateValue, Token},
-    },
-    sbpf_common::opcode::Opcode,
+    crate::{debuginfo::DebugInfo, errors::CompileError, lexer::Token},
+    sbpf_common::{inst_param::Number, instruction::Instruction},
     std::{collections::HashMap, ops::Range},
 };
 
 #[derive(Debug, Clone)]
 pub enum ASTNode {
-    // only present in the AST
+    // only present in AST
     Directive {
         directive: Directive,
     },
@@ -31,7 +26,7 @@ pub enum ASTNode {
         label: Label,
         offset: u64,
     },
-    // present in the bytecode
+    // present in both AST and bytecode
     ROData {
         rodata: ROData,
         offset: u64,
@@ -72,7 +67,7 @@ impl EquDecl {
     pub fn get_name(&self) -> String {
         self.name.clone()
     }
-    pub fn get_val(&self) -> ImmediateValue {
+    pub fn get_val(&self) -> Number {
         match &self.value {
             Token::ImmediateValue(val, _) => val.clone(),
             _ => panic!("Invalid Equ declaration"),
@@ -107,13 +102,13 @@ pub struct ROData {
 impl ROData {
     /// Validates that an immediate value is within the specified range
     fn validate_immediate_range(
-        value: &ImmediateValue,
+        value: &Number,
         min: i64,
         max: i64,
         span: Range<usize>,
     ) -> Result<(), CompileError> {
         match value {
-            ImmediateValue::Int(val) => {
+            Number::Int(val) => {
                 if *val < min || *val > max {
                     return Err(CompileError::OutOfRangeLiteral {
                         span,
@@ -121,7 +116,7 @@ impl ROData {
                     });
                 }
             }
-            ImmediateValue::Addr(val) => {
+            Number::Addr(val) => {
                 if *val < min || *val > max {
                     return Err(CompileError::OutOfRangeLiteral {
                         span,
@@ -236,188 +231,16 @@ impl ASTNode {
     pub fn bytecode_with_debug_map(&self) -> Option<(Vec<u8>, HashMap<u64, DebugInfo>)> {
         match self {
             ASTNode::Instruction {
-                instruction:
-                    Instruction {
-                        opcode,
-                        operands,
-                        span,
-                    },
+                instruction,
                 offset,
             } => {
-                let mut bytes = Vec::new();
+                // TODO: IMPLEMENT DEBUG INFO HANDLING AND DELETE THIS
                 let mut debug_map = HashMap::new();
-                let mut debug_info = DebugInfo::new(span.clone());
-                bytes.push(Into::<u8>::into(*opcode)); // 1 byte opcode
-
-                if *opcode == Opcode::Call {
-                    bytes.extend_from_slice(&[0x10, 0x00, 0x00]);
-                    if let Some(Token::ImmediateValue(imm, _)) = operands.last() {
-                        let imm32 = match imm {
-                            ImmediateValue::Int(val) => *val as i32,
-                            ImmediateValue::Addr(val) => *val as i32,
-                        };
-                        bytes.extend_from_slice(&imm32.to_le_bytes());
-                    } else {
-                        // external calls
-                        bytes.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]);
-                    }
-                } else if *opcode == Opcode::Lddw {
-                    if let [Token::Register(reg, _), Token::ImmediateValue(imm, _)] = &operands[..]
-                    {
-                        // 1 byte register number (strip 'r' prefix)
-                        bytes.push(*reg);
-
-                        // 2 bytes of zeros (offset/reserved)
-                        bytes.extend_from_slice(&[0, 0]);
-
-                        // 8 bytes immediate value in little-endian
-                        let imm64 = match imm {
-                            ImmediateValue::Int(val) => *val,
-                            ImmediateValue::Addr(val) => *val,
-                        };
-                        bytes.extend_from_slice(&imm64.to_le_bytes()[..4]);
-                        bytes.extend_from_slice(&[0, 0, 0, 0]);
-                        bytes.extend_from_slice(&imm64.to_le_bytes()[4..8]);
-                    }
-                } else {
-                    match &operands[..] {
-                        [Token::ImmediateValue(imm, _)] => {
-                            // 1 byte of zeros (no register)
-                            bytes.push(0);
-
-                            if *opcode == Opcode::Ja {
-                                // 2 bytes immediate value in little-endian for 'ja'
-                                let imm16 = match imm {
-                                    ImmediateValue::Int(val) => *val as i16,
-                                    ImmediateValue::Addr(val) => *val as i16,
-                                };
-                                bytes.extend_from_slice(&imm16.to_le_bytes());
-                            } else {
-                                // 4 bytes immediate value in little-endian
-                                let imm32 = match imm {
-                                    ImmediateValue::Int(val) => *val as i32,
-                                    ImmediateValue::Addr(val) => *val as i32,
-                                };
-                                bytes.extend_from_slice(&imm32.to_le_bytes());
-                            }
-                        }
-
-                        [Token::Register(reg, _)] => {
-                            if *opcode == Opcode::Callx {
-                                bytes.push(0);
-                                bytes.extend_from_slice(&[0, 0]);
-                                bytes.extend_from_slice(&[*reg, 0, 0, 0]);
-                            } else {
-                                bytes.push(*reg);
-                                bytes.extend_from_slice(&[0, 0, 0, 0, 0, 0]);
-                            }
-                        }
-
-                        [Token::Register(reg, _), Token::ImmediateValue(imm, _)] => {
-                            // 1 byte register number (strip 'r' prefix)
-                            bytes.push(*reg);
-
-                            // 2 bytes of zeros (offset/reserved)
-                            bytes.extend_from_slice(&[0, 0]);
-
-                            // 4 bytes immediate value in little-endian
-                            let imm32 = match imm {
-                                ImmediateValue::Int(val) => *val as i32,
-                                ImmediateValue::Addr(val) => {
-                                    debug_info.register_hint = RegisterHint {
-                                        register: *reg as usize,
-                                        register_type: RegisterType::Addr,
-                                    };
-                                    *val as i32
-                                }
-                            };
-                            bytes.extend_from_slice(&imm32.to_le_bytes());
-                        }
-
-                        [
-                            Token::Register(reg, _),
-                            Token::ImmediateValue(imm, _),
-                            Token::ImmediateValue(offset, _),
-                        ] => {
-                            // 1 byte register number (strip 'r' prefix)
-                            bytes.push(*reg);
-
-                            // 2 bytes of offset in little-endian
-                            let offset16 = match offset {
-                                ImmediateValue::Int(val) => *val as u16,
-                                ImmediateValue::Addr(val) => *val as u16,
-                            };
-                            bytes.extend_from_slice(&offset16.to_le_bytes());
-
-                            // 4 bytes immediate value in little-endianß
-                            let imm32 = match imm {
-                                ImmediateValue::Int(val) => *val as i32,
-                                ImmediateValue::Addr(val) => {
-                                    debug_info.register_hint = RegisterHint {
-                                        register: *reg as usize,
-                                        register_type: RegisterType::Addr,
-                                    };
-                                    *val as i32
-                                }
-                            };
-                            bytes.extend_from_slice(&imm32.to_le_bytes());
-                        }
-
-                        [Token::Register(dst, _), Token::Register(src, _)] => {
-                            // Convert register strings to numbers
-                            let dst_num = dst;
-                            let src_num = src;
-
-                            // Combine src and dst into a single byte (src in high nibble, dst in low nibble)
-                            let reg_byte = (src_num << 4) | dst_num;
-                            bytes.push(reg_byte);
-                        }
-                        [
-                            Token::Register(dst, _),
-                            Token::Register(reg, _),
-                            Token::ImmediateValue(offset, _),
-                        ] => {
-                            // Combine base register and destination register into a single byte
-                            let reg_byte = (reg << 4) | dst;
-                            bytes.push(reg_byte);
-
-                            // Add the offset as a 16-bit value in little-endian
-                            let offset16 = match offset {
-                                ImmediateValue::Int(val) => *val as u16,
-                                ImmediateValue::Addr(val) => *val as u16,
-                            };
-                            bytes.extend_from_slice(&offset16.to_le_bytes());
-                        }
-                        [
-                            Token::Register(reg, _),
-                            Token::ImmediateValue(offset, _),
-                            Token::Register(dst, _),
-                        ] => {
-                            // Combine base register and destination register into a single byte
-                            let reg_byte = (dst << 4) | reg;
-                            bytes.push(reg_byte);
-
-                            // Add the offset as a 16-bit value in little-endian
-                            let offset16 = match offset {
-                                ImmediateValue::Int(val) => *val as u16,
-                                ImmediateValue::Addr(val) => *val as u16,
-                            };
-                            bytes.extend_from_slice(&offset16.to_le_bytes());
-                        }
-
-                        _ => {}
-                    }
-                }
-
-                // Add padding to make it 8 or 16 bytes depending on opcode
-                let target_len = if *opcode == Opcode::Lddw { 16 } else { 8 };
-                while bytes.len() < target_len {
-                    bytes.push(0);
-                }
+                let debug_info = DebugInfo::new(instruction.span.clone());
 
                 debug_map.insert(*offset, debug_info);
 
-                Some((bytes, debug_map))
+                Some((instruction.to_bytes().unwrap(), debug_map))
             }
             ASTNode::ROData {
                 rodata: ROData { name: _, args, .. },
@@ -434,32 +257,32 @@ impl ASTNode {
                         if directive == "byte" {
                             for value in values {
                                 let imm8 = match value {
-                                    ImmediateValue::Int(val) => *val as i8,
-                                    ImmediateValue::Addr(val) => *val as i8,
+                                    Number::Int(val) => *val as i8,
+                                    Number::Addr(val) => *val as i8,
                                 };
                                 bytes.extend(imm8.to_le_bytes());
                             }
                         } else if directive == "short" {
                             for value in values {
                                 let imm16 = match value {
-                                    ImmediateValue::Int(val) => *val as i16,
-                                    ImmediateValue::Addr(val) => *val as i16,
+                                    Number::Int(val) => *val as i16,
+                                    Number::Addr(val) => *val as i16,
                                 };
                                 bytes.extend(imm16.to_le_bytes());
                             }
                         } else if directive == "int" || directive == "long" {
                             for value in values {
                                 let imm32 = match value {
-                                    ImmediateValue::Int(val) => *val as i32,
-                                    ImmediateValue::Addr(val) => *val as i32,
+                                    Number::Int(val) => *val as i32,
+                                    Number::Addr(val) => *val as i32,
                                 };
                                 bytes.extend(imm32.to_le_bytes());
                             }
                         } else if directive == "quad" {
                             for value in values {
                                 let imm64 = match value {
-                                    ImmediateValue::Int(val) => *val,
-                                    ImmediateValue::Addr(val) => *val,
+                                    Number::Int(val) => *val,
+                                    Number::Addr(val) => *val,
                                 };
                                 bytes.extend(imm64.to_le_bytes());
                             }

+ 21 - 1
crates/assembler/src/dynsym.rs

@@ -1,4 +1,8 @@
-use std::collections::BTreeMap;
+use {
+    either::Either,
+    sbpf_common::{instruction::Instruction, opcode::Opcode},
+    std::collections::BTreeMap,
+};
 
 #[derive(Debug)]
 pub struct DynamicSymbol {
@@ -109,6 +113,22 @@ pub enum RelocationType {
     RSbfSyscall = 0x0a,
 }
 
+pub fn get_relocation_info(inst: &Instruction) -> (RelocationType, String) {
+    match inst.opcode {
+        Opcode::Lddw => match &inst.imm {
+            Some(Either::Left(identifier)) => (RelocationType::RSbf64Relative, identifier.clone()),
+            _ => panic!("Expected label operand"),
+        },
+        _ => {
+            if let Some(Either::Left(identifier)) = &inst.imm {
+                (RelocationType::RSbfSyscall, identifier.clone())
+            } else {
+                panic!("Expected label operand")
+            }
+        }
+    }
+}
+
 #[derive(Debug, Clone, PartialEq)]
 pub struct RelDyn {
     offset: u64,

+ 0 - 398
crates/assembler/src/instruction.rs

@@ -1,398 +0,0 @@
-use {
-    crate::{
-        dynsym::RelocationType,
-        errors::CompileError,
-        lexer::{ImmediateValue, Token},
-        syscall::SYSCALLS,
-    },
-    sbpf_common::opcode::{JUMP_IMM_OPS, JUMP_OPS, JUMP_REG_OPS, Opcode},
-    std::ops::Range,
-};
-
-#[derive(Debug, Clone)]
-pub struct Instruction {
-    pub opcode: Opcode,
-    pub operands: Vec<Token>,
-    pub span: Range<usize>,
-}
-
-impl Instruction {
-    //
-    pub fn get_size(&self) -> u64 {
-        match self.opcode {
-            Opcode::Lddw => 16,
-            _ => 8,
-        }
-    }
-    //
-    pub fn needs_relocation(&self) -> bool {
-        match self.opcode {
-            Opcode::Call | Opcode::Lddw => {
-                matches!(&self.operands.last(), Some(Token::Identifier(_, _)))
-            }
-            _ => false,
-        }
-    }
-
-    //
-    pub fn is_jump(&self) -> bool {
-        JUMP_OPS.contains(&self.opcode)
-            || JUMP_IMM_OPS.contains(&self.opcode)
-            || JUMP_REG_OPS.contains(&self.opcode)
-    }
-    //
-    pub fn get_relocation_info(&self) -> (RelocationType, String) {
-        match self.opcode {
-            Opcode::Lddw => match &self.operands[1] {
-                Token::Identifier(name, _) => (RelocationType::RSbf64Relative, name.clone()),
-                _ => panic!("Expected label operand"),
-            },
-            _ => {
-                if let Token::Identifier(name, _) = &self.operands[0] {
-                    (RelocationType::RSbfSyscall, name.clone())
-                } else {
-                    panic!("Expected label operand")
-                }
-            }
-        }
-    }
-    //
-    pub fn from_bytes(bytes: &[u8]) -> Result<Self, CompileError> {
-        let mut operands = Vec::new();
-        let span = 0..bytes.len();
-
-        let opcode: Opcode = bytes[0]
-            .try_into()
-            .map_err(|e| CompileError::BytecodeError {
-                error: format!("Invalid opcode 0x{:02x}: {}", bytes[0], e),
-                span: 0..1,
-                custom_label: None,
-            })?;
-        let reg = bytes[1];
-        let src = reg >> 4;
-        let dst = reg & 0x0f;
-        let off = i16::from_le_bytes([bytes[2], bytes[3]]);
-        let imm = match opcode {
-            Opcode::Lddw => {
-                let imm_low = i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
-                let imm_high = i32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]);
-
-                ((imm_high as i64) << 32) | (imm_low as u32 as i64)
-            }
-            _ => i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as i64,
-        };
-
-        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 => {
-                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));
-            }
-
-            Opcode::JeqImm
-            | Opcode::JgtImm
-            | Opcode::JgeImm
-            | Opcode::JltImm
-            | Opcode::JleImm
-            | Opcode::JsetImm
-            | Opcode::JneImm
-            | Opcode::JsgtImm
-            | 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));
-            }
-
-            Opcode::JeqReg
-            | Opcode::JgtReg
-            | Opcode::JgeReg
-            | Opcode::JltReg
-            | Opcode::JleReg
-            | Opcode::JsetReg
-            | Opcode::JneReg
-            | Opcode::JsgtReg
-            | 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));
-            }
-
-            // Arithmetic instructions with immediate values
-            Opcode::Add32Imm
-            | Opcode::Sub32Imm
-            | Opcode::Mul32Imm
-            | Opcode::Div32Imm
-            | Opcode::Or32Imm
-            | Opcode::And32Imm
-            | Opcode::Lsh32Imm
-            | Opcode::Rsh32Imm
-            | Opcode::Mod32Imm
-            | Opcode::Xor32Imm
-            | Opcode::Mov32Imm
-            | Opcode::Arsh32Imm
-            | Opcode::Lmul32Imm
-            | Opcode::Udiv32Imm
-            | Opcode::Urem32Imm
-            | Opcode::Sdiv32Imm
-            | Opcode::Srem32Imm
-            | Opcode::Add64Imm
-            | Opcode::Sub64Imm
-            | Opcode::Mul64Imm
-            | Opcode::Div64Imm
-            | Opcode::Or64Imm
-            | Opcode::And64Imm
-            | Opcode::Lsh64Imm
-            | Opcode::Rsh64Imm
-            | Opcode::Mod64Imm
-            | Opcode::Xor64Imm
-            | Opcode::Mov64Imm
-            | Opcode::Arsh64Imm
-            | Opcode::Hor64Imm
-            | Opcode::Lmul64Imm
-            | Opcode::Uhmul64Imm
-            | Opcode::Udiv64Imm
-            | Opcode::Urem64Imm
-            | Opcode::Shmul64Imm
-            | Opcode::Sdiv64Imm
-            | 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));
-            }
-
-            // Arithmetic instructions with register operands
-            Opcode::Add32Reg
-            | Opcode::Sub32Reg
-            | Opcode::Mul32Reg
-            | Opcode::Div32Reg
-            | Opcode::Or32Reg
-            | Opcode::And32Reg
-            | Opcode::Lsh32Reg
-            | Opcode::Rsh32Reg
-            | Opcode::Mod32Reg
-            | Opcode::Xor32Reg
-            | Opcode::Mov32Reg
-            | Opcode::Arsh32Reg
-            | Opcode::Lmul32Reg
-            | Opcode::Udiv32Reg
-            | Opcode::Urem32Reg
-            | Opcode::Sdiv32Reg
-            | Opcode::Srem32Reg
-            | Opcode::Add64Reg
-            | Opcode::Sub64Reg
-            | Opcode::Mul64Reg
-            | Opcode::Div64Reg
-            | Opcode::Or64Reg
-            | Opcode::And64Reg
-            | Opcode::Lsh64Reg
-            | Opcode::Rsh64Reg
-            | Opcode::Mod64Reg
-            | Opcode::Xor64Reg
-            | Opcode::Mov64Reg
-            | Opcode::Arsh64Reg
-            | Opcode::Lmul64Reg
-            | Opcode::Uhmul64Reg
-            | Opcode::Udiv64Reg
-            | Opcode::Urem64Reg
-            | 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));
-            }
-
-            // 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 Err(CompileError::BytecodeError {
-              //         error: format!("Unsupported opcode: {:?}", opcode),
-              //         span: span.clone(),
-              //         custom_label: None,
-              //     });
-              // }
-        }
-
-        Ok(Instruction {
-            opcode,
-            operands,
-            span,
-        })
-    }
-}

+ 5 - 65
crates/assembler/src/lexer.rs

@@ -1,6 +1,6 @@
 use {
     crate::errors::CompileError,
-    sbpf_common::opcode::Opcode,
+    sbpf_common::{inst_param::Number, opcode::Opcode},
     std::{ops::Range, str::FromStr as _},
 };
 
@@ -12,60 +12,6 @@ pub enum Op {
     Div,
 }
 
-#[derive(Debug, Clone, PartialEq)]
-pub enum ImmediateValue {
-    Int(i64),
-    Addr(i64),
-}
-
-impl std::ops::Add for ImmediateValue {
-    type Output = ImmediateValue;
-    fn add(self, other: Self) -> ImmediateValue {
-        match (self, other) {
-            (ImmediateValue::Int(a), ImmediateValue::Int(b)) => ImmediateValue::Int(a + b),
-            (ImmediateValue::Addr(a), ImmediateValue::Addr(b)) => ImmediateValue::Addr(a + b),
-            (ImmediateValue::Int(a), ImmediateValue::Addr(b)) => ImmediateValue::Addr(a + b),
-            (ImmediateValue::Addr(a), ImmediateValue::Int(b)) => ImmediateValue::Addr(a + b),
-        }
-    }
-}
-
-impl std::ops::Sub for ImmediateValue {
-    type Output = ImmediateValue;
-    fn sub(self, other: Self) -> ImmediateValue {
-        match (self, other) {
-            (ImmediateValue::Int(a), ImmediateValue::Int(b)) => ImmediateValue::Int(a - b),
-            (ImmediateValue::Addr(a), ImmediateValue::Addr(b)) => ImmediateValue::Addr(a - b),
-            (ImmediateValue::Int(a), ImmediateValue::Addr(b)) => ImmediateValue::Addr(a - b),
-            (ImmediateValue::Addr(a), ImmediateValue::Int(b)) => ImmediateValue::Addr(a - b),
-        }
-    }
-}
-
-impl std::ops::Mul for ImmediateValue {
-    type Output = ImmediateValue;
-    fn mul(self, other: Self) -> ImmediateValue {
-        match (self, other) {
-            (ImmediateValue::Int(a), ImmediateValue::Int(b)) => ImmediateValue::Int(a * b),
-            (ImmediateValue::Addr(a), ImmediateValue::Addr(b)) => ImmediateValue::Addr(a * b),
-            (ImmediateValue::Int(a), ImmediateValue::Addr(b)) => ImmediateValue::Addr(a * b),
-            (ImmediateValue::Addr(a), ImmediateValue::Int(b)) => ImmediateValue::Addr(a * b),
-        }
-    }
-}
-
-impl std::ops::Div for ImmediateValue {
-    type Output = ImmediateValue;
-    fn div(self, other: Self) -> ImmediateValue {
-        match (self, other) {
-            (ImmediateValue::Int(a), ImmediateValue::Int(b)) => ImmediateValue::Int(a / b),
-            (ImmediateValue::Addr(a), ImmediateValue::Addr(b)) => ImmediateValue::Addr(a / b),
-            (ImmediateValue::Int(a), ImmediateValue::Addr(b)) => ImmediateValue::Addr(a / b),
-            (ImmediateValue::Addr(a), ImmediateValue::Int(b)) => ImmediateValue::Addr(a / b),
-        }
-    }
-}
-
 #[derive(Debug, Clone)]
 pub enum Token {
     Directive(String, Range<usize>),
@@ -73,10 +19,10 @@ pub enum Token {
     Identifier(String, Range<usize>),
     Opcode(Opcode, Range<usize>),
     Register(u8, Range<usize>),
-    ImmediateValue(ImmediateValue, Range<usize>),
+    ImmediateValue(Number, Range<usize>),
     BinaryOp(Op, Range<usize>),
     StringLiteral(String, Range<usize>),
-    VectorLiteral(Vec<ImmediateValue>, Range<usize>),
+    VectorLiteral(Vec<Number>, Range<usize>),
 
     LeftBracket(Range<usize>),
     RightBracket(Range<usize>),
@@ -131,10 +77,7 @@ pub fn tokenize(source: &str) -> Result<Vec<Token>, Vec<CompileError>> {
                     if is_addr {
                         if let Ok(value) = u64::from_str_radix(&number, 16) {
                             let value = value as i64;
-                            tokens.push(Token::ImmediateValue(
-                                ImmediateValue::Addr(value),
-                                span.clone(),
-                            ));
+                            tokens.push(Token::ImmediateValue(Number::Addr(value), span.clone()));
                         } else {
                             errors.push(CompileError::InvalidNumber {
                                 number,
@@ -143,10 +86,7 @@ pub fn tokenize(source: &str) -> Result<Vec<Token>, Vec<CompileError>> {
                             });
                         }
                     } else if let Ok(value) = number.parse::<i64>() {
-                        tokens.push(Token::ImmediateValue(
-                            ImmediateValue::Int(value),
-                            span.clone(),
-                        ));
+                        tokens.push(Token::ImmediateValue(Number::Int(value), span.clone()));
                     } else {
                         errors.push(CompileError::InvalidNumber {
                             number,

+ 0 - 1
crates/assembler/src/lib.rs

@@ -13,7 +13,6 @@ pub mod messages;
 pub mod ast;
 pub mod astnode;
 pub mod dynsym;
-pub mod instruction;
 pub mod syscall;
 
 // ELF header, program, section

+ 124 - 80
crates/assembler/src/parser.rs

@@ -5,12 +5,16 @@ use {
         bug,
         dynsym::{DynamicSymbolMap, RelDynMap},
         errors::CompileError,
-        instruction::Instruction,
-        lexer::{ImmediateValue, Op, Token},
+        lexer::{Op, Token},
         messages::*,
         section::{CodeSection, DataSection},
     },
-    sbpf_common::opcode::Opcode,
+    either::Either,
+    sbpf_common::{
+        inst_param::{Number, Register},
+        instruction::Instruction,
+        opcode::Opcode,
+    },
     std::collections::HashMap,
 };
 
@@ -42,7 +46,7 @@ pub trait Parse {
 pub trait ParseWithConstMap {
     fn parse_with_constmap<'a>(
         tokens: &'a [Token],
-        const_map: &HashMap<String, ImmediateValue>,
+        const_map: &HashMap<String, Number>,
     ) -> Result<(Self, &'a [Token]), CompileError>
     where
         Self: Sized;
@@ -78,7 +82,7 @@ impl Parse for GlobalDecl {
 impl ParseWithConstMap for EquDecl {
     fn parse_with_constmap<'a>(
         tokens: &'a [Token],
-        const_map: &HashMap<String, ImmediateValue>,
+        const_map: &HashMap<String, Number>,
     ) -> Result<(Self, &'a [Token]), CompileError> {
         let Token::Directive(_, span) = &tokens[0] else {
             bug!("EquDecl not a valid directive")
@@ -214,13 +218,17 @@ impl Parse for ROData {
 impl ParseWithConstMap for Instruction {
     fn parse_with_constmap<'a>(
         tokens: &'a [Token],
-        const_map: &HashMap<String, ImmediateValue>,
+        const_map: &HashMap<String, Number>,
     ) -> Result<(Self, &'a [Token]), CompileError> {
         let next_token_num;
         match &tokens[0] {
             Token::Opcode(opcode, span) => {
                 let mut opcode = *opcode;
-                let mut operands = Vec::new();
+                // let mut operands = Vec::new();
+                let mut dst = None;
+                let mut src = None;
+                let mut off = None;
+                let mut imm = None;
                 match opcode {
                     Opcode::Lddw => {
                         if tokens.len() < 4 {
@@ -240,12 +248,14 @@ impl ParseWithConstMap for Instruction {
                                 // Third operand is folded to an immediate value
                             ) {
                                 (
-                                    Token::Register(_, _),
+                                    Token::Register(r, _),
                                     Token::Comma(_),
                                     // Third operand is folded to an immediate value
                                 ) => {
-                                    operands.push(tokens[1].clone());
-                                    operands.push(Token::ImmediateValue(value, span.clone()));
+                                    dst = Some(Register { n: *r });
+                                    // operands.push(tokens[1].clone());
+                                    imm = Some(Either::Right(value));
+                                    // operands.push(Token::ImmediateValue(value, span.clone()));
                                 }
                                 _ => {
                                     return Err(CompileError::InvalidInstruction {
@@ -260,12 +270,14 @@ impl ParseWithConstMap for Instruction {
                         } else {
                             match (&tokens[1], &tokens[2], &tokens[3]) {
                                 (
-                                    Token::Register(_, _),
+                                    Token::Register(r, _),
                                     Token::Comma(_),
-                                    Token::Identifier(_, _),
+                                    Token::Identifier(ident, _),
                                 ) => {
-                                    operands.push(tokens[1].clone());
-                                    operands.push(tokens[3].clone());
+                                    dst = Some(Register { n: *r });
+                                    // operands.push(tokens[1].clone());
+                                    imm = Some(Either::Left(ident.clone()));
+                                    // operands.push(tokens[3].clone());
                                 }
                                 _ => {
                                     return Err(CompileError::InvalidInstruction {
@@ -301,17 +313,20 @@ impl ParseWithConstMap for Instruction {
                                 &tokens[advance_token_num],
                             ) {
                                 (
-                                    Token::Register(_, _),
+                                    Token::Register(d, _),
                                     Token::Comma(_),
                                     Token::LeftBracket(_),
-                                    Token::Register(_, _),
+                                    Token::Register(s, _),
                                     Token::BinaryOp(_, _),
                                     // Sixth operand is folded to an immediate value
                                     Token::RightBracket(_),
                                 ) => {
-                                    operands.push(tokens[1].clone());
-                                    operands.push(tokens[4].clone());
-                                    operands.push(Token::ImmediateValue(value, span.clone()));
+                                    dst = Some(Register { n: *d });
+                                    // operands.push(tokens[1].clone());
+                                    src = Some(Register { n: *s });
+                                    // operands.push(tokens[4].clone());
+                                    off = Some(Either::Right(value.to_i16()));
+                                    // operands.push(Token::ImmediateValue(value, span.clone()));
                                 }
                                 _ => {
                                     return Err(CompileError::InvalidInstruction {
@@ -361,15 +376,19 @@ impl ParseWithConstMap for Instruction {
                                 ) {
                                     (
                                         Token::LeftBracket(_),
-                                        Token::Register(_, _),
+                                        Token::Register(r, _),
                                         Token::BinaryOp(_, _),
                                         // Fourth operand is folded to an immediate value
                                         Token::RightBracket(_),
                                         Token::Comma(_),
+                                        // Sixth operand is also folded to an immediate value
                                     ) => {
-                                        operands.push(tokens[2].clone());
-                                        operands.push(Token::ImmediateValue(value2, span.clone()));
-                                        operands.push(Token::ImmediateValue(value, span.clone()));
+                                        dst = Some(Register { n: *r });
+                                        off = Some(Either::Right(value.to_i16()));
+                                        imm = Some(Either::Right(value2));
+                                        // operands.push(tokens[2].clone());
+                                        // operands.push(Token::ImmediateValue(value2, span.clone()));
+                                        // operands.push(Token::ImmediateValue(value, span.clone()));
                                     }
                                     _ => {
                                         return Err(CompileError::InvalidInstruction {
@@ -425,16 +444,19 @@ impl ParseWithConstMap for Instruction {
                             ) {
                                 (
                                     Token::LeftBracket(_),
-                                    Token::Register(_, _),
+                                    Token::Register(d, _),
                                     Token::BinaryOp(_, _),
                                     // Fourth operand is folded to an immediate value
                                     Token::RightBracket(_),
                                     Token::Comma(_),
-                                    Token::Register(_, _),
+                                    Token::Register(s, _),
                                 ) => {
-                                    operands.push(tokens[2].clone());
-                                    operands.push(Token::ImmediateValue(value, span.clone()));
-                                    operands.push(tokens[advance_token_num + 2].clone());
+                                    dst = Some(Register { n: *d });
+                                    src = Some(Register { n: *s });
+                                    // operands.push(tokens[2].clone());
+                                    off = Some(Either::Right(value.to_i16()));
+                                    // operands.push(Token::ImmediateValue(value, span.clone()));
+                                    // operands.push(tokens[advance_token_num + 2].clone());
                                 }
                                 _ => {
                                     return Err(CompileError::InvalidInstruction {
@@ -509,13 +531,15 @@ impl ParseWithConstMap for Instruction {
                                 // Third operand is folded to an immediate value
                             ) {
                                 (
-                                    Token::Register(_, _),
+                                    Token::Register(r, _),
                                     Token::Comma(_),
                                     // Third operand is folded to an immediate value
                                 ) => {
                                     // Opcode already represents the immediate variant (no conversion needed)
-                                    operands.push(tokens[1].clone());
-                                    operands.push(Token::ImmediateValue(value, span.clone()));
+                                    // operands.push(tokens[1].clone());
+                                    dst = Some(Register { n: *r });
+                                    imm = Some(Either::Right(value));
+                                    // operands.push(Token::ImmediateValue(value, span.clone()));
                                 }
                                 _ => {
                                     return Err(CompileError::InvalidInstruction {
@@ -529,7 +553,7 @@ impl ParseWithConstMap for Instruction {
                             next_token_num = advance_token_num;
                         } else {
                             match (&tokens[1], &tokens[2], &tokens[3]) {
-                                (Token::Register(_, _), Token::Comma(_), Token::Register(_, _)) => {
+                                (Token::Register(d, _), Token::Comma(_), Token::Register(s, _)) => {
                                     // Convert immediate variant to register variant using BPF_X flag
                                     let new_opcode = Into::<u8>::into(opcode) | BPF_X;
                                     opcode = new_opcode.try_into().map_err(|e| {
@@ -542,8 +566,10 @@ impl ParseWithConstMap for Instruction {
                                             custom_label: None,
                                         }
                                     })?;
-                                    operands.push(tokens[1].clone());
-                                    operands.push(tokens[3].clone());
+                                    dst = Some(Register { n: *d });
+                                    src = Some(Register { n: *s });
+                                    // operands.push(tokens[1].clone());
+                                    // operands.push(tokens[3].clone());
                                 }
                                 _ => {
                                     return Err(CompileError::InvalidInstruction {
@@ -575,12 +601,14 @@ impl ParseWithConstMap for Instruction {
                                 // Third operand is folded to an immediate value
                             ) {
                                 (
-                                    Token::Register(_, _),
+                                    Token::Register(r, _),
                                     Token::Comma(_),
                                     // Third operand is folded to an immediate value
                                 ) => {
-                                    operands.push(tokens[1].clone());
-                                    operands.push(Token::ImmediateValue(value, span.clone()));
+                                    dst = Some(Register { n: *r });
+                                    // operands.push(tokens[1].clone());
+                                    imm = Some(Either::Right(value));
+                                    // operands.push(Token::ImmediateValue(value, span.clone()));
                                 }
                                 _ => {
                                     return Err(CompileError::InvalidInstruction {
@@ -634,17 +662,20 @@ impl ParseWithConstMap for Instruction {
                                     // Fifth operand is folded to an immediate value
                                 ) {
                                     (
-                                        Token::Register(_, _),
+                                        Token::Register(r, _),
                                         Token::Comma(_),
                                         // Third operand is folded to an immediate value
                                         Token::Comma(_),
                                         // Fifth operand is folded to an immediate value
                                     ) => {
                                         // Opcode is already the Imm variant, no conversion needed
-                                        operands.push(tokens[1].clone());
-                                        operands.push(Token::ImmediateValue(value, span.clone()));
-                                        operands
-                                            .push(Token::ImmediateValue(jump_val, span.clone()));
+                                        dst = Some(Register { n: *r });
+                                        // operands.push(tokens[1].clone());
+                                        imm = Some(Either::Right(value));
+                                        // operands.push(Token::ImmediateValue(value, span.clone()));
+                                        off = Some(Either::Right(jump_val.to_i16()));
+                                        // operands
+                                        //     .push(Token::ImmediateValue(jump_val, span.clone()));
                                     }
                                     _ => {
                                         return Err(CompileError::InvalidInstruction {
@@ -666,16 +697,19 @@ impl ParseWithConstMap for Instruction {
                                     &tokens[advance_token_num + 1],
                                 ) {
                                     (
-                                        Token::Register(_, _),
+                                        Token::Register(r, _),
                                         Token::Comma(_),
                                         // Third operand is folded to an immediate value
                                         Token::Comma(_),
-                                        Token::Identifier(_, _),
+                                        Token::Identifier(ident, _),
                                     ) => {
                                         // Opcode is already the Imm variant, no conversion needed
-                                        operands.push(tokens[1].clone());
-                                        operands.push(Token::ImmediateValue(value, span.clone()));
-                                        operands.push(tokens[advance_token_num + 1].clone());
+                                        // operands.push(tokens[1].clone());
+                                        dst = Some(Register { n: *r });
+                                        imm = Some(Either::Right(value));
+                                        off = Some(Either::Left(ident.clone()));
+                                        // operands.push(Token::ImmediateValue(value, span.clone()));
+                                        // operands.push(tokens[advance_token_num + 1].clone());
                                     }
                                     _ => {
                                         return Err(CompileError::InvalidInstruction {
@@ -700,9 +734,9 @@ impl ParseWithConstMap for Instruction {
                                     // Fifth operand is folded to an immediate value
                                 ) {
                                     (
-                                        Token::Register(_, _),
+                                        Token::Register(d, _),
                                         Token::Comma(_),
-                                        Token::Register(_, _),
+                                        Token::Register(s, _),
                                         Token::Comma(_),
                                         // Fifth operand is folded to an immediate value
                                     ) => {
@@ -718,10 +752,13 @@ impl ParseWithConstMap for Instruction {
                                                 custom_label: None,
                                             }
                                         })?;
-                                        operands.push(tokens[1].clone());
-                                        operands.push(tokens[3].clone());
-                                        operands
-                                            .push(Token::ImmediateValue(jump_val, span.clone()));
+                                        dst = Some(Register { n: *d });
+                                        src = Some(Register { n: *s });
+                                        // operands.push(tokens[1].clone());
+                                        // operands.push(tokens[3].clone());
+                                        off = Some(Either::Right(jump_val.to_i16()));
+                                        // operands
+                                        //     .push(Token::ImmediateValue(jump_val, span.clone()));
                                     }
                                     _ => {
                                         return Err(CompileError::InvalidInstruction {
@@ -738,11 +775,11 @@ impl ParseWithConstMap for Instruction {
                             } else {
                                 match (&tokens[1], &tokens[2], &tokens[3], &tokens[4], &tokens[5]) {
                                     (
-                                        Token::Register(_, _),
+                                        Token::Register(d, _),
                                         Token::Comma(_),
-                                        Token::Register(_, _),
+                                        Token::Register(s, _),
                                         Token::Comma(_),
-                                        Token::Identifier(_, _),
+                                        Token::Identifier(ident, _),
                                     ) => {
                                         // Convert Imm variant to Reg variant using BPF_X flag
                                         let new_opcode = Into::<u8>::into(opcode) | BPF_X;
@@ -756,9 +793,12 @@ impl ParseWithConstMap for Instruction {
                                                 custom_label: None,
                                             }
                                         })?;
-                                        operands.push(tokens[1].clone());
-                                        operands.push(tokens[3].clone());
-                                        operands.push(tokens[5].clone());
+                                        dst = Some(Register { n: *d });
+                                        src = Some(Register { n: *s });
+                                        off = Some(Either::Left(ident.clone()));
+                                        // operands.push(tokens[1].clone());
+                                        // operands.push(tokens[3].clone());
+                                        // operands.push(tokens[5].clone());
                                     }
                                     _ => {
                                         return Err(CompileError::InvalidInstruction {
@@ -785,8 +825,9 @@ impl ParseWithConstMap for Instruction {
                             });
                         }
                         match &tokens[1] {
-                            Token::Register(_, _) => {
-                                operands.push(tokens[1].clone());
+                            Token::Register(r, _) => {
+                                dst = Some(Register { n: *r });
+                                // operands.push(tokens[1].clone());
                             }
                             _ => {
                                 return Err(CompileError::InvalidInstruction {
@@ -811,12 +852,14 @@ impl ParseWithConstMap for Instruction {
                         let (value, advance_token_num) =
                             inline_and_fold_constant(tokens, const_map, 1);
                         if let Some(value) = value {
-                            operands.push(Token::ImmediateValue(value, span.clone()));
+                            off = Some(Either::Right(value.to_i16()));
+                            // operands.push(Token::ImmediateValue(value, span.clone()));
                             next_token_num = advance_token_num;
                         } else {
                             match &tokens[1] {
-                                Token::Identifier(_, _) => {
-                                    operands.push(tokens[1].clone());
+                                Token::Identifier(ident, _) => {
+                                    off = Some(Either::Left(ident.clone()));
+                                    // operands.push(tokens[1].clone());
                                 }
                                 _ => {
                                     return Err(CompileError::InvalidInstruction {
@@ -840,8 +883,9 @@ impl ParseWithConstMap for Instruction {
                             });
                         }
                         match &tokens[1] {
-                            Token::Identifier(_, _) => {
-                                operands.push(tokens[1].clone());
+                            Token::Identifier(ident, _) => {
+                                imm = Some(Either::Left(ident.clone()));
+                                // operands.push(tokens[1].clone());
                             }
                             _ => {
                                 return Err(CompileError::InvalidInstruction {
@@ -864,8 +908,9 @@ impl ParseWithConstMap for Instruction {
                             });
                         }
                         match &tokens[1] {
-                            Token::Register(_, _) => {
-                                operands.push(tokens[1].clone());
+                            Token::Register(r, _) => {
+                                dst = Some(Register { n: *r });
+                                // operands.push(tokens[1].clone());
                             }
                             _ => {
                                 return Err(CompileError::InvalidInstruction {
@@ -888,7 +933,10 @@ impl ParseWithConstMap for Instruction {
                 Ok((
                     Instruction {
                         opcode,
-                        operands,
+                        dst,
+                        src,
+                        off,
+                        imm,
                         span: span.clone(),
                     },
                     &tokens[next_token_num..],
@@ -901,11 +949,7 @@ impl ParseWithConstMap for Instruction {
     }
 }
 
-fn parse_vector_literal(
-    tokens: &[Token],
-    stack: &mut Vec<ImmediateValue>,
-    start_idx: usize,
-) -> usize {
+fn parse_vector_literal(tokens: &[Token], stack: &mut Vec<Number>, start_idx: usize) -> usize {
     let mut idx = start_idx;
     while idx < tokens.len() - 1 {
         match (&tokens[idx], &tokens[idx + 1]) {
@@ -950,17 +994,17 @@ fn fold_top(stack: &mut Vec<Token>) {
 
 fn inline_and_fold_constant(
     tokens: &[Token],
-    const_map: &std::collections::HashMap<String, ImmediateValue>,
+    const_map: &std::collections::HashMap<String, Number>,
     start_idx: usize,
-) -> (Option<ImmediateValue>, usize) {
+) -> (Option<Number>, usize) {
     inline_and_fold_constant_with_map(tokens, Some(const_map), start_idx)
 }
 
 fn inline_and_fold_constant_with_map(
     tokens: &[Token],
-    const_map: Option<&std::collections::HashMap<String, ImmediateValue>>,
+    const_map: Option<&std::collections::HashMap<String, Number>>,
     start_idx: usize,
-) -> (Option<ImmediateValue>, usize) {
+) -> (Option<Number>, usize) {
     let mut stack: Vec<Token> = Vec::new();
     let mut expect_number = true;
     let mut idx = start_idx;
@@ -1005,7 +1049,7 @@ fn inline_and_fold_constant_with_map(
                 match op {
                     Op::Sub if expect_number => {
                         // unary minus → 0 - expr
-                        stack.push(Token::ImmediateValue(ImmediateValue::Int(0), span.clone()));
+                        stack.push(Token::ImmediateValue(Number::Int(0), span.clone()));
                         stack.push(Token::BinaryOp(Op::Sub, span.clone()));
                     }
                     _ => {
@@ -1074,7 +1118,7 @@ pub fn parse_tokens(mut tokens: &[Token]) -> Result<ParseResult, Vec<CompileErro
     let mut rodata_phase = false;
     let mut accum_offset = 0;
     let mut rodata_accum_offset = 0;
-    let mut const_map = HashMap::<String, ImmediateValue>::new();
+    let mut const_map = HashMap::<String, Number>::new();
     let mut label_spans = HashMap::<String, std::ops::Range<usize>>::new();
     let mut errors = Vec::new();
 

+ 1 - 1
crates/common/Cargo.toml

@@ -15,11 +15,11 @@ crate-type = ["cdylib", "lib"]
 name = "sbpf_common"
 
 [dependencies]
+either = { workspace = true }
 num-derive = { workspace = true }
 num-traits = { workspace = true }
 thiserror = { workspace = true }
 serde = { version = "1.0.228", features = ["derive"] }
-either = { version = "1.15.0", features = ["serde"] }
 sbpf-syscall-map = { workspace = true }
 once_cell = "1.21.3"
 

+ 4 - 2
crates/common/src/decode.rs

@@ -257,7 +257,8 @@ pub fn decode_jump_register(bytes: &[u8]) -> Result<Instruction, SBPFError> {
 pub fn decode_call_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
     assert!(bytes.len() >= 8);
     let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
-    if SYSCALLS.get(imm as u32).is_some() {
+    let mut callimm = Some(Either::Right(Number::Int(imm.into())));
+    if let Some(syscall) = SYSCALLS.get(imm as u32) {
         if dst != 0 || src != 0 || off != 0 {
             return Err(SBPFError::BytecodeError {
                 error: format!(
@@ -268,6 +269,7 @@ pub fn decode_call_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
                 custom_label: None,
             });
         }
+        callimm = Some(Either::Left(syscall.to_string()));
     } else if dst != 0 || src != 1 || off != 0 {
         return Err(SBPFError::BytecodeError {
             error: format!(
@@ -284,7 +286,7 @@ pub fn decode_call_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
         dst: None,
         src: None,
         off: None,
-        imm: Some(Either::Right(Number::Int(imm.into()))),
+        imm: callimm,
         span: 0..8,
     })
 }

+ 9 - 0
crates/common/src/inst_param.rs

@@ -20,6 +20,15 @@ pub enum Number {
     Addr(i64),
 }
 
+impl Number {
+    pub fn to_i16(&self) -> i16 {
+        match self {
+            Number::Int(v) => *v as i16,
+            Number::Addr(a) => *a as i16,
+        }
+    }
+}
+
 impl fmt::Display for Number {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {

+ 24 - 3
crates/common/src/instruction.rs

@@ -39,6 +39,15 @@ impl Instruction {
         )
     }
 
+    pub fn needs_relocation(&self) -> bool {
+        match self.opcode {
+            Opcode::Call | Opcode::Lddw => {
+                matches!(&self.imm, Some(Either::Left(_identifier)))
+            }
+            _ => false,
+        }
+    }
+
     // only used for be/le
     pub fn op_imm_bits(&self) -> Result<String, SBPFError> {
         match &self.imm {
@@ -77,8 +86,12 @@ impl Instruction {
     }
 
     pub fn to_bytes(&self) -> Result<Vec<u8>, SBPFError> {
-        let src_val = self.src.as_ref().map(|r| r.n).unwrap_or(0);
         let dst_val = self.dst.as_ref().map(|r| r.n).unwrap_or(0);
+        let src_val = if self.opcode == Opcode::Call {
+            1
+        } else {
+            self.src.as_ref().map(|r| r.n).unwrap_or(0)
+        };
         let off_val = match &self.off {
             Some(Either::Left(ident)) => {
                 unreachable!("Identifier '{}' should have been resolved earlier", ident)
@@ -88,11 +101,20 @@ impl Instruction {
         };
         let imm_val = match &self.imm {
             Some(Either::Left(ident)) => {
-                unreachable!("Identifier '{}' should have been resolved earlier", ident)
+                if self.opcode == Opcode::Call {
+                    -1i64 // FF FF FF FF
+                } else {
+                    unreachable!("Identifier '{}' should have been resolved earlier", ident)
+                }
             }
             Some(Either::Right(Number::Int(imm))) | Some(Either::Right(Number::Addr(imm))) => *imm,
             None => 0,
         };
+        // fix callx encoding in sbpf
+        let (dst_val, imm_val) = match self.opcode {
+            Opcode::Callx => (0, dst_val as i64), // callx: dst register encoded in imm
+            _ => (dst_val, imm_val),
+        };
 
         let mut b = vec![self.opcode.into(), src_val << 4 | dst_val];
         b.extend_from_slice(&off_val.to_le_bytes());
@@ -159,7 +181,6 @@ impl Instruction {
                         if let Some(off) = &self.off {
                             param.push(off_str(off).to_string());
                         }
-                        // param.join(", ");
                     }
                     if !param.is_empty() {
                         asm.push(' ');

+ 1 - 1
crates/disassembler/Cargo.toml

@@ -15,11 +15,11 @@ crate-type = ["cdylib", "lib"]
 name = "sbpf_disassembler"
 
 [dependencies]
+either = { workspace = true }
 object = { workspace = true }
 sbpf-common = { workspace = true }
 thiserror = "2.0.17"
 serde = { version = "1.0.228", features = ["derive"] }
-either = { version = "1.15.0", features = ["serde"] }
 
 [target.'cfg(target_arch = "wasm32")'.dependencies]
 wasm-bindgen = { version = "0.2.92", features = ["serde-serialize"] }