Arachne ties aspects to the base program by rewriting the assembly instructions belonging to the base program interpreted by IA-32 processors. Let's take an example to clarify how does Arachne works internally. Suppose we have our original program running. This base program includes foo and bar functions.
Let's now consider the following Arachne aspect:
This aspect changes the behavior of the bar when it is invoked in the base program by foo. In this case, when this patch aspect is woven, the bar invocation is replaced by bar_corrected.
The compilation of this aspect will produce a dynamically loaded library (DLL) that is a .so file.
At weaving time, Arachne will rewrite the calls to the most imbricated function in the definition of the pointcut of the aspect (here: bar). Therefore, at weaving time, every assembly instruction that performs a bar call in the base program will be replaced by a call to a hook. A hook is a small piece of code generated under the hoods by the Arachne runtime. Depending on the control flow, the hook is responsible to test whether aspect advice must be called or if the original function (bar) should be invoked. Here this test can be understood as "do we come from foo?".
The weaving process is a follow. First, a generic hook is loaded into the base program memory space. As you can notice there are some blanks remaining in the hook. This is because as the hook is generic and as the aspect is not loaded yet, Arachne don't have all necessary informations to complete the hook.
Then, Arachne ask via dlopen() to dynamically load the compiled aspect DLL within the base program. At this point, Arachne can fill the blanks in the hook because all addresses needed are now known. It is also important to notice that at this point, the hook and the compiled aspect that have been dynamicaly linked are dead code: there is no problem in modifying it.
Once the hook is rewritten, the last task is to rewrite every call to bar in the base program by a call to the hook. As a call instruction on IA-32 architecture is a 5 bytes long instruction (1 for the opcode and 4 for the 32bits address) and because the IA-32 allows to rewrite up to 4 bytes atomicaly, rewriting the call target address will never break the execution.
However it is possible that the execution flows within the hook before the complete rewriting of every bar call in the base program. We deal with this issue by using a guard weaving_complete within the hook. This guard is set to false prior weaving and set to true when all aspects contained in the compiled aspect DLL have been woven.
Finally when the weaving process is over the base program looks like: