Erlang

часть 1 - компиляция

Hello World

        
-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
    

Пример Makefile

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
    

Внутреннее представление

Core Erlang

$ 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
    

BEAM

$ 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

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

Регистры

BEAM

Пример функции для декодирования 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))]).
    

ERTS представление

$ 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
    

HiPE

$ erlc +native hello.erl
    

HiPE

Доступные опции

HiPE

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

Ссылки