Always cool to see people hacking ELF! I see you're using argv[0] to find the executable file. This is fragile because argument vector contents are arbitrary and controlled entirely by the parent process. In other words, argv[0] could contain anything, even an empty string. If you're targeting Linux specifically, there's a better way: /proc/self/exe.
I created something similar to your tool: an ELF embedder. It's for arbitrary data rather than native code injection.
I leveraged ELF segments to get the kernel to mmap the data into memory on my behalf, no file I/O needed. The auxvec allows the program to reach its own program header table. From there it's just a matter of finding the right segment.
https://www.matheusmoreira.com/articles/self-contained-lone-...
My programming language's interpreter introspects into its own ELF header, finds the embedded segments and uses them to load data and code from inside itself.
I'm not entirely sure whether this approach is applicable to your case but it might be worth a try. My embedding tool could just as easily map in executable segments.