summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
Diffstat (limited to 'ldso')
-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
3 files changed, 116 insertions, 39 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. */