In my last blog, I was still trying to make things happen in Linux with no clue about Mac OS X implementation and failed attempt at Microsoft’s MSVC as well. Things have changed a lot since then. With this blog, I’ll continue from I left off.
From my previous researches and tries at attempting to run main() on HPX thread, I now finally implemented it and it has been successfully integrated in HPX as well. The implementation consists of using Linker flag -Wl,-wrap to wrap __libc_start_main and change the program’s entry point. More on this can be read in my previous blogs.
Mac OSX Implementation
After taking care of my Linux implementation, I went ahead to look for ways to implement the same in Mac OSX. We need to first understand why my Linux implementation is not portable enough that we need to implement it differently for different OSes.
- Every OS has its own Linker with different Linker Flags. The -wrap linker flag is not available in both Windows and Mac OSX.
- Mac OSX uses its own version of libc and __libc_start_main is a libc function provided by glibc. Therefore Mac OSX does not contain that very same function to try to hook to.
This called for an alternate way of changing the entry point of the program. That’s when I stumbled upon -e linker flag. This changes the entry point of program to user defined entry point as opposed to main(). While this flag was available in Linux as well, it served no good use as it changed the entry point of the ELF from _start to that of the user defined entry point. This would have meant that I had to implement _start first and then create the function stack altogether. Clearly -wrap provided me with better alternatives.
Things will get clearer with the following example:
Create a file (let’s call it link.cpp) and copy the following code:
Now let’s create another file (let’s call it main.cpp) which will contain our main function.
Now open up the terminal and write the following commands:
$ clang++ -c -o link.cpp.o link.cpp
$ clang++ -c -o main.cpp.o main.cpp
$ clang++ -Wl,-e,_before_main -o result link.cpp.o main.cpp.o
From the above commands we can see the use of -e linker flag. Running the generated executable should give the following output:
It is quite clear from the above output that the entry point has been changed from main to before_main. I have used this method to implement all the initializations necessary for initiating the HPX runtime.
I was able to successfully implement it and is currently undergoing review by my mentors.
Let’s now shift gears to Window’s end.
After failing to achieve expected output with MSVC, my mentor got me in contact with MSVC team. I shared my doubts and sought out ways to implement them.
Unfortunately, MSVC does not provide any elegant way of initializing the HPX runtime system. After exchanging a few emails, we came down to 2 ways of implementing it.
Re-implementing the mainCRTStartup which is the entry point of an exe file. Implementing the function in a separate file any compiling it to an obj file and further linking it at link time will make sure that my implementation of mainCRTStartup is run as opposed to MSVC’s implementation.
While this method will make for an elegant solution, there are some serious maintenance issues that needs to be resolved. Firstly, there is a question of portability amongst different architecture. There is a need to re-write code specific to every architecture. Secondly, the code for the function changes quite often. This would mean that I will have to keep the multiple implementation of the function for different versions of MSVC Compiler.
I’m currently trying to explore this method in depth to understand its feasibility.
It involves using #pragma init_seg. It can allow users to inject code at various steps of the program. While this looks lucrative at first glance, we cannot force it to run after all the user defined global objects have been constructed. We can run, however, run before it.
While running it before all the global objects using hpx_start will register the kernel thread with HPX thread, I would still not be able to use all the functionality that it provides. With that said, one could always use run_on_hpx_thread() since global objects and main are registered with the HPX runtime system (but are not running on it!). This method is similar to the one provided in init_globally example.
I’m exploring this method in depth as well.
While implementing for Linux and Mac OSX, I came up with an idea of having a custom init function for the HPX library. If you’re not familiar with the purpose of init function, then in short, it is responsible for initializing the .init_array section and also calling the constructors of global objects. Basically, it deals with all the initializations relating to global scope variables and objects. If we implement an init function for HPX then we could deal with certain global scope initializations and run them on HPX thread as well.
That’s what I’ll be focusing on in the future along with MSVC implementation.
Until next time, I bid you farewell!