mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-22 04:27:58 +00:00
@@ -6,5 +6,5 @@ fn main() {
|
||||
let bytecode = hex::decode(hexcode.trim()).unwrap();
|
||||
let instructions = bytecode.disassemble();
|
||||
|
||||
Program::new(instructions).dot(BasicBlockFormatOption::Ir);
|
||||
Program::new(instructions).dot(BasicBlockFormatOption::ByteCode);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ use evmil::bytecode::Instruction as EvmInstruction;
|
||||
use primitive_types::U256;
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::symbol::{Global, Symbol, SymbolTable, Type};
|
||||
use crate::{
|
||||
symbol::{Global, Symbol, SymbolTable, Type},
|
||||
POINTER_SIZE,
|
||||
};
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum Instruction {
|
||||
@@ -162,7 +165,7 @@ fn decrement_stack_height(symbol_table: &mut SymbolTable) -> Instruction {
|
||||
x: symbol_table.global(Global::StackHeight),
|
||||
y: symbol_table.global(Global::StackHeight),
|
||||
operator: Operator::Sub,
|
||||
z: symbol_table.constant(U256::one(), Some(Type::Int(4))),
|
||||
z: symbol_table.constant(U256::one(), Some(Global::StackHeight.typ())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +194,7 @@ fn increment_stack_height(symbol_table: &mut SymbolTable) -> Instruction {
|
||||
x: symbol_table.global(Global::StackHeight),
|
||||
y: symbol_table.global(Global::StackHeight),
|
||||
operator: Operator::Add,
|
||||
z: symbol_table.constant(U256::one(), Some(Type::Int(4))),
|
||||
z: symbol_table.constant(U256::one(), Some(Global::StackHeight.typ())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,6 +308,41 @@ pub fn translate(opcode: &EvmInstruction, symbol_table: &mut SymbolTable) -> Vec
|
||||
]
|
||||
}
|
||||
|
||||
STOP => {
|
||||
vec![Instruction::Procedure {
|
||||
symbol: Global::Stop,
|
||||
parameters: Default::default(),
|
||||
}]
|
||||
}
|
||||
|
||||
INVALID => {
|
||||
let offset = symbol_table.constant(U256::zero(), Some(Type::Int(POINTER_SIZE)));
|
||||
let size = symbol_table.constant(U256::zero(), Some(Type::Int(POINTER_SIZE)));
|
||||
|
||||
vec![Instruction::Procedure {
|
||||
symbol: Global::Revert,
|
||||
parameters: vec![offset, size],
|
||||
}]
|
||||
}
|
||||
|
||||
REVERT => {
|
||||
let offset = stack_pop(symbol_table);
|
||||
let size = stack_pop(symbol_table);
|
||||
|
||||
let procedure = Instruction::Procedure {
|
||||
symbol: Global::Revert,
|
||||
parameters: vec![offset.load.target_address(), size.load.target_address()],
|
||||
};
|
||||
|
||||
vec![
|
||||
offset.decrement,
|
||||
offset.load,
|
||||
size.decrement,
|
||||
size.load,
|
||||
procedure,
|
||||
]
|
||||
}
|
||||
|
||||
//_ => todo!("{opcode}"),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
@@ -333,12 +371,12 @@ mod tests {
|
||||
Instruction::IndexedAssign {
|
||||
x: Symbol {
|
||||
address: Address::Label(Global::Stack),
|
||||
type_hint: Type::Word,
|
||||
type_hint: Global::Stack.typ(),
|
||||
kind: Global::Stack.kind(),
|
||||
},
|
||||
index: Symbol {
|
||||
address: Address::Label(Global::StackHeight),
|
||||
type_hint: Type::Int(4),
|
||||
type_hint: Global::StackHeight.typ(),
|
||||
kind: Global::StackHeight.kind(),
|
||||
},
|
||||
y: Symbol {
|
||||
@@ -350,18 +388,18 @@ mod tests {
|
||||
Instruction::BinaryAssign {
|
||||
x: Symbol {
|
||||
address: Address::Label(Global::StackHeight),
|
||||
type_hint: Type::Int(4),
|
||||
type_hint: Global::StackHeight.typ(),
|
||||
kind: Global::StackHeight.kind(),
|
||||
},
|
||||
y: Symbol {
|
||||
address: Address::Label(Global::StackHeight),
|
||||
type_hint: Type::Int(4),
|
||||
type_hint: Global::StackHeight.typ(),
|
||||
kind: Global::StackHeight.kind(),
|
||||
},
|
||||
operator: Operator::Add,
|
||||
z: Symbol {
|
||||
address: Address::Constant(U256::one()),
|
||||
type_hint: Type::Int(4),
|
||||
type_hint: Global::StackHeight.typ(),
|
||||
kind: Kind::Value,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2,6 +2,8 @@ pub mod cfg;
|
||||
pub mod instruction;
|
||||
pub mod symbol;
|
||||
|
||||
pub static POINTER_SIZE: usize = 32;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
||||
+79
-77
@@ -1,26 +1,53 @@
|
||||
use indexmap::IndexSet;
|
||||
use primitive_types::U256;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum Address {
|
||||
Constant(U256),
|
||||
Temporary(usize),
|
||||
Label(Global),
|
||||
use crate::POINTER_SIZE;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SymbolTable {
|
||||
symbols: IndexSet<Symbol>,
|
||||
nonce: usize,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Address {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Constant(value) => write!(f, "{value:02x}"),
|
||||
Self::Temporary(n) => write!(f, "tmp_{n}"),
|
||||
Self::Label(label) => write!(f, "{label:?}"),
|
||||
}
|
||||
impl SymbolTable {
|
||||
fn next(&mut self) -> usize {
|
||||
let current = self.nonce;
|
||||
self.nonce += 1;
|
||||
current
|
||||
}
|
||||
}
|
||||
|
||||
impl Address {
|
||||
pub fn from_be_bytes(bytes: &[u8]) -> Self {
|
||||
Self::Constant(U256::from_big_endian(bytes))
|
||||
pub fn temporary(&mut self, type_hint: Option<Type>) -> Symbol {
|
||||
let id = self.next();
|
||||
let symbol = Symbol {
|
||||
address: Address::Temporary(id),
|
||||
type_hint: type_hint.unwrap_or_default(),
|
||||
kind: Kind::Value,
|
||||
};
|
||||
assert!(self.symbols.insert(symbol));
|
||||
|
||||
symbol
|
||||
}
|
||||
|
||||
pub fn constant(&mut self, value: U256, type_hint: Option<Type>) -> Symbol {
|
||||
let symbol = Symbol {
|
||||
address: Address::Constant(value),
|
||||
type_hint: type_hint.unwrap_or_default(),
|
||||
kind: Kind::Value,
|
||||
};
|
||||
self.symbols.insert(symbol);
|
||||
|
||||
symbol
|
||||
}
|
||||
|
||||
pub fn global(&mut self, label: Global) -> Symbol {
|
||||
let symbol = Symbol {
|
||||
address: Address::Label(label),
|
||||
type_hint: label.typ(),
|
||||
kind: label.kind(),
|
||||
};
|
||||
self.symbols.insert(symbol);
|
||||
|
||||
symbol
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,33 +60,43 @@ pub struct Symbol {
|
||||
|
||||
impl std::fmt::Display for Symbol {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "({}) {}", self.type_hint, self.address)
|
||||
write!(f, "({} {})", self.type_hint, self.address)?;
|
||||
|
||||
match self.kind {
|
||||
Kind::Pointer => write!(f, "*"),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
fn global(symbol: Global) -> Self {
|
||||
let type_hint = match symbol {
|
||||
Global::StackHeight => Type::Int(4),
|
||||
_ => Default::default(),
|
||||
};
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum Address {
|
||||
Constant(U256),
|
||||
Temporary(usize),
|
||||
Label(Global),
|
||||
}
|
||||
|
||||
Self::new(Address::Label(symbol), type_hint, symbol.kind())
|
||||
}
|
||||
|
||||
fn new(address: Address, type_hint: Type, kind: Kind) -> Self {
|
||||
Self {
|
||||
address,
|
||||
type_hint,
|
||||
kind,
|
||||
impl std::fmt::Display for Address {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Constant(value) => write!(f, "0x{value:02x}"),
|
||||
Self::Temporary(n) => write!(f, "tmp_{n}"),
|
||||
Self::Label(label) => write!(f, "{label:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Address {
|
||||
pub fn from_be_bytes(bytes: &[u8]) -> Self {
|
||||
Self::Constant(U256::from_big_endian(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Default, Clone, Copy)]
|
||||
pub enum Type {
|
||||
#[default]
|
||||
Word,
|
||||
UInt(usize),
|
||||
Int(usize),
|
||||
Bytes(usize),
|
||||
Bool,
|
||||
@@ -69,7 +106,8 @@ impl std::fmt::Display for Type {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Word => write!(f, "word"),
|
||||
Self::Int(size) => write!(f, "int{}", size * 8),
|
||||
Self::UInt(size) => write!(f, "u{}", size),
|
||||
Self::Int(size) => write!(f, "i{}", size),
|
||||
Self::Bytes(size) => write!(f, "bytes{size}"),
|
||||
Self::Bool => write!(f, "bool"),
|
||||
}
|
||||
@@ -78,7 +116,7 @@ impl std::fmt::Display for Type {
|
||||
|
||||
impl Type {
|
||||
pub fn pointer() -> Self {
|
||||
Self::Int(4)
|
||||
Self::UInt(POINTER_SIZE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +178,14 @@ pub enum Global {
|
||||
}
|
||||
|
||||
impl Global {
|
||||
pub fn typ(&self) -> Type {
|
||||
match self {
|
||||
Self::Stack | Self::CallData | Self::Memory | Self::ReturnData => Type::pointer(),
|
||||
Self::StackHeight => Type::UInt(POINTER_SIZE),
|
||||
_ => Type::Word,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> Kind {
|
||||
match self {
|
||||
Self::Stack | Self::CallData | Self::Memory | Self::ReturnData => Kind::Pointer,
|
||||
@@ -148,47 +194,3 @@ impl Global {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SymbolTable {
|
||||
symbols: IndexSet<Symbol>,
|
||||
nonce: usize,
|
||||
}
|
||||
|
||||
impl SymbolTable {
|
||||
fn next(&mut self) -> usize {
|
||||
let current = self.nonce;
|
||||
self.nonce += 1;
|
||||
current
|
||||
}
|
||||
|
||||
pub fn temporary(&mut self, type_hint: Option<Type>) -> Symbol {
|
||||
let id = self.next();
|
||||
let symbol = Symbol::new(
|
||||
Address::Temporary(id),
|
||||
type_hint.unwrap_or_default(),
|
||||
Kind::Value,
|
||||
);
|
||||
assert!(self.symbols.insert(symbol));
|
||||
|
||||
symbol
|
||||
}
|
||||
|
||||
pub fn constant(&mut self, value: U256, type_hint: Option<Type>) -> Symbol {
|
||||
let symbol = Symbol::new(
|
||||
Address::Constant(value),
|
||||
type_hint.unwrap_or_default(),
|
||||
Kind::Value,
|
||||
);
|
||||
self.symbols.insert(symbol);
|
||||
|
||||
symbol
|
||||
}
|
||||
|
||||
pub fn global(&mut self, label: Global) -> Symbol {
|
||||
let symbol = Symbol::global(label);
|
||||
self.symbols.insert(symbol);
|
||||
|
||||
symbol
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user