Copy respository files and add rebar.config

This commit is contained in:
Thomas Arts 2018-12-21 10:27:02 +01:00
parent 55e5657b62
commit 2269a01e18
11 changed files with 1229 additions and 0 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ ebin/*.beam
rel/example_project rel/example_project
.concrete/DEV_MODE .concrete/DEV_MODE
.rebar .rebar
aeb_asm_scan.erl

181
include/aeb_opcodes.hrl Normal file
View File

@ -0,0 +1,181 @@
%% AEVM opcodes
-define( 'STOP', 16#00).
-define( 'ADD', 16#01).
-define( 'MUL', 16#02).
-define( 'SUB', 16#03).
-define( 'DIV', 16#04).
-define( 'SDIV', 16#05).
-define( 'MOD', 16#06).
-define( 'SMOD', 16#07).
-define( 'ADDMOD', 16#08).
-define( 'MULMOD', 16#09).
-define( 'EXP', 16#0a).
-define( 'SIGNEXTEND', 16#0b).
-define( 'LT', 16#10).
-define( 'GT', 16#11).
-define( 'SLT', 16#12).
-define( 'SGT', 16#13).
-define( 'EQ', 16#14).
-define( 'ISZERO', 16#15).
-define( 'AND', 16#16).
-define( 'OR', 16#17).
-define( 'XOR', 16#18).
-define( 'NOT', 16#19).
-define( 'BYTE', 16#1a).
-define( 'SHA3', 16#20).
-define( 'ADDRESS', 16#30).
-define( 'BALANCE', 16#31).
-define( 'ORIGIN', 16#32).
-define( 'CALLER', 16#33).
-define( 'CALLVALUE', 16#34).
-define( 'CALLDATALOAD', 16#35).
-define( 'CALLDATASIZE', 16#36).
-define( 'CALLDATACOPY', 16#37).
-define( 'CODESIZE', 16#38).
-define( 'CODECOPY', 16#39).
-define( 'GASPRICE', 16#3a).
-define( 'EXTCODESIZE', 16#3b).
-define( 'EXTCODECOPY', 16#3c).
-define( 'RETURNDATASIZE', 16#3d).
-define( 'RETURNDATACOPY', 16#3e).
-define( 'BLOCKHASH', 16#40).
-define( 'COINBASE', 16#41).
-define( 'TIMESTAMP', 16#42).
-define( 'NUMBER', 16#43).
-define( 'DIFFICULTY', 16#44).
-define( 'GASLIMIT', 16#45).
-define( 'POP', 16#50).
-define( 'MLOAD', 16#51).
-define( 'MSTORE', 16#52).
-define( 'MSTORE8', 16#53).
-define( 'SLOAD', 16#54).
-define( 'SSTORE', 16#55).
-define( 'JUMP', 16#56).
-define( 'JUMPI', 16#57).
-define( 'PC', 16#58).
-define( 'MSIZE', 16#59).
-define( 'GAS', 16#5a).
-define( 'JUMPDEST', 16#5b).
-define( 'PUSH1', 16#60).
-define( 'PUSH2', 16#61).
-define( 'PUSH3', 16#62).
-define( 'PUSH4', 16#63).
-define( 'PUSH5', 16#64).
-define( 'PUSH6', 16#65).
-define( 'PUSH7', 16#66).
-define( 'PUSH8', 16#67).
-define( 'PUSH9', 16#68).
-define( 'PUSH10', 16#69).
-define( 'PUSH11', 16#6a).
-define( 'PUSH12', 16#6b).
-define( 'PUSH13', 16#6c).
-define( 'PUSH14', 16#6d).
-define( 'PUSH15', 16#6e).
-define( 'PUSH16', 16#6f).
-define( 'PUSH17', 16#70).
-define( 'PUSH18', 16#71).
-define( 'PUSH19', 16#72).
-define( 'PUSH20', 16#73).
-define( 'PUSH21', 16#74).
-define( 'PUSH22', 16#75).
-define( 'PUSH23', 16#76).
-define( 'PUSH24', 16#77).
-define( 'PUSH25', 16#78).
-define( 'PUSH26', 16#79).
-define( 'PUSH27', 16#7a).
-define( 'PUSH28', 16#7b).
-define( 'PUSH29', 16#7c).
-define( 'PUSH30', 16#7d).
-define( 'PUSH31', 16#7e).
-define( 'PUSH32', 16#7f).
-define( 'DUP1', 16#80).
-define( 'DUP2', 16#81).
-define( 'DUP3', 16#82).
-define( 'DUP4', 16#83).
-define( 'DUP5', 16#84).
-define( 'DUP6', 16#85).
-define( 'DUP7', 16#86).
-define( 'DUP8', 16#87).
-define( 'DUP9', 16#88).
-define( 'DUP10', 16#89).
-define( 'DUP11', 16#8a).
-define( 'DUP12', 16#8b).
-define( 'DUP13', 16#8c).
-define( 'DUP14', 16#8d).
-define( 'DUP15', 16#8e).
-define( 'DUP16', 16#8f).
-define( 'SWAP1', 16#90).
-define( 'SWAP2', 16#91).
-define( 'SWAP3', 16#92).
-define( 'SWAP4', 16#93).
-define( 'SWAP5', 16#94).
-define( 'SWAP6', 16#95).
-define( 'SWAP7', 16#96).
-define( 'SWAP8', 16#97).
-define( 'SWAP9', 16#98).
-define( 'SWAP10', 16#99).
-define( 'SWAP11', 16#9a).
-define( 'SWAP12', 16#9b).
-define( 'SWAP13', 16#9c).
-define( 'SWAP14', 16#9d).
-define( 'SWAP15', 16#9e).
-define( 'SWAP16', 16#9f).
-define( 'LOG0', 16#a0).
-define( 'LOG1', 16#a1).
-define( 'LOG2', 16#a2).
-define( 'LOG3', 16#a3).
-define( 'LOG4', 16#a4).
-define( 'CREATE', 16#f0).
-define( 'CALL', 16#f1).
-define( 'CALLCODE', 16#f2).
-define( 'RETURN', 16#f3).
-define( 'DELEGATECALL', 16#f4).
-define( 'STATICCALL', 16#fa).
-define( 'REVERT', 16#fd).
-define( 'INVALID', 16#fe).
-define( 'SUICIDE', 16#ff).
-define( COMMENT(X), {comment, X}).
%% Transactions are implemented as contract calls to address zero, with the
%% first argument encoding the transaction type according to the below.
-define(PRIM_CALLS_CONTRACT, 0).
-define(PRIM_CALL_SPEND, 1).
-define(PRIM_CALL_IN_ORACLE_RANGE(__TTYPE__), (((__TTYPE__) > 99) andalso ((__TTYPE__) < 200))).
-define(PRIM_CALL_ORACLE_REGISTER, 100).
-define(PRIM_CALL_ORACLE_QUERY, 101).
-define(PRIM_CALL_ORACLE_RESPOND, 102).
-define(PRIM_CALL_ORACLE_EXTEND, 103).
-define(PRIM_CALL_ORACLE_GET_ANSWER, 104).
-define(PRIM_CALL_ORACLE_GET_QUESTION, 105).
-define(PRIM_CALL_ORACLE_QUERY_FEE, 106).
-define(PRIM_CALL_IN_AENS_RANGE(__TTYPE__), (((__TTYPE__) > 199) andalso ((__TTYPE__) < 300))).
-define(PRIM_CALL_AENS_RESOLVE, 200).
-define(PRIM_CALL_AENS_PRECLAIM, 201).
-define(PRIM_CALL_AENS_CLAIM, 202).
-define(PRIM_CALL_AENS_UPDATE, 203).
-define(PRIM_CALL_AENS_TRANSFER, 204).
-define(PRIM_CALL_AENS_REVOKE, 205).
-define(PRIM_CALL_IN_MAP_RANGE(__TTYPE__), (((__TTYPE__) > 299) andalso ((__TTYPE__) < 400))).
-define(PRIM_CALL_MAP_EMPTY, 300).
-define(PRIM_CALL_MAP_GET, 301).
-define(PRIM_CALL_MAP_PUT, 302).
-define(PRIM_CALL_MAP_DELETE, 303).
-define(PRIM_CALL_MAP_SIZE, 304).
-define(PRIM_CALL_MAP_TOLIST, 305).

1
rebar.lock Normal file
View File

@ -0,0 +1 @@
[].

147
src/aeb_asm.erl Normal file
View File

@ -0,0 +1,147 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc Assembler for aevm machine code.
%%%
%%% Assembler code can be read from a file.
%%% The assembler has the following format
%%% Comments start with 2 semicolons and runs till end of line
%%% ;; This is a comment
%%% Opcode mnemonics start with an upper case letter.
%%% DUP1
%%% Identifiers start with a lower case letter
%%% an_identifier
%%% All identifiers has to be decleard with a label.
%%% A label is an identifier that ends with a colon.
%%% The label is the byte code address of the next instruction.
%%% a_label:
%%% Immediates can be of four types:
%%% 1. integers
%%% 42
%%% 2. hexadecimal integers starting with 0x
%%% 0x0deadbeef0
%%% 3. 256-bit hash strings starting with #
%%% followed by up to 64 hex chars
%%% #00000deadbeef
%%% 4. labels as descibed above.
%%%
%%% @end
%%% Created : 21 Dec 2017
%%%-------------------------------------------------------------------
-module(aeb_asm).
-export([ file/2
, pp/1
, to_hexstring/1
]).
-include_lib("aebytecode/include/aeb_opcodes.hrl").
pp(Asm) ->
Listing = format(Asm),
io:format("~s~n", [Listing]).
format(Asm) -> format(Asm, 0).
format([{comment, Comment} | Rest], Address) ->
";; " ++ Comment ++ "\n" ++ format(Rest, Address);
format([Mnemonic | Rest], Address) ->
Op = aeb_opcodes:m_to_op(Mnemonic),
case (Op >= ?PUSH1) andalso (Op =< ?PUSH32) of
true ->
Arity = aeb_opcodes:op_size(Op) - 1,
{Args, Code} = get_args(Arity, Rest),
" " ++ atom_to_list(Mnemonic)
++ " " ++ Args ++ "\n"
++ format(Code, Address + Arity + 1);
false ->
" " ++ atom_to_list(Mnemonic) ++ "\n"
++ format(Rest, Address + 1)
end;
format([],_) -> [].
%% TODO: Are args encoded as one list element or as a number of bytes...
get_args(1, [Arg|Code]) ->
{integer_to_list(Arg), Code};
get_args(N, [Arg|Code]) ->
{Args, Rest} = get_args(N-1, Code),
{integer_to_list(Arg) ++ ", " ++ Args, Rest}.
file(Filename, Options) ->
{ok, File} = file:read_file(Filename),
{ok, Tokens, _} = aeb_asm_scan:scan(binary_to_list(File)),
case proplists:lookup(pp_tokens, Options) of
{pp_tokens, true} ->
io:format("Tokens ~p~n",[Tokens]);
none ->
ok
end,
ByteList = to_bytecode(Tokens, 0, #{}, [], Options),
case proplists:lookup(pp_hex_string, Options) of
{pp_hex_string, true} ->
io:format("Code: ~s~n",[to_hexstring(ByteList)]);
none ->
ok
end,
list_to_binary(ByteList).
to_hexstring(ByteList) ->
"0x" ++ lists:flatten(
[io_lib:format("~2.16.0b", [X])
|| X <- ByteList]).
to_bytecode([{mnemonic,_line, Op}|Rest], Address, Env, Code, Opts) ->
OpCode = aeb_opcodes:m_to_op(Op),
OpSize = aeb_opcodes:op_size(OpCode),
to_bytecode(Rest, Address + OpSize, Env, [OpCode|Code], Opts);
to_bytecode([{int,_line, Int}|Rest], Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env, [Int|Code], Opts);
to_bytecode([{hash,_line, Hash}|Rest], Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env, [Hash|Code], Opts);
to_bytecode([{id,_line, ID}|Rest], Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env, [{ref, ID}|Code], Opts);
to_bytecode([{label,_line, Label}|Rest], Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env#{Label => Address}, Code, Opts);
to_bytecode([], _Address, Env, Code, Opts) ->
case proplists:lookup(pp_opcodes, Opts) of
{pp_opcodes, true} ->
io:format("opcodes ~p~n", [lists:reverse(Code)]);
none ->
ok
end,
PatchedCode = resolve_refs(Code, Env, []),
case proplists:lookup(pp_patched_code, Opts) of
{pp_patched_code, true} ->
io:format("Patched Code: ~p~n", [PatchedCode]);
none ->
ok
end,
expand_args(PatchedCode).
%% Also reverses the code (back to unreversed state).
resolve_refs([{ref, ID} | Rest], Env, Code) ->
Address = maps:get(ID, Env),
resolve_refs(Rest, Env, [Address | Code]);
resolve_refs([Op | Rest], Env, Code) ->
resolve_refs(Rest, Env, [Op | Code]);
resolve_refs([],_Env, Code) -> Code.
expand_args([OP, Arg | Rest]) when OP >= ?PUSH1 andalso OP =< ?PUSH32 ->
BitSize = (aeb_opcodes:op_size(OP) - 1) * 8,
Bin = << << X:BitSize>> || X <- [Arg] >>,
ArgByteList = binary_to_list(Bin),
[OP | ArgByteList] ++ expand_args(Rest);
expand_args([OP | Rest]) ->
[OP | expand_args(Rest)];
expand_args([]) -> [].

211
src/aeb_asm_scan.xrl Normal file
View File

@ -0,0 +1,211 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%-------------------------------------------------------------------
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc Assembler lexer.
%%%
%%% @end
%%%-------------------------------------------------------------------
Definitions.
DIGIT = [0-9]
HEXDIGIT = [0-9a-fA-F]
LOWER = [a-z_]
UPPER = [A-Z]
INT = {DIGIT}+
HEX = 0x{HEXDIGIT}+
HASH = #{HEXDIGIT}+
WS = [\000-\s]
ID = {LOWER}[a-zA-Z0-9_]*
LABEL = {ID}:
Rules.
{LABEL} : {token, {label, TokenLine, TokenChars -- ":"}}.
STOP : {token, {mnemonic, TokenLine, 'STOP'}}.
ADD : {token, {mnemonic, TokenLine, 'ADD'}}.
MUL : {token, {mnemonic, TokenLine, 'MUL'}}.
SUB : {token, {mnemonic, TokenLine, 'SUB'}}.
DIV : {token, {mnemonic, TokenLine, 'DIV'}}.
SDIV : {token, {mnemonic, TokenLine, 'SDIV'}}.
MOD : {token, {mnemonic, TokenLine, 'MOD'}}.
SMOD : {token, {mnemonic, TokenLine, 'SMOD'}}.
ADDMOD : {token, {mnemonic, TokenLine, 'ADDMOD'}}.
MULMOD : {token, {mnemonic, TokenLine, 'MULMOD'}}.
EXP : {token, {mnemonic, TokenLine, 'EXP'}}.
SIGNEXTEND : {token, {mnemonic, TokenLine, 'SIGNEXTEND'}}.
LT : {token, {mnemonic, TokenLine, 'LT'}}.
GT : {token, {mnemonic, TokenLine, 'GT'}}.
SLT : {token, {mnemonic, TokenLine, 'SLT'}}.
SGT : {token, {mnemonic, TokenLine, 'SGT'}}.
EQ : {token, {mnemonic, TokenLine, 'EQ'}}.
ISZERO : {token, {mnemonic, TokenLine, 'ISZERO'}}.
AND : {token, {mnemonic, TokenLine, 'AND'}}.
OR : {token, {mnemonic, TokenLine, 'OR'}}.
XOR : {token, {mnemonic, TokenLine, 'XOR'}}.
NOT : {token, {mnemonic, TokenLine, 'NOT'}}.
BYTE : {token, {mnemonic, TokenLine, 'BYTE'}}.
SHA3 : {token, {mnemonic, TokenLine, 'SHA3'}}.
ADDRESS : {token, {mnemonic, TokenLine, 'ADDRESS'}}.
BALANCE : {token, {mnemonic, TokenLine, 'BALANCE'}}.
ORIGIN : {token, {mnemonic, TokenLine, 'ORIGIN'}}.
CALLER : {token, {mnemonic, TokenLine, 'CALLER'}}.
CALLVALUE : {token, {mnemonic, TokenLine, 'CALLVALUE'}}.
CALLDATALOAD : {token, {mnemonic, TokenLine, 'CALLDATALOAD'}}.
CALLDATASIZE : {token, {mnemonic, TokenLine, 'CALLDATASIZE'}}.
CALLDATACOPY : {token, {mnemonic, TokenLine, 'CALLDATACOPY'}}.
CODESIZE : {token, {mnemonic, TokenLine, 'CODESIZE'}}.
CODECOPY : {token, {mnemonic, TokenLine, 'CODECOPY'}}.
GASPRICE : {token, {mnemonic, TokenLine, 'GASPRICE'}}.
EXTCODESIZE : {token, {mnemonic, TokenLine, 'EXTCODESIZE'}}.
EXTCODECOPY : {token, {mnemonic, TokenLine, 'EXTCODECOPY'}}.
RETURNDATASIZE : {token, {mnemonic, TokenLine, 'RETURNDATASIZE'}}.
RETURNDATACOPY : {token, {mnemonic, TokenLine, 'RETURNDATACOPY'}}.
BLOCKHASH : {token, {mnemonic, TokenLine, 'BLOCKHASH'}}.
COINBASE : {token, {mnemonic, TokenLine, 'COINBASE'}}.
TIMESTAMP : {token, {mnemonic, TokenLine, 'TIMESTAMP'}}.
NUMBER : {token, {mnemonic, TokenLine, 'NUMBER'}}.
DIFFICULTY : {token, {mnemonic, TokenLine, 'DIFFICULTY'}}.
GASLIMIT : {token, {mnemonic, TokenLine, 'GASLIMIT'}}.
POP : {token, {mnemonic, TokenLine, 'POP'}}.
MLOAD : {token, {mnemonic, TokenLine, 'MLOAD'}}.
MSTORE : {token, {mnemonic, TokenLine, 'MSTORE'}}.
MSTORE8 : {token, {mnemonic, TokenLine, 'MSTORE8'}}.
SLOAD : {token, {mnemonic, TokenLine, 'SLOAD'}}.
SSTORE : {token, {mnemonic, TokenLine, 'SSTORE'}}.
JUMP : {token, {mnemonic, TokenLine, 'JUMP'}}.
JUMPI : {token, {mnemonic, TokenLine, 'JUMPI'}}.
PC : {token, {mnemonic, TokenLine, 'PC'}}.
MSIZE : {token, {mnemonic, TokenLine, 'MSIZE'}}.
GAS : {token, {mnemonic, TokenLine, 'GAS'}}.
JUMPDEST : {token, {mnemonic, TokenLine, 'JUMPDEST'}}.
PUSH1 : {token, {mnemonic, TokenLine, 'PUSH1'}}.
PUSH2 : {token, {mnemonic, TokenLine, 'PUSH2'}}.
PUSH3 : {token, {mnemonic, TokenLine, 'PUSH3'}}.
PUSH4 : {token, {mnemonic, TokenLine, 'PUSH4'}}.
PUSH5 : {token, {mnemonic, TokenLine, 'PUSH5'}}.
PUSH6 : {token, {mnemonic, TokenLine, 'PUSH6'}}.
PUSH7 : {token, {mnemonic, TokenLine, 'PUSH7'}}.
PUSH8 : {token, {mnemonic, TokenLine, 'PUSH8'}}.
PUSH9 : {token, {mnemonic, TokenLine, 'PUSH9'}}.
PUSH10 : {token, {mnemonic, TokenLine, 'PUSH10'}}.
PUSH11 : {token, {mnemonic, TokenLine, 'PUSH11'}}.
PUSH12 : {token, {mnemonic, TokenLine, 'PUSH12'}}.
PUSH13 : {token, {mnemonic, TokenLine, 'PUSH13'}}.
PUSH14 : {token, {mnemonic, TokenLine, 'PUSH14'}}.
PUSH15 : {token, {mnemonic, TokenLine, 'PUSH15'}}.
PUSH16 : {token, {mnemonic, TokenLine, 'PUSH16'}}.
PUSH17 : {token, {mnemonic, TokenLine, 'PUSH17'}}.
PUSH18 : {token, {mnemonic, TokenLine, 'PUSH18'}}.
PUSH19 : {token, {mnemonic, TokenLine, 'PUSH19'}}.
PUSH20 : {token, {mnemonic, TokenLine, 'PUSH20'}}.
PUSH21 : {token, {mnemonic, TokenLine, 'PUSH21'}}.
PUSH22 : {token, {mnemonic, TokenLine, 'PUSH22'}}.
PUSH23 : {token, {mnemonic, TokenLine, 'PUSH23'}}.
PUSH24 : {token, {mnemonic, TokenLine, 'PUSH24'}}.
PUSH25 : {token, {mnemonic, TokenLine, 'PUSH25'}}.
PUSH26 : {token, {mnemonic, TokenLine, 'PUSH26'}}.
PUSH27 : {token, {mnemonic, TokenLine, 'PUSH27'}}.
PUSH28 : {token, {mnemonic, TokenLine, 'PUSH28'}}.
PUSH29 : {token, {mnemonic, TokenLine, 'PUSH29'}}.
PUSH30 : {token, {mnemonic, TokenLine, 'PUSH30'}}.
PUSH31 : {token, {mnemonic, TokenLine, 'PUSH31'}}.
PUSH32 : {token, {mnemonic, TokenLine, 'PUSH32'}}.
DUP1 : {token, {mnemonic, TokenLine, 'DUP1'}}.
DUP2 : {token, {mnemonic, TokenLine, 'DUP2'}}.
DUP3 : {token, {mnemonic, TokenLine, 'DUP3'}}.
DUP4 : {token, {mnemonic, TokenLine, 'DUP4'}}.
DUP5 : {token, {mnemonic, TokenLine, 'DUP5'}}.
DUP6 : {token, {mnemonic, TokenLine, 'DUP6'}}.
DUP7 : {token, {mnemonic, TokenLine, 'DUP7'}}.
DUP8 : {token, {mnemonic, TokenLine, 'DUP8'}}.
DUP9 : {token, {mnemonic, TokenLine, 'DUP9'}}.
DUP10 : {token, {mnemonic, TokenLine, 'DUP10'}}.
DUP11 : {token, {mnemonic, TokenLine, 'DUP11'}}.
DUP12 : {token, {mnemonic, TokenLine, 'DUP12'}}.
DUP13 : {token, {mnemonic, TokenLine, 'DUP13'}}.
DUP14 : {token, {mnemonic, TokenLine, 'DUP14'}}.
DUP15 : {token, {mnemonic, TokenLine, 'DUP15'}}.
DUP16 : {token, {mnemonic, TokenLine, 'DUP16'}}.
SWAP1 : {token, {mnemonic, TokenLine, 'SWAP1'}}.
SWAP2 : {token, {mnemonic, TokenLine, 'SWAP2'}}.
SWAP3 : {token, {mnemonic, TokenLine, 'SWAP3'}}.
SWAP4 : {token, {mnemonic, TokenLine, 'SWAP4'}}.
SWAP5 : {token, {mnemonic, TokenLine, 'SWAP5'}}.
SWAP6 : {token, {mnemonic, TokenLine, 'SWAP6'}}.
SWAP7 : {token, {mnemonic, TokenLine, 'SWAP7'}}.
SWAP8 : {token, {mnemonic, TokenLine, 'SWAP8'}}.
SWAP9 : {token, {mnemonic, TokenLine, 'SWAP9'}}.
SWAP10 : {token, {mnemonic, TokenLine, 'SWAP10'}}.
SWAP11 : {token, {mnemonic, TokenLine, 'SWAP11'}}.
SWAP12 : {token, {mnemonic, TokenLine, 'SWAP12'}}.
SWAP13 : {token, {mnemonic, TokenLine, 'SWAP13'}}.
SWAP14 : {token, {mnemonic, TokenLine, 'SWAP14'}}.
SWAP15 : {token, {mnemonic, TokenLine, 'SWAP15'}}.
SWAP16 : {token, {mnemonic, TokenLine, 'SWAP16'}}.
LOG0 : {token, {mnemonic, TokenLine, 'LOG0'}}.
LOG1 : {token, {mnemonic, TokenLine, 'LOG1'}}.
LOG2 : {token, {mnemonic, TokenLine, 'LOG2'}}.
LOG3 : {token, {mnemonic, TokenLine, 'LOG3'}}.
LOG4 : {token, {mnemonic, TokenLine, 'LOG4'}}.
CREATE : {token, {mnemonic, TokenLine, 'CREATE'}}.
CALL : {token, {mnemonic, TokenLine, 'CALL'}}.
CALLCODE : {token, {mnemonic, TokenLine, 'CALLCODE'}}.
RETURN : {token, {mnemonic, TokenLine, 'RETURN'}}.
DELEGATECALL : {token, {mnemonic, TokenLine, 'DELEGATECALL'}}.
STATICCALL : {token, {mnemonic, TokenLine, 'STATICCALL'}}.
REVERT : {token, {mnemonic, TokenLine, 'REVERT'}}.
INVALID : {token, {mnemonic, TokenLine, 'INVALID'}}.
SUICIDE : {token, {mnemonic, TokenLine, 'SUICIDE'}}.
COMMENT : {token, {mnemonic, TokenLine, 'COMMENT'}}.
{ID} :
{token, {id, TokenLine, TokenChars}}.
{HEX} :
{token, {int, TokenLine, parse_hex(TokenChars)}}.
{INT} :
{token, {int, TokenLine, parse_int(TokenChars)}}.
{HASH} :
{token, {hash, TokenLine, parse_hash(TokenChars)}}.
%% Symbols
, : {token, {',', TokenLine}}.
\. : {token, {'.', TokenLine}}.
\( : {token, {'(', TokenLine}}.
\) : {token, {')', TokenLine}}.
\[ : {token, {'[', TokenLine}}.
\] : {token, {']', TokenLine}}.
{ : {token, {'{', TokenLine}}.
} : {token, {'}', TokenLine}}.
%% Whitespace ignore
{WS} : skip_token.
%% Comments (TODO: nested comments)
;;.* : skip_token.
. : {error, "Unexpected token: " ++ TokenChars}.
Erlang code.
-export([scan/1]).
-dialyzer({nowarn_function, yyrev/2}).
-ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]).
-include_lib("aebytecode/include/aeb_opcodes.hrl").
parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16).
parse_int(Chars) -> list_to_integer(Chars).
parse_hash("#" ++ Chars) ->
N = list_to_integer(Chars, 16),
<<N:256>>.
scan(S) ->
string(S).

102
src/aeb_disassemble.erl Normal file
View File

@ -0,0 +1,102 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc
%%% Prettyprint aevm machine code
%%% @end
%%% Created : 2 Oct 2017
%%%-------------------------------------------------------------------
-module(aeb_disassemble).
-export([ pp/1,
format/2,
format_address/1
]).
-include_lib("aebytecode/include/aeb_opcodes.hrl").
pp(Binary) ->
Listing = format(Binary, fun io:format/2),
io:format("~s~n", [Listing]).
format(Binary, ErrFormatFun) ->
pp(0, binary:bin_to_list(Binary), [], ErrFormatFun).
pp(Address, [Op|Ops], Assembly, ErrFormatFun) ->
case Op of
X when (X >= ?STOP) andalso (X =< ?SIGNEXTEND) ->
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?LT) andalso (X =< ?BYTE) ->
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?SHA3) andalso (X =< ?SHA3) ->
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?ADDRESS) andalso (X =< ?EXTCODECOPY) ->
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?BLOCKHASH) andalso (X =< ?GASLIMIT) ->
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?POP) andalso (X =< ?JUMPDEST) ->
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?PUSH1) andalso (X =< ?PUSH32) ->
Bytes = X-?PUSH1+1,
{ArgList, NextOps} = lists:split(Bytes, Ops),
Arg = arglist_to_arg(ArgList),
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), [{Arg,8*Bytes}]),
next(Address+Bytes, NextOps, Instr, Assembly, ErrFormatFun);
X when (X >= ?DUP1) andalso (X =< ?LOG4) ->
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?CREATE) andalso (X =< ?DELEGATECALL) ->
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
X when (X >= ?INVALID) andalso (X =< ?SUICIDE) ->
Instr = pp_instruction(Address, aeb_opcodes:mnemonic(Op), []),
next(Address, Ops, Instr, Assembly, ErrFormatFun);
_ ->
ErrFormatFun("unhandled op ~p at ~p",[Op, Address]),
next(Address, Ops, "", Assembly, ErrFormatFun)
end;
pp(_, [], Assembly, _) -> lists:reverse(Assembly).
arglist_to_arg([B|Bs]) ->
arglist_to_arg(Bs, B).
arglist_to_arg([B|Bs], Acc) ->
arglist_to_arg(Bs, Acc*256 + B);
arglist_to_arg([], Acc) -> Acc.
pp_instruction(Address, Op, Args) ->
[format_address(Address), " ",
pad_op(atom_to_list(Op)),
pp_args(Args),
"\n"].
format_address(Address) ->
io_lib:format("0x~8.16.0B",[Address]).
pad_op(Op) ->
N = length(Op),
Pad = 17 - N,
[Op,lists:duplicate(Pad, 32)].
pp_args([]) -> [];
pp_args([{Arg, Size}]) ->
case Size of
8 -> io_lib:format("0x~2.16.0B",[Arg]);
160 -> io_lib:format("0x~64.16.0B",[Arg]);
232 -> io_lib:format("0x~64.16.0B",[Arg]);
256 -> io_lib:format("0x~64.16.0B",[Arg]);
_ -> io_lib:format("0x~64.16.0B",[Arg])
end;
pp_args([{Arg, Size}|Args]) ->
[pp_args([{Arg, Size}]), " ", pp_args(Args)].
next(Address, Ops, Instr, Assembly, ErrFormatFun) ->
pp(Address+1, Ops, [Instr|Assembly], ErrFormatFun).

448
src/aeb_opcodes.erl Normal file
View File

@ -0,0 +1,448 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc
%%% Opcodes
%%% @end
%%% Created : 2 Oct 2017
%%%-------------------------------------------------------------------
-module(aeb_opcodes).
-export([ dup/1
, mnemonic/1
, m_to_op/1
, opcode/1
, op_size/1
, push/1
, swap/1
]).
-include_lib("aebytecode/include/aeb_opcodes.hrl").
%%====================================================================
%% API
%%====================================================================
opcode(?STOP) -> ?STOP;
opcode(?ADD) -> ?ADD;
opcode(?MUL) -> ?MUL;
opcode(?SUB) -> ?SUB;
opcode(?DIV) -> ?DIV;
opcode(?SDIV) -> ?SDIV;
opcode(?MOD) -> ?MOD;
opcode(?SMOD) -> ?SMOD;
opcode(?ADDMOD) -> ?ADDMOD;
opcode(?MULMOD) -> ?MULMOD;
opcode(?EXP) -> ?EXP;
opcode(?SIGNEXTEND) -> ?SIGNEXTEND;
opcode(?LT) -> ?LT;
opcode(?GT) -> ?GT;
opcode(?SLT) -> ?SLT;
opcode(?SGT) -> ?SGT;
opcode(?EQ) -> ?EQ;
opcode(?ISZERO) -> ?ISZERO;
opcode(?AND) -> ?AND;
opcode(?OR) -> ?OR;
opcode(?XOR) -> ?XOR;
opcode(?NOT) -> ?NOT;
opcode(?BYTE) -> ?BYTE;
opcode(?SHA3) -> ?SHA3;
opcode(?ADDRESS) -> ?ADDRESS;
opcode(?BALANCE) -> ?BALANCE;
opcode(?ORIGIN) -> ?ORIGIN;
opcode(?CALLER) -> ?CALLER;
opcode(?CALLVALUE) -> ?CALLVALUE;
opcode(?CALLDATALOAD) -> ?CALLDATALOAD;
opcode(?CALLDATASIZE) -> ?CALLDATASIZE;
opcode(?CALLDATACOPY) -> ?CALLDATACOPY;
opcode(?CODESIZE) -> ?CODESIZE;
opcode(?CODECOPY) -> ?CODECOPY;
opcode(?GASPRICE) -> ?GASPRICE;
opcode(?EXTCODESIZE) -> ?EXTCODESIZE;
opcode(?EXTCODECOPY) -> ?EXTCODECOPY;
opcode(?RETURNDATASIZE) -> ?RETURNDATASIZE; %% TODO
opcode(?RETURNDATACOPY) -> ?RETURNDATACOPY; %% TODO
opcode(?BLOCKHASH) -> ?BLOCKHASH;
opcode(?COINBASE) -> ?COINBASE;
opcode(?TIMESTAMP) -> ?TIMESTAMP;
opcode(?NUMBER) -> ?NUMBER;
opcode(?DIFFICULTY) -> ?DIFFICULTY;
opcode(?GASLIMIT) -> ?GASLIMIT;
opcode(?POP) -> ?POP;
opcode(?MLOAD) -> ?MLOAD;
opcode(?MSTORE) -> ?MSTORE;
opcode(?MSTORE8) -> ?MSTORE8;
opcode(?SLOAD) -> ?SLOAD;
opcode(?SSTORE) -> ?SSTORE;
opcode(?JUMP) -> ?JUMP;
opcode(?JUMPI) -> ?JUMPI;
opcode(?PC) -> ?PC;
opcode(?MSIZE) -> ?MSIZE;
opcode(?GAS) -> ?GAS;
opcode(?JUMPDEST) -> ?JUMPDEST;
opcode(?PUSH1) -> ?PUSH1;
opcode(?PUSH2) -> ?PUSH2;
opcode(?PUSH3) -> ?PUSH3;
opcode(?PUSH4) -> ?PUSH4;
opcode(?PUSH5) -> ?PUSH5;
opcode(?PUSH6) -> ?PUSH6;
opcode(?PUSH7) -> ?PUSH7;
opcode(?PUSH8) -> ?PUSH8;
opcode(?PUSH9) -> ?PUSH9;
opcode(?PUSH10) -> ?PUSH10;
opcode(?PUSH11) -> ?PUSH11;
opcode(?PUSH12) -> ?PUSH12;
opcode(?PUSH13) -> ?PUSH13;
opcode(?PUSH14) -> ?PUSH14;
opcode(?PUSH15) -> ?PUSH15;
opcode(?PUSH16) -> ?PUSH16;
opcode(?PUSH17) -> ?PUSH17;
opcode(?PUSH18) -> ?PUSH18;
opcode(?PUSH19) -> ?PUSH19;
opcode(?PUSH20) -> ?PUSH20;
opcode(?PUSH21) -> ?PUSH21;
opcode(?PUSH22) -> ?PUSH22;
opcode(?PUSH23) -> ?PUSH23;
opcode(?PUSH24) -> ?PUSH24;
opcode(?PUSH25) -> ?PUSH25;
opcode(?PUSH26) -> ?PUSH26;
opcode(?PUSH27) -> ?PUSH27;
opcode(?PUSH28) -> ?PUSH28;
opcode(?PUSH29) -> ?PUSH29;
opcode(?PUSH30) -> ?PUSH30;
opcode(?PUSH31) -> ?PUSH31;
opcode(?PUSH32) -> ?PUSH32;
opcode(?DUP1) -> ?DUP1;
opcode(?DUP2) -> ?DUP2;
opcode(?DUP3) -> ?DUP3;
opcode(?DUP4) -> ?DUP4;
opcode(?DUP5) -> ?DUP5;
opcode(?DUP6) -> ?DUP6;
opcode(?DUP7) -> ?DUP7;
opcode(?DUP8) -> ?DUP8;
opcode(?DUP9) -> ?DUP9;
opcode(?DUP10) -> ?DUP10;
opcode(?DUP11) -> ?DUP11;
opcode(?DUP12) -> ?DUP12;
opcode(?DUP13) -> ?DUP13;
opcode(?DUP14) -> ?DUP14;
opcode(?DUP15) -> ?DUP15;
opcode(?DUP16) -> ?DUP16;
opcode(?SWAP1) -> ?SWAP1;
opcode(?SWAP2) -> ?SWAP2;
opcode(?SWAP3) -> ?SWAP3;
opcode(?SWAP4) -> ?SWAP4;
opcode(?SWAP5) -> ?SWAP5;
opcode(?SWAP6) -> ?SWAP6;
opcode(?SWAP7) -> ?SWAP7;
opcode(?SWAP8) -> ?SWAP8;
opcode(?SWAP9) -> ?SWAP9;
opcode(?SWAP10) -> ?SWAP10;
opcode(?SWAP11) -> ?SWAP11;
opcode(?SWAP12) -> ?SWAP12;
opcode(?SWAP13) -> ?SWAP13;
opcode(?SWAP14) -> ?SWAP14;
opcode(?SWAP15) -> ?SWAP15;
opcode(?SWAP16) -> ?SWAP16;
opcode(?LOG0) -> ?LOG0;
opcode(?LOG1) -> ?LOG1;
opcode(?LOG2) -> ?LOG2;
opcode(?LOG3) -> ?LOG3;
opcode(?LOG4) -> ?LOG4;
opcode(?CREATE) -> ?CREATE;
opcode(?CALL) -> ?CALL;
opcode(?CALLCODE) -> ?CALLCODE;
opcode(?RETURN) -> ?RETURN;
opcode(?DELEGATECALL) -> ?DELEGATECALL;
opcode(?STATICCALL) -> ?STATICCALL; %% TODO
opcode(?REVERT) -> ?REVERT;
opcode({comment,X}) -> ?COMMENT(X);
opcode(?SUICIDE) -> ?SUICIDE.
mnemonic(?STOP) -> 'STOP' ;
mnemonic(?ADD) -> 'ADD' ;
mnemonic(?MUL) -> 'MUL' ;
mnemonic(?SUB) -> 'SUB' ;
mnemonic(?DIV) -> 'DIV' ;
mnemonic(?SDIV) -> 'SDIV' ;
mnemonic(?MOD) -> 'MOD' ;
mnemonic(?SMOD) -> 'SMOD' ;
mnemonic(?ADDMOD) -> 'ADDMOD' ;
mnemonic(?MULMOD) -> 'MULMOD' ;
mnemonic(?EXP) -> 'EXP' ;
mnemonic(?SIGNEXTEND) -> 'SIGNEXTEND' ;
mnemonic(?LT) -> 'LT' ;
mnemonic(?GT) -> 'GT' ;
mnemonic(?SLT) -> 'SLT' ;
mnemonic(?SGT) -> 'SGT' ;
mnemonic(?EQ) -> 'EQ' ;
mnemonic(?ISZERO) -> 'ISZERO' ;
mnemonic(?AND) -> 'AND' ;
mnemonic(?OR) -> 'OR' ;
mnemonic(?XOR) -> 'XOR' ;
mnemonic(?NOT) -> 'NOT' ;
mnemonic(?BYTE) -> 'BYTE' ;
mnemonic(?SHA3) -> 'SHA3' ;
mnemonic(?ADDRESS) -> 'ADDRESS' ;
mnemonic(?BALANCE) -> 'BALANCE' ;
mnemonic(?ORIGIN) -> 'ORIGIN' ;
mnemonic(?CALLER) -> 'CALLER' ;
mnemonic(?CALLVALUE) -> 'CALLVALUE' ;
mnemonic(?CALLDATALOAD) -> 'CALLDATALOAD' ;
mnemonic(?CALLDATASIZE) -> 'CALLDATASIZE' ;
mnemonic(?CALLDATACOPY) -> 'CALLDATACOPY' ;
mnemonic(?CODESIZE) -> 'CODESIZE' ;
mnemonic(?CODECOPY) -> 'CODECOPY' ;
mnemonic(?GASPRICE) -> 'GASPRICE' ;
mnemonic(?EXTCODESIZE) -> 'EXTCODESIZE' ;
mnemonic(?EXTCODECOPY) -> 'EXTCODECOPY' ;
mnemonic(?RETURNDATASIZE) -> 'RETURNDATASIZE' ;
mnemonic(?RETURNDATACOPY) -> 'RETURNDATACOPY' ;
mnemonic(?BLOCKHASH) -> 'BLOCKHASH' ;
mnemonic(?COINBASE) -> 'COINBASE' ;
mnemonic(?TIMESTAMP) -> 'TIMESTAMP' ;
mnemonic(?NUMBER) -> 'NUMBER' ;
mnemonic(?DIFFICULTY) -> 'DIFFICULTY' ;
mnemonic(?GASLIMIT) -> 'GASLIMIT' ;
mnemonic(?POP) -> 'POP' ;
mnemonic(?MLOAD) -> 'MLOAD' ;
mnemonic(?MSTORE) -> 'MSTORE' ;
mnemonic(?MSTORE8) -> 'MSTORE8' ;
mnemonic(?SLOAD) -> 'SLOAD' ;
mnemonic(?SSTORE) -> 'SSTORE' ;
mnemonic(?JUMP) -> 'JUMP' ;
mnemonic(?JUMPI) -> 'JUMPI' ;
mnemonic(?PC) -> 'PC' ;
mnemonic(?MSIZE) -> 'MSIZE' ;
mnemonic(?GAS) -> 'GAS' ;
mnemonic(?JUMPDEST) -> 'JUMPDEST' ;
mnemonic(?PUSH1) -> 'PUSH1' ;
mnemonic(?PUSH2) -> 'PUSH2' ;
mnemonic(?PUSH3) -> 'PUSH3' ;
mnemonic(?PUSH4) -> 'PUSH4' ;
mnemonic(?PUSH5) -> 'PUSH5' ;
mnemonic(?PUSH6) -> 'PUSH6' ;
mnemonic(?PUSH7) -> 'PUSH7' ;
mnemonic(?PUSH8) -> 'PUSH8' ;
mnemonic(?PUSH9) -> 'PUSH9' ;
mnemonic(?PUSH10) -> 'PUSH10' ;
mnemonic(?PUSH11) -> 'PUSH11' ;
mnemonic(?PUSH12) -> 'PUSH12' ;
mnemonic(?PUSH13) -> 'PUSH13' ;
mnemonic(?PUSH14) -> 'PUSH14' ;
mnemonic(?PUSH15) -> 'PUSH15' ;
mnemonic(?PUSH16) -> 'PUSH16' ;
mnemonic(?PUSH17) -> 'PUSH17' ;
mnemonic(?PUSH18) -> 'PUSH18' ;
mnemonic(?PUSH19) -> 'PUSH19' ;
mnemonic(?PUSH20) -> 'PUSH20' ;
mnemonic(?PUSH21) -> 'PUSH21' ;
mnemonic(?PUSH22) -> 'PUSH22' ;
mnemonic(?PUSH23) -> 'PUSH23' ;
mnemonic(?PUSH24) -> 'PUSH24' ;
mnemonic(?PUSH25) -> 'PUSH25' ;
mnemonic(?PUSH26) -> 'PUSH26' ;
mnemonic(?PUSH27) -> 'PUSH27' ;
mnemonic(?PUSH28) -> 'PUSH28' ;
mnemonic(?PUSH29) -> 'PUSH29' ;
mnemonic(?PUSH30) -> 'PUSH30' ;
mnemonic(?PUSH31) -> 'PUSH31' ;
mnemonic(?PUSH32) -> 'PUSH32' ;
mnemonic(?DUP1) -> 'DUP1' ;
mnemonic(?DUP2) -> 'DUP2' ;
mnemonic(?DUP3) -> 'DUP3' ;
mnemonic(?DUP4) -> 'DUP4' ;
mnemonic(?DUP5) -> 'DUP5' ;
mnemonic(?DUP6) -> 'DUP6' ;
mnemonic(?DUP7) -> 'DUP7' ;
mnemonic(?DUP8) -> 'DUP8' ;
mnemonic(?DUP9) -> 'DUP9' ;
mnemonic(?DUP10) -> 'DUP10' ;
mnemonic(?DUP11) -> 'DUP11' ;
mnemonic(?DUP12) -> 'DUP12' ;
mnemonic(?DUP13) -> 'DUP13' ;
mnemonic(?DUP14) -> 'DUP14' ;
mnemonic(?DUP15) -> 'DUP15' ;
mnemonic(?DUP16) -> 'DUP16' ;
mnemonic(?SWAP1) -> 'SWAP1' ;
mnemonic(?SWAP2) -> 'SWAP2' ;
mnemonic(?SWAP3) -> 'SWAP3' ;
mnemonic(?SWAP4) -> 'SWAP4' ;
mnemonic(?SWAP5) -> 'SWAP5' ;
mnemonic(?SWAP6) -> 'SWAP6' ;
mnemonic(?SWAP7) -> 'SWAP7' ;
mnemonic(?SWAP8) -> 'SWAP8' ;
mnemonic(?SWAP9) -> 'SWAP9' ;
mnemonic(?SWAP10) -> 'SWAP10' ;
mnemonic(?SWAP11) -> 'SWAP11' ;
mnemonic(?SWAP12) -> 'SWAP12' ;
mnemonic(?SWAP13) -> 'SWAP13' ;
mnemonic(?SWAP14) -> 'SWAP14' ;
mnemonic(?SWAP15) -> 'SWAP15' ;
mnemonic(?SWAP16) -> 'SWAP16' ;
mnemonic(?LOG0) -> 'LOG0' ;
mnemonic(?LOG1) -> 'LOG1' ;
mnemonic(?LOG2) -> 'LOG2' ;
mnemonic(?LOG3) -> 'LOG3' ;
mnemonic(?LOG4) -> 'LOG4' ;
mnemonic(?CREATE) -> 'CREATE' ;
mnemonic(?CALL) -> 'CALL' ;
mnemonic(?CALLCODE) -> 'CALLCODE' ;
mnemonic(?RETURN) -> 'RETURN' ;
mnemonic(?DELEGATECALL) -> 'DELEGATECALL' ;
mnemonic(?STATICCALL) -> 'STATICCALL' ;
mnemonic(?REVERT) -> 'REVERT' ;
mnemonic({comment,_}) -> 'COMMENT' ;
mnemonic(?SUICIDE) -> 'SUICIDE' .
m_to_op('STOP') -> ?STOP ;
m_to_op('ADD') -> ?ADD ;
m_to_op('MUL') -> ?MUL ;
m_to_op('SUB') -> ?SUB ;
m_to_op('DIV') -> ?DIV ;
m_to_op('SDIV') -> ?SDIV ;
m_to_op('MOD') -> ?MOD ;
m_to_op('SMOD') -> ?SMOD ;
m_to_op('ADDMOD') -> ?ADDMOD ;
m_to_op('MULMOD') -> ?MULMOD ;
m_to_op('EXP') -> ?EXP ;
m_to_op('SIGNEXTEND') -> ?SIGNEXTEND ;
m_to_op('LT') -> ?LT ;
m_to_op('GT') -> ?GT ;
m_to_op('SLT') -> ?SLT ;
m_to_op('SGT') -> ?SGT ;
m_to_op('EQ') -> ?EQ ;
m_to_op('ISZERO') -> ?ISZERO ;
m_to_op('AND') -> ?AND ;
m_to_op('OR') -> ?OR ;
m_to_op('XOR') -> ?XOR ;
m_to_op('NOT') -> ?NOT ;
m_to_op('BYTE') -> ?BYTE ;
m_to_op('SHA3') -> ?SHA3 ;
m_to_op('ADDRESS') -> ?ADDRESS ;
m_to_op('BALANCE') -> ?BALANCE ;
m_to_op('ORIGIN') -> ?ORIGIN ;
m_to_op('CALLER') -> ?CALLER ;
m_to_op('CALLVALUE') -> ?CALLVALUE ;
m_to_op('CALLDATALOAD') -> ?CALLDATALOAD ;
m_to_op('CALLDATASIZE') -> ?CALLDATASIZE ;
m_to_op('CALLDATACOPY') -> ?CALLDATACOPY ;
m_to_op('CODESIZE') -> ?CODESIZE ;
m_to_op('CODECOPY') -> ?CODECOPY ;
m_to_op('GASPRICE') -> ?GASPRICE ;
m_to_op('EXTCODESIZE') -> ?EXTCODESIZE ;
m_to_op('EXTCODECOPY') -> ?EXTCODECOPY ;
m_to_op('RETURNDATASIZE') -> ?RETURNDATASIZE ;
m_to_op('RETURNDATACOPY') -> ?RETURNDATACOPY ;
m_to_op('BLOCKHASH') -> ?BLOCKHASH ;
m_to_op('COINBASE') -> ?COINBASE ;
m_to_op('TIMESTAMP') -> ?TIMESTAMP ;
m_to_op('NUMBER') -> ?NUMBER ;
m_to_op('DIFFICULTY') -> ?DIFFICULTY ;
m_to_op('GASLIMIT') -> ?GASLIMIT ;
m_to_op('POP') -> ?POP ;
m_to_op('MLOAD') -> ?MLOAD ;
m_to_op('MSTORE') -> ?MSTORE ;
m_to_op('MSTORE8') -> ?MSTORE8 ;
m_to_op('SLOAD') -> ?SLOAD ;
m_to_op('SSTORE') -> ?SSTORE ;
m_to_op('JUMP') -> ?JUMP ;
m_to_op('JUMPI') -> ?JUMPI ;
m_to_op('PC') -> ?PC ;
m_to_op('MSIZE') -> ?MSIZE ;
m_to_op('GAS') -> ?GAS ;
m_to_op('JUMPDEST') -> ?JUMPDEST ;
m_to_op('PUSH1') -> ?PUSH1 ;
m_to_op('PUSH2') -> ?PUSH2 ;
m_to_op('PUSH3') -> ?PUSH3 ;
m_to_op('PUSH4') -> ?PUSH4 ;
m_to_op('PUSH5') -> ?PUSH5 ;
m_to_op('PUSH6') -> ?PUSH6 ;
m_to_op('PUSH7') -> ?PUSH7 ;
m_to_op('PUSH8') -> ?PUSH8 ;
m_to_op('PUSH9') -> ?PUSH9 ;
m_to_op('PUSH10') -> ?PUSH10 ;
m_to_op('PUSH11') -> ?PUSH11 ;
m_to_op('PUSH12') -> ?PUSH12 ;
m_to_op('PUSH13') -> ?PUSH13 ;
m_to_op('PUSH14') -> ?PUSH14 ;
m_to_op('PUSH15') -> ?PUSH15 ;
m_to_op('PUSH16') -> ?PUSH16 ;
m_to_op('PUSH17') -> ?PUSH17 ;
m_to_op('PUSH18') -> ?PUSH18 ;
m_to_op('PUSH19') -> ?PUSH19 ;
m_to_op('PUSH20') -> ?PUSH20 ;
m_to_op('PUSH21') -> ?PUSH21 ;
m_to_op('PUSH22') -> ?PUSH22 ;
m_to_op('PUSH23') -> ?PUSH23 ;
m_to_op('PUSH24') -> ?PUSH24 ;
m_to_op('PUSH25') -> ?PUSH25 ;
m_to_op('PUSH26') -> ?PUSH26 ;
m_to_op('PUSH27') -> ?PUSH27 ;
m_to_op('PUSH28') -> ?PUSH28 ;
m_to_op('PUSH29') -> ?PUSH29 ;
m_to_op('PUSH30') -> ?PUSH30 ;
m_to_op('PUSH31') -> ?PUSH31 ;
m_to_op('PUSH32') -> ?PUSH32 ;
m_to_op('DUP1') -> ?DUP1 ;
m_to_op('DUP2') -> ?DUP2 ;
m_to_op('DUP3') -> ?DUP3 ;
m_to_op('DUP4') -> ?DUP4 ;
m_to_op('DUP5') -> ?DUP5 ;
m_to_op('DUP6') -> ?DUP6 ;
m_to_op('DUP7') -> ?DUP7 ;
m_to_op('DUP8') -> ?DUP8 ;
m_to_op('DUP9') -> ?DUP9 ;
m_to_op('DUP10') -> ?DUP10 ;
m_to_op('DUP11') -> ?DUP11 ;
m_to_op('DUP12') -> ?DUP12 ;
m_to_op('DUP13') -> ?DUP13 ;
m_to_op('DUP14') -> ?DUP14 ;
m_to_op('DUP15') -> ?DUP15 ;
m_to_op('DUP16') -> ?DUP16 ;
m_to_op('SWAP1') -> ?SWAP1 ;
m_to_op('SWAP2') -> ?SWAP2 ;
m_to_op('SWAP3') -> ?SWAP3 ;
m_to_op('SWAP4') -> ?SWAP4 ;
m_to_op('SWAP5') -> ?SWAP5 ;
m_to_op('SWAP6') -> ?SWAP6 ;
m_to_op('SWAP7') -> ?SWAP7 ;
m_to_op('SWAP8') -> ?SWAP8 ;
m_to_op('SWAP9') -> ?SWAP9 ;
m_to_op('SWAP10') -> ?SWAP10 ;
m_to_op('SWAP11') -> ?SWAP11 ;
m_to_op('SWAP12') -> ?SWAP12 ;
m_to_op('SWAP13') -> ?SWAP13 ;
m_to_op('SWAP14') -> ?SWAP14 ;
m_to_op('SWAP15') -> ?SWAP15 ;
m_to_op('SWAP16') -> ?SWAP16 ;
m_to_op('LOG0') -> ?LOG0 ;
m_to_op('LOG1') -> ?LOG1 ;
m_to_op('LOG2') -> ?LOG2 ;
m_to_op('LOG3') -> ?LOG3 ;
m_to_op('LOG4') -> ?LOG4 ;
m_to_op('CREATE') -> ?CREATE ;
m_to_op('CALL') -> ?CALL ;
m_to_op('CALLCODE') -> ?CALLCODE ;
m_to_op('RETURN') -> ?RETURN ;
m_to_op('DELEGATECALL') -> ?DELEGATECALL ;
m_to_op('STATICCALL') -> ?STATICCALL ;
m_to_op('REVERT') -> ?REVERT ;
m_to_op('COMMENT') -> ?COMMENT("") ;
m_to_op('SUICIDE') -> ?SUICIDE ;
m_to_op(Data) when 0=<Data, Data=<255
-> Data .
push(N) when N >= 1, N =< 32 -> ?PUSH1 + N - 1.
dup(N) when N >= 1, N =< 16 -> ?DUP1 + N - 1.
swap(N) when N >= 1, N =< 16 -> ?SWAP1 + N - 1.
op_size(OP) when OP >= ?PUSH1 andalso OP =< ?PUSH32 ->
(OP - ?PUSH1) + 2;
op_size({comment, _}) -> 0;
op_size(_) -> 1.

31
src/aeb_primops.erl Normal file
View File

@ -0,0 +1,31 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc
%%% Handle interaction with the aeternity chain
%%% through calls to AEternity primitive operations at address 0.
%%% @end
%%% Created : 18 Dec 2018
%%%-------------------------------------------------------------------
-module(aeb_primops).
-export([ is_local_primop_op/1
, op_needs_type_check/1
]).
-include("aeb_opcodes.hrl").
is_local_primop_op(Op) when ?PRIM_CALL_IN_MAP_RANGE(Op) -> true;
is_local_primop_op(Op) when is_integer(Op) -> false.
op_needs_type_check(Op) ->
(not is_local_primop_op(Op)) andalso op_has_dynamic_type(Op).
op_has_dynamic_type(?PRIM_CALL_ORACLE_QUERY) -> true;
op_has_dynamic_type(?PRIM_CALL_ORACLE_RESPOND) -> true;
op_has_dynamic_type(?PRIM_CALL_ORACLE_GET_QUESTION) -> true;
op_has_dynamic_type(?PRIM_CALL_ORACLE_GET_ANSWER) -> true;
op_has_dynamic_type(?PRIM_CALL_MAP_GET) -> true;
op_has_dynamic_type(?PRIM_CALL_MAP_PUT) -> true;
op_has_dynamic_type(?PRIM_CALL_MAP_TOLIST) -> true;
op_has_dynamic_type(?PRIM_CALL_AENS_RESOLVE) -> true;
op_has_dynamic_type(_) -> false.

14
src/aebytecode.app.src Normal file
View File

@ -0,0 +1,14 @@
{application, aebytecode,
[{description, "Bytecode definitions for AEthernity VM shared with compiler."},
{vsn, "1.0.0"},
{registered, []},
{applications,
[kernel,
stdlib
]},
{env,[]},
{modules, []},
{maintainers, []},
{licenses, []},
{links, []}
]}.

19
test/aebytecode_SUITE.erl Normal file
View File

@ -0,0 +1,19 @@
-module(aebytecode_SUITE).
%% common_test exports
-export([ all/0 ]).
%% test case exports
-export([ roundtrip_identy/1 ]).
-include_lib("common_test/include/ct.hrl").
all() ->
[ roundtrip_identy ].
roundtrip_identy(_Cfg) ->
CodeDir = code:lib_dir(aebytecode, test),
FileName = filename:join(CodeDir, "asm_code/identity.aesm"),
Code = aeb_asm:file(FileName, []),
ct:log("Code ~p:~n~s~n", [FileName, aeb_disassemble:format(Code, fun io:format/2)]),
ok.

View File

@ -0,0 +1,74 @@
;; CONTRACT: Identity
PUSH1 0
CALLDATALOAD
DUP1
;; Should be the hash of
;; the signature of the
;; first function (use 0 as placeholder)
PUSH32 0x0000000000000000000000000000
EQ
PUSH32 id_entry
JUMPI
STOP
id_entry: JUMPDEST
;; Skip the function name in the calldata
PUSH1 32
;; Load argument on stack
CALLDATALOAD
;; This function only takes one immidiate as argument.
;; Call the local version of the function
;; Get return address
PC
PUSH1 39
ADD
;; Get Argument
SWAP1
PUSH32 id_local
JUMP
;; return here from local call
;; Store top of stack at mem[0]
JUMPDEST
PUSH1 0
MSTORE
;; Return mem[0]-mem[32]
PUSH1 32
PUSH1 0
RETURN
;; for local calls
;; Stack:
;; | |
;; | Arg | <- SP
;; | RetAdr |
;; ...
id_local: JUMPDEST
;; Just return the argument
SWAP1
;; Stack:
;; | |
;; | RetAdr | <- SP
;; | RetVal | (Arg in this case)
;; ...
JUMP
;; Test the code from the shell
;; aevm_eeevm:eval(aevm_eeevm_state:init(#{ exec => #{ code => list_to_binary(aeb_asm:file("apps/aesophia/test/contracts/identity.aesm", [])), address => 0, caller => 0, data => <<0:256, 42:256>>, gas => 1000000, gasPrice => 1, origin => 0, value => 0 }, env => #{currentCoinbase => 0, currentDifficulty => 0, currentGasLimit => 10000, currentNumber => 0, currentTimestamp => 0}, pre => #{}}, #{})).
;; Test the code from the shell with tracing.
;; aevm_eeevm:eval(aevm_eeevm_state:init(#{ exec => #{ code => aeb_asm:file("apps/aesophia/test/contracts/identity.aesm", []), address => 0, caller => 0, data => <<0:256, 42:256>>, gas => 1000000, gasPrice => 1, origin => 0, value => 0 }, env => #{currentCoinbase => 0, currentDifficulty => 0, currentGasLimit => 10000, currentNumber => 0, currentTimestamp => 0}, pre => #{}}, #{ trace => true})).
;; Test the code from the shell with tracing.
;; aevm_eeevm:eval(aevm_eeevm_state:init(#{ exec => #{ code => aeb_asm:file("apps/aesophia/test/contracts/identity.aesm", [pp_tokens, pp_opcodes, pp_patched_code, pp_hex_string]), address => 0, caller => 0, data => <<0:256, 42:256>>, gas => 1000000, gasPrice => 1, origin => 0, value => 0}, env => #{currentCoinbase => 0, currentDifficulty => 0, currentGasLimit => 10000, currentNumber => 0, currentTimestamp => 0}, pre => #{}}, #{ trace => true})).
;; aec_conductor:stop_mining().