Table of Contents
The kernel loads some bytes of the binary to start and tries to determine it's file type. Therefor, it calls a number of binary handlers (which try to detect their specific binary signature). Two are commonly called:
First, there's the script handler. It matches if the binary starts with "#!", the so-called "shell bang". The script handler then copies the remaining rest of the very first (shell bang) line and starts whatever is mentioned there, plus the script's file name.
Second, there is the ELF binary handler. If it finds the ELF signature, it calls the "interpreter" mentioned inside the ELF binary.
The ELF interpreter (it's only called an interpreter, it isn't in real life) is most of the time /lib/ld-linux.so.2, the dynamic loader of GNU's glibc. It's always the "library" with absolute path that is printed by "ldd /path/to/binary". Procedure is the same as for scripts: the "interpreter" is called with the binary to start as it's command line argument. That is, you can manually call the dynamic ELF interpreter by hand: /lib/ld-linux.so.2 /bin/ls
The interpreter's task is to finally link the program. Remember, it's dynamically linked. That said, it needs to load the binary into proper memory locations and do the same for all needed libraries. Proper addresses are partially coded into the binary, partially they're just calculated.
For speed (and resource) reasons, ld-linux.so.2 doesn't just load all the binary into RAM, but uses a trick. It calls mmap() to do some kind of projection of the binary. This way, the kernel "knows" where the file's parts need to be inside RAM, but may decide to load them as they're needed.
After all the executable's needed parts (the executable ("text") section, the data sections, constructors and destructors, ...), ld-linux.so.2 jumps to the libc's entry point within the program. libc then starts all constructors (if there are any) and finally calls the main() function, which is the programs starting function from the programmer's point of view.