Sfoglia il codice sorgente

Update C6X support

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@redhat.com>
Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
Mark Salter 12 anni fa
parent
commit
9af6ea0bc9

+ 69 - 3
ldso/ldso/c6x/dl-startup.h

@@ -6,10 +6,9 @@
  * 
  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  */
-
 #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,7 +33,6 @@ _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
@@ -44,6 +42,74 @@ __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		" __stringify(DT_C6000_DSBT_BASE) ",B7\n"
+	"          MVKH .S2		" __stringify(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"

+ 29 - 22
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,

+ 18 - 14
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.  */

+ 2 - 7
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];