summaryrefslogtreecommitdiff
path: root/vm
diff options
context:
space:
mode:
Diffstat (limited to 'vm')
-rw-r--r--vm/instruction.go147
-rw-r--r--vm/instructions.go162
-rw-r--r--vm/main.go8
-rw-r--r--vm/memory.go14
-rw-r--r--vm/opcodes.go9
-rw-r--r--vm/rom.go9
-rw-r--r--vm/stack.go5
-rw-r--r--vm/vm.go28
8 files changed, 213 insertions, 169 deletions
diff --git a/vm/instruction.go b/vm/instruction.go
deleted file mode 100644
index 5cd56e6..0000000
--- a/vm/instruction.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package main
-
-import (
- "github.com/holiman/uint256"
-)
-
-type Handler func(vm *Evm)
-
-type Instruction struct {
- name string
- n int // number of params
- handler Handler
-}
-
-type Inst Instruction // shorthand
-
-// i miss c macros :(
-var Instructions = [256]Instruction{
- STOP: {
- name: "STOP",
- n: 0,
- handler: func(vm *Evm) { vm.stopped = true },
- } ,
- ADD: {
- name: "ADD",
- n: 2,
- handler: func(vm *Evm) {
- o := uint256.NewInt(0)
- vm.stack.Push(o.Add(vm.stack.Pop(), vm.stack.Pop()))
- },
- },
- MUL: {
- n: 2,
- name: "MUL",
- handler: func(vm *Evm) {
- o := uint256.NewInt(0)
- vm.stack.Push(o.Mul(vm.stack.Pop(), vm.stack.Pop()))
- },
- },
- SUB: {
- n: 2,
- name: "SUB",
- handler: func(vm *Evm) {
- o := uint256.NewInt(0)
- vm.stack.Push(o.Sub(vm.stack.Pop(), vm.stack.Pop()))
- },
- },
- DIV: {
- n: 2,
- name: "DIV",
- handler: func(vm *Evm) {
- o := uint256.NewInt(0)
- vm.stack.Push(o.Div(vm.stack.Pop(), vm.stack.Pop()))
- },
- },
- SDIV: {
- n: 2,
- name: "SDIV",
- handler: func(vm *Evm) {
- o := uint256.NewInt(0)
- vm.stack.Push(o.SDiv(vm.stack.Pop(), vm.stack.Pop()))
- },
- },
- MOD: {
- n: 2,
- name: "MOD",
- handler: func(vm *Evm) {
- o := uint256.NewInt(0)
- vm.stack.Push(o.Mod(vm.stack.Pop(), vm.stack.Pop()))
- },
- },
- SMOD: {
- n: 2,
- name: "SMOD",
- handler: func(vm *Evm) {
- o := uint256.NewInt(0)
- vm.stack.Push(o.SMod(vm.stack.Pop(), vm.stack.Pop()))
- },
- },
- ADDMOD: {
- n: 3,
- name: "ADDMOD",
- handler: func(vm *Evm) {
- o := uint256.NewInt(0)
- vm.stack.Push(o.AddMod(vm.stack.Pop(), vm.stack.Pop(), vm.stack.Pop()))
- },
- },
- MULMOD: {
- n: 3,
- name: "MULMOD",
- handler: func(vm *Evm) {
- o := uint256.NewInt(0)
- vm.stack.Push(o.MulMod(vm.stack.Pop(), vm.stack.Pop(), vm.stack.Pop()))
- },
- },
- POP: {
- n: 1,
- name: "POP",
- handler: func(vm *Evm) {
- vm.stack.Pop()
- },
- },
- MLOAD: {
- n: 1,
- name: "MLOAD",
- },
- MSTORE: {
- n: 2,
- name: "MSTORE",
- },
- MSTORE8: {
- n: 2,
- name: "MSTORE8",
- },
- PUSH1: { name: "PUSH1" },
- PUSH2: { name: "PUSH2" },
- PUSH3: { name: "PUSH3" },
- PUSH4: { name: "PUSH4" },
- PUSH5: { name: "PUSH5" },
- PUSH6: { name: "PUSH6" },
- PUSH7: { name: "PUSH7" },
- PUSH8: { name: "PUSH8" },
- PUSH9: { name: "PUSH9" },
- PUSH10: { name: "PUSH0" },
- PUSH11: { name: "PUSH11" },
- PUSH12: { name: "PUSH12" },
- PUSH13: { name: "PUSH13" },
- PUSH14: { name: "PUSH14" },
- PUSH15: { name: "PUSH15" },
- PUSH16: { name: "PUSH16" },
- PUSH17: { name: "PUSH17" },
- PUSH18: { name: "PUSH18" },
- PUSH19: { name: "PUSH19" },
- PUSH20: { name: "PUSH20" },
- PUSH21: { name: "PUSH21" },
- PUSH22: { name: "PUSH22" },
- PUSH23: { name: "PUSH23" },
- PUSH24: { name: "PUSH24" },
- PUSH25: { name: "PUSH25" },
- PUSH26: { name: "PUSH26" },
- PUSH27: { name: "PUSH27" },
- PUSH28: { name: "PUSH28" },
- PUSH29: { name: "PUSH29" },
- PUSH30: { name: "PUSH30" },
- PUSH31: { name: "PUSH31" },
- PUSH32: { name: "PUSH32" },
-}
diff --git a/vm/instructions.go b/vm/instructions.go
index 5a1220b..8b8b2e2 100644
--- a/vm/instructions.go
+++ b/vm/instructions.go
@@ -1,3 +1,163 @@
package main
-type InstructionHandler func (vm *Evm)
+import (
+ "github.com/holiman/uint256"
+)
+
+type Handler func(vm *Evm)
+
+type Instruction struct {
+ name string
+ n int // number of params
+ handler Handler
+}
+
+type Inst Instruction // shorthand
+
+// i miss c macros :(
+var Instructions = [256]Instruction{
+ STOP: {
+ name: "STOP",
+ n: 0,
+ handler: func(vm *Evm) { vm.stopped = true },
+ } ,
+ ADD: {
+ name: "ADD",
+ n: 2,
+ handler: func(vm *Evm) {
+ o := uint256.NewInt(0)
+ vm.stack.Push(o.Add(vm.stack.Pop(), vm.stack.Pop()))
+ },
+ },
+ MUL: {
+ n: 2,
+ name: "MUL",
+ handler: func(vm *Evm) {
+ o := uint256.NewInt(0)
+ vm.stack.Push(o.Mul(vm.stack.Pop(), vm.stack.Pop()))
+ },
+ },
+ SUB: {
+ n: 2,
+ name: "SUB",
+ handler: func(vm *Evm) {
+ o := uint256.NewInt(0)
+ vm.stack.Push(o.Sub(vm.stack.Pop(), vm.stack.Pop()))
+ },
+ },
+ DIV: {
+ n: 2,
+ name: "DIV",
+ handler: func(vm *Evm) {
+ o := uint256.NewInt(0)
+ vm.stack.Push(o.Div(vm.stack.Pop(), vm.stack.Pop()))
+ },
+ },
+ SDIV: {
+ n: 2,
+ name: "SDIV",
+ handler: func(vm *Evm) {
+ o := uint256.NewInt(0)
+ vm.stack.Push(o.SDiv(vm.stack.Pop(), vm.stack.Pop()))
+ },
+ },
+ MOD: {
+ n: 2,
+ name: "MOD",
+ handler: func(vm *Evm) {
+ o := uint256.NewInt(0)
+ vm.stack.Push(o.Mod(vm.stack.Pop(), vm.stack.Pop()))
+ },
+ },
+ SMOD: {
+ n: 2,
+ name: "SMOD",
+ handler: func(vm *Evm) {
+ o := uint256.NewInt(0)
+ vm.stack.Push(o.SMod(vm.stack.Pop(), vm.stack.Pop()))
+ },
+ },
+ ADDMOD: {
+ n: 3,
+ name: "ADDMOD",
+ handler: func(vm *Evm) {
+ o := uint256.NewInt(0)
+ vm.stack.Push(o.AddMod(vm.stack.Pop(), vm.stack.Pop(), vm.stack.Pop()))
+ },
+ },
+ MULMOD: {
+ n: 3,
+ name: "MULMOD",
+ handler: func(vm *Evm) {
+ o := uint256.NewInt(0)
+ vm.stack.Push(o.MulMod(vm.stack.Pop(), vm.stack.Pop(), vm.stack.Pop()))
+ },
+ },
+ POP: {
+ n: 1,
+ name: "POP",
+ handler: func(vm *Evm) {
+ vm.stack.Pop()
+ },
+ },
+ MLOAD: {
+ n: 1,
+ name: "MLOAD",
+ },
+ MSTORE: {
+ n: 2,
+ name: "MSTORE",
+ handler: func(vm *Evm) {
+ vm.memory.sw(vm.stack.Pop().Uint64(), vm.stack.Pop())
+ },
+ },
+ MSTORE8: {
+ n: 2,
+ name: "MSTORE8",
+ handler: func(vm *Evm) {
+ ost := vm.stack.Pop().Uint64()
+ x := vm.stack.Pop().Bytes()
+ n := x[len(x)-1]
+ vm.memory.sb(ost, n)
+ },
+ },
+ PUSH1: { name: "PUSH1" },
+ PUSH2: { name: "PUSH2" },
+ PUSH3: { name: "PUSH3" },
+ PUSH4: { name: "PUSH4" },
+ PUSH5: { name: "PUSH5" },
+ PUSH6: { name: "PUSH6" },
+ PUSH7: { name: "PUSH7" },
+ PUSH8: { name: "PUSH8" },
+ PUSH9: { name: "PUSH9" },
+ PUSH10: { name: "PUSH0" },
+ PUSH11: { name: "PUSH11" },
+ PUSH12: { name: "PUSH12" },
+ PUSH13: { name: "PUSH13" },
+ PUSH14: { name: "PUSH14" },
+ PUSH15: { name: "PUSH15" },
+ PUSH16: { name: "PUSH16" },
+ PUSH17: { name: "PUSH17" },
+ PUSH18: { name: "PUSH18" },
+ PUSH19: { name: "PUSH19" },
+ PUSH20: { name: "PUSH20" },
+ PUSH21: { name: "PUSH21" },
+ PUSH22: { name: "PUSH22" },
+ PUSH23: { name: "PUSH23" },
+ PUSH24: { name: "PUSH24" },
+ PUSH25: { name: "PUSH25" },
+ PUSH26: { name: "PUSH26" },
+ PUSH27: { name: "PUSH27" },
+ PUSH28: { name: "PUSH28" },
+ PUSH29: { name: "PUSH29" },
+ PUSH30: { name: "PUSH30" },
+ PUSH31: { name: "PUSH31" },
+ PUSH32: { name: "PUSH32" },
+ RETURN: {
+ n: 2,
+ name: "RETURN",
+ handler: func(vm *Evm) {
+ vm.returndata = vm.memory.ld(vm.stack.Pop().Uint64(), vm.stack.Pop().Uint64())
+ },
+ },
+}
diff --git a/vm/main.go b/vm/main.go
index 61aeebb..688918a 100644
--- a/vm/main.go
+++ b/vm/main.go
@@ -21,6 +21,12 @@ func main() {
vm := NewEvm(b)
- vm.Start()
+ returndata := vm.Run()
+
+ fmt.Printf("finished execution.\n")
+
+ if (returndata != nil) {
+ fmt.Printf("callee returned: %v\n", returndata)
+ }
}
diff --git a/vm/memory.go b/vm/memory.go
index 0a9dd2c..a0c610a 100644
--- a/vm/memory.go
+++ b/vm/memory.go
@@ -26,14 +26,18 @@ func (m *Memory) sb(ost uint64, val byte) {
(*m)[ost] = val
}
-// loads 256b word fron offset in memory
-func (m *Memory) ld(ost uint64) []byte {
- if ost + 32 > uint64(len(*m)) {
+func (m *Memory) ld(ost uint64, n uint64) []byte {
+ if ost + n > uint64(len(*m)) {
log.Fatal("trying to load out of memory")
}
- r := make([]byte, 32)
- copy(r, (*m)[ost:ost+32])
+ r := make([]byte, n)
+ copy(r, (*m)[ost:ost+n])
+ return r
+}
+
+func (m *Memory) lw(ost uint64) []byte {
+ r := m.ld(ost, 32)
return r
}
diff --git a/vm/opcodes.go b/vm/opcodes.go
index b3d4229..d1f6905 100644
--- a/vm/opcodes.go
+++ b/vm/opcodes.go
@@ -49,9 +49,18 @@ const (
PUSH30 = 0x7d
PUSH31 = 0x7e
PUSH32 = 0x7f
+ RETURN = 0xF3
//...
)
func (op *Opcode) String() string {
return Instructions[*op].name
}
+
+func (o *Opcode) IsPush() byte {
+ d := *o - PUSH1
+ if d >= 0 && d < 31 {
+ return byte(d) + 1
+ }
+ return 0
+}
diff --git a/vm/rom.go b/vm/rom.go
index 958e70e..b638da0 100644
--- a/vm/rom.go
+++ b/vm/rom.go
@@ -1,16 +1,15 @@
package main
import (
- "os"
- "fmt"
+// "os"
+// "fmt"
)
type Rom []byte
func (r *Rom) Fetch(pc *uint64, n uint64) []byte {
- if (*pc + n > uint64(len(*r)) - 1) {
- fmt.Fprintf(os.Stderr, "error: trying to read outside of rom\n")
- os.Exit(1)
+ if (*pc + n > uint64(len(*r))) {
+ return nil
}
x := make([]byte, n)
copy(x, (*r)[*pc:*pc + n])
diff --git a/vm/stack.go b/vm/stack.go
index fc1cbd4..ec2a738 100644
--- a/vm/stack.go
+++ b/vm/stack.go
@@ -2,8 +2,8 @@ package main
import (
"log"
-
- "github.com/holiman/uint256"
+ "fmt"
+ "github.com/holiman/uint256"
)
const STACK_CAP = (1 << 10)
@@ -11,6 +11,7 @@ const STACK_CAP = (1 << 10)
type Stack []uint256.Int
func (s *Stack) Push(x *uint256.Int) {
+ fmt.Printf("pushing %s to stack\n", x.String())
*s = append(*s, *x)
if len(*s) + 1 > STACK_CAP {
log.Fatal("stack overflow")
diff --git a/vm/vm.go b/vm/vm.go
index 209ab71..7a6178f 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -11,6 +11,7 @@ type Evm struct {
memory Memory
pc uint64
stopped bool
+ returndata []byte
}
func NewEvm(_code []byte) *Evm {
@@ -19,25 +20,36 @@ func NewEvm(_code []byte) *Evm {
stopped: true,
stack : Stack{},
code: _code,
+ returndata: nil,
}
}
-func (vm *Evm) Start() {
+func (vm *Evm) Run() []byte {
vm.stopped = false
+ fmt.Printf("code: ", vm.code)
for !(vm.stopped) {
- op := vm.code.Fetch(&(vm.pc), 1)[0]
- fmt.Printf("pc: %d | opcode: %x -> string: %s\n", vm.pc, op, Instructions[op].name)
- if op >= PUSH1 && op <= PUSH32 {
- nb := op - PUSH1 + 1
- fmt.Printf("pushing %d byte value to the stack!\n", vm.pc, nb)
- b := vm.code.Fetch(&(vm.pc), uint64(nb))
+ s := vm.code.Fetch(&(vm.pc), 1)
+ op := Opcode(STOP)
+ if (s != nil) {
+ op = Opcode(s[0])
+ }
+
+ fmt.Printf("pc: %d | opcode: 0x%x -> string: %s\n", vm.pc, op, Instructions[op].name)
+ push := (&op).IsPush()
+ if (push != 0) {
+ b := vm.code.Fetch(&(vm.pc), uint64(push))
x := uint256.NewInt(0)
x = x.SetBytes(b)
vm.stack.Push(x)
} else {
- vm.Execute(op)
+ vm.Execute(byte(op))
}
+
+ if (op == RETURN) {
+ return vm.returndata
+ }
}
+ return nil
}
func (vm *Evm) Execute(op byte) {