On the Uno and similar AVR-based boards, the compiler and assembler are
not aware of the bootloader. The compiled program starts at address
zero. There you have the interrupt vector table, starting with the reset
vector. That vector is a jump to the C runtime startup code, which does
some low-level initialization, then calls
main() from the Arduino core
library, which calls
loop() from your sketch.
The bootloader lives at the end of the flash. The AVR chip has a few
bytes of non-volatile configuration memory called “fuses”. These bytes
are configured by the Arduino board maker to dedicate the last
512 bytes of flash to the bootloader, and to start executing the
code at the start of the bootloader on power up and on reset events. It
is then the bootloader's responsibility to jump to address zero in order
to start the user's program.