OSDN Git Service

ldso: fix fdpic support broken from prelink patch
authorFilippo Arcidiacono <filippo.arcidiacono@st.com>
Fri, 6 Apr 2012 09:18:35 +0000 (11:18 +0200)
committerMike Frysinger <vapier@gentoo.org>
Sun, 8 Apr 2012 04:49:16 +0000 (00:49 -0400)
The fdpic support has been broken since the prelink support was added,
because it didn't take into account DL_LOADADDR_TYPE could be a different
type of ElfW(Addr).

Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono@st.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
ldso/include/dl-defs.h
ldso/ldso/c6x/dl-sysdep.h
ldso/ldso/dl-elf.c
ldso/ldso/dl-startup.c
ldso/ldso/fdpic/dl-sysdep.h
ldso/ldso/ldso.c

index 11edc4d..f71ba9b 100644 (file)
@@ -259,4 +259,26 @@ typedef struct {
 # define DL_MAP_SEGMENT(EPNT, PPNT, INFILE, FLAGS) 0
 #endif
 
+/* Define this to declare the library offset. */
+#ifndef DL_DEF_LIB_OFFSET
+# define DL_DEF_LIB_OFFSET static unsigned long _dl_library_offset
+#endif
+
+/* Define this to get the library offset. */
+#ifndef DL_GET_LIB_OFFSET
+# define DL_GET_LIB_OFFSET() _dl_library_offset
+#endif
+
+/* Define this to set the library offset  as difference beetwen the mapped
+   library address and the smallest virtual address of the first PT_LOAD
+   segment. */
+#ifndef DL_SET_LIB_OFFSET
+# define DL_SET_LIB_OFFSET(offset) (_dl_library_offset = (offset))
+#endif
+
+/* Define this to get the real object's runtime address. */
+#ifndef DL_GET_RUN_ADDR
+# define DL_GET_RUN_ADDR(loadaddr, mapaddr) (mapaddr)
+#endif
+
 #endif /* _LD_DEFS_H */
index ff7accd..0dbe8bf 100644 (file)
@@ -166,6 +166,17 @@ while (0)
 #define DL_BOOT_COMPUTE_DYN(dpnt, got, load_addr) \
   ((dpnt) = dl_boot_ldso_dyn_pointer)
 
+/* Define this to declare the library offset. */
+#define DL_DEF_LIB_OFFSET
+
+/* Define this to get the library offset. */
+#define DL_GET_LIB_OFFSET() 0
+
+/* Define this to set the library offset. */
+#define DL_SET_LIB_OFFSET(offset)
+
+/* Define this to get the real object's runtime address. */
+#define DL_GET_RUN_ADDR(loadaddr, mapaddr) (loadaddr)
 
 #ifdef __USE_GNU
 # include <link.h>
index b9de199..9e2a12c 100644 (file)
@@ -315,6 +315,9 @@ goof:
        return NULL;
 }
 
+/* Define the _dl_library_offset for the architectures that need it */
+DL_DEF_LIB_OFFSET;
+
 /*
  * Make a writeable mapping of a segment, regardless of whether PF_W is
  * set or not.
@@ -357,7 +360,7 @@ map_writeable (int infile, ElfW(Phdr) *ppnt, int piclib, int flags,
        }
 
        tryaddr = piclib == 2 ? piclib2map
-               : ((char*) (piclib ? libaddr : 0) +
+               : ((char *) (piclib ? libaddr : DL_GET_LIB_OFFSET()) +
                   (ppnt->p_vaddr & PAGE_ALIGN));
 
        size = (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz;
@@ -459,7 +462,7 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned rflags,
        size_t relro_size = 0;
        struct stat st;
        uint32_t *p32;
-       DL_LOADADDR_TYPE lib_loadaddr = 0;
+       DL_LOADADDR_TYPE lib_loadaddr;
        DL_INIT_LOADADDR_EXTRA_DECLS
 
        libaddr = 0;
@@ -617,6 +620,8 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned rflags,
        ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff];
 
        DL_INIT_LOADADDR(lib_loadaddr, libaddr - minvma, ppnt, epnt->e_phnum);
+       /* Set _dl_library_offset to lib_loadaddr or 0. */
+       DL_SET_LIB_OFFSET(lib_loadaddr);
 
        for (i = 0; i < epnt->e_phnum; i++) {
                if (DL_IS_SPECIAL_SEGMENT (epnt, ppnt)) {
@@ -648,7 +653,7 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned rflags,
                        } else {
                                tryaddr = (piclib == 2 ? 0
                                           : (char *) (ppnt->p_vaddr & PAGE_ALIGN)
-                                          + (piclib ? libaddr : lib_loadaddr));
+                                          + (piclib ? libaddr : DL_GET_LIB_OFFSET()));
                                size = (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz;
                                status = (char *) _dl_mmap
                                           (tryaddr, size, LXFLAGS(ppnt->p_flags),
@@ -675,7 +680,11 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned rflags,
         * 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) {
+#ifdef __LDSO_PRELINK_SUPPORT__
+       if (DL_GET_LIB_OFFSET()) {
+#else
+       if (piclib) {
+#endif
                dynamic_addr = (unsigned long) DL_RELOC_ADDR(lib_loadaddr, dynamic_addr);
        }
 
@@ -708,7 +717,7 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned rflags,
                for (i = 0; i < epnt->e_phnum; i++, ppnt++) {
                        if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) {
 #ifdef __ARCH_USE_MMU__
-                               _dl_mprotect((void *) ((piclib ? libaddr : lib_loadaddr) +
+                               _dl_mprotect((void *) ((piclib ? libaddr : DL_GET_LIB_OFFSET()) +
                                                        (ppnt->p_vaddr & PAGE_ALIGN)),
                                                (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz,
                                                PROT_READ | PROT_WRITE | PROT_EXEC);
@@ -746,7 +755,9 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned rflags,
        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->mapaddr, epnt->e_phoff);
+       tpnt->ppnt = (ElfW(Phdr) *)
+               DL_RELOC_ADDR(DL_GET_RUN_ADDR(tpnt->loadaddr, tpnt->mapaddr),
+               epnt->e_phoff);
        tpnt->n_phent = epnt->e_phnum;
        tpnt->rtld_flags |= rtld_flags;
 #ifdef __LDSO_STANDALONE_SUPPORT__
@@ -954,11 +965,9 @@ int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, 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);
-                       if (tpnt->loadaddr
 #ifdef __LDSO_PRELINK_SUPPORT__
-                               || (!tpnt->dynamic_info[DT_GNU_PRELINKED_IDX])
+                       if (tpnt->loadaddr || (!tpnt->dynamic_info[DT_GNU_PRELINKED_IDX]))
 #endif
-                               )
                                elf_machine_relative(tpnt->loadaddr, reloc_addr, relative_count);
                        reloc_addr += relative_count * sizeof(ELF_RELOC);
                }
index 75ea564..4893409 100644 (file)
@@ -203,7 +203,8 @@ DL_START(unsigned long args)
                _dl_exit(0);
        }
        SEND_EARLY_STDERR_DEBUG("ELF header=");
-       SEND_ADDRESS_STDERR_DEBUG(DL_LOADADDR_BASE(header), 1);
+       SEND_ADDRESS_STDERR_DEBUG(
+               DL_LOADADDR_BASE(DL_GET_RUN_ADDR(load_addr, header)), 1);
 
        /* Locate the global offset table.  Since this code must be PIC
         * we can take advantage of the magic offset register, if we
@@ -278,11 +279,9 @@ DL_START(unsigned long args)
 
                        if (!indx && relative_count) {
                                rel_size -= relative_count * sizeof(ELF_RELOC);
-                               if (load_addr
 #ifdef __LDSO_PRELINK_SUPPORT__
-                                       || !tpnt->dynamic_info[DT_GNU_PRELINKED_IDX]
+                               if (load_addr || !tpnt->dynamic_info[DT_GNU_PRELINKED_IDX])
 #endif
-                                       )
                                        elf_machine_relative(load_addr, rel_addr, relative_count);
                                rel_addr += relative_count * sizeof(ELF_RELOC);
                        }
@@ -347,7 +346,7 @@ DL_START(unsigned long args)
        __rtld_stack_end = (void *)(argv - 1);
 
        _dl_elf_main = (int (*)(int, char **, char **))
-                       _dl_get_ready_to_run(tpnt, (DL_LOADADDR_TYPE) header, auxvt, envp, argv
+                       _dl_get_ready_to_run(tpnt, load_addr, auxvt, envp, argv
                                             DL_GET_READY_TO_RUN_EXTRA_ARGS);
 
        /* Transfer control to the application.  */
index 75d7951..546811a 100644 (file)
@@ -115,6 +115,18 @@ struct funcdesc_ht;
 #define DL_GET_READY_TO_RUN_EXTRA_ARGS \
     , dl_boot_progmap, dl_boot_got_pointer
 
+/* Define this to declare the library offset. */
+#define DL_DEF_LIB_OFFSET
+
+/* Define this to get the library offset. */
+#define DL_GET_LIB_OFFSET() 0
+
+/* Define this to set the library offset. */
+#define DL_SET_LIB_OFFSET(offset)
+
+/* Define this to get the real object's runtime address. */
+#define DL_GET_RUN_ADDR(loadaddr, mapaddr) (loadaddr)
+
 #ifdef __USE_GNU
 # include <link.h>
 #else
index 014bbf5..85d27a3 100644 (file)
@@ -351,12 +351,14 @@ static void trace_objects(struct elf_resolve *tpnt, char *str_name)
 
 static struct elf_resolve * add_ldso(struct elf_resolve *tpnt,
                                                                         DL_LOADADDR_TYPE load_addr,
+                                                                        ElfW(Addr) ldso_mapaddr,
                                                                         ElfW(auxv_t) auxvt[AT_EGID + 1],
                                                                         struct dyn_elf *rpnt)
 {
                ElfW(Ehdr) *epnt = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_val;
                ElfW(Phdr) *myppnt = (ElfW(Phdr) *)
-                                                               DL_RELOC_ADDR(load_addr, epnt->e_phoff);
+                               DL_RELOC_ADDR(DL_GET_RUN_ADDR(load_addr, ldso_mapaddr),
+                                                         epnt->e_phoff);
                int j;
                struct stat st;
 
@@ -364,7 +366,7 @@ static struct elf_resolve * add_ldso(struct elf_resolve *tpnt,
                                              tpnt->dynamic_info, (unsigned long)tpnt->dynamic_addr,
                                              0);
 
-               tpnt->mapaddr = load_addr;
+               tpnt->mapaddr = ldso_mapaddr;
                if (_dl_stat(tpnt->libname, &st) >= 0) {
                        tpnt->st_dev = st.st_dev;
                        tpnt->st_ino = st.st_ino;
@@ -411,7 +413,7 @@ void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
                          ElfW(auxv_t) auxvt[AT_EGID + 1], char **envp, char **argv
                          DL_GET_READY_TO_RUN_EXTRA_PARMS)
 {
-       ElfW(Addr) app_mapaddr = 0;
+       ElfW(Addr) app_mapaddr = 0, ldso_mapaddr = 0;
        ElfW(Phdr) *ppnt;
        ElfW(Dyn) *dpnt;
        char *lpntstr;
@@ -826,6 +828,7 @@ of this helper program; chances are you did not intend to run this program.\n\
        }
 #endif
 
+       ldso_mapaddr = (ElfW(Addr)) auxvt[AT_BASE].a_un.a_val;
        /*
         * OK, fix one more thing - set up debug_addr so it will point
         * to our chain.  Later we may need to fill in more fields, but this
@@ -833,7 +836,8 @@ of this helper program; chances are you did not intend to run this program.\n\
         */
        debug_addr->r_map = (struct link_map *) _dl_loaded_modules;
        debug_addr->r_version = 1;
-       debug_addr->r_ldbase = (ElfW(Addr)) DL_LOADADDR_BASE(load_addr);
+       debug_addr->r_ldbase = (ElfW(Addr))
+               DL_LOADADDR_BASE(DL_GET_RUN_ADDR(load_addr, ldso_mapaddr));
        debug_addr->r_brk = (unsigned long) &_dl_debug_state;
        _dl_debug_addr = debug_addr;
 
@@ -1012,7 +1016,8 @@ of this helper program; chances are you did not intend to run this program.\n\
                                if (_dl_strcmp(name, UCLIBC_LDSO) == 0) {
                                                if (!ldso_tpnt) {
                                                        /* Insert the ld.so only once */
-                                                       ldso_tpnt = add_ldso(tpnt, load_addr, auxvt, rpnt);
+                                                       ldso_tpnt = add_ldso(tpnt, load_addr,
+                                                                                                ldso_mapaddr, auxvt, rpnt);
                                                }
                                                ldso_tpnt->usage_count++;
                                                tpnt1 = ldso_tpnt;
@@ -1112,7 +1117,7 @@ of this helper program; chances are you did not intend to run this program.\n\
         * again once all libs are loaded.
         */
        if (!ldso_tpnt) {
-               tpnt = add_ldso(tpnt, load_addr, auxvt, rpnt);
+               tpnt = add_ldso(tpnt, load_addr, ldso_mapaddr, auxvt, rpnt);
                tpnt->usage_count++;
                nscope_elem++;
        } else