After the Community Bonding period ended, the Coding period kicked off and with full zeal and enthusiasm, I started to write code that could run HPX functionality on Compiler’s main itself (if you didn’t get the reference, read this).
I focused on Linux and Unix based systems first. My motive was to somehow run HPX functionality directly from Compiler’s main, but that would mean that the HPX system somehow needs to get initialized before it. And so my journey began to find out ways to make this happen (this dates back to March when I was writing my proposal) and I stumbled upon a solution that involved hooking. To start off with, hooking can be described as: (as per given in Wikipedia)
A range of techniques used to alter or augment the behavior of an operating system, of applications, or of other software components by intercepting function calls or messages or events passed between software components.
So with a clear picture of what a hook is, let’s move on to the function I decided to hook into to intercept the function call to alter (or override the function) the behavior, a libc function __libc_start_main. The work of __libc_start_main is to initialize the process, call the main with appropriate arguments, and then handle the return from main. The next thing would be to understand how to create a hook. The usual method to employ a hook is by using the dlfcn.h header which provides a programming interface to dynamic loader.
A clear picture of what I’ve written above can be established by explaining the following code snippet:
Starting from line 2, we see a classic definition of the __libc_start_main function. Next from line 13 to 26 we see a rather complex code. To break it into simpler chunks, what we want to do is to load this function with the dynamic linker instead of the actual function. This can be done using dlsym() (provided in the dlfcn.h header) function which takes two parameters handler and function name. For handler we use RTLD_NEXT which returns the next object after the actual one that defines __libc_start_main and store it in a pointer real_start_main and we use __libc_start_main as the function_name.
The pointer real_start_main now contains info to initialize the process, call the main function with appropriate arguments, and handle return from main. So if we were to return real_start_main from the defined function, the code will function exactly the same as pre-implemented __libc_start_main. One thing to note here is that this pointer contains the Compiler’s main function itself. So, if we were to switch this function with our own implementation of main (like initializing_main in the code snippet) then our pointer would call that function instead, and that too with appropriate arguments! This would mean that the new entry point of the program will now change from Compiler’s main to our implementation of main.
With that said, if the entry point of our system changes to our own implementation, then we could simply initiate the HPX system and call the main function from there. This would mean that for Linux and Unix based system this implementation would suffice!
With this work done, I’m now shifting to Windows implementation and it will therefore be my focus for the next week i.e. week 2.
Until then, I bid you farewell!