[PATCH V2] ldso: fix fdpic support broken from prelink patch

Filippo ARCIDIACONO filippo.arcidiacono at st.com
Wed Mar 7 09:07:01 UTC 2012


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 at st.com>
---
 ldso/include/dl-defs.h      |   11 +++++++++++
 ldso/ldso/c6x/dl-sysdep.h   |    9 +++++++++
 ldso/ldso/dl-elf.c          |   26 +++++++++++++++++---------
 ldso/ldso/dl-startup.c      |    8 +++-----
 ldso/ldso/fdpic/dl-sysdep.h |   10 ++++++++++
 ldso/ldso/ldso.c            |   17 +++++++++++------
 6 files changed, 61 insertions(+), 20 deletions(-)

diff --git a/ldso/include/dl-defs.h b/ldso/include/dl-defs.h
index 11edc4d..86ad22f 100644
--- a/ldso/include/dl-defs.h
+++ b/ldso/include/dl-defs.h
@@ -259,4 +259,15 @@ typedef struct {
 # define DL_MAP_SEGMENT(EPNT, PPNT, INFILE, FLAGS) 0
 #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 map address. */
+#ifndef DL_GET_LOADADDR_MAPADDR
+# define DL_GET_LOADADDR_MAPADDR(loadaddr, mapaddr) (mapaddr)
+#endif
 #endif	/* _LD_DEFS_H */
diff --git a/ldso/ldso/c6x/dl-sysdep.h b/ldso/ldso/c6x/dl-sysdep.h
index ff7accd..235fea6 100644
--- a/ldso/ldso/c6x/dl-sysdep.h
+++ b/ldso/ldso/c6x/dl-sysdep.h
@@ -166,6 +166,15 @@ while (0)
 #define DL_BOOT_COMPUTE_DYN(dpnt, got, load_addr) \
   ((dpnt) = dl_boot_ldso_dyn_pointer)
 
+/* Define this to set the library offset. */
+#ifndef DL_SET_LIB_OFFSET
+# define DL_SET_LIB_OFFSET(offset) (_dl_library_offset = 0)
+#endif
+
+/* Define this to get the real object's load address. */
+#ifndef DL_GET_LOADADDR_MAPADDR
+# define DL_GET_LOADADDR_MAPADDR(loadaddr, mapaddr) (loadaddr)
+#endif
 
 #ifdef __USE_GNU
 # include <link.h>
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index b9de199..bffc4a9 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -315,6 +315,8 @@ goof:
 	return NULL;
 }
 
+static unsigned long _dl_library_offset;
+
 /*
  * Make a writeable mapping of a segment, regardless of whether PF_W is
  * set or not.
@@ -357,7 +359,7 @@ map_writeable (int infile, ElfW(Phdr) *ppnt, int piclib, int flags,
 	}
 
 	tryaddr = piclib == 2 ? piclib2map
-		: ((char*) (piclib ? libaddr : 0) +
+		: ((char *) (piclib ? libaddr : _dl_library_offset) +
 		   (ppnt->p_vaddr & PAGE_ALIGN));
 
 	size = (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz;
@@ -459,7 +461,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 +619,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 +652,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_library_offset));
 				size = (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz;
 				status = (char *) _dl_mmap
 					   (tryaddr, size, LXFLAGS(ppnt->p_flags),
@@ -675,7 +679,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_library_offset) {
+#else
+	if (piclib) {
+#endif
 		dynamic_addr = (unsigned long) DL_RELOC_ADDR(lib_loadaddr, dynamic_addr);
 	}
 
@@ -708,7 +716,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_library_offset) +
 							(ppnt->p_vaddr & PAGE_ALIGN)),
 						(ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz,
 						PROT_READ | PROT_WRITE | PROT_EXEC);
@@ -746,7 +754,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_LOADADDR_MAPADDR(tpnt->loadaddr, tpnt->mapaddr),
+		epnt->e_phoff);
 	tpnt->n_phent = epnt->e_phnum;
 	tpnt->rtld_flags |= rtld_flags;
 #ifdef __LDSO_STANDALONE_SUPPORT__
@@ -954,11 +964,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);
 		}
diff --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c
index 75ea564..d7b114c 100644
--- a/ldso/ldso/dl-startup.c
+++ b/ldso/ldso/dl-startup.c
@@ -203,7 +203,7 @@ 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(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 +278,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 +345,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.  */
diff --git a/ldso/ldso/fdpic/dl-sysdep.h b/ldso/ldso/fdpic/dl-sysdep.h
index 75d7951..c006f08 100644
--- a/ldso/ldso/fdpic/dl-sysdep.h
+++ b/ldso/ldso/fdpic/dl-sysdep.h
@@ -115,6 +115,16 @@ struct funcdesc_ht;
 #define DL_GET_READY_TO_RUN_EXTRA_ARGS \
     , dl_boot_progmap, dl_boot_got_pointer
 
+/* Define this to set the library offset. */
+#ifndef DL_SET_LIB_OFFSET
+# define DL_SET_LIB_OFFSET(offset) (_dl_library_offset = 0)
+#endif
+
+/* Define this to get the real object's load address. */
+#ifndef DL_GET_LOADADDR_MAPADDR
+# define DL_GET_LOADADDR_MAPADDR(loadaddr, mapaddr) (loadaddr)
+#endif
+
 #ifdef __USE_GNU
 # include <link.h>
 #else
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index 014bbf5..7793f9d 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -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_LOADADDR_MAPADDR(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_LOADADDR_MAPADDR(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
-- 
1.5.5.6



More information about the uClibc mailing list