mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-13 11:51:06 +00:00
@@ -6,9 +6,5 @@ fn main() {
|
|||||||
let bytecode = hex::decode(hexcode.trim()).unwrap();
|
let bytecode = hex::decode(hexcode.trim()).unwrap();
|
||||||
let instructions = bytecode.disassemble();
|
let instructions = bytecode.disassemble();
|
||||||
|
|
||||||
//for instruction in instructions.iter() {
|
Program::new(instructions).dot(BasicBlockFormatOption::Ir);
|
||||||
// println!("{instruction:?}");
|
|
||||||
//}
|
|
||||||
|
|
||||||
Program::new(instructions).dot(BasicBlockFormatOption::ByteCode);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,14 @@ impl BasicBlock {
|
|||||||
writeln!(&mut acc, "{:?}", opcode.instruction).unwrap();
|
writeln!(&mut acc, "{:?}", opcode.instruction).unwrap();
|
||||||
acc
|
acc
|
||||||
}),
|
}),
|
||||||
|
BasicBlockFormatOption::Ir => {
|
||||||
|
self.instructions
|
||||||
|
.iter()
|
||||||
|
.fold(String::new(), |mut acc, instruction| {
|
||||||
|
writeln!(&mut acc, "{instruction}").unwrap();
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
}
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use evmil::bytecode::Instruction as EvmInstruction;
|
use evmil::bytecode::Instruction as EvmInstruction;
|
||||||
use primitive_types::U256;
|
use primitive_types::U256;
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
use crate::symbol::{Global, Symbol, SymbolTable, Type};
|
use crate::symbol::{Global, Symbol, SymbolTable, Type};
|
||||||
|
|
||||||
@@ -16,8 +17,8 @@ pub enum Instruction {
|
|||||||
/// `x = op y`
|
/// `x = op y`
|
||||||
UnaryAssign {
|
UnaryAssign {
|
||||||
x: Symbol,
|
x: Symbol,
|
||||||
y: Symbol,
|
|
||||||
operator: Operator,
|
operator: Operator,
|
||||||
|
y: Symbol,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// `branch target`
|
/// `branch target`
|
||||||
@@ -36,7 +37,7 @@ pub enum Instruction {
|
|||||||
Function {
|
Function {
|
||||||
symbol: Global,
|
symbol: Global,
|
||||||
x: Symbol,
|
x: Symbol,
|
||||||
args: Vec<Symbol>,
|
parameters: Vec<Symbol>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// `x = y`
|
/// `x = y`
|
||||||
@@ -49,6 +50,61 @@ pub enum Instruction {
|
|||||||
IndexedCopy { x: Symbol, y: Symbol, index: Symbol },
|
IndexedCopy { x: Symbol, y: Symbol, index: Symbol },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Instruction {
|
||||||
|
fn target_address(&self) -> Symbol {
|
||||||
|
match self {
|
||||||
|
Instruction::Copy { x, .. } => *x,
|
||||||
|
Instruction::IndexedAssign { x, .. } => *x,
|
||||||
|
Instruction::IndexedCopy { x, .. } => *x,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Instruction {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::BinaryAssign { x, y, operator, z } => write!(f, "{x} = {y} {operator:?} {z}"),
|
||||||
|
|
||||||
|
Self::UnaryAssign { x, operator, y } => write!(f, "{x} = {operator:?} {y} "),
|
||||||
|
|
||||||
|
Self::UncoditionalBranch { target } => write!(f, "branch {target}"),
|
||||||
|
|
||||||
|
Self::ConditionalBranch { condition, target } => {
|
||||||
|
write!(f, "if {condition} branch {target}")
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::Procedure { symbol, parameters } => write!(
|
||||||
|
f,
|
||||||
|
"{symbol:?}({})",
|
||||||
|
parameters.iter().fold(String::new(), |mut acc, p| {
|
||||||
|
write!(&mut acc, "{p}, ").unwrap();
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|
||||||
|
Self::Function {
|
||||||
|
symbol,
|
||||||
|
x,
|
||||||
|
parameters: args,
|
||||||
|
} => write!(
|
||||||
|
f,
|
||||||
|
"{x} = {symbol:?}({})",
|
||||||
|
args.iter().fold(String::new(), |mut acc, p| {
|
||||||
|
write!(&mut acc, "{p}, ").unwrap();
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
),
|
||||||
|
|
||||||
|
Self::Copy { x, y } => write!(f, "{x} = {y}"),
|
||||||
|
|
||||||
|
Self::IndexedAssign { x, index, y } => write!(f, "{x}[{index}] = {y}"),
|
||||||
|
|
||||||
|
Self::IndexedCopy { x, y, index } => write!(f, "{x} = {y}[{index}]"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub enum Operator {
|
pub enum Operator {
|
||||||
Add,
|
Add,
|
||||||
@@ -139,17 +195,6 @@ fn increment_stack_height(symbol_table: &mut SymbolTable) -> Instruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instruction {
|
|
||||||
fn target_address(&self) -> Symbol {
|
|
||||||
match self {
|
|
||||||
Instruction::Copy { x, .. } => *x,
|
|
||||||
Instruction::IndexedAssign { x, .. } => *x,
|
|
||||||
Instruction::IndexedCopy { x, .. } => *x,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lower an EVM instruction into corresponding 3AC instructions.
|
/// Lower an EVM instruction into corresponding 3AC instructions.
|
||||||
pub fn translate(opcode: &EvmInstruction, symbol_table: &mut SymbolTable) -> Vec<Instruction> {
|
pub fn translate(opcode: &EvmInstruction, symbol_table: &mut SymbolTable) -> Vec<Instruction> {
|
||||||
use EvmInstruction::*;
|
use EvmInstruction::*;
|
||||||
@@ -272,7 +317,7 @@ mod tests {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
instruction::Operator,
|
instruction::Operator,
|
||||||
symbol::{Global, Kind, Symbol, Type},
|
symbol::{Address, Global, Kind, Symbol, Type},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Instruction;
|
use super::Instruction;
|
||||||
@@ -287,31 +332,37 @@ mod tests {
|
|||||||
let expected = vec![
|
let expected = vec![
|
||||||
Instruction::IndexedAssign {
|
Instruction::IndexedAssign {
|
||||||
x: Symbol {
|
x: Symbol {
|
||||||
kind: Kind::Label(Global::Stack),
|
address: Address::Label(Global::Stack),
|
||||||
type_hint: Type::Word,
|
type_hint: Type::Word,
|
||||||
|
kind: Global::Stack.kind(),
|
||||||
},
|
},
|
||||||
index: Symbol {
|
index: Symbol {
|
||||||
kind: Kind::Label(Global::StackHeight),
|
address: Address::Label(Global::StackHeight),
|
||||||
type_hint: Type::Int(4),
|
type_hint: Type::Int(4),
|
||||||
|
kind: Global::StackHeight.kind(),
|
||||||
},
|
},
|
||||||
y: Symbol {
|
y: Symbol {
|
||||||
kind: Kind::Constant(U256::one()),
|
address: Address::Constant(U256::one()),
|
||||||
type_hint: Type::Bytes(1),
|
type_hint: Type::Bytes(1),
|
||||||
|
kind: Kind::Value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Instruction::BinaryAssign {
|
Instruction::BinaryAssign {
|
||||||
x: Symbol {
|
x: Symbol {
|
||||||
kind: Kind::Label(Global::StackHeight),
|
address: Address::Label(Global::StackHeight),
|
||||||
type_hint: Type::Int(4),
|
type_hint: Type::Int(4),
|
||||||
|
kind: Global::StackHeight.kind(),
|
||||||
},
|
},
|
||||||
y: Symbol {
|
y: Symbol {
|
||||||
kind: Kind::Label(Global::StackHeight),
|
address: Address::Label(Global::StackHeight),
|
||||||
type_hint: Type::Int(4),
|
type_hint: Type::Int(4),
|
||||||
|
kind: Global::StackHeight.kind(),
|
||||||
},
|
},
|
||||||
operator: Operator::Add,
|
operator: Operator::Add,
|
||||||
z: Symbol {
|
z: Symbol {
|
||||||
kind: Kind::Constant(U256::one()),
|
address: Address::Constant(U256::one()),
|
||||||
type_hint: Type::Int(4),
|
type_hint: Type::Int(4),
|
||||||
|
kind: Kind::Value,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
+66
-15
@@ -2,13 +2,23 @@ use indexmap::IndexSet;
|
|||||||
use primitive_types::U256;
|
use primitive_types::U256;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub enum Kind {
|
pub enum Address {
|
||||||
Constant(U256),
|
Constant(U256),
|
||||||
Temporary(usize),
|
Temporary(usize),
|
||||||
Label(Global),
|
Label(Global),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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, "{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 {
|
pub fn from_be_bytes(bytes: &[u8]) -> Self {
|
||||||
Self::Constant(U256::from_big_endian(bytes))
|
Self::Constant(U256::from_big_endian(bytes))
|
||||||
}
|
}
|
||||||
@@ -16,8 +26,15 @@ impl Kind {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub struct Symbol {
|
pub struct Symbol {
|
||||||
pub kind: Kind,
|
pub address: Address,
|
||||||
pub type_hint: Type,
|
pub type_hint: Type,
|
||||||
|
pub kind: Kind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Symbol {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({}) {}", self.type_hint, self.address)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol {
|
impl Symbol {
|
||||||
@@ -27,11 +44,15 @@ impl Symbol {
|
|||||||
_ => Default::default(),
|
_ => Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::new(Kind::Label(symbol), type_hint)
|
Self::new(Address::Label(symbol), type_hint, symbol.kind())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(kind: Kind, type_hint: Type) -> Self {
|
fn new(address: Address, type_hint: Type, kind: Kind) -> Self {
|
||||||
Self { kind, type_hint }
|
Self {
|
||||||
|
address,
|
||||||
|
type_hint,
|
||||||
|
kind,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,30 +65,42 @@ pub enum Type {
|
|||||||
Bool,
|
Bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::Bytes(size) => write!(f, "bytes{size}"),
|
||||||
|
Self::Bool => write!(f, "bool"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
pub fn pointer() -> Self {
|
pub fn pointer() -> Self {
|
||||||
Self::Int(4)
|
Self::Int(4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
pub enum Kind {
|
||||||
|
Pointer,
|
||||||
|
Value,
|
||||||
|
Function,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub enum Global {
|
pub enum Global {
|
||||||
/// Pointer
|
|
||||||
Stack,
|
Stack,
|
||||||
/// Stack height variable
|
|
||||||
StackHeight,
|
StackHeight,
|
||||||
|
|
||||||
/// Pointer
|
|
||||||
CallData,
|
CallData,
|
||||||
/// Pointer
|
|
||||||
Memory,
|
Memory,
|
||||||
/// Pointer
|
|
||||||
ReturnData,
|
ReturnData,
|
||||||
|
|
||||||
/// Low level `memcpy` like function
|
|
||||||
MemoryCopy,
|
MemoryCopy,
|
||||||
|
|
||||||
// EVM
|
// EVM runtime environment
|
||||||
Sha3,
|
Sha3,
|
||||||
Address,
|
Address,
|
||||||
CallDataLoad,
|
CallDataLoad,
|
||||||
@@ -106,6 +139,16 @@ pub enum Global {
|
|||||||
Event,
|
Event,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Global {
|
||||||
|
pub fn kind(&self) -> Kind {
|
||||||
|
match self {
|
||||||
|
Self::Stack | Self::CallData | Self::Memory | Self::ReturnData => Kind::Pointer,
|
||||||
|
Self::StackHeight => Kind::Value,
|
||||||
|
_ => Kind::Function,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct SymbolTable {
|
pub struct SymbolTable {
|
||||||
symbols: IndexSet<Symbol>,
|
symbols: IndexSet<Symbol>,
|
||||||
@@ -121,14 +164,22 @@ impl SymbolTable {
|
|||||||
|
|
||||||
pub fn temporary(&mut self, type_hint: Option<Type>) -> Symbol {
|
pub fn temporary(&mut self, type_hint: Option<Type>) -> Symbol {
|
||||||
let id = self.next();
|
let id = self.next();
|
||||||
let symbol = Symbol::new(Kind::Temporary(id), type_hint.unwrap_or_default());
|
let symbol = Symbol::new(
|
||||||
|
Address::Temporary(id),
|
||||||
|
type_hint.unwrap_or_default(),
|
||||||
|
Kind::Value,
|
||||||
|
);
|
||||||
assert!(self.symbols.insert(symbol));
|
assert!(self.symbols.insert(symbol));
|
||||||
|
|
||||||
symbol
|
symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constant(&mut self, value: U256, type_hint: Option<Type>) -> Symbol {
|
pub fn constant(&mut self, value: U256, type_hint: Option<Type>) -> Symbol {
|
||||||
let symbol = Symbol::new(Kind::Constant(value), type_hint.unwrap_or_default());
|
let symbol = Symbol::new(
|
||||||
|
Address::Constant(value),
|
||||||
|
type_hint.unwrap_or_default(),
|
||||||
|
Kind::Value,
|
||||||
|
);
|
||||||
self.symbols.insert(symbol);
|
self.symbols.insert(symbol);
|
||||||
|
|
||||||
symbol
|
symbol
|
||||||
|
|||||||
Reference in New Issue
Block a user