I know both are used to make code that can be placed in different locations, but how does each work, and why?
For starters, they are options to different parts of the toolchain:
-fPICare GCC options that generates position-independent code. This affects the actual instructions chosen, to make the code run regardless of where it is located in memory. This requires support by the operating system's dynamic loader to actually make it runnable once loaded.
-ris a linker option that makes it emit relocatable code, i.e. code that can be linked again later on. It's part of ld's support for incremental linking.
I think their usage doesn't overlap, you can create relocatable (library) code without using