2

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

给定 m 作为模块,我尝试了几种重新编译反汇编梁文件的排列,但无济于事。这是我尝试的一个例子,在长生不老药中:

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

我试图在编译过程中实现这一点。我想到的唯一方法是分解光束文件,适当地改变它并重新组装它。我非常愿意接受其他建议。

4

3 回答 3

1

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

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

或者,对于您的情况,使用解析转换可能会非常好,您可以在其中替换所有本地调用?MODULE:call(),然后将透明地编译而不会侵入您想要的内容。

于 2018-08-19T19:16:57.860 回答
0

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

于 2018-09-10T23:47:38.023 回答
0

同样,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 年的文档有关于 Erlang 解析转换的完整教程吗?

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

于 2018-09-18T14:14:05.310 回答