mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-04-22 06:48:03 +00:00
@@ -0,0 +1,2 @@
|
||||
/target
|
||||
*.dot
|
||||
Generated
+1483
File diff suppressed because it is too large
Load Diff
+14
@@ -0,0 +1,14 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
|
||||
members = [
|
||||
"crates/ir-tac",
|
||||
"crates/cli",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
evmil = "0.4"
|
||||
hex = "0.4"
|
||||
petgraph = "0.6"
|
||||
primitive-types = "0.12"
|
||||
indexmap = "2.1.0"
|
||||
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "revive"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
hex = { workspace = true }
|
||||
evmil = { workspace = true }
|
||||
ir-tac = { path = "../ir-tac" }
|
||||
@@ -0,0 +1,14 @@
|
||||
use evmil::bytecode::Disassemble;
|
||||
use ir_tac::cfg::{BasicBlockFormatOption, Program};
|
||||
|
||||
fn main() {
|
||||
let hexcode = std::fs::read_to_string(std::env::args().nth(1).unwrap()).unwrap();
|
||||
let bytecode = hex::decode(hexcode.trim()).unwrap();
|
||||
let instructions = bytecode.disassemble();
|
||||
|
||||
//for instruction in instructions.iter() {
|
||||
// println!("{instruction:?}");
|
||||
//}
|
||||
|
||||
Program::new(instructions).dot(BasicBlockFormatOption::ByteCode);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "ir-tac"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
evmil = { workspace = true }
|
||||
petgraph = { workspace = true }
|
||||
primitive-types = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
@@ -0,0 +1,58 @@
|
||||
use primitive_types::U256;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Kind {
|
||||
Constant(U256),
|
||||
Temporary(usize),
|
||||
Stack,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Address {
|
||||
pub kind: Kind,
|
||||
pub type_hint: Option<Type>,
|
||||
}
|
||||
|
||||
impl From<(Kind, Option<Type>)> for Address {
|
||||
fn from(value: (Kind, Option<Type>)) -> Self {
|
||||
Self {
|
||||
kind: value.0,
|
||||
type_hint: value.1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Address {
|
||||
pub fn new(kind: Kind, type_hint: Option<Type>) -> Self {
|
||||
Self { kind, type_hint }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Type {
|
||||
Int { size: u8 },
|
||||
Bytes { size: u8 },
|
||||
Bool,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn int(size: u8) -> Self {
|
||||
Self::Int { size }
|
||||
}
|
||||
|
||||
fn bytes(size: u8) -> Self {
|
||||
Self::Bytes { size }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Type {
|
||||
fn default() -> Self {
|
||||
Type::Int { size: 32 }
|
||||
}
|
||||
}
|
||||
|
||||
pub enum LinearMemory {
|
||||
CallData,
|
||||
Memory,
|
||||
ReturnData,
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
use std::fmt::Write;
|
||||
use std::ops::Range;
|
||||
|
||||
use evmil::bytecode;
|
||||
use petgraph::{
|
||||
dot::{Config, Dot},
|
||||
graph::DiGraph,
|
||||
stable_graph::NodeIndex,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
instruction::{self, Instruction},
|
||||
symbol::SymbolTable,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EvmInstruction {
|
||||
pub bytecode_offset: usize,
|
||||
pub instruction: bytecode::Instruction,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct BasicBlock {
|
||||
pub entry: Option<Entry>,
|
||||
pub opcodes: Range<usize>,
|
||||
pub instructions: Vec<Instruction>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub enum BasicBlockFormatOption {
|
||||
ByteCode,
|
||||
Ir,
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
|
||||
impl BasicBlock {
|
||||
fn format(&self, evm_bytecode: &[EvmInstruction], options: BasicBlockFormatOption) -> String {
|
||||
let offset = evm_bytecode[self.opcodes.start].bytecode_offset;
|
||||
let start = if let Some(Entry::Start) = self.entry {
|
||||
"Start\n".to_string()
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let instructions = match options {
|
||||
BasicBlockFormatOption::ByteCode => evm_bytecode[self.opcodes.start..self.opcodes.end]
|
||||
.iter()
|
||||
.fold(String::new(), |mut acc, opcode| {
|
||||
writeln!(&mut acc, "{:?}", opcode.instruction).unwrap();
|
||||
acc
|
||||
}),
|
||||
_ => String::new(),
|
||||
};
|
||||
|
||||
format!("{start}Offset: 0x{offset:02x}\n---\n{instructions}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Entry {
|
||||
Start,
|
||||
Jumpdest(NodeIndex),
|
||||
Else(NodeIndex),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Jump {
|
||||
Direct,
|
||||
Indirect,
|
||||
}
|
||||
|
||||
pub struct Program {
|
||||
pub evm_instructions: Vec<EvmInstruction>,
|
||||
pub cfg: DiGraph<BasicBlock, Jump>,
|
||||
pub symbol_table: SymbolTable,
|
||||
}
|
||||
|
||||
impl Program {
|
||||
pub fn new(bytecode: Vec<bytecode::Instruction>) -> Self {
|
||||
let mut cfg = DiGraph::new();
|
||||
let mut symbol_table = SymbolTable::default();
|
||||
let mut evm_instructions = Vec::with_capacity(bytecode.len());
|
||||
|
||||
let mut current_block = Some(BasicBlock {
|
||||
entry: Some(Entry::Start),
|
||||
..Default::default()
|
||||
});
|
||||
let mut bytecode_offset = 0;
|
||||
|
||||
for (index, opcode) in bytecode.iter().enumerate() {
|
||||
evm_instructions.push(EvmInstruction {
|
||||
bytecode_offset,
|
||||
instruction: opcode.clone(),
|
||||
});
|
||||
bytecode_offset += opcode.length();
|
||||
|
||||
let instructions = instruction::translate(opcode, &mut symbol_table);
|
||||
|
||||
use bytecode::Instruction::*;
|
||||
match opcode {
|
||||
JUMPDEST => {
|
||||
// If we are already in a bb, conclude it
|
||||
let entry = current_block.take().map(|mut node| {
|
||||
node.opcodes.end = index + 1;
|
||||
let entry = node.entry.clone();
|
||||
let node_index = cfg.add_node(node);
|
||||
|
||||
// If the block had an entry, add an edge from the previous block to it
|
||||
if let Some(Entry::Else(incoming)) | Some(Entry::Jumpdest(incoming)) = entry
|
||||
{
|
||||
cfg.add_edge(incoming, node_index, Jump::Direct);
|
||||
}
|
||||
node_index
|
||||
});
|
||||
|
||||
// JUMPDEST implicitly starts a new bb
|
||||
current_block = Some(BasicBlock {
|
||||
entry: entry.map(Entry::Jumpdest),
|
||||
opcodes: Range {
|
||||
start: index + 1,
|
||||
end: index + 1,
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
JUMP | STOP | RETURN | REVERT | INVALID => {
|
||||
// Conclude this bb; if we are not already in a bb we must create a new one
|
||||
let mut node = current_block.take().unwrap_or_else(|| BasicBlock {
|
||||
opcodes: Range {
|
||||
start: index,
|
||||
end: index + 1,
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
node.instructions.extend(instructions);
|
||||
node.opcodes.end = index + 1;
|
||||
|
||||
let entry = node.entry.clone();
|
||||
let node_index = cfg.add_node(node);
|
||||
|
||||
// If the block had an entry, add an edge from the previous block to it
|
||||
if let Some(Entry::Else(incoming)) | Some(Entry::Jumpdest(incoming)) = entry {
|
||||
cfg.add_edge(incoming, node_index, Jump::Direct);
|
||||
}
|
||||
}
|
||||
|
||||
JUMPI => {
|
||||
// Conclude this bb; if we are not already in a bb we must create a new one
|
||||
let mut node = current_block.take().unwrap_or_else(|| BasicBlock {
|
||||
opcodes: Range {
|
||||
start: index,
|
||||
end: index + 1,
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
node.instructions.extend(instructions);
|
||||
node.opcodes.end = index + 1;
|
||||
|
||||
let entry = node.entry.clone();
|
||||
let node_index = cfg.add_node(node);
|
||||
|
||||
// If the block had an entry, add an edge from the previous block to it
|
||||
if let Some(Entry::Else(incoming)) | Some(Entry::Jumpdest(incoming)) = entry {
|
||||
cfg.add_edge(incoming, node_index, Jump::Direct);
|
||||
}
|
||||
|
||||
// JUMPI implicitly starts a new bb for the else branch
|
||||
current_block = Some(BasicBlock {
|
||||
entry: Some(Entry::Else(node_index)),
|
||||
opcodes: Range {
|
||||
start: index + 1,
|
||||
end: index + 1,
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
_ => current_block
|
||||
.get_or_insert(BasicBlock {
|
||||
opcodes: Range {
|
||||
start: index,
|
||||
end: index + 1,
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.instructions
|
||||
.extend(instructions),
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
evm_instructions,
|
||||
cfg,
|
||||
symbol_table,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dot(&self, format_options: BasicBlockFormatOption) {
|
||||
let get_node_attrs = move |_, (_, node): (_, &BasicBlock)| {
|
||||
format!(
|
||||
"label = \"{}\"",
|
||||
node.format(&self.evm_instructions, format_options)
|
||||
)
|
||||
};
|
||||
|
||||
let dot = Dot::with_attr_getters(
|
||||
&self.cfg,
|
||||
&[Config::EdgeNoLabel, Config::NodeNoLabel],
|
||||
&|_, edge| format!("label = \"{:?}\"", edge.weight()),
|
||||
&get_node_attrs,
|
||||
);
|
||||
|
||||
println!("{dot:?}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
use evmil::bytecode::Instruction as EvmInstruction;
|
||||
use primitive_types::U256;
|
||||
|
||||
use crate::symbol::{Global, Symbol, SymbolTable, Type};
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum Instruction {
|
||||
/// `x = y op z`
|
||||
BinaryAssign {
|
||||
x: Symbol,
|
||||
y: Symbol,
|
||||
operator: Operator,
|
||||
z: Symbol,
|
||||
},
|
||||
|
||||
/// `x = op y`
|
||||
UnaryAssign {
|
||||
x: Symbol,
|
||||
y: Symbol,
|
||||
operator: Operator,
|
||||
},
|
||||
|
||||
/// `branch target`
|
||||
UncoditionalBranch { target: Symbol },
|
||||
|
||||
/// `branch target if condition`
|
||||
ConditionalBranch { condition: Symbol, target: Symbol },
|
||||
|
||||
/// `call(label, n)`
|
||||
Procedure {
|
||||
symbol: Global,
|
||||
parameters: Vec<Symbol>,
|
||||
},
|
||||
|
||||
/// `x = call(label, n)`
|
||||
Function {
|
||||
symbol: Global,
|
||||
x: Symbol,
|
||||
args: Vec<Symbol>,
|
||||
},
|
||||
|
||||
/// `x = y`
|
||||
Copy { x: Symbol, y: Symbol },
|
||||
|
||||
/// `x[index] = y`
|
||||
IndexedAssign { x: Symbol, index: Symbol, y: Symbol },
|
||||
|
||||
/// `x = y[index]`
|
||||
IndexedCopy { x: Symbol, y: Symbol, index: Symbol },
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum Operator {
|
||||
Add,
|
||||
Mul,
|
||||
Sub,
|
||||
Div,
|
||||
SDiv,
|
||||
Mod,
|
||||
SMod,
|
||||
AddMod,
|
||||
MulMod,
|
||||
Exp,
|
||||
SignExtend,
|
||||
|
||||
LessThat,
|
||||
GreaterThan,
|
||||
SignedLessThan,
|
||||
SignedGreaterThan,
|
||||
Eq,
|
||||
IsZero,
|
||||
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
Not,
|
||||
Byte,
|
||||
ShiftLeft,
|
||||
ShiftRight,
|
||||
ShiftArithmeticRight,
|
||||
}
|
||||
|
||||
struct StackPop {
|
||||
decrement: Instruction,
|
||||
load: Instruction,
|
||||
}
|
||||
|
||||
/// Pop a value from the stack.
|
||||
///
|
||||
/// Returns 2 `Instruction`: Decrementing the stack pointer and the value copy.
|
||||
fn stack_pop(symbol_table: &mut SymbolTable) -> StackPop {
|
||||
let decrement = decrement_stack_height(symbol_table);
|
||||
|
||||
let load = Instruction::IndexedCopy {
|
||||
x: symbol_table.temporary(None),
|
||||
y: symbol_table.global(Global::Stack),
|
||||
index: symbol_table.global(Global::StackHeight),
|
||||
};
|
||||
|
||||
StackPop { decrement, load }
|
||||
}
|
||||
|
||||
/// Decrease the stack height by one.
|
||||
fn decrement_stack_height(symbol_table: &mut SymbolTable) -> Instruction {
|
||||
Instruction::BinaryAssign {
|
||||
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))),
|
||||
}
|
||||
}
|
||||
|
||||
struct StackPush {
|
||||
assign: Instruction,
|
||||
increment: Instruction,
|
||||
}
|
||||
|
||||
/// Push a `value` to the stack.
|
||||
///
|
||||
/// Returns 2 `Instruction`: the value assign and the stack height increase.
|
||||
fn stack_push(symbol_table: &mut SymbolTable, value: Symbol) -> StackPush {
|
||||
let assign = Instruction::IndexedAssign {
|
||||
x: symbol_table.global(Global::Stack),
|
||||
index: symbol_table.global(Global::StackHeight),
|
||||
y: value,
|
||||
};
|
||||
let increment = increment_stack_height(symbol_table);
|
||||
|
||||
StackPush { assign, increment }
|
||||
}
|
||||
|
||||
/// Increment the stack height by one.
|
||||
fn increment_stack_height(symbol_table: &mut SymbolTable) -> Instruction {
|
||||
Instruction::BinaryAssign {
|
||||
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))),
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
pub fn translate(opcode: &EvmInstruction, symbol_table: &mut SymbolTable) -> Vec<Instruction> {
|
||||
use EvmInstruction::*;
|
||||
match opcode {
|
||||
JUMPDEST => Vec::new(),
|
||||
|
||||
PUSH(bytes) => {
|
||||
let type_hint = Some(Type::Bytes(bytes.len()));
|
||||
let value = symbol_table.constant(U256::from_big_endian(bytes), type_hint);
|
||||
let push = stack_push(symbol_table, value);
|
||||
|
||||
vec![push.assign, push.increment]
|
||||
}
|
||||
|
||||
POP => vec![decrement_stack_height(symbol_table)],
|
||||
|
||||
MSTORE => {
|
||||
let offset = stack_pop(symbol_table);
|
||||
let value = stack_pop(symbol_table);
|
||||
|
||||
let store = Instruction::IndexedAssign {
|
||||
x: symbol_table.global(Global::Memory),
|
||||
index: offset.load.target_address(),
|
||||
y: value.load.target_address(),
|
||||
};
|
||||
|
||||
vec![
|
||||
offset.decrement,
|
||||
offset.load,
|
||||
value.decrement,
|
||||
value.load,
|
||||
store,
|
||||
]
|
||||
}
|
||||
|
||||
JUMP => {
|
||||
let target = stack_pop(symbol_table);
|
||||
|
||||
let jump = Instruction::UncoditionalBranch {
|
||||
target: target.load.target_address(),
|
||||
};
|
||||
|
||||
vec![target.decrement, target.load, jump]
|
||||
}
|
||||
|
||||
RETURN => {
|
||||
let offset = stack_pop(symbol_table);
|
||||
let size = stack_pop(symbol_table);
|
||||
|
||||
let procedure = Instruction::Procedure {
|
||||
symbol: Global::Return,
|
||||
parameters: vec![offset.load.target_address(), size.load.target_address()],
|
||||
};
|
||||
|
||||
vec![
|
||||
offset.decrement,
|
||||
offset.load,
|
||||
size.decrement,
|
||||
size.load,
|
||||
procedure,
|
||||
]
|
||||
}
|
||||
|
||||
CALLDATACOPY => {
|
||||
let destination_offset = stack_pop(symbol_table);
|
||||
let offset = stack_pop(symbol_table);
|
||||
let size = stack_pop(symbol_table);
|
||||
|
||||
let parameters = vec![
|
||||
destination_offset.load.target_address(),
|
||||
offset.load.target_address(),
|
||||
size.load.target_address(),
|
||||
];
|
||||
|
||||
let procedure = Instruction::Procedure {
|
||||
symbol: Global::MemoryCopy,
|
||||
parameters,
|
||||
};
|
||||
|
||||
vec![
|
||||
destination_offset.decrement,
|
||||
destination_offset.load,
|
||||
offset.decrement,
|
||||
offset.load,
|
||||
size.decrement,
|
||||
size.load,
|
||||
procedure,
|
||||
]
|
||||
}
|
||||
|
||||
CALLDATALOAD => {
|
||||
let index = stack_pop(symbol_table);
|
||||
|
||||
let value = Instruction::IndexedCopy {
|
||||
x: symbol_table.temporary(None),
|
||||
y: symbol_table.global(Global::CallData),
|
||||
index: index.load.target_address(),
|
||||
};
|
||||
|
||||
let push = stack_push(symbol_table, value.target_address());
|
||||
|
||||
vec![
|
||||
index.decrement,
|
||||
index.load,
|
||||
value,
|
||||
push.assign,
|
||||
push.increment,
|
||||
]
|
||||
}
|
||||
|
||||
//_ => todo!("{opcode}"),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use evmil::bytecode;
|
||||
use primitive_types::U256;
|
||||
|
||||
use crate::{
|
||||
instruction::Operator,
|
||||
symbol::{Global, Kind, Symbol, Type},
|
||||
};
|
||||
|
||||
use super::Instruction;
|
||||
|
||||
#[test]
|
||||
fn lower_push_works() {
|
||||
let mut symbol_table = Default::default();
|
||||
|
||||
let opcode = bytecode::Instruction::PUSH(vec![0x01]);
|
||||
let result = super::translate(&opcode, &mut symbol_table);
|
||||
|
||||
let expected = vec![
|
||||
Instruction::IndexedAssign {
|
||||
x: Symbol {
|
||||
kind: Kind::Label(Global::Stack),
|
||||
type_hint: Type::Word,
|
||||
},
|
||||
index: Symbol {
|
||||
kind: Kind::Label(Global::StackHeight),
|
||||
type_hint: Type::Int(4),
|
||||
},
|
||||
y: Symbol {
|
||||
kind: Kind::Constant(U256::one()),
|
||||
type_hint: Type::Bytes(1),
|
||||
},
|
||||
},
|
||||
Instruction::BinaryAssign {
|
||||
x: Symbol {
|
||||
kind: Kind::Label(Global::StackHeight),
|
||||
type_hint: Type::Int(4),
|
||||
},
|
||||
y: Symbol {
|
||||
kind: Kind::Label(Global::StackHeight),
|
||||
type_hint: Type::Int(4),
|
||||
},
|
||||
operator: Operator::Add,
|
||||
z: Symbol {
|
||||
kind: Kind::Constant(U256::one()),
|
||||
type_hint: Type::Int(4),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
assert_eq!(expected, result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
pub mod cfg;
|
||||
pub mod instruction;
|
||||
pub mod symbol;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
#[test]
|
||||
fn it_works() {}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
use indexmap::IndexSet;
|
||||
use primitive_types::U256;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum Kind {
|
||||
Constant(U256),
|
||||
Temporary(usize),
|
||||
Label(Global),
|
||||
}
|
||||
|
||||
impl Kind {
|
||||
pub fn from_be_bytes(bytes: &[u8]) -> Self {
|
||||
Self::Constant(U256::from_big_endian(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct Symbol {
|
||||
pub kind: Kind,
|
||||
pub type_hint: Type,
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
fn global(symbol: Global) -> Self {
|
||||
let type_hint = match symbol {
|
||||
Global::StackHeight => Type::Int(4),
|
||||
_ => Default::default(),
|
||||
};
|
||||
|
||||
Self::new(Kind::Label(symbol), type_hint)
|
||||
}
|
||||
|
||||
fn new(kind: Kind, type_hint: Type) -> Self {
|
||||
Self { kind, type_hint }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Default, Clone, Copy)]
|
||||
pub enum Type {
|
||||
#[default]
|
||||
Word,
|
||||
Int(usize),
|
||||
Bytes(usize),
|
||||
Bool,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn pointer() -> Self {
|
||||
Self::Int(4)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum Global {
|
||||
/// Pointer
|
||||
Stack,
|
||||
/// Stack height variable
|
||||
StackHeight,
|
||||
|
||||
/// Pointer
|
||||
CallData,
|
||||
/// Pointer
|
||||
Memory,
|
||||
/// Pointer
|
||||
ReturnData,
|
||||
|
||||
/// Low level `memcpy` like function
|
||||
MemoryCopy,
|
||||
|
||||
// EVM
|
||||
Sha3,
|
||||
Address,
|
||||
CallDataLoad,
|
||||
CallDataSize,
|
||||
CallDataCopy,
|
||||
CodeSize,
|
||||
CodeCopy,
|
||||
GasPrice,
|
||||
ExtCodeSize,
|
||||
ExtCodeCopy,
|
||||
ReturnDataSize,
|
||||
ReturnDataCopy,
|
||||
ExtCodeHash,
|
||||
BlockHash,
|
||||
Coinbase,
|
||||
Timestamp,
|
||||
BlockNumber,
|
||||
PrevRanDao,
|
||||
GasLimit,
|
||||
ChainId,
|
||||
SelfBalance,
|
||||
BaseFee,
|
||||
SLoad,
|
||||
SStore,
|
||||
Gas,
|
||||
Create,
|
||||
Create2,
|
||||
Call,
|
||||
StaticCall,
|
||||
DelegateCall,
|
||||
CallCode,
|
||||
Return,
|
||||
Stop,
|
||||
Revert,
|
||||
SelfDestruct,
|
||||
Event,
|
||||
}
|
||||
|
||||
#[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(Kind::Temporary(id), type_hint.unwrap_or_default());
|
||||
assert!(self.symbols.insert(symbol));
|
||||
|
||||
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());
|
||||
self.symbols.insert(symbol);
|
||||
|
||||
symbol
|
||||
}
|
||||
|
||||
pub fn global(&mut self, label: Global) -> Symbol {
|
||||
let symbol = Symbol::global(label);
|
||||
self.symbols.insert(symbol);
|
||||
|
||||
symbol
|
||||
}
|
||||
}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
600035565b607f600052610014565b60ff6000525b60206000f3
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
608060405234801561000f575f80fd5b50600436106100f0575f3560e01c806370a082311161009357806395d89b411161006357806395d89b41146101ef578063a9059cbb146101f7578063dd62ed3e1461020a578063f2fde38b14610242575f80fd5b806370a0823114610191578063715018a6146101b957806379cc6790146101c15780638da5cb5b146101d4575f80fd5b806323b872dd116100ce57806323b872dd14610147578063313ce5671461015a57806340c10f191461016957806342966c681461017e575f80fd5b806306fdde03146100f4578063095ea7b31461011257806318160ddd14610135575b5f80fd5b6100fc610255565b604051610109919061078f565b60405180910390f35b6101256101203660046107f6565b6102e5565b6040519015158152602001610109565b6002545b604051908152602001610109565b61012561015536600461081e565b6102fe565b60405160128152602001610109565b61017c6101773660046107f6565b610321565b005b61017c61018c366004610857565b610337565b61013961019f36600461086e565b6001600160a01b03165f9081526020819052604090205490565b61017c610344565b61017c6101cf3660046107f6565b610357565b6005546040516001600160a01b039091168152602001610109565b6100fc61036c565b6101256102053660046107f6565b61037b565b61013961021836600461088e565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b61017c61025036600461086e565b610388565b606060038054610264906108bf565b80601f0160208091040260200160405190810160405280929190818152602001828054610290906108bf565b80156102db5780601f106102b2576101008083540402835291602001916102db565b820191905f5260205f20905b8154815290600101906020018083116102be57829003601f168201915b5050505050905090565b5f336102f28185856103c7565b60019150505b92915050565b5f3361030b8582856103d9565b610316858585610454565b506001949350505050565b6103296104b1565b61033382826104de565b5050565b6103413382610512565b50565b61034c6104b1565b6103555f610546565b565b6103628233836103d9565b6103338282610512565b606060048054610264906108bf565b5f336102f2818585610454565b6103906104b1565b6001600160a01b0381166103be57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b61034181610546565b6103d48383836001610597565b505050565b6001600160a01b038381165f908152600160209081526040808320938616835292905220545f19811461044e578181101561044057604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016103b5565b61044e84848484035f610597565b50505050565b6001600160a01b03831661047d57604051634b637e8f60e11b81525f60048201526024016103b5565b6001600160a01b0382166104a65760405163ec442f0560e01b81525f60048201526024016103b5565b6103d4838383610669565b6005546001600160a01b031633146103555760405163118cdaa760e01b81523360048201526024016103b5565b6001600160a01b0382166105075760405163ec442f0560e01b81525f60048201526024016103b5565b6103335f8383610669565b6001600160a01b03821661053b57604051634b637e8f60e11b81525f60048201526024016103b5565b610333825f83610669565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b0384166105c05760405163e602df0560e01b81525f60048201526024016103b5565b6001600160a01b0383166105e957604051634a1406b160e11b81525f60048201526024016103b5565b6001600160a01b038085165f908152600160209081526040808320938716835292905220829055801561044e57826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161065b91815260200190565b60405180910390a350505050565b6001600160a01b038316610693578060025f82825461068891906108f7565b909155506107039050565b6001600160a01b0383165f90815260208190526040902054818110156106e55760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016103b5565b6001600160a01b0384165f9081526020819052604090209082900390555b6001600160a01b03821661071f5760028054829003905561073d565b6001600160a01b0382165f9081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161078291815260200190565b60405180910390a3505050565b5f602080835283518060208501525f5b818110156107bb5785810183015185820160400152820161079f565b505f604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146107f1575f80fd5b919050565b5f8060408385031215610807575f80fd5b610810836107db565b946020939093013593505050565b5f805f60608486031215610830575f80fd5b610839846107db565b9250610847602085016107db565b9150604084013590509250925092565b5f60208284031215610867575f80fd5b5035919050565b5f6020828403121561087e575f80fd5b610887826107db565b9392505050565b5f806040838503121561089f575f80fd5b6108a8836107db565b91506108b6602084016107db565b90509250929050565b600181811c908216806108d357607f821691505b6020821081036108f157634e487b7160e01b5f52602260045260245ffd5b50919050565b808201808211156102f857634e487b7160e01b5f52601160045260245ffdfea26469706673582212203436d2f76da96888f84c631a86a77acc02d0494c4ed226857c2872074984910064736f6c63430008170033
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
@@ -0,0 +1 @@
|
||||
600035600160009160025b818111601c576001019180930191600a565b505060005260206000f350
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
600035600160009160025b818111601c576001019180930191600a565b505060005260206000f350
|
||||
Reference in New Issue
Block a user