-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}