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 <msal...@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

_______________________________________________
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Reply via email to