Avoiding fixed code addresses
Instructions can embed absolute addresses, use relative displacements or load addresses indirectly. Position-independent code uses suitable addressing and reference sequences so moving the code does not require rewriting every reference in its instruction bytes.
External addresses can still depend on linking or loading. ELF shared objects can use a global offset table for indirection and a procedure linkage table for calls. Exact instructions and table layouts depend on the processor ABI rather than a universal sequence.
Building shared objects and executables
GCC -fpic and -fPIC generate position-independent code suitable for shared objects on supported targets, with target-dependent code-model or table-size differences. The -fpie and -fPIE forms target executables and usually pair with -pie at link time. Compilation and linking are distinct steps.
Position independence does not necessarily require a dynamic linker. On supported platforms, GCC -static-pie produces a static position-independent executable that can load at different addresses without one. Availability and startup details remain platform and toolchain dependent.
Relocation and randomization remain separate
Relative displacements can remain valid when code moves as a unit, but pointers stored in data and references to external symbols can still need relocation. Position independence does not imply that the file contains no fixups.
Address randomization is a loading-policy choice. Position independence supports flexible placement without proving that a system actually randomizes it. Nor is it an automatic speed or security guarantee: indirection, code models, permissions and program defects remain separate concerns.