我正在尝试修改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之类的远程调用。
我正在尝试在编译过程中实现这一目标。我认为唯一的方法是分解梁文件,适当地对其进行更改然后重新组装。我非常乐意接受其他建议。
答案 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
我无法想象可能的用例。你想做什么?