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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重新编译Erlang的beam_disasm.file的输出相关的知识,希望对你有一定的参考价值。

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

鉴于m作为模块,我尝试了几种重新编译反汇编光束文件的排列无效。这是一个例子,在elixir中,我的一个尝试:

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文件的任何输入。

谢谢!

编辑:证明更多信息

假设我有一个如下所示的elixir模块:

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这样的远程调用。

我正在尝试在编译过程中实现这一目标。我认为唯一的方法是拆卸光束文件,适当改变它并重新组装。我非常愿意接受其他建议。

答案

通过erlc -S xxx.erl编译将产生xxx.S,当你修改时可以用erlc xxx.S编译成BEAM文件。但是您没有指定用例是什么,输入来自何处以及输出位于何处?可以使用解析变换吗?是否可以使用命令行编译器或必须从代码中调用?

是否有必要从代码编译?如果是这样,那么更熟悉compiler模块的人会建议你的案件正确。

或者对于你的情况,使用解析转换是完全没问题的,你用?MODULE:call()替换所有本地调用,然后将透明地编译而不会侵入你想要的内容。

另一答案

好的,这是Elixir编译时处理。我不熟悉它在Elixir中是如何工作的,但它们更依赖于宏,并且在编译之前的预处理被弃用/不可用,如Erlang或难以获得。如果这是Erlang,你可以找到你想要的工具。在Slack上挖掘Elixir聊天。

另一答案

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

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

还要注意你在低级别的编译器领域,如果龙来吃你,只有少数人可以真正帮助你,所以在Slack或邮件列表中找到它们。

我将如何在Erlang中执行此操作:我将通过编写解析转换来修改Erlang AST 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的beam_disasm.file的输出的主要内容,如果未能解决你的问题,请参考以下文章

为啥代码版本控制器在 erlang 中不起作用?

centos 6.5安装erlang和RabbitMQ

如何重新编译 Elixir 项目并从 iex 中重新加载它?

如何编译 Erlang 驱动程序?

RabbitMQ/Erlang 崩溃:无法重新分配 313760 字节的内存(“代码”类型)

加快 Erlang 的编辑、编译、运行/调试周期