summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Salter <msalter@redhat.com>2012-06-06 16:44:45 -0400
committerBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2012-06-13 09:53:19 +0200
commit9af6ea0bc9db91e151fb7c34862c667b7acb584b (patch)
treeafe26fd6022fbcc8e4557edd484e51216451ff2e
parent11d8a813edfffee29354e69548e1ce41c950691b (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.h72
-rw-r--r--ldso/ldso/c6x/dl-sysdep.h51
-rw-r--r--ldso/ldso/c6x/elfinterp.c32
-rw-r--r--libc/sysdeps/linux/c6x/bits/elf-dsbt.h9
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];