it’s a bit unfair to call fixups a “hack”, and in fact they never fail (DLL hell has another cause entirely). Fixing up object code at load time is no different to the routine relocations linkers routinely do when merging compiled object files (for example, when loading static object code libraries).
To be fair to Microsoft, the standard set of Windows system DLLs always had carefully predefined load addresses so that collisions were rare (and when they did occur they could be statically relocated at load time), which typically meant they COULD be shared across processes via shared copy-on-write pages. It was only when random-address loading was added as an anti-virus measure that pic became desirable/necessary.
And it should be remembered that pic has runtime overhead (slower execution) as the compiler must generate extra code in many cases.