diff options
| author | Mark Salter <msalter@redhat.com> | 2012-06-06 16:44:45 -0400 | 
|---|---|---|
| committer | Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> | 2012-06-13 09:53:19 +0200 | 
| commit | 9af6ea0bc9db91e151fb7c34862c667b7acb584b (patch) | |
| tree | afe26fd6022fbcc8e4557edd484e51216451ff2e | |
| parent | 11d8a813edfffee29354e69548e1ce41c950691b (diff) | |
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>
| -rw-r--r-- | ldso/ldso/c6x/dl-startup.h | 72 | ||||
| -rw-r--r-- | ldso/ldso/c6x/dl-sysdep.h | 51 | ||||
| -rw-r--r-- | ldso/ldso/c6x/elfinterp.c | 32 | ||||
| -rw-r--r-- | libc/sysdeps/linux/c6x/bits/elf-dsbt.h | 9 | 
4 files changed, 118 insertions, 46 deletions
diff --git a/ldso/ldso/c6x/dl-startup.h b/ldso/ldso/c6x/dl-startup.h index 70a8b89a7..c83e33cb3 100644 --- a/ldso/ldso/c6x/dl-startup.h +++ b/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" diff --git a/ldso/ldso/c6x/dl-sysdep.h b/ldso/ldso/c6x/dl-sysdep.h index 0dbe8bf90..c2e91d2f0 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 3772f90b3..f0e05b9d0 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 ff8b24bd7..5ad8bb3b0 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];  | 
