重新编译Erlang的beam_disasm.file的输出

时间:2018-08-07 20:16:28

标签: erlang elixir beam

我正在尝试修改Beam文件,以便将本地函数调用解释为外部模块调用,即使某个函数可以在调用它的同一模块中定义。

考虑到作为一个模块,我尝试了几种重新编译反汇编梁文件的排列方法,但无济于事。这是长生不老药中我的尝试之一的示例:

  

IO.inspect(:file.write_file(“ / tmp / disasm.asm”,:io_lib.fwrite(“〜p。\ n”,   [:beam_disasm.file(:code.which m)]))))

     

IO.inspect(:compile.noenv_file(“ / tmp / disasm.asm”,[:from_asm]))

我非常感谢任何有关如何轻松将:beam_disasm.file的输出重新编译回.beam文件的输入。

谢谢!

编辑:提供更多信息

假设我有一个长生不老药模块,看起来像这样:

defmodule MyApp.IndirectMod do

  def value do
    1
  end

  def indirect_value do
    value()
  end

  def indirect_value_2 do
    MyApp.IndirectMod.value()
  end

end

在编译应用程序之后,:beam.disasm提供其梁文件的以下输出:

[   {:attribute, 1, :file, {'lib/temp.ex', 1}},   {:attribute, 1, :module, MyApp.IndirectMod},   {:attribute, 1, :compile, :no_auto_import},   {:attribute, 1, :export,    [__info__: 1, indirect_value: 0, indirect_value_2: 0, value: 0]},   {:attribute, 1, :spec,    {{:__info__, 1},
    [
      {:type, 1, :fun,
       [
         {:type, 1, :product,
          [
            {:type, 1, :union,
             [
               {:atom, 1, :attributes},
               {:atom, 1, :compile},
               {:atom, 1, :functions},
               {:atom, 1, :macros},
               {:atom, 1, :md5},
               {:atom, 1, :module},
               {:atom, 1, :deprecated}
             ]}
          ]},
         {:type, 1, :any, []}
       ]}
    ]}},   {:function, 0, :__info__, 1,    [
     {:clause, 0, [{:atom, 0, :module}], [], [{:atom, 0, MyApp.IndirectMod}]},
     {:clause, 0, [{:atom, 0, :functions}], [],
      [
        {:cons, 0, {:tuple, 0, [{:atom, 0, :indirect_value}, {:integer, 0, 0}]},
         {:cons, 0,
          {:tuple, 0, [{:atom, 0, :indirect_value_2}, {:integer, 0, 0}]},
          {:cons, 0, {:tuple, 0, [{:atom, 0, :value}, {:integer, 0, 0}]},
           {nil, 0}}}}
      ]},
     {:clause, 0, [{:atom, 0, :macros}], [], [nil: 0]},
     {:clause, 0, [{:atom, 0, :attributes}], [],
      [
        {:call, 0,
         {:remote, 0, {:atom, 0, :erlang}, {:atom, 0, :get_module_info}},
         [{:atom, 0, MyApp.IndirectMod}, {:atom, 0, :attributes}]}
      ]},
     {:clause, 0, [{:atom, 0, :compile}], [],
      [
        {:call, 0,
         {:remote, 0, {:atom, 0, :erlang}, {:atom, 0, :get_module_info}},
         [{:atom, 0, MyApp.IndirectMod}, {:atom, 0, :compile}]}
      ]},
     {:clause, 0, [{:atom, 0, :md5}], [],
      [
        {:call, 0,
         {:remote, 0, {:atom, 0, :erlang}, {:atom, 0, :get_module_info}},
         [{:atom, 0, MyApp.IndirectMod}, {:atom, 0, :md5}]}
      ]},
     {:clause, 0, [{:atom, 0, :deprecated}], [], [nil: 0]}    ]},   {:function, 7, :indirect_value, 0,    [{:clause, 7, [], [], [{:call, 8, {:atom, 8, :value}, []}]}]},   {:function, 11, :indirect_value_2, 0,    [
     {:clause, 11, [], [],
      [
        {:call, 12,
         {:remote, 12, {:atom, 0, MyApp.IndirectMod}, {:atom, 12, :value}}, []}
      ]}    ]},   {:function, 3, :value, 0, [{:clause, 3, [], [], [{:integer, 0, 1}]}]} ]

我想提醒您的特定信息是:

{:function, 7, :indirect_value, 0,
 [{:clause, 7, [], [], [{:call, 8, {:atom, 8, :value}, []}]}]},
{:function, 11, :indirect_value_2, 0,
 [
   {:clause, 11, [], [],
    [
      {:call, 12,
       {:remote, 12, {:atom, 0, MyApp.IndirectMod}, {:atom, 12, :value}}, []}
    ]}
 ]},

indirect_value2是“远程”呼叫,而indirect_value是“本地”呼叫。我要实现的目标是将indirect_value模仿/看成是像indirect_value_2之类的远程调用。

我正在尝试在编译过程中实现这一目标。我认为唯一的方法是分解梁文件,适当地对其进行更改然后重新组装。我非常乐意接受其他建议。

3 个答案:

答案 0 :(得分:1)

通过erlc -S xxx.erl进行编译将产生xxx.S,在您进行修改时可以将erlc xxx.S编译为BEAM文件。但是您没有指定用例是什么,输入来自哪里,输出去哪里?可以使用解析转换吗?可以使用命令行编译器还是必须从代码中调用?

是否需要从代码进行编译?如果是这样,那么更熟悉compiler模块的人会为您的情况建议正确的电话。

或者对于您而言,最好使用解析转换,将所有本地调用替换为?MODULE:call(),然后将其透明地编译,而不会干扰您想要的内容。

答案 1 :(得分:0)

好的,这就是Elixir的编译时处理。我不熟悉它在Elixir中的工作方式,但是它们更多地依赖于宏,并且不赞成在编译之前/像在Erlang中那样无法使用或很难获得预处理。如果这是Erlang,那么就有满足您需求的工具。在Slack上挖Elixir聊天。

答案 2 :(得分:0)

同样,Erlang编译器能够编译编译过程的中间结果。您正在考虑修改梁组件,该梁组件在Erlang中也可以使用to_asm标志生成,或者在外壳中使用+S选项生成,可以将其发送回编译器输入。我只是不确定如何在代码中执行此操作,但是在shell中,您只需调用erlc file.asm或您的文件名即可。即它可以在理论上工作,所有组件都在那里。这样做感觉有点不对劲,因为光束装配是编译的最终结果,经过高度优化,并且许多内容都被重写或删除。

请注意,您提供的beam.disasm文件是使用Elixir语法编写的,而erlc编译器可能不会读取它,也许elixir编译器会读取。

还请注意,您身处低级编译器领域,如果龙吞噬了您,那么实际上只有少数人可以帮助您,因此请在Slack或邮件列表中找到他们。

我将如何在Erlang中做到这一点:我将通过编写解析转换http://www.erlang-factory.com/upload/presentations/521/yrashk_parse_transformations_sf12.pdf以及2010-2013年Is there a good, complete tutorial on Erlang parse transforms available?的更多文档来修改Erlang AST

我无法想象可能的用例。你想做什么?