Erlang
часть 1 - компиляция
-module(hello).
-export([world/0]).
world() ->
io:fwrite("Hello, world\n").
Компилируем и запускаем
$ erlc hello.erl
$ erl -noshell -s hello world -s init stop
Hello World
$ erlc +debug_info hello.erl
$ erl
Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:4:4] [async-threads:0] [kernel-poll:false]
Eshell V5.9.3.1 (abort with ^G)
1> {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks("hello.beam",[abstract_code]).
{ok,{hello,[{abstract_code,{raw_abstract_v1,[{attribute,1,
file,
{"hello.erl",1}},
{attribute,1,module,hello},
{attribute,2,export,[{world,0}]},
{function,4,world,0,
[{clause,4,[],[],[{call,5,{remote,...},[...]}]}]},
{eof,5}]}}]}}
2> io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).
-file("hello.erl", 1).
-module(hello).
-export([world/0]).
world() -> io:fwrite("Hello, world\n").
ok
EBIN_DIR := ebin
SRC_DIR := src
INCLUDE_DIR := include
ERLC := erlc
ERLC_FLAGS := +debug_info -W -I $(INCLUDE_DIR) -o $(EBIN_DIR)
all:
@mkdir -p $(EBIN_DIR)
$(ERLC) $(ERLC_FLAGS) $(SRC_DIR)/*.erl
clean:
@rm -rf $(EBIN_DIR)/*
@rm -f erl_crash.dump
$ erl
1> c(hello, to_core).
2> c(hello, from_core).
3> q().
$ cat hello.core
module 'hello' ['module_info'/0,
'module_info'/1,
'world'/0]
attributes []
'world'/0 =
%% Line 4
fun () ->
%% Line 5
call 'io':'fwrite'
([72|[101|[108|[108|[111|[44|[32|[119|[111|[114|[108|[100|[10]]]]]]]]]]]]])
'module_info'/0 =
fun () ->
call 'erlang':'get_module_info'
('hello')
'module_info'/1 =
fun (_cor0) ->
call 'erlang':'get_module_info'
('hello', _cor0)
end
$ erlc -S hello.erl
$ cat hello.S
{module, hello}. %% version = 0
{exports, [{module_info,0},{module_info,1},{world,0}]}.
{attributes, []}.
{labels, 7}.
{function, world, 0, 2}.
{label,1}.
{line,[{location,"hello.erl",4}]}.
{func_info,{atom,hello},{atom,world},0}.
{label,2}.
{move,{literal,"Hello, world\n"},{x,0}}.
{line,[{location,"hello.erl",5}]}.
{call_ext_only,1,{extfunc,io,fwrite,1}}.
{function, module_info, 0, 4}.
{label,3}.
{line,[]}.
{func_info,{atom,hello},{atom,module_info},0}.
{label,4}.
{move,{atom,hello},{x,0}}.
{line,[]}.
{call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
{function, module_info, 1, 6}.
{label,5}.
{line,[]}.
{func_info,{atom,hello},{atom,module_info},1}.
{label,6}.
{move,{x,0},{x,1}}.
{move,{atom,hello},{x,0}}.
{line,[]}.
{call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
BEAM - Bogdan's Erlang Abstract Machine
Interchange File Format (IFF) - формат файла-контейнера
| Идентификатор | Имя чанка | Описание |
|---|---|---|
| Atom | Atom Table Chunk | Определения атомов используемых в файле |
| Code | Code Chunk | Определения кода для исполнения |
| StrT | String Table Chunk | Определения строк используемых в файле |
| ImpT | Import Table Chunk | Определения методов которые импортируются в модуль |
| ExpT | Export Table Chunk | Определения методов которые экспортируются из модуля |
Пример функции для декодирования beam-файла в исходный код
decode_beam(BeamFile) ->
{ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(BeamFile,[abstract_code]),
io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).
$ erl
1> erts_debug:df(hello).
2> q().
$ cat hello.dis
00007FF25CEE4EA8: i_func_info_IaaI 0 hello world 0
00007FF25CEE4ED0: move_cr "Hello, world\n" x(0)
00007FF25CEE4EE0: i_call_ext_only_e io:fwrite/1
00007FF25CEE4EF0: i_func_info_IaaI 0 hello module_info 0
00007FF25CEE4F18: move_cr hello x(0)
00007FF25CEE4F28: allocate_tt 0 1
00007FF25CEE4F38: call_bif_e erlang:get_module_info/1
00007FF25CEE4F48: deallocate_return_Q 0
00007FF25CEE4F58: i_func_info_IaaI 0 hello module_info 1
00007FF25CEE4F80: move_rx x(0) x(1)
00007FF25CEE4F90: move_cr hello x(0)
00007FF25CEE4FA0: allocate_tt 0 2
00007FF25CEE4FB0: call_bif_e erlang:get_module_info/2
00007FF25CEE4FC0: deallocate_return_Q 0
$ erlc +native hello.erl
Доступные опции
$ erl
1> hipe:c(hello, [pp_asm]).
****************** Assembling *******************
Generating code for:{hello,module_info,1}
Offset | Opcode | Instruction
0 | | ._3:
0 | 488bd6 | mov %rsi, %rdx
3 | | ._2:
3 | 48c7c600000000 | mov $hello, %rsi
a | e900000000 | jmp erlang:get_module_info/2 remote
f | 90 | # padding
Finished.
Generating code for:{hello,module_info,0}
Offset | Opcode | Instruction
10 | | ._2:
10 | 48c7c600000000 | mov $hello, %rsi
17 | e900000000 | jmp erlang:get_module_info/1 remote
Finished.
Generating code for:{hello,world,0}
Offset | Opcode | Instruction
1c | | ._6:
1c | 4883ad4001000001 | sub $0x1, 0x140(%rbp)
24 | 7c0f | jl ._3
26 | | ._5:
26 | 48be0000000000000000 | mov64 ${0,constant}, %rsi
30 | e900000000 | jmp io:fwrite/1 remote
35 | | ._3:
35 | e800000000 | call suspend_0 # [] 0x0 0 [] not_remote
3a | ebea | jmp ._5
Finished.
Total num bytes=60
{ok,hello}