[Patch v2 2/2] Update C6X support

Mark Salter msalter at redhat.com
Tue May 22 14:53:30 UTC 2012


This patch updates the C6X support to work with latest uClibc code and
uses reworked DSBT support to allow using kernel FDPIC loader.

Signed-off-by: Mark Salter <msalter at redhat.com>
---
 ldso/ldso/c6x/dl-startup.h             |   74 +++++++++++++++++++++++++++++++-
 ldso/ldso/c6x/dl-sysdep.h              |   51 ++++++++++++---------
 ldso/ldso/c6x/elfinterp.c              |   32 ++++++++------
 libc/sysdeps/linux/c6x/bits/elf-dsbt.h |    9 +---
 4 files changed, 121 insertions(+), 45 deletions(-)

diff --git a/ldso/ldso/c6x/dl-startup.h b/ldso/ldso/c6x/dl-startup.h
index 70a8b89..fca02f1 100644
--- a/ldso/ldso/c6x/dl-startup.h
+++ b/ldso/ldso/c6x/dl-startup.h
@@ -9,7 +9,7 @@
 
 #undef DL_START
 #define DL_START(X)   \
-int  \
+static void * __attribute_used__  \
 _dl_start (unsigned placeholder, \
 	   struct elf32_dsbt_loadmap *dl_boot_progmap, \
 	   struct elf32_dsbt_loadmap *dl_boot_ldsomap, \
@@ -34,16 +34,86 @@ _dl_start (unsigned placeholder, \
  *	B4  --> executable loadmap address
  *	A6  --> interpreter loadmap address
  *	B6  --> dynamic section address
- *	B14 --> our DP setup by kernel
  *
  * NB: DSBT index is always 0 for the executable
  *     and 1 for the interpreter
  */
 
+#define __xstr(s) __str(s)
+#define __str(s) #s
+
 __asm__("	.text\n"
 	".globl _start\n"
 	".hidden _start\n"
 	"_start:\n"
+	/* Find interpreter DSBT base in dynamic section */
+	"	   MV .S2		B6,B2\n"
+	" ||	   ADD .D1X		B6,4,A2\n"
+	"          LDW .D2T2		*B2++[2],B0\n"
+	" ||	   LDW .D1T1		*A2++[2],A0\n"
+	"          MVKL .S2		" __xstr(DT_C6000_DSBT_BASE) ",B7\n"
+	"          MVKH .S2		" __xstr(DT_C6000_DSBT_BASE) ",B7\n"
+	"          NOP\n"
+	"          NOP\n"
+	/*
+	 * B0 now holds dynamic tag and A0 holds tag value.
+	 * Loop through looking for DSBT base tag
+	 */
+	"0:\n"
+	" [B0]     CMPEQ .L2		B0,B7,B1\n"
+	" || [!B0] MVK .S2		1,B1\n"
+	" [!B1]	   BNOP .S1		0b,5\n"
+	" ||[!B1]  LDW .D2T2		*B2++[2],B0\n"
+	" ||[!B1]  LDW .D1T1		*A2++[2],A0\n"
+	/*
+	 * DSBT base in A0 needs to be relocated.
+	 * Search through our loadmap to find where it got loaded.
+	 *
+	 * struct elf32_dsbt_loadmap {
+	 *     Elf32_Half version;
+	 *     Elf32_Half nsegs;
+	 *     struct {
+	 *         Elf32_Addr addr;
+	 *         Elf32_Addr p_vaddr;
+	 *         Elf32_Word p_memsz;
+	 *     } segments[];
+	 * }
+	 *
+	 */
+	"          MV .S1		A6,A1\n"
+	" [!A1]	   MV .S1X		B4,A1\n"
+	"          ADD .D1		A1,2,A3\n"
+	"          LDHU .D1T2		*A3++[1],B0\n"  /* nsegs */
+	"          LDW .D1T1		*A3++[1],A10\n" /* addr */
+	"          LDW .D1T1		*A3++[1],A11\n" /* p_vaddr */
+	"          LDW .D1T1		*A3++[1],A12\n" /* p_memsz */
+	"	   NOP\n"
+	"	   NOP\n"
+	/*
+	 * Here we have:
+	 *     B0  -> number of segments to search.
+	 *     A3  -> pointer to next segment to check
+	 *     A10 -> segment load address
+	 *     A11 -> ELF segment virt address
+	 *     A12 -> ELF segment size
+	 */
+	"0:\n"
+	" [!B0]    B .S2                0f\n"
+	" 	   SUB .D2              B0,1,B0\n"
+	"	   CMPLTU .L1           A0,A11,A13\n"
+	" ||	   SUB .S1              A12,1,A12\n"
+	"	   ADD .D1              A11,A12,A12\n"
+	"	   CMPGTU .L1           A0,A12,A14\n"
+	"	   OR .L1               A13,A14,A2\n"
+	" [A2]     B .S2                0b\n"
+	" || [!A2] SUB .L1              A0,A11,A0\n"
+	" [B0]     LDW .D1T1		*A3++[1],A10\n" /* addr */
+	" || [!A2] ADD .L1              A0,A10,A0\n"
+	" [B0]     LDW .D1T1		*A3++[1],A11\n" /* p_vaddr */
+	" [B0]     LDW .D1T1		*A3++[1],A12\n" /* p_memsz */
+	"          MV  .S2X		A0,B14\n"
+	"	   NOP\n"
+	"0:\n"
 	"          B .S2		_dl_start\n"
 	"          STW .D2T2		B14, *+B14[1]\n"
 	"          ADD .D1X		B15,8,A8\n"
diff --git a/ldso/ldso/c6x/dl-sysdep.h b/ldso/ldso/c6x/dl-sysdep.h
index 0dbe8bf..c2e91d2 100644
--- a/ldso/ldso/c6x/dl-sysdep.h
+++ b/ldso/ldso/c6x/dl-sysdep.h
@@ -52,13 +52,13 @@ extern int _dl_linux_resolve(void) attribute_hidden;
 struct funcdesc_ht;
 struct elf32_dsbt_loadaddr;
 
-/* We must force strings used early in the bootstrap into the text
-   segment (const data), such that they are referenced relative to
-   the DP register rather than through the GOT which will not have
-   been relocated when these are used. */
+/* Current toolchains access constant strings via unrelocated GOT
+   entries. Fortunately, we have enough in place to just call the
+   relocation function early on. */
 #undef SEND_EARLY_STDERR
 #define SEND_EARLY_STDERR(S) \
-  do { static char __s[] = (S); SEND_STDERR (__s); } while (0)
+  do { char *__p = __reloc_pointer((S), dl_boot_ldsomap?:dl_boot_progmap);\
+	  SEND_STDERR (__p); } while (0)
 
 #define DL_LOADADDR_TYPE struct elf32_dsbt_loadaddr
 
@@ -114,7 +114,7 @@ struct elf32_dsbt_loadaddr;
   (__dl_loadaddr_unmap ((LIB)->loadaddr))
 
 #define DL_LOADADDR_BASE(LOADADDR) \
-  ((LOADADDR).map->dsbt_table)
+  ((LOADADDR).map)
 
 #define DL_ADDR_IN_LOADADDR(ADDR, TPNT, TFROM) \
   (! (TFROM) && __dl_addr_in_loadaddr ((void*)(ADDR), (TPNT)->loadaddr))
@@ -150,18 +150,28 @@ while (0)
 
 
 /*
- * Compute the GOT address.
- * Also setup program and interpreter DSBT table entries.
+ * C6X doesn't really need the GOT here.
+ * The GOT is placed just past the DSBT table, so we could find it by
+ * using the DSBT register + table size found in the dynamic section.
+ *
+ *	do {						  		\
+ *		unsigned long *ldso_dsbt;				\
+ *		ElfW(Dyn) *d = dl_boot_ldso_dyn_pointer;		\
+ *		while (d->d_tag != DT_NULL) {				\
+ *			if (d->d_tag == DT_C6000_DSBT_SIZE)	{	\
+ *				__asm__ (" MV .S2 B14,%0\n"		\
+ *				     : "=b" (ldso_dsbt));		\
+ *				(GOT) = ldso_dsbt + d->d_un.d_val;	\
+ *				break;					\
+ *			}						\
+ *			d++;						\
+ *		}							\
+ *	} while(0)
+ *
+ * Instead, just point it to the DSBT table to avoid unused variable warning.
  */
 #define DL_BOOT_COMPUTE_GOT(GOT) \
-  do {								\
-    unsigned long *ldso_dsbt, *prog_dsbt;			\
-    ldso_dsbt = dl_boot_ldsomap->dsbt_table;			\
-    prog_dsbt = dl_boot_progmap->dsbt_table;			\
-    ldso_dsbt[0] = prog_dsbt[0] = (unsigned long)prog_dsbt;	\
-    ldso_dsbt[1] = prog_dsbt[1] = (unsigned long)ldso_dsbt;	\
-    (GOT) = ldso_dsbt + dl_boot_ldsomap->dsbt_size;		\
-  } while(0)
+	__asm__ (" MV .S2 B14,%0\n" : "=b" (GOT))
 
 #define DL_BOOT_COMPUTE_DYN(dpnt, got, load_addr) \
   ((dpnt) = dl_boot_ldso_dyn_pointer)
@@ -186,12 +196,9 @@ while (0)
 # undef __USE_GNU
 #endif
 
-static __always_inline Elf32_Addr
-elf_machine_load_address (void)
-{
-	/* this is never an issue on DSBT systems */
-	return 0;
-}
+/* we need this for __LDSO_STANDALONE_SUPPORT__ */
+#define elf_machine_load_address() \
+	(dl_boot_ldsomap ?: dl_boot_progmap)->segs[0].addr
 
 static __always_inline void
 elf_machine_relative (DL_LOADADDR_TYPE load_off, const Elf32_Addr rel_addr,
diff --git a/ldso/ldso/c6x/elfinterp.c b/ldso/ldso/c6x/elfinterp.c
index 3772f90..f0e05b9 100644
--- a/ldso/ldso/c6x/elfinterp.c
+++ b/ldso/ldso/c6x/elfinterp.c
@@ -69,14 +69,12 @@ _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
 	got_addr = (char **) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
 
 	/* Get the address to be used to fill in the GOT entry.  */
-	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt,
-				 ELF_RTYPE_CLASS_PLT, NULL);
+	new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
 	if (unlikely(!new_addr)) {
 		_dl_dprintf(2, "%s: can't resolve symbol '%s' in lib '%s'.\n", _dl_progname, symname, tpnt->libname);
 		_dl_exit(1);
 	}
 
-
 #if defined (__SUPPORT_LD_DEBUG__)
 	if (_dl_debug_bindings) {
 		_dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
@@ -96,9 +94,9 @@ _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
 }
 
 static int
-_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
 	  unsigned long rel_addr, unsigned long rel_size,
-	  int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
+	  int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 			    ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
 {
 	unsigned int i;
@@ -148,7 +146,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
 }
 
 static int
-_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
+_dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope,
 	      ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
 {
 	int reloc_type;
@@ -157,7 +155,9 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 	unsigned long *reloc_addr;
 	unsigned long symbol_addr, sym_val;
 	long reloc_addend;
-	unsigned long old_val, new_val;
+	unsigned long old_val, new_val = 0;
+	struct symbol_ref sym_ref;
+	struct elf_resolve *symbol_tpnt;
 
 	reloc_addr = (unsigned long *)(intptr_t)
 		DL_RELOC_ADDR (tpnt->loadaddr, rpnt->r_offset);
@@ -167,14 +167,17 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 	symtab_index = ELF_R_SYM(rpnt->r_info);
 	symbol_addr  = 0;
 	symname      = strtab + symtab[symtab_index].st_name;
+	sym_ref.sym = &symtab[symtab_index];
+	sym_ref.tpnt = NULL;
 
 	if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
 		symbol_addr = (unsigned long)
 			DL_RELOC_ADDR (tpnt->loadaddr, symtab[symtab_index].st_value);
+		symbol_tpnt = tpnt;
 	} else {
-		symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
-							    scope, tpnt, elf_machine_type_class(reloc_type),
-							    NULL);
+		symbol_addr = (unsigned long) _dl_find_hash(symname,
+							    scope, NULL, elf_machine_type_class(reloc_type),
+							    &sym_ref);
 		/*
 		 * We want to allow undefined references to weak symbols - this might
 		 * have been intentional.  We should not be linking local symbols
@@ -186,6 +189,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 				     _dl_progname, strtab + symtab[symtab_index].st_name);
 			_dl_exit (1);
 		}
+		symbol_tpnt = sym_ref.tpnt;
 	}
 	old_val = *reloc_addr;
 	sym_val = symbol_addr + reloc_addend;
@@ -199,7 +203,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 		*reloc_addr = sym_val;
 		break;
 	case R_C6000_DSBT_INDEX:
-		new_val = (old_val & ~0x007fff00) | ((tpnt->loadaddr.map->dsbt_index & 0x7fff) << 8);
+		new_val = (old_val & ~0x007fff00) | ((symbol_tpnt->dsbt_index & 0x7fff) << 8);
 		*reloc_addr = new_val;
 		break;
 	case R_C6000_ABS_L16:
@@ -242,7 +246,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 
 static int
 _dl_do_lazy_reloc (struct elf_resolve *tpnt,
-		   struct dyn_elf *scope attribute_unused,
+		   struct r_scope_elem *scope attribute_unused,
 		   ELF_RELOC *rpnt, ElfW(Sym) *symtab attribute_unused,
 		   char *strtab attribute_unused)
 {
@@ -283,9 +287,9 @@ _dl_parse_lazy_relocation_information
 
 int
 _dl_parse_relocation_information
-(struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
+(struct dyn_elf *rpnt, struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size)
 {
-	return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
+	return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
 }
 
 /* We don't have copy relocs.  */
diff --git a/libc/sysdeps/linux/c6x/bits/elf-dsbt.h b/libc/sysdeps/linux/c6x/bits/elf-dsbt.h
index ff8b24b..5ad8bb3 100644
--- a/libc/sysdeps/linux/c6x/bits/elf-dsbt.h
+++ b/libc/sysdeps/linux/c6x/bits/elf-dsbt.h
@@ -59,15 +59,10 @@ struct elf32_dsbt_loadseg
 
 struct elf32_dsbt_loadmap {
 	/* Protocol version number, must be zero.  */
-	Elf32_Word version;
-
-	/* Pointer to DSBT */
-	unsigned   *dsbt_table;
-	unsigned   dsbt_size;
-	unsigned   dsbt_index;
+	Elf32_Half version;
 
 	/* number of segments */
-	Elf32_Word nsegs;
+	Elf32_Half nsegs;
 
 	/* The actual memory map.  */
 	struct elf32_dsbt_loadseg segs[0];
-- 
1.7.9.1



More information about the uClibc mailing list