[PATCH 1/2] Clean up DSBT support

Mark Salter msalter at redhat.com
Tue Apr 24 13:47:09 UTC 2012


The current DSBT support relies on the kernel to provide DSBT info as
part of the load maps passed to user space. The problem with this
approach is that it requires the kernel to access a userspace mapping
of the dynamic section (or separately read a copy for the kernel) to
retrieve the DSBT it needs to pass to userspace. This patch reworks
the DSBT support to remove the reliance on DSBT info coming from the
kernel. Instead, ldso reads the info itself from the dynamic section.
One other benefit of this is that it allows the kernel FDPIC loader
to load DSBT binaries without any modification.

Signed-off-by: Mark Salter <msalter at redhat.com>
---
 ldso/include/dl-elf.h  |    5 ---
 ldso/include/dl-hash.h |    6 ++++
 ldso/include/ldso.h    |    3 ++
 ldso/ldso/dl-elf.c     |   70 +++++++++++++++++++++++------------------------
 ldso/ldso/dl-hash.c    |    9 ++++++
 ldso/ldso/ldso.c       |   14 +++++++++
 6 files changed, 66 insertions(+), 41 deletions(-)

diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h
index 29d1a00..060ee3d 100644
--- a/ldso/include/dl-elf.h
+++ b/ldso/include/dl-elf.h
@@ -222,11 +222,6 @@ unsigned int __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info
 #ifdef __DSBT__
 	/* Get the mapped address of the DSBT base.  */
 	ADJUST_DYN_INFO(DT_DSBT_BASE_IDX, load_off);
-
-	/* Initialize loadmap dsbt info.  */
-	load_off.map->dsbt_table = (void *)dynamic_info[DT_DSBT_BASE_IDX];
-	load_off.map->dsbt_size = dynamic_info[DT_DSBT_SIZE_IDX];
-	load_off.map->dsbt_index = dynamic_info[DT_DSBT_INDEX_IDX];
 #endif
 #undef ADJUST_DYN_INFO
 	return rtld_flags;
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
index c7effc5..7bccdca 100644
--- a/ldso/include/dl-hash.h
+++ b/ldso/include/dl-hash.h
@@ -139,6 +139,12 @@ struct elf_resolve {
      memory when the module is dlclose()d.  */
   struct funcdesc_ht *funcdesc_ht;
 #endif
+#ifdef __DSBT__
+  /* Information for DSBT */
+  void **dsbt_table;
+  unsigned long dsbt_size;
+  unsigned long dsbt_index;
+#endif
 };
 
 #define RELOCS_DONE	    0x000001
diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h
index 6f3b728..cb7b122 100644
--- a/ldso/include/ldso.h
+++ b/ldso/include/ldso.h
@@ -84,6 +84,9 @@ extern struct elf_resolve *_dl_trace_prelink_map;	/* Library map for prelinking
 #else
 #define _dl_trace_prelink		0
 #endif
+#ifdef __DSBT__
+extern void **_dl_ldso_dsbt;
+#endif
 
 #if defined(USE_TLS) && USE_TLS
 extern void _dl_add_to_slotinfo (struct link_map  *l);
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index 9e2a12c..799e316 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -851,10 +851,15 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned rflags,
 	/* Handle DSBT initialization */
 	{
 		struct elf_resolve *t, *ref;
-		int idx = tpnt->loadaddr.map->dsbt_index;
-		unsigned *dsbt = tpnt->loadaddr.map->dsbt_table;
+		int idx = tpnt->dsbt_index;
+		void **dsbt = tpnt->dsbt_table;
 
-		if (idx == 0) {
+		/*
+		 * It is okay (required actually) to have zero idx for an executable.
+		 * This is the case when running ldso standalone and the program
+		 * is being mapped in via _dl_load_shared_library().
+		 */
+		if (idx == 0 && tpnt->libtype != elf_executable) {
 			if (!dynamic_info[DT_TEXTREL]) {
 				/* This DSO has not been assigned an index. */
 				_dl_dprintf(2, "%s: '%s' is missing a dsbt index assignment!\n",
@@ -869,9 +874,9 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned rflags,
 					break;
 				}
 			}
-			idx = tpnt->loadaddr.map->dsbt_size;
+			idx = tpnt->dsbt_size;
 			while (idx-- > 0)
-				if (!ref || ref->loadaddr.map->dsbt_table[idx] == NULL)
+				if (!ref || ref->dsbt_table[idx] == NULL)
 					break;
 			if (idx <= 0) {
 				_dl_dprintf(2, "%s: '%s' caused DSBT table overflow!\n",
@@ -880,43 +885,36 @@ struct elf_resolve *_dl_load_elf_shared_library(unsigned rflags,
 			}
 			_dl_if_debug_dprint("\n\tfile='%s';  assigned index %d\n",
 					    libname, idx);
-			tpnt->loadaddr.map->dsbt_index = idx;
+			tpnt->dsbt_index = idx;
+		}
 
+		/* make sure index is not already used */
+		if (_dl_ldso_dsbt[idx]) {
+			struct elf_resolve *dup;
+			char *dup_name;
+
+			for (dup = _dl_loaded_modules; dup; dup = dup->next)
+				if (dup != tpnt && dup->dsbt_index == idx)
+					break;
+			if (dup)
+				dup_name = dup->libname;
+			else if (idx == 1)
+				dup_name = "runtime linker";
+			else
+				dup_name = "unknown library";
+			_dl_dprintf(2, "%s: '%s' dsbt index %d already used by %s!\n",
+				    _dl_progname, libname, idx, dup_name);
+			_dl_exit(1);
 		}
 
 		/*
 		 * Setup dsbt slot for this module in dsbt of all modules.
 		 */
-		ref = NULL;
-		for (t = _dl_loaded_modules; t; t = t->next) {
-			/* find a dsbt table from another module */
-			if (ref == NULL && t != tpnt) {
-				ref = t;
-
-				/* make sure index is not already used */
-				if (t->loadaddr.map->dsbt_table[idx]) {
-					struct elf_resolve *dup;
-					char *dup_name;
-
-					for (dup = _dl_loaded_modules; dup; dup = dup->next)
-						if (dup != tpnt && dup->loadaddr.map->dsbt_index == idx)
-							break;
-					if (dup)
-						dup_name = dup->libname;
-					else if (idx == 1)
-						dup_name = "runtime linker";
-					else
-						dup_name = "unknown library";
-					_dl_dprintf(2, "%s: '%s' dsbt index %d already used by %s!\n",
-						    _dl_progname, libname, idx, dup_name);
-					_dl_exit(1);
-				}
-			}
-			t->loadaddr.map->dsbt_table[idx] = (unsigned)dsbt;
-		}
-		if (ref)
-			_dl_memcpy(dsbt, ref->loadaddr.map->dsbt_table,
-				   tpnt->loadaddr.map->dsbt_size * sizeof(unsigned *));
+		for (t = _dl_loaded_modules; t; t = t->next)
+			t->dsbt_table[idx] = dsbt;
+		_dl_ldso_dsbt[idx] = dsbt;
+		_dl_memcpy(dsbt, _dl_ldso_dsbt,
+			   tpnt->dsbt_size * sizeof(tpnt->dsbt_table[0]));
 	}
 #endif
 	_dl_if_debug_dprint("\n\tfile='%s';  generating link map\n", libname);
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
index 36ebec6..2c659dc 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -115,6 +115,15 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
 	tpnt->dynamic_addr = (ElfW(Dyn) *)dynamic_addr;
 	tpnt->libtype = loaded_file;
 
+#ifdef __DSBT__
+	if (dynamic_info[DT_DSBT_BASE_IDX] != 0)
+		tpnt->dsbt_table = (void *)dynamic_info[DT_DSBT_BASE_IDX];
+	if (dynamic_info[DT_DSBT_SIZE_IDX] != 0)
+		tpnt->dsbt_size = dynamic_info[DT_DSBT_SIZE_IDX];
+	if (dynamic_info[DT_DSBT_INDEX_IDX] != 0)
+		tpnt->dsbt_index = dynamic_info[DT_DSBT_INDEX_IDX];
+#endif /* __DSBT__ */
+
 #ifdef __LDSO_GNU_HASH_SUPPORT__
 	if (dynamic_info[DT_GNU_HASH_IDX] != 0) {
 		Elf32_Word *hash32 = (Elf_Symndx*)dynamic_info[DT_GNU_HASH_IDX];
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index 85d27a3..9192415 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -77,6 +77,10 @@ char *_dl_debug_bindings  = NULL;
 int   _dl_debug_file      = 2;
 #endif
 
+#ifdef __DSBT__
+void **_dl_ldso_dsbt = NULL;
+#endif
+
 #if defined (__LDSO_STANDALONE_SUPPORT__) && defined (__sh__)
 /* Not hidden, needed for standalone execution. */
 /*
@@ -464,6 +468,11 @@ void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
 		_dl_progname = argv[0];
 	}
 
+#ifdef __DSBT__
+	_dl_ldso_dsbt = (void *)tpnt->dynamic_info[DT_DSBT_BASE_IDX];
+	_dl_ldso_dsbt[tpnt->dynamic_info[DT_DSBT_INDEX_IDX]] = _dl_ldso_dsbt;
+#endif
+
 #ifndef __LDSO_STANDALONE_SUPPORT__
 	if (_start == (void *) auxvt[AT_ENTRY].a_un.a_val) {
 		_dl_dprintf(_dl_debug_file, "Standalone execution is not enabled\n");
@@ -698,6 +707,11 @@ of this helper program; chances are you did not intend to run this program.\n\
 			app_tpnt->mapaddr = app_mapaddr;
 			app_tpnt->rtld_flags = unlazy | RTLD_GLOBAL;
 			app_tpnt->usage_count++;
+#ifdef __DSBT__
+			_dl_ldso_dsbt[0] = app_tpnt->dsbt_table;
+			_dl_memcpy(app_tpnt->dsbt_table, _dl_ldso_dsbt,
+				   app_tpnt->dsbt_size * sizeof(tpnt->dsbt_table[0]));
+#endif
 			lpnt = (unsigned long *) (app_tpnt->dynamic_info[DT_PLTGOT]);
 #ifdef ALLOW_ZERO_PLTGOT
 			if (lpnt)
-- 
1.7.9.1



More information about the uClibc mailing list