Link time optimization and link time code generation
This technique is unsurprisingly called link-time optimization (LTO) and exploits the fact that the linker will see the whole of the program when it's finished linking. But linkers are not optimizers, so what could be done here? The trick is to call back the compiler to do the optimizations! For that, the object files emitted by the compiler do not contain machine code, but the intermediate representation (IR) of the code. The linker puts all of the parts of the program together and then calls back the compiler to optimize the whole program. For that reason, this technique is also called link-time code generation (LTCG), as the compiler will generate the final machine code only in the link phase.
Sounds complicated? Yes, and it has a couple of problems too: it is very slow, and it requires large amounts of memory, which can be prohibitive for large programs and smaller machines. Additionally, it kills incremental linking. There are attempts to fight these problems. For example, ThinLTO keeps all of the compilation units separate, but imports information about external functions in each unit, this is able to parallelize the optimizations. The GCC compiler contained in MinGW supports base LTO.
Another optimization linkers can do is removing duplicate function definitions, which decreases the size of the executable and improves the code locality. This is known in the Windows world as identical COMDAT folding (ICF) and is supported by GCC linker.