* after resolving ELF shared library symbols
*
* Copyright (C) 2005 by Joakim Tjernlund
- * Copyright (C) 2000-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2000-2006 by Erik Andersen <andersen@codepoet.org>
* Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
* David Engel, Hongjiu Lu and Mitch D'Souza
*
#include "dl-startup.h"
/* Static declarations */
-int (*_dl_elf_main) (int, char **, char **);
-
-
+static int (*_dl_elf_main) (int, char **, char **);
+static void* __rtld_stack_end; /* Points to argc on stack, e.g *((long *)__rtld_stackend) == argc */
+strong_alias(__rtld_stack_end, __libc_stack_end) /* Exported version of __rtld_stack_end */
/* When we enter this piece of code, the program stack looks like this:
- argc argument counter (integer)
- argv[0] program name (pointer)
- argv[1...N] program args (pointers)
- argv[argc-1] end of args (integer)
- NULL
- env[0...N] environment variables (pointers)
- NULL
- auxvt[0...N] Auxiliary Vector Table elements (mixed types)
+ argc argument counter (integer)
+ argv[0] program name (pointer)
+ argv[1..argc-1] program args (pointers)
+ NULL
+ env[0...N] environment variables (pointers)
+ NULL
+ auxvt[0...N] Auxiliary Vector Table elements (mixed types)
*/
-static void * __attribute_used__ _dl_start(unsigned long args)
+DL_START(unsigned long args)
{
unsigned int argc;
char **argv, **envp;
- unsigned long load_addr;
- Elf32_Addr got;
+ DL_LOADADDR_TYPE load_addr;
+ ElfW(Addr) got;
unsigned long *aux_dat;
- int goof = 0;
ElfW(Ehdr) *header;
struct elf_resolve tpnt_tmp;
struct elf_resolve *tpnt = &tpnt_tmp;
- Elf32_auxv_t auxvt[AT_EGID + 1];
- Elf32_Dyn *dpnt;
- int indx;
+ ElfW(auxv_t) auxvt[AT_EGID + 1];
+ ElfW(Dyn) *dpnt;
+ uint32_t *p32;
- /* WARNING! -- we cannot make _any_ funtion calls until we have
+ /* WARNING! -- we cannot make _any_ function calls until we have
* taken care of fixing up our own relocations. Making static
* inline calls is ok, but _no_ function calls. Not yet
* anyways. */
/* First obtain the information on the stack that tells us more about
what binary is loaded, where it is loaded, etc, etc */
GET_ARGV(aux_dat, args);
- argc = *(aux_dat - 1);
+ argc = aux_dat[-1];
argv = (char **) aux_dat;
aux_dat += argc; /* Skip over the argv pointers */
aux_dat++; /* Skip over NULL at end of argv */
envp = (char **) aux_dat;
+#if !defined(NO_EARLY_SEND_STDERR)
+ SEND_EARLY_STDERR_DEBUG("argc=");
+ SEND_NUMBER_STDERR_DEBUG(argc, 0);
+ SEND_EARLY_STDERR_DEBUG(" argv=");
+ SEND_ADDRESS_STDERR_DEBUG(argv, 0);
+ SEND_EARLY_STDERR_DEBUG(" envp=");
+ SEND_ADDRESS_STDERR_DEBUG(envp, 1);
+#endif
while (*aux_dat)
aux_dat++; /* Skip over the envp pointers */
aux_dat++; /* Skip over NULL at end of envp */
* the Auxiliary Vector Table. Read out the elements of the auxvt,
* sort and store them in auxvt for later use. */
while (*aux_dat) {
- Elf32_auxv_t *auxv_entry = (Elf32_auxv_t *) aux_dat;
+ ElfW(auxv_t) *auxv_entry = (ElfW(auxv_t) *) aux_dat;
if (auxv_entry->a_type <= AT_EGID) {
- _dl_memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(Elf32_auxv_t));
+ _dl_memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(ElfW(auxv_t)));
}
aux_dat += 2;
}
* (esp since SEND_STDERR() needs this on some platforms... */
if (!auxvt[AT_BASE].a_un.a_val)
auxvt[AT_BASE].a_un.a_val = elf_machine_load_address();
- load_addr = auxvt[AT_BASE].a_un.a_val;
- header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_ptr;
+ DL_INIT_LOADADDR_BOOT(load_addr, auxvt[AT_BASE].a_un.a_val);
+ header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_val;
/* Check the ELF header to make sure everything looks ok. */
- if (!header || header->e_ident[EI_CLASS] != ELFCLASS32 ||
+ if (!header || header->e_ident[EI_CLASS] != ELF_CLASS ||
header->e_ident[EI_VERSION] != EV_CURRENT
/* Do not use an inline _dl_strncmp here or some arches
* will blow chunks, i.e. those that need to relocate all
* string constants... */
- || header->e_ident[EI_MAG0] != ELFMAG0
- || header->e_ident[EI_MAG1] != ELFMAG1
- || header->e_ident[EI_MAG2] != ELFMAG2
- || header->e_ident[EI_MAG3] != ELFMAG3)
- {
- SEND_STDERR("Invalid ELF header\n");
+ || *(p32 = (uint32_t*)&header->e_ident) != ELFMAG_U32
+ ) {
+ SEND_EARLY_STDERR("Invalid ELF header\n");
_dl_exit(0);
}
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
- SEND_STDERR("ELF header=");
- SEND_ADDRESS_STDERR(load_addr, 1);
-#endif
-
+ SEND_EARLY_STDERR_DEBUG("ELF header=");
+ SEND_ADDRESS_STDERR_DEBUG(DL_LOADADDR_BASE(load_addr), 1);
/* Locate the global offset table. Since this code must be PIC
* we can take advantage of the magic offset register, if we
* happen to know what that is for this architecture. If not,
* we can always read stuff out of the ELF file to find it... */
- got = elf_machine_dynamic();
- dpnt = (Elf32_Dyn *) (got + load_addr);
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
- SEND_STDERR("First Dynamic section entry=");
- SEND_ADDRESS_STDERR(dpnt, 1);
-#endif
+ DL_BOOT_COMPUTE_GOT(got);
+
+ /* Now, finally, fix up the location of the dynamic stuff */
+ DL_BOOT_COMPUTE_DYN(dpnt, got, load_addr);
+
+ SEND_EARLY_STDERR_DEBUG("First Dynamic section entry=");
+ SEND_ADDRESS_STDERR_DEBUG(dpnt, 1);
_dl_memset(tpnt, 0, sizeof(struct elf_resolve));
tpnt->loadaddr = load_addr;
/* OK, that was easy. Next scan the DYNAMIC section of the image.
We are only doing ourself right now - we will have to do the rest later */
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
- SEND_STDERR("scanning DYNAMIC section\n");
-#endif
+ SEND_EARLY_STDERR_DEBUG("Scanning DYNAMIC section\n");
tpnt->dynamic_addr = dpnt;
-#if defined(__mips__) || defined(__cris__)
+#if defined(NO_FUNCS_BEFORE_BOOTSTRAP)
/* Some architectures cannot call functions here, must inline */
__dl_parse_dynamic_info(dpnt, tpnt->dynamic_info, NULL, load_addr);
#else
_dl_parse_dynamic_info(dpnt, tpnt->dynamic_info, NULL, load_addr);
#endif
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
- SEND_STDERR("done scanning DYNAMIC section\n");
+ /*
+ * BIG ASSUMPTION: We assume that the dynamic loader does not
+ * have any TLS data itself. If this ever occurs
+ * more work than what is done below for the
+ * loader will have to happen.
+ */
+#if defined(USE_TLS) && USE_TLS
+ /* This was done by _dl_memset above. */
+ /* tpnt->l_tls_modid = 0; */
+# if NO_TLS_OFFSET != 0
+ tpnt->l_tls_offset = NO_TLS_OFFSET;
+# endif
#endif
-#ifndef __FORCE_SHAREABLE_TEXT_SEGMENTS__
- /* Ugly, ugly. We need to call mprotect to change the protection of
- the text pages so that we can do the dynamic linking. We can set the
- protection back again once we are done */
+ SEND_EARLY_STDERR_DEBUG("Done scanning DYNAMIC section\n");
- {
- ElfW(Phdr) *ppnt;
- int i;
-
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
- SEND_STDERR("calling mprotect on the shared library/dynamic linker\n");
-#endif
-
- /* First cover the shared library/dynamic linker. */
- if (tpnt->dynamic_info[DT_TEXTREL]) {
- header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_ptr;
- ppnt = (ElfW(Phdr) *) ((int)auxvt[AT_BASE].a_un.a_ptr +
- header->e_phoff);
- for (i = 0; i < header->e_phnum; i++, ppnt++) {
- if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) {
- _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & PAGE_ALIGN)),
- (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz,
- PROT_READ | PROT_WRITE | PROT_EXEC);
- }
- }
- }
- }
-#endif
-#ifdef PERFORM_BOOTSTRAP_GOT
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
- SEND_STDERR("About to do specific GOT bootstrap\n");
-#endif
- /* For MIPS we have to do stuff to the GOT before we do relocations. */
+#if defined(PERFORM_BOOTSTRAP_GOT)
+ SEND_EARLY_STDERR_DEBUG("About to do specific GOT bootstrap\n");
+ /* some arches (like MIPS) we have to tweak the GOT before relocations */
PERFORM_BOOTSTRAP_GOT(tpnt);
#endif
+#if !defined(PERFORM_BOOTSTRAP_GOT) || defined(__avr32__)
+
/* OK, now do the relocations. We do not do a lazy binding here, so
that once we are done, we have considerably more flexibility. */
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
- SEND_STDERR("About to do library loader relocations\n");
-#endif
-#ifdef ELF_MACHINE_PLTREL_OVERLAP
+ SEND_EARLY_STDERR_DEBUG("About to do library loader relocations\n");
+
+ {
+ int indx;
+#if defined(ELF_MACHINE_PLTREL_OVERLAP)
# define INDX_MAX 1
#else
# define INDX_MAX 2
#endif
- goof = 0;
- for (indx = 0; indx < INDX_MAX; indx++) {
- unsigned int i;
- unsigned long *reloc_addr;
- unsigned long symbol_addr;
- int symtab_index;
- Elf32_Sym *sym;
- ELF_RELOC *rpnt;
- unsigned long rel_addr, rel_size;
- Elf32_Word relative_count = tpnt->dynamic_info[DT_RELCONT_IDX];
-
- rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->
- dynamic_info[DT_RELOC_TABLE_ADDR]);
- rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->
- dynamic_info[DT_RELOC_TABLE_SIZE]);
-
- if (!rel_addr)
- continue;
-
- /* Now parse the relocation information */
- /* Since ldso is linked with -Bsymbolic, all relocs will be RELATIVE(for those archs that have
- RELATIVE relocs) which means that the for(..) loop below has noting to do and can be deleted.
- Possibly one should add a HAVE_RELATIVE_RELOCS directive and #ifdef away some code. */
- if (!indx && relative_count) {
- rel_size -= relative_count * sizeof(ELF_RELOC);
- elf_machine_relative (load_addr, rel_addr, relative_count);
- rel_addr += relative_count * sizeof(ELF_RELOC);;
- }
+ for (indx = 0; indx < INDX_MAX; indx++) {
+ unsigned long rel_addr, rel_size;
+ ElfW(Word) relative_count = tpnt->dynamic_info[DT_RELCONT_IDX];
+
+ rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] :
+ tpnt->dynamic_info[DT_RELOC_TABLE_ADDR]);
+ rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] :
+ tpnt->dynamic_info[DT_RELOC_TABLE_SIZE]);
+
+ if (!rel_addr)
+ continue;
+
+ if (!indx && relative_count) {
+ rel_size -= relative_count * sizeof(ELF_RELOC);
+ elf_machine_relative(load_addr, rel_addr, relative_count);
+ rel_addr += relative_count * sizeof(ELF_RELOC);
+ }
- rpnt = (ELF_RELOC *) (rel_addr + load_addr);
- for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) {
- reloc_addr = (unsigned long *) (load_addr + (unsigned long) rpnt->r_offset);
- symtab_index = ELF32_R_SYM(rpnt->r_info);
- symbol_addr = 0;
- sym = NULL;
- if (symtab_index) {
- char *strtab;
- Elf32_Sym *symtab;
-
- symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
- strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
- sym = &symtab[symtab_index];
- symbol_addr = load_addr + sym->st_value;
-
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
- SEND_STDERR("relocating symbol: ");
- SEND_STDERR(strtab + sym->st_name);
- SEND_STDERR("\n");
+ /*
+ * Since ldso is linked with -Bsymbolic, all relocs should be RELATIVE. All archs
+ * that need bootstrap relocations need to define ARCH_NEEDS_BOOTSTRAP_RELOCS.
+ */
+#ifdef ARCH_NEEDS_BOOTSTRAP_RELOCS
+ {
+ ELF_RELOC *rpnt;
+ unsigned int i;
+ ElfW(Sym) *sym;
+ unsigned long symbol_addr;
+ int symtab_index;
+ unsigned long *reloc_addr;
+
+ /* Now parse the relocation information */
+ rpnt = (ELF_RELOC *) rel_addr;
+ for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) {
+ reloc_addr = (unsigned long *) DL_RELOC_ADDR(load_addr, (unsigned long)rpnt->r_offset);
+ symtab_index = ELF_R_SYM(rpnt->r_info);
+ symbol_addr = 0;
+ sym = NULL;
+ if (symtab_index) {
+ char *strtab;
+ ElfW(Sym) *symtab;
+
+ symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
+ strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
+ sym = &symtab[symtab_index];
+ symbol_addr = (unsigned long) DL_RELOC_ADDR(load_addr, sym->st_value);
+#if !defined(EARLY_STDERR_SPECIAL)
+ SEND_STDERR_DEBUG("relocating symbol: ");
+ SEND_STDERR_DEBUG(strtab + sym->st_name);
+ SEND_STDERR_DEBUG("\n");
#endif
+ } else {
+ SEND_STDERR_DEBUG("relocating unknown symbol\n");
+ }
+ /* Use this machine-specific macro to perform the actual relocation. */
+ PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr, sym);
+ }
+ }
+#else /* ARCH_NEEDS_BOOTSTRAP_RELOCS */
+ if (rel_size) {
+ SEND_EARLY_STDERR("Cannot continue, found non relative relocs during the bootstrap.\n");
+ _dl_exit(14);
}
- /* Use this machine-specific macro to perform the actual relocation. */
- PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr, sym);
+#endif
}
}
-
- if (goof) {
- _dl_exit(14);
- }
-
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
- /* Wahoo!!! */
- SEND_STDERR("Done relocating library loader, so we can now\n"
- "\tuse globals and make function calls!\n");
#endif
+ SEND_STDERR_DEBUG("Done relocating ldso; we can now use globals and make function calls!\n");
+
/* Now we have done the mandatory linking of some things. We are now
free to start using global variables, since these things have all been
- fixed up by now. Still no function calls outside of this library ,
+ fixed up by now. Still no function calls outside of this library,
since the dynamic resolver is not yet ready. */
- _dl_get_ready_to_run(tpnt, load_addr, auxvt, envp, argv);
+ __rtld_stack_end = (void *)(argv - 1);
+
+ _dl_get_ready_to_run(tpnt, load_addr, auxvt, envp, argv
+ DL_GET_READY_TO_RUN_EXTRA_ARGS);
/* Transfer control to the application. */
-#ifdef __SUPPORT_LD_DEBUG_EARLY__
- SEND_STDERR("transfering control to application\n");
-#endif
- _dl_elf_main = (int (*)(int, char **, char **)) auxvt[AT_ENTRY].a_un.a_fcn;
+ SEND_STDERR_DEBUG("transfering control to application @ ");
+ _dl_elf_main = (int (*)(int, char **, char **)) auxvt[AT_ENTRY].a_un.a_val;
+ SEND_ADDRESS_STDERR_DEBUG(_dl_elf_main, 1);
+
+#if !defined(START)
+ return _dl_elf_main;
+#else
START();
+#endif
}
-