OSDN Git Service

Merge remote-tracking branch 'origin/master' into prelink
[uclinux-h8/uClibc.git] / ldso / ldso / dl-elf.c
index 505247e..a881b7d 100644 (file)
@@ -322,7 +322,7 @@ goof:
  */
 
 struct elf_resolve *_dl_load_elf_shared_library(int secure,
-       struct dyn_elf **rpnt, char *libname)
+       struct dyn_elf **rpnt, const char *libname)
 {
        ElfW(Ehdr) *epnt;
        unsigned long dynamic_addr = 0;
@@ -343,7 +343,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
        size_t relro_size = 0;
        struct stat st;
        uint32_t *p32;
-       DL_LOADADDR_TYPE lib_loadaddr;
+       DL_LOADADDR_TYPE lib_loadaddr = 0;
        DL_INIT_LOADADDR_EXTRA_DECLS
 
        libaddr = 0;
@@ -397,11 +397,15 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
                return NULL;
        }
 
-       if ((epnt->e_type != ET_DYN) || (epnt->e_machine != MAGIC1
+       if ((epnt->e_type != ET_DYN
+#ifdef __LDSO_STANDALONE_SUPPORT__
+               && epnt->e_type != ET_EXEC
+#endif
+               ) || (epnt->e_machine != MAGIC1
 #ifdef MAGIC2
                                && epnt->e_machine != MAGIC2
 #endif
-                               ))
+                       ))
        {
                _dl_internal_error_number =
                        (epnt->e_type != ET_DYN ? LD_ERROR_NOTDYN : LD_ERROR_NOTMAGIC);
@@ -426,7 +430,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 
                if (ppnt->p_type == PT_LOAD) {
                        /* See if this is a PIC library. */
-                       if (i == 0 && ppnt->p_vaddr > 0x1000000) {
+                       if (minvma == 0xffffffff && ppnt->p_vaddr > 0x1000000) {
                                piclib = 0;
                                minvma = ppnt->p_vaddr;
                        }
@@ -462,14 +466,17 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
                ppnt++;
        }
 
+#ifdef __LDSO_STANDALONE_SUPPORT__
+       if (epnt->e_type == ET_EXEC)
+               piclib = 0;
+#endif
+
        DL_CHECK_LIB_TYPE (epnt, piclib, _dl_progname, libname);
 
        maxvma = (maxvma + ADDR_ALIGN) & PAGE_ALIGN;
        minvma = minvma & ~ADDR_ALIGN;
 
        flags = MAP_PRIVATE /*| MAP_DENYWRITE */ ;
-       if (!piclib)
-               flags |= MAP_FIXED;
 
        if (piclib == 0 || piclib == 1) {
                status = (char *) _dl_mmap((char *) (piclib ? 0 : minvma),
@@ -488,7 +495,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
        /* Get the memory to store the library */
        ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff];
 
-       DL_INIT_LOADADDR(lib_loadaddr, libaddr, ppnt, epnt->e_phnum);
+       DL_INIT_LOADADDR(lib_loadaddr, libaddr - minvma, ppnt, epnt->e_phnum);
 
        for (i = 0; i < epnt->e_phnum; i++) {
                if (DL_IS_SPECIAL_SEGMENT (epnt, ppnt)) {
@@ -510,12 +517,6 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
                        char *tryaddr;
                        ssize_t size;
 
-                       /* See if this is a PIC library. */
-                       if (i == 0 && ppnt->p_vaddr > 0x1000000) {
-                               piclib = 0;
-                               /* flags |= MAP_FIXED; */
-                       }
-
                        if (ppnt->p_flags & PF_W) {
                                unsigned long map_size;
                                char *cpnt;
@@ -559,7 +560,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
                                  }
 
                                tryaddr = piclib == 2 ? piclib2map
-                                 : ((char*) (piclib ? libaddr : 0) +
+                                 : ((char*) (piclib ? libaddr : lib_loadaddr) +
                                     (ppnt->p_vaddr & PAGE_ALIGN));
 
                                size = (ppnt->p_vaddr & ADDR_ALIGN)
@@ -644,7 +645,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 
                                if (map_size < ppnt->p_vaddr + ppnt->p_memsz
                                    && !piclib2map) {
-                                       tryaddr = map_size + (char*)(piclib ? libaddr : 0);
+                                       tryaddr = map_size + (char*)(piclib ? libaddr : lib_loadaddr);
                                        status = (char *) _dl_mmap(tryaddr,
                                                ppnt->p_vaddr + ppnt->p_memsz - map_size,
                                                LXFLAGS(ppnt->p_flags), flags | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
@@ -655,7 +656,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
                        } else {
                                tryaddr = (piclib == 2 ? 0
                                           : (char *) (ppnt->p_vaddr & PAGE_ALIGN)
-                                          + (piclib ? libaddr : 0));
+                                          + (piclib ? libaddr : lib_loadaddr));
                                size = (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz;
                                status = (char *) _dl_mmap
                                           (tryaddr, size, LXFLAGS(ppnt->p_flags),
@@ -679,8 +680,11 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
        }
        _dl_close(infile);
 
-       /* For a non-PIC library, the addresses are all absolute */
-       if (piclib) {
+       /*
+        * The dynamic_addr must be take into acount lib_loadaddr value, to note
+        * it is zero when the SO has been mapped to the elf's physical addr
+        */
+       if (lib_loadaddr) {
                dynamic_addr = (unsigned long) DL_RELOC_ADDR(lib_loadaddr, dynamic_addr);
        }
 
@@ -711,7 +715,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
                ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff];
                for (i = 0; i < epnt->e_phnum; i++, ppnt++) {
                        if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) {
-                               _dl_mprotect((void *) ((piclib ? libaddr : 0) +
+                               _dl_mprotect((void *) ((piclib ? libaddr : lib_loadaddr) +
                                                        (ppnt->p_vaddr & PAGE_ALIGN)),
                                                (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz,
                                                PROT_READ | PROT_WRITE | PROT_EXEC);
@@ -727,13 +731,17 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 
        tpnt = _dl_add_elf_hash_table(libname, lib_loadaddr, dynamic_info,
                        dynamic_addr, 0);
+       tpnt->mapaddr = libaddr;
        tpnt->relro_addr = relro_addr;
        tpnt->relro_size = relro_size;
        tpnt->st_dev = st.st_dev;
        tpnt->st_ino = st.st_ino;
-       tpnt->ppnt = (ElfW(Phdr) *) DL_RELOC_ADDR(tpnt->loadaddr, epnt->e_phoff);
+       tpnt->ppnt = (ElfW(Phdr) *) DL_RELOC_ADDR(tpnt->mapaddr, epnt->e_phoff);
        tpnt->n_phent = epnt->e_phnum;
        tpnt->rtld_flags |= rtld_flags;
+#ifdef __LDSO_STANDALONE_SUPPORT__
+       tpnt->l_entry = epnt->e_entry;
+#endif
 
 #if defined(USE_TLS) && USE_TLS
        if (tlsppnt) {
@@ -755,7 +763,11 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
                tpnt->l_tls_modid = _dl_next_tls_modid ();
 
                /* We know the load address, so add it to the offset. */
+#ifdef __LDSO_STANDALONE_SUPPORT__
+               if ((tpnt->l_tls_initimage != NULL) && piclib)
+#else
                if (tpnt->l_tls_initimage != NULL)
+#endif
                {
 # ifdef __SUPPORT_LD_DEBUG_EARLY__
                        unsigned int tmp = (unsigned int) tpnt->l_tls_initimage;
@@ -772,7 +784,12 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
        /*
         * Add this object into the symbol chain
         */
-       if (*rpnt) {
+       if (*rpnt
+#ifdef __LDSO_STANDALONE_SUPPORT__
+               /* Do not create a new chain entry for the main executable */
+               && (*rpnt)->dyn
+#endif
+               ) {
                (*rpnt)->next = _dl_malloc(sizeof(struct dyn_elf));
                _dl_memset((*rpnt)->next, 0, sizeof(struct dyn_elf));
                (*rpnt)->next->prev = (*rpnt);
@@ -789,9 +806,12 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
        }
 #endif
        (*rpnt)->dyn = tpnt;
-       tpnt->symbol_scope = _dl_symbol_tables;
        tpnt->usage_count++;
+#ifdef __LDSO_STANDALONE_SUPPORT__
+       tpnt->libtype = (epnt->e_type == ET_DYN) ? elf_lib : elf_executable;
+#else
        tpnt->libtype = elf_lib;
+#endif
 
        /*
         * OK, the next thing we need to do is to insert the dynamic linker into
@@ -865,7 +885,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 }
 
 /* now_flag must be RTLD_NOW or zero */
-int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
+int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int now_flag)
 {
        int goof = 0;
        struct elf_resolve *tpnt;
@@ -873,7 +893,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
        ElfW(Addr) reloc_addr;
 
        if (rpnt->next)
-               goof = _dl_fixup(rpnt->next, now_flag);
+               goof = _dl_fixup(rpnt->next, scope, now_flag);
        if (goof)
                return goof;
        tpnt = rpnt->dyn;
@@ -900,10 +920,15 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
                relative_count = tpnt->dynamic_info[DT_RELCONT_IDX];
                if (relative_count) { /* Optimize the XX_RELATIVE relocations if possible */
                        reloc_size -= relative_count * sizeof(ELF_RELOC);
-                       elf_machine_relative(tpnt->loadaddr, reloc_addr, relative_count);
+                       if (tpnt->loadaddr
+#ifdef __LDSO_PRELINK_SUPPORT__
+                               || (!tpnt->dynamic_info[DT_GNU_PRELINKED_IDX])
+#endif
+                               )
+                               elf_machine_relative(tpnt->loadaddr, reloc_addr, relative_count);
                        reloc_addr += relative_count * sizeof(ELF_RELOC);
                }
-               goof += _dl_parse_relocation_information(rpnt,
+               goof += _dl_parse_relocation_information(rpnt, scope,
                                reloc_addr,
                                reloc_size);
                tpnt->init_flag |= RELOCS_DONE;
@@ -919,7 +944,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
                                        tpnt->dynamic_info[DT_JMPREL],
                                        tpnt->dynamic_info [DT_PLTRELSZ]);
                } else {
-                       goof += _dl_parse_relocation_information(rpnt,
+                       goof += _dl_parse_relocation_information(rpnt, scope,
                                        tpnt->dynamic_info[DT_JMPREL],
                                        tpnt->dynamic_info[DT_PLTRELSZ]);
                }