gcc has all kind of options to control how it works. Here's a few relevant ones:
-nostdlib
to omit linking to the standard libraries and startup code-nostdinc
to omit searching for header files in the standard locations.-ffreestanding
to compile for a freestanding environment (such as a kernel)
You also do not need to use gcc for linking. You can invoke the linker directly, supply it with your own linker map, startup object code, and anything else you need.
The linux kernel build seems, for arbitrary reasons not to use -ffreestanding
, it does control the linking stage though, and ensures the kernel gets linked without pulling in any userspace code.