I doubt anyone can help with this question because of the following in Erlang's compile documentation:
Note that the format of assembler files is not documented, and may change between releases - this option is primarily for internal debugging use.
... but just in case, here goes the story's stack trace:
Unfortunately I just quickly skimmed the .S files generated when compiling a module containing the following function, with and without the first expression in the function commented out:
spawn_worker(Which) ->
%syner:sync_pt(),
case Which of
?NAIVE -> spawn(err1, naive_worker_loop, [])
end.
When I did that, I thought that the only thing that changed was the tuple:
{call_ext,0,{extfunc,syner,sync_pt,0}}.
... so I assumed that the only thing necessary to inject a function call in the assembly was to add that tuple... but now that I got to actually injecting the tuple... I'm seeing that the assembly generated has some extra instructions:
Without syner:sync_pt():
{function, spawn_worker, 1, 4}.
{label,3}.
{func_info,{atom,err1},{atom,spawn_worker},1}.
{label,4}.
{test,is_eq_exact,{f,5},[{x,0},{atom,naive}]}.
{move,{atom,naive_worker_loop},{x,1}}.
{move,nil,{x,2}}.
{move,{atom,err1},{x,0}}.
{call_ext_only,3,{extfunc,erlang,spawn,3}}.
{label,5}.
{case_end,{x,0}}.
With syner:sync_pt():
{function, spawn_worker, 1, 4}.
{label,3}.
{func_info,{atom,err1},{atom,spawn_worker},1}.
{label,4}.
{allocate,1,1}.
{move,{x,0},{y,0}}.
{call_ext,0,{extfunc,syner,sync_pt,0}}.
{test,is_eq_exact,{f,5},[{y,0},{atom,naive}]}.
{move,{atom,naive_worker_loop},{x,1}}.
{move,nil,{x,2}}.
{move,{atom,err1},{x,0}}.
{call_ext_last,3,{extfunc,erlang,spawn,3},1}.
{label,5}.
{case_end,{y,0}}.
I can't just conclude that adding something like:
{allocate,1,1}.
{move,{x,0},{y,0}}.
{call_ext,0,{extfunc,syner,sync_pt,0}}.
to every function I want to inject an external function call into, will do the trick.
So now the question is, is there any resource out there I can use to understand and manipulate the assembly generated by Erlang's compile:file/2?
I'm asking this question just in case. I doubt there is a resource for this since the documentation clearly states that there isn't, but I have nothing to lose I guess. Even if there was, it seems like manipulating the assembly code is going to be trickier than I'd like it to be. Using parse_transform/2 is definitely easier, and I did manage to get something similar to work with it... just trying out different alternatives.
Thanks for your time.
The only tool I know of that use the beam asm is HiPE, there is alot of code examples and such in https://github.com/erlang/otp/tree/master/lib/hipe/icode, though I would not recommend doing much with this format as it is changing all the time.
I'm not sure what are you trying to achieve with this, but core erlang might be a better level to do code manipulation. This is documented (well one version of it anyhow, but this is still better than nothing) here (and there are more just google for core erlang):
To compile to and from core erlang use the 'to_core' and 'from_core' (unfortunately undocumented) options:
c(my_module, to_core). %%this generates my_module.core
c(my_module, from_core). %%this loads my_module.core
It seemed to me that what you're trying to do could easily be addressed by manipulating the abstract code. Just write a parse_transform module within which you could insert the function call into the functions in question.
I wrote a ?funclog
based on the erlang decorators
. see https://github.com/nicoster/erl-decorator-pt#funclog
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With