evmas - An Assembler for the Ethereum Virtual Machine (EVM)
==

Evmas is a simple assembler for the EVM written in Common Lisp.

Numbers are automatically pushed onto the stack with the appropriately
sized push instruction.

Strings up to 32 characters are supported and autopushed onto the
stack using the correctly sized push instruction.

Labels are keywords and thus must be prefixed with a colon (:) and
prefixed by the assembler op .label.  Labels currently take up 4 bytes
in the bytecode stream; I hope to add an optimizer for this in the
future to reduce the byte count on code smaller than 64k, but this
value will be big enough even for the largest of contracts.  Should
this be too big or small, change +jump-label-size+ to a number of
bytes value.

.address is like .label but it saves the current ip in the label
without outputting any bytecode. Used for relocation calculations
during contract construction and not for jump targets.

Source files must be ended with the assembler op .end to signal end of
code.

After assembly the Gas cost of the bytecode and the bytecode are
printed. Labels and statistics are printed to Standard Error so the
bytecode can be redirected to a file easily.

Preprocessing	
--
	
Comments are started with semicolon (;).
	
Constant words may be defined using .define, ie:

	.define x 10
	.define s "string"

	x x add		;; x is replaced by 10 in the assembly

	s pop		;; s is replaced by the above string and popped

	;; Multiple instructions can be defined in a list
	.define sequence (10 10 add)

Files may be included with the .include "" directive and are
inserted inline into the bytecode stream.

Basic, non-recursively expanded macros with arguments (ie. you can't
yet use a macro within a macro) can be defined with the .macro
operator:

	.macro add3 (x y z) (x y add z add)

And used as such:

	add3 1 2 3 => 1 2 add 3 add

Where => means "expands to".
	

Usage
--

Evmas read source from standard input.  Set the environment variable
VERBOSE=1 to get debugging output that could be helpful for catching
typos.
	

```
bash-3.2$ ./evmas < test.evm

:BYTECODE-GAS-COST 
6268 
:BYTECODE 
630000001D565B6461626F7274005B80910180911163000000065790565B600A600A0150630000003056630000001D565B6F74686973206973206120737472696E67507774686973206973206120616E6F7468657220737472696E6750630000006C600A600A630000000E565B5000

bash-3.2$ cat test.evm
:main jump			;; jump to main code start

.include "examples/abort.evm"	;; required by safeAdd	
.include "examples/safeAdd.evm"	;; include library code

.define defined-number 10	
.define defined-string "this is a string"	

.label :main			;; main code start

	10 defined-number add	;; unsafe add instruction call	
	pop
	
	:after jump		;; jump past infinite loop

	:main jump  		;; loop back to main, but jumped over abov

.label :after			;; after infinite loop call
	
	defined-string pop	;; push defined string and pop it
	
	"this is a another string"	;; autopushed string less than 32 characters
	pop

	;; Call :safeAdd from library
	:afterSafeAdd 10 10 :safeAdd jump .label :afterSafeAdd
	
	pop			;; remove value from stack

	stop				;; stop execution

.end
```

Dissasembly/Verification
--

Assembly can be verified using the following, using evm from the go-ethereum package:

```
bash-3.2$ ./evmas < test.evm | ./evm-disassemble
630000001D565B6461626F7274005B80910180911163000000065790565B600A600A0150630000003056630000001D565B6F74686973206973206120737472696E67507774686973206973206120616E6F7468657220737472696E6750630000006C600A600A630000000E565B5000
00000: PUSH4 0x0000001d
00005: JUMP
00006: JUMPDEST
00007: PUSH5 0x61626f7274
0000d: STOP
0000e: JUMPDEST
0000f: DUP1
00010: SWAP2
00011: ADD
00012: DUP1
00013: SWAP2
00014: GT
00015: PUSH4 0x00000006
0001a: JUMPI
0001b: SWAP1
0001c: JUMP
0001d: JUMPDEST
0001e: PUSH1 0x0a
00020: PUSH1 0x0a
00022: ADD
00023: POP
00024: PUSH4 0x00000030
00029: JUMP
0002a: PUSH4 0x0000001d
0002f: JUMP
00030: JUMPDEST
00031: PUSH16 0x74686973206973206120737472696e67
00042: POP
00043: PUSH24 0x74686973206973206120616e6f7468657220737472696e67
0005c: POP
0005d: PUSH4 0x0000006c
00062: PUSH1 0x0a
00064: PUSH1 0x0a
00066: PUSH4 0x0000000e
0006b: JUMP
0006c: JUMPDEST
0006d: POP
0006e: STOP
```

Debugging
--

```
bash-3.2$ ./evmas < test.evm | ./evm-debug

Including "examples/abort.evm"

Succesfully included "examples/abort.evm"

Including "examples/safeAdd.evm"

Succesfully included "examples/safeAdd.evm"

:BYTECODE-GAS-COST 
6268 
:BYTECODE 
0x
#### TRACE ####
PUSH4           pc=00000000 gas=10000000000 cost=3

JUMP            pc=00000005 gas=9999999997 cost=8
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000001d

JUMPDEST        pc=00000029 gas=9999999989 cost=1

PUSH1           pc=00000030 gas=9999999988 cost=3

PUSH1           pc=00000032 gas=9999999985 cost=3
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000000a

ADD             pc=00000034 gas=9999999982 cost=3
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000000a
00000001  000000000000000000000000000000000000000000000000000000000000000a

POP             pc=00000035 gas=9999999979 cost=2
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000014

PUSH4           pc=00000036 gas=9999999977 cost=3

JUMP            pc=00000041 gas=9999999974 cost=8
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000030

JUMPDEST        pc=00000048 gas=9999999966 cost=1

PUSH16          pc=00000049 gas=9999999965 cost=3

POP             pc=00000066 gas=9999999962 cost=2
Stack:
00000000  0000000000000000000000000000000074686973206973206120737472696e67

PUSH24          pc=00000067 gas=9999999960 cost=3

POP             pc=00000092 gas=9999999957 cost=2
Stack:
00000000  000000000000000074686973206973206120616e6f7468657220737472696e67

PUSH4           pc=00000093 gas=9999999955 cost=3

PUSH1           pc=00000098 gas=9999999952 cost=3
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000006c

PUSH1           pc=00000100 gas=9999999949 cost=3
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000000a
00000001  000000000000000000000000000000000000000000000000000000000000006c

PUSH4           pc=00000102 gas=9999999946 cost=3
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000000a
00000001  000000000000000000000000000000000000000000000000000000000000000a
00000002  000000000000000000000000000000000000000000000000000000000000006c

JUMP            pc=00000107 gas=9999999943 cost=8
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000000e
00000001  000000000000000000000000000000000000000000000000000000000000000a
00000002  000000000000000000000000000000000000000000000000000000000000000a
00000003  000000000000000000000000000000000000000000000000000000000000006c

JUMPDEST        pc=00000014 gas=9999999935 cost=1
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000000a
00000001  000000000000000000000000000000000000000000000000000000000000000a
00000002  000000000000000000000000000000000000000000000000000000000000006c

DUP1            pc=00000015 gas=9999999934 cost=3
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000000a
00000001  000000000000000000000000000000000000000000000000000000000000000a
00000002  000000000000000000000000000000000000000000000000000000000000006c

SWAP2           pc=00000016 gas=9999999931 cost=3
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000000a
00000001  000000000000000000000000000000000000000000000000000000000000000a
00000002  000000000000000000000000000000000000000000000000000000000000000a
00000003  000000000000000000000000000000000000000000000000000000000000006c

ADD             pc=00000017 gas=9999999928 cost=3
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000000a
00000001  000000000000000000000000000000000000000000000000000000000000000a
00000002  000000000000000000000000000000000000000000000000000000000000000a
00000003  000000000000000000000000000000000000000000000000000000000000006c

DUP1            pc=00000018 gas=9999999925 cost=3
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000014
00000001  000000000000000000000000000000000000000000000000000000000000000a
00000002  000000000000000000000000000000000000000000000000000000000000006c

SWAP2           pc=00000019 gas=9999999922 cost=3
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000014
00000001  0000000000000000000000000000000000000000000000000000000000000014
00000002  000000000000000000000000000000000000000000000000000000000000000a
00000003  000000000000000000000000000000000000000000000000000000000000006c

GT              pc=00000020 gas=9999999919 cost=3
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000000a
00000001  0000000000000000000000000000000000000000000000000000000000000014
00000002  0000000000000000000000000000000000000000000000000000000000000014
00000003  000000000000000000000000000000000000000000000000000000000000006c

PUSH4           pc=00000021 gas=9999999916 cost=3
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000000
00000001  0000000000000000000000000000000000000000000000000000000000000014
00000002  000000000000000000000000000000000000000000000000000000000000006c

JUMPI           pc=00000026 gas=9999999913 cost=10
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000006
00000001  0000000000000000000000000000000000000000000000000000000000000000
00000002  0000000000000000000000000000000000000000000000000000000000000014
00000003  000000000000000000000000000000000000000000000000000000000000006c

SWAP1           pc=00000027 gas=9999999903 cost=3
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000014
00000001  000000000000000000000000000000000000000000000000000000000000006c

JUMP            pc=00000028 gas=9999999900 cost=8
Stack:
00000000  000000000000000000000000000000000000000000000000000000000000006c
00000001  0000000000000000000000000000000000000000000000000000000000000014

JUMPDEST        pc=00000108 gas=9999999892 cost=1
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000014

POP             pc=00000109 gas=9999999891 cost=2
Stack:
00000000  0000000000000000000000000000000000000000000000000000000000000014

STOP            pc=00000110 gas=9999999889 cost=0

#### LOGS ####
```

Supported Instructions
--

Some EVM instruction set references can be found here:

https://solidity.readthedocs.io/en/v0.4.25/assembly.html

https://ethervm.io
	
Building
--

Building evmas requires SBCL to be installed: https://sbcl.org.

On MacOS you can use brew: ```brew install sbcl```

Then use the following command to build evmas:	

```
$ sh build.sh
```

Evmas should also build with with other lisps (clisp, ecl, etc) using
a different build command to export an executable.


Some of the helper scripts requires node.js, so install it run:

```
$ brew install npm	
$ npm install
```

To get deploy.sh and the function selector generator to work.

Function Selector Generator
--

To be compatible wit the Ethereum ABI, I have included the a function
signature generator.  Use 'npm install' to install its dependencies.
See the ABI docs and examples for more details.

Security
--

Read time evaluation is disabled by default for safety and security.
Use the assembler ops .enable-read-eval! and .disable-read-eval! to
enable/disable sharp dot (#.(...)) evaluation.

TODO:

-- automatically define x-size when doing '.define x ...' as the
   number of bytes the definition takes
	
-- some sort of lispy macro'ish support of sort

--

References
==

[1] Local Source Repository for EVMAS.

Burton Samograd 2022