Recompiling output of Erlang's beam_disasm.file

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Recompiling output of Erlang's beam_disasm.file



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.


:beam_disasm.file


.beam



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:


: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]] ]



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.


indirect_value2


indirect_value


indirect_value



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.




3 Answers
3



Compiling via erlc -S xxx.erl will produce xxx.S which when you modify can be compiled with erlc xxx.S into 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?


erlc -S xxx.erl


xxx.S


erlc xxx.S



Is it necessary to compile from code? If so, then someone more familiar with compiler module will suggest correct call for your case.


compiler



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.


?MODULE:call()





Thanks for the reply! I've provided some more details so perhaps what I'm trying to achieve will be clearer.
– Olshansk
Sep 3 at 22:21



Ok, so this is Elixir compile-time processing. I am not familiar with how it works in Elixir, but they rely on macros more, and preprocessing before compilation is deprecated/not available like in Erlang or hard to get. If this was Erlang there are tools for what you want. Dig Elixir chat on Slack.





I've tried the elixir chat, a few elixir people on twitter, emailed the erlang mailing list, reached out to Francesco Cesarini directly, and have now posted my question on stackoverflow. If this was Erlang there are tools for what you want - Isn't everything in erlang also available in elixir? Let's pretend this was a purely erlang problem, do you have suggestions on how I would recompile the output of :beam_disasm.file(:code.which m)?
– Olshansk
Sep 11 at 13:42


If this was Erlang there are tools for what you want


:beam_disasm.file(:code.which m)



Again, Erlang compiler is able to compile intermediate results of compilation process. You're thinking to modify beam assembly which in Erlang you can also produce with to_asm flag or in shell with a +S option, it can be sent back to compiler input. I am just not sure how to do this in code, but in shell you just call erlc file.asm or whatever is your filename. I.e. it can work in theory, all pieces are there. It just feels a bit wrong to do because beam assembly is a final result of compilation, highly optimised and many things are rewritten or removed.


to_asm


+S


erlc file.asm



Please note that beam.disasm file you provided is written with Elixir syntax and the erlc compiler will not read it, maybe elixir compiler could.



Also note that you're deep in low level compiler territory and if the dragon comes to eat you, only a handful of people can actually help you, so find them in Slack or on the Mailing List.



How I would do this in Erlang: I would modify Erlang AST by writing a parse transformation http://www.erlang-factory.com/upload/presentations/521/yrashk_parse_transformations_sf12.pdf also more docs for it from 2010-2013 Is there a good, complete tutorial on Erlang parse transforms available?



I cannot imagine a possible use case for this. What are you trying to do?






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

make 2 or more post in bootsrap

Store custom data using WC_Cart add_to_cart() method in Woocommerce 3

Firebase Auth - with Email and Password - Check user already registered