I'm trying to modify a beam file such that local function calls are interpreted as external module calls even though a function may be defined in the same module where it is being called.
Given m as a module, I've tried several permutations of recompiling a disassembled beam file to no avail. Here is an example, in elixir, of one of my attempts:
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]))
I'd really appreciate any input on how I could easily recompile the output of :beam_disasm.file back into a .beam file.
Thanks!
EDIT: Proving more information
Assume I have an elixir module that looks like this:
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
After the application is compiled, :beam.disasm provides the following output of its beam file:
[ {: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}]}]} ]
The particular piece of information to which I'd like to bring to your attention is this:
{: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 is a "remote" call while indirect_value is a "local" call. What I'm trying to achieve is to have indirect_value be mimicked/seen as a remote call like indirect_value_2.
I'm trying to achieve this during the compilation process. The only approach I've thought is is to dissassemble the beam file, alter it appropriately and reassemble it. I'm very much open to alternative suggestions.
Compiling via
erlc -S xxx.erlwill producexxx.Swhich when you modify can be compiled witherlc xxx.Sinto BEAM file. But you did not specify what is the use case, where input comes from and where the output goes? Is it OK to use parse transform? Is it OK to use command line compiler or must be called from code?Is it necessary to compile from code? If so, then someone more familiar with
compilermodule will suggest correct call for your case.Or maybe for your case it would be perfectly fine to use a parse transformation, where you replace all local calls with
?MODULE:call()which then will transparently be compiled without any intrusion into what you want.