You can always populate .init_array section with a hidden constructor. It would work just like ifunc and would always execute at shared library load time.
I think .init_array is too late in the game. ifunc lets you hijack the loader, because it is sort of like a plugin or dynamic config for the loader itself. Everything should be loaded and resolved by the point that .init_array stuff starts getting triggered, though ELF is dark and full of terrors so who knows really.