(On Unix variants the term loader is often used as a synonym for linker, blurring the distinction between the compile-time process, and the run-time process. Although these processes are somewhat similar, this article will still use linking for the former and loading for the latter.)
The objects are program modules containing machine code and information for the linker. This information comes mainly in the form of symbol definitions, which come in two varieties:
Linkers can take objects from a collection called a library. The advantage of such a collection over a single big object is that the final program does not include the whole library, only those objects from it that are needed (define relevant symbols). Libraries for diverse purposes exist, and one or more system libraries are usually linked in by default.
The linker also takes care of arranging the objects in a program's address space. This may involve relocating code that assumes a specific base address to another base. Since a compiler seldom knows where an object will reside, it often assumes a fixed base location (for example, zero). Relocating machine code may involve re-targeting of absolute jumps, loads and stores.
The executable output by the linker may need another relocation pass when it is finally loaded into memory (just before execution). On hardware offering virtual memory this is usually omitted, though -- every program is put into its own address space, so there is no conflict even if all programs load at the same base address.
Modern operating system environments allow dynamic linking, that is the postponing of the resolving of some undefined symbols until a program is run. That means that the executable still contains undefined symbols, plus a list of objects or libraries that will provide definitions for these. Loading the program will load these objects/libraries as well, and perform a final linking.
This approach offers two advantages: