I did a fair amount of grepping and munging around to get a partial answer to this question. It seems part of the answer is in fs/binfmt_elf.c; load_elf_binary() calls load_elf_interp(), which in turn sets up /lib/ld-linux.so.2 to do the actual work. I suspect that the code for ld-linux is in glibc-2.4.tar.gz which you can get here:
http://directory.fsf.org/GNU/glibc.html , but I haven't pinned down where yet.
The reason I know that the interpreter is /lib/ld-linux.so.2 is this:
Code:
$ objdump -p hw | grep -A1 INTERP
INTERP off 0x00000114 vaddr 0x08048114 paddr 0x08048114 align 2**0
filesz 0x00000013 memsz 0x00000013 flags r--
$ dd if=hw bs=1 count=19 skip=276 2>/dev/null; echo
/lib/ld-linux.so.2
(0x114 is 276 and 0x13 is 19) You can see load_elf_binary() reading this string from the file analogously to my dd command:
Code:
if (elf_ppnt->p_type == PT_INTERP) {
/* skip a bit */
retval = kernel_read(bprm->file, elf_ppnt->p_offset,
elf_interpreter,
elf_ppnt->p_filesz);
If you strace the executable (mine is just 'hello world'), you'll see the loader mmapping shared libraries:
Code:
$ strace ./hw
execve("./hw", ["./hw"], [/* 40 vars */]) = 0
/* skip a bit... */
open("/lib/tls/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320O\1"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1266800, ...}) = 0
old_mmap(NULL, 1272764, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7e6a000
/* more... */
So ultimately, the code to load a shared library is just an mmap(), after read()ing the elf header from the library. See 'man 5 elf' for the elf format.
I would feel a lot more confident of everything I just wrote if I had disected ld-linux. I haven't, so take it all with several grains of salt...