summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
Diffstat (limited to 'ldso')
-rw-r--r--ldso/include/dl-string.h2
-rw-r--r--ldso/ldso/xtensa/dl-debug.h61
-rw-r--r--ldso/ldso/xtensa/dl-startup.h106
-rw-r--r--ldso/ldso/xtensa/dl-syscalls.h7
-rw-r--r--ldso/ldso/xtensa/dl-sysdep.h132
-rw-r--r--ldso/ldso/xtensa/elfinterp.c285
-rw-r--r--ldso/ldso/xtensa/resolve.S61
7 files changed, 653 insertions, 1 deletions
diff --git a/ldso/include/dl-string.h b/ldso/include/dl-string.h
index bf993b29c..746bd91c6 100644
--- a/ldso/include/dl-string.h
+++ b/ldso/include/dl-string.h
@@ -286,7 +286,7 @@ static __always_inline char * _dl_simple_ltoahex(char * local, unsigned long i)
* This requires that load_addr must already be defined... */
#if defined(mc68000) || defined(__arm__) || defined(__thumb__) || \
defined(__mips__) || defined(__sh__) || defined(__powerpc__) || \
- defined(__avr32__)
+ defined(__avr32__) || defined(__xtensa__)
# define CONSTANT_STRING_GOT_FIXUP(X) \
if ((X) < (const char *) load_addr) (X) += load_addr
# define NO_EARLY_SEND_STDERR
diff --git a/ldso/ldso/xtensa/dl-debug.h b/ldso/ldso/xtensa/dl-debug.h
new file mode 100644
index 000000000..327defc07
--- /dev/null
+++ b/ldso/ldso/xtensa/dl-debug.h
@@ -0,0 +1,61 @@
+/* vi: set sw=4 ts=4: */
+/* Xtensa ELF shared library loader suppport
+ *
+ * Copyright (C) 2007 Tensilica Inc.
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+static const char *_dl_reltypes_tab[] =
+{
+ "R_XTENSA_NONE",
+ "R_XTENSA_32",
+ "R_XTENSA_RTLD",
+ "R_XTENSA_GLOB_DAT",
+ "R_XTENSA_JMP_SLOT",
+ "R_XTENSA_RELATIVE",
+ "R_XTENSA_PLT",
+ "R_XTENSA_UNUSED7",
+ "R_XTENSA_OP0",
+ "R_XTENSA_OP1",
+ "R_XTENSA_OP2",
+ "R_XTENSA_ASM_EXPAND",
+ "R_XTENSA_ASM_SIMPLIFY",
+ "R_XTENSA_UNUSED13",
+ "R_XTENSA_UNUSED14",
+ "R_XTENSA_GNU_VTINHERIT",
+ "R_XTENSA_GNU_VTENTRY",
+ "R_XTENSA_DIFF8",
+ "R_XTENSA_DIFF16",
+ "R_XTENSA_DIFF32",
+ "R_XTENSA_SLOT0_OP",
+ "R_XTENSA_SLOT1_OP",
+ "R_XTENSA_SLOT2_OP",
+ "R_XTENSA_SLOT3_OP",
+ "R_XTENSA_SLOT4_OP",
+ "R_XTENSA_SLOT5_OP",
+ "R_XTENSA_SLOT6_OP",
+ "R_XTENSA_SLOT7_OP",
+ "R_XTENSA_SLOT8_OP",
+ "R_XTENSA_SLOT9_OP",
+ "R_XTENSA_SLOT10_OP",
+ "R_XTENSA_SLOT11_OP",
+ "R_XTENSA_SLOT12_OP",
+ "R_XTENSA_SLOT13_OP",
+ "R_XTENSA_SLOT14_OP",
+ "R_XTENSA_SLOT0_ALT",
+ "R_XTENSA_SLOT1_ALT",
+ "R_XTENSA_SLOT2_ALT",
+ "R_XTENSA_SLOT3_ALT",
+ "R_XTENSA_SLOT4_ALT",
+ "R_XTENSA_SLOT5_ALT",
+ "R_XTENSA_SLOT6_ALT",
+ "R_XTENSA_SLOT7_ALT",
+ "R_XTENSA_SLOT8_ALT",
+ "R_XTENSA_SLOT9_ALT",
+ "R_XTENSA_SLOT10_ALT",
+ "R_XTENSA_SLOT11_ALT",
+ "R_XTENSA_SLOT12_ALT",
+ "R_XTENSA_SLOT13_ALT",
+ "R_XTENSA_SLOT14_ALT"
+};
diff --git a/ldso/ldso/xtensa/dl-startup.h b/ldso/ldso/xtensa/dl-startup.h
new file mode 100644
index 000000000..2fd012846
--- /dev/null
+++ b/ldso/ldso/xtensa/dl-startup.h
@@ -0,0 +1,106 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Xtensa ELF code used by dl-startup.c.
+ *
+ * Copyright (C) 2007 Tensilica Inc.
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ * Parts taken from glibc/sysdeps/xtensa/dl-machine.h.
+ */
+
+__asm__ (
+ " .text\n"
+ " .align 4\n"
+ " .global _start\n"
+ " .type _start, @function\n"
+ "_start:\n"
+ " # Compute load offset in a2: the GOT has not yet been relocated\n"
+ " # but the entries for local symbols contain the relative offsets\n"
+ " # and we can explicitly add the load offset in this code.\n"
+ " _call0 0f\n"
+ " .align 4\n"
+ "0: movi a3, _start+3\n"
+ " sub a2, a0, a3\n"
+ " # Make sure a0 is cleared to mark the top of stack.\n"
+ " movi a0, 0\n"
+ " # user_entry_point = _dl_start(pointer to argument block)\n"
+ " movi a4, _dl_start\n"
+ " mov a6, sp\n"
+ " add a4, a4, a2\n"
+ " callx4 a4\n"
+ " # Save user_entry_point so we can jump to it.\n"
+ " mov a3, a6\n"
+ " l32i a7, sp, 0 # load argc\n"
+ " # Load _dl_skip_args into a4.\n"
+ " movi a4, _dl_skip_args\n"
+ " l32i a4, a4, 0\n"
+ " bnez a4, .Lfixup_stack\n"
+ ".Lfixup_stack_ret:\n"
+ " # Pass finalizer (_dl_fini) in a2 to the user entry point.\n"
+ " movi a2, _dl_fini\n"
+ " # Jump to user's entry point (_start).\n"
+ " jx a3\n"
+ ".Lfixup_stack:\n"
+ " # argc -= _dl_skip_args (with argc @ sp+0)\n"
+ " sub a7, a7, a4\n"
+ " s32i a7, sp, 0\n"
+ " # Shift everything by _dl_skip_args.\n"
+ " addi a5, sp, 4 # a5 = destination ptr = argv\n"
+ " add a4, a5, a4 # a4 = source ptr = argv + _dl_skip_args\n"
+ " # Shift argv.\n"
+ "1: l32i a6, a4, 0\n"
+ " addi a4, a4, 4\n"
+ " s32i a6, a5, 0\n"
+ " addi a5, a5, 4\n"
+ " bnez a6, 1b\n"
+ " # Shift envp.\n"
+ "2: l32i a6, a4, 0\n"
+ " addi a4, a4, 4\n"
+ " s32i a6, a5, 0\n"
+ " addi a5, a5, 4\n"
+ " bnez a6, 2b\n"
+ " # Shift auxiliary table.\n"
+ "3: l32i a6, a4, 0\n"
+ " l32i a8, a4, 4\n"
+ " addi a4, a4, 8\n"
+ " s32i a6, a5, 0\n"
+ " s32i a8, a5, 4\n"
+ " addi a5, a5, 8\n"
+ " bnez a6, 3b\n"
+ " j .Lfixup_stack_ret");
+
+/* Get a pointer to the argv value. */
+#define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long *) ARGS) + 1)
+
+/* Function calls are not safe until the GOT relocations have been done. */
+#define NO_FUNCS_BEFORE_BOOTSTRAP
+
+#define PERFORM_BOOTSTRAP_GOT(tpnt) \
+do { \
+ xtensa_got_location *got_loc; \
+ unsigned long l_addr = tpnt->loadaddr; \
+ Elf32_Word relative_count; \
+ unsigned long rel_addr; \
+ int x; \
+\
+ got_loc = (xtensa_got_location *) \
+ (tpnt->dynamic_info[DT_XTENSA (GOT_LOC_OFF)] + l_addr); \
+\
+ for (x = 0; x < tpnt->dynamic_info[DT_XTENSA (GOT_LOC_SZ)]; x++) { \
+ Elf32_Addr got_start, got_end; \
+ got_start = got_loc[x].offset & ~(PAGE_SIZE - 1); \
+ got_end = ((got_loc[x].offset + got_loc[x].length + PAGE_SIZE - 1) \
+ & ~(PAGE_SIZE - 1)); \
+ _dl_mprotect ((void *)(got_start + l_addr), got_end - got_start, \
+ PROT_READ | PROT_WRITE | PROT_EXEC); \
+ } \
+\
+ /* The following is a stripped down version of the code following \
+ the invocation of PERFORM_BOOTSTRAP_GOT in dl-startup.c. That \
+ code is skipped when PERFORM_BOOTSTRAP_GOT is defined, so it has \
+ to be done here instead. */ \
+ relative_count = tpnt->dynamic_info[DT_RELCONT_IDX]; \
+ rel_addr = tpnt->dynamic_info[DT_RELOC_TABLE_ADDR]; \
+ if (rel_addr) \
+ elf_machine_relative(load_addr, rel_addr, relative_count); \
+} while (0)
diff --git a/ldso/ldso/xtensa/dl-syscalls.h b/ldso/ldso/xtensa/dl-syscalls.h
new file mode 100644
index 000000000..4b42a57e0
--- /dev/null
+++ b/ldso/ldso/xtensa/dl-syscalls.h
@@ -0,0 +1,7 @@
+/* We can't use the real errno in ldso, since it has not yet
+ * been dynamicly linked in yet. */
+#include "sys/syscall.h"
+extern int _dl_errno;
+#undef __set_errno
+#define __set_errno(X) {(_dl_errno) = (X);}
+
diff --git a/ldso/ldso/xtensa/dl-sysdep.h b/ldso/ldso/xtensa/dl-sysdep.h
new file mode 100644
index 000000000..afbbf3bfe
--- /dev/null
+++ b/ldso/ldso/xtensa/dl-sysdep.h
@@ -0,0 +1,132 @@
+/* Machine-dependent ELF dynamic relocation.
+ Parts copied from glibc/sysdeps/xtensa/dl-machine.h
+ Copyright (C) 2001, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* Define this if the system uses RELOCA. */
+#define ELF_USES_RELOCA
+#include <elf.h>
+#include <link.h>
+
+/* Translate a processor specific dynamic tag to the index
+ in l_info array. */
+#define DT_XTENSA(x) (DT_XTENSA_##x - DT_LOPROC + DT_NUM + OS_NUM)
+
+typedef struct xtensa_got_location_struct {
+ Elf32_Off offset;
+ Elf32_Word length;
+} xtensa_got_location;
+
+/* Initialization sequence for the GOT. */
+#define INIT_GOT(GOT_BASE, MODULE) \
+ do { \
+ xtensa_got_location *got_loc; \
+ Elf32_Addr l_addr = MODULE->loadaddr; \
+ int x; \
+ \
+ got_loc = (xtensa_got_location *) \
+ (MODULE->dynamic_info[DT_XTENSA (GOT_LOC_OFF)] + l_addr); \
+ \
+ for (x = 0; x < MODULE->dynamic_info[DT_XTENSA (GOT_LOC_SZ)]; x++) \
+ { \
+ Elf32_Addr got_start, got_end; \
+ got_start = got_loc[x].offset & ~(PAGE_SIZE - 1); \
+ got_end = ((got_loc[x].offset + got_loc[x].length + PAGE_SIZE - 1) \
+ & ~(PAGE_SIZE - 1)); \
+ _dl_mprotect ((void *)(got_start + l_addr) , got_end - got_start, \
+ PROT_READ | PROT_WRITE | PROT_EXEC); \
+ } \
+ \
+ /* Fill in first GOT entry according to the ABI. */ \
+ GOT_BASE[0] = (unsigned long) _dl_linux_resolve; \
+ } while (0)
+
+/* Parse dynamic info */
+#define ARCH_NUM 2
+#define ARCH_DYNAMIC_INFO(dpnt, dynamic, debug_addr) \
+ do { \
+ if (dpnt->d_tag == DT_XTENSA_GOT_LOC_OFF) \
+ dynamic[DT_XTENSA (GOT_LOC_OFF)] = dpnt->d_un.d_ptr; \
+ else if (dpnt->d_tag == DT_XTENSA_GOT_LOC_SZ) \
+ dynamic[DT_XTENSA (GOT_LOC_SZ)] = dpnt->d_un.d_val; \
+ } while (0)
+
+/* Here we define the magic numbers that this dynamic loader should accept. */
+#define MAGIC1 EM_XTENSA
+#undef MAGIC2
+
+/* Used for error messages. */
+#define ELF_TARGET "Xtensa"
+
+struct elf_resolve;
+extern unsigned long _dl_linux_resolver (struct elf_resolve *, int);
+
+/* 4096 bytes alignment */
+#define PAGE_ALIGN 0xfffff000
+#define ADDR_ALIGN 0xfff
+#define OFFS_ALIGN 0x7ffff000
+
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
+ undefined references should not be allowed to define the value. */
+#define elf_machine_type_class(type) \
+ (((type) == R_XTENSA_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)
+
+/* Return the link-time address of _DYNAMIC. */
+static inline Elf32_Addr
+elf_machine_dynamic (void)
+{
+ /* This function is only used while bootstrapping the runtime linker.
+ The "_DYNAMIC" symbol is always local so its GOT entry will initially
+ contain the link-time address. */
+ return (Elf32_Addr) &_DYNAMIC;
+}
+
+/* Return the run-time load address of the shared object. */
+static inline Elf32_Addr
+elf_machine_load_address (void)
+{
+ Elf32_Addr addr, tmp;
+
+ /* At this point, the runtime linker is being bootstrapped and the GOT
+ entry used for ".Lhere" will contain the link address. The CALL0 will
+ produce the dynamic address of ".Lhere" + 3. Thus, the end result is
+ equal to "dynamic_address(.Lhere) - link_address(.Lhere)". */
+ __asm__ ("\
+ movi %0, .Lhere\n\
+ mov %1, a0\n\
+.Lhere: _call0 0f\n\
+ .align 4\n\
+0: sub %0, a0, %0\n\
+ mov a0, %1"
+ : "=a" (addr), "=a" (tmp));
+
+ return addr - 3;
+}
+
+static inline void
+elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+ Elf32_Word relative_count)
+{
+ Elf32_Rela *rpnt = (Elf32_Rela *) rel_addr;
+ while (relative_count--)
+ {
+ Elf32_Addr *const reloc_addr = (Elf32_Addr *) (load_off + rpnt->r_offset);
+ *reloc_addr += load_off + rpnt->r_addend;
+ rpnt++;
+ }
+}
diff --git a/ldso/ldso/xtensa/elfinterp.c b/ldso/ldso/xtensa/elfinterp.c
new file mode 100644
index 000000000..a459431b1
--- /dev/null
+++ b/ldso/ldso/xtensa/elfinterp.c
@@ -0,0 +1,285 @@
+/* vi: set sw=4 ts=4: */
+/* Xtensa ELF shared library loader suppport
+ *
+ * Copyright (C) 2007 Tensilica Inc.
+ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
+ * David Engel, Hongjiu Lu and Mitch D'Souza
+ * Copyright (C) 2001-2004 Erik Andersen
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the above contributors may not be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "ldso.h"
+
+unsigned long
+_dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
+{
+ int reloc_type;
+ ELF_RELOC *this_reloc;
+ char *strtab;
+ Elf32_Sym *symtab;
+ int symtab_index;
+ char *rel_addr;
+ char *new_addr;
+ char **got_addr;
+ char *symname;
+
+ rel_addr = (char *) tpnt->dynamic_info[DT_JMPREL];
+ this_reloc = (ELF_RELOC *) (rel_addr + reloc_entry);
+ reloc_type = ELF32_R_TYPE (this_reloc->r_info);
+ symtab_index = ELF32_R_SYM (this_reloc->r_info);
+
+ symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
+ strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
+ symname = strtab + symtab[symtab_index].st_name;
+
+ if (unlikely (reloc_type != R_XTENSA_JMP_SLOT)) {
+ _dl_dprintf (2, "%s: Incorrect relocation type in jump relocations\n",
+ _dl_progname);
+ _dl_exit (1);
+ }
+
+ /* Address of the literal to fix up. */
+ got_addr = (char **) (this_reloc->r_offset + tpnt->loadaddr);
+
+ /* Get the address of the GOT entry. */
+ new_addr = _dl_find_hash (symname, tpnt->symbol_scope, tpnt,
+ ELF_RTYPE_CLASS_PLT);
+ if (unlikely (!new_addr)) {
+ _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, symname);
+ _dl_exit (1);
+ }
+
+#if defined (__SUPPORT_LD_DEBUG__)
+ if (_dl_debug_bindings) {
+ _dl_dprintf (_dl_debug_file, "\nresolve function: %s", symname);
+ if (_dl_debug_detail)
+ _dl_dprintf (_dl_debug_file, "\n\tpatched %x ==> %x @ %x\n",
+ *got_addr, new_addr, got_addr);
+ }
+ if (!_dl_debug_nofixups)
+ *got_addr = new_addr;
+#else
+ *got_addr = new_addr;
+#endif
+
+ return (unsigned long) new_addr;
+}
+
+
+static int
+_dl_parse (struct elf_resolve *tpnt, struct dyn_elf *scope,
+ unsigned long rel_addr, unsigned long rel_size,
+ int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
+ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
+{
+ unsigned int i;
+ char *strtab;
+ Elf32_Sym *symtab;
+ ELF_RELOC *rpnt;
+ int symtab_index;
+
+ /* Parse the relocation information. */
+ rpnt = (ELF_RELOC *) rel_addr;
+ rel_size /= sizeof (ELF_RELOC);
+
+ symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
+ strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
+
+ for (i = 0; i < rel_size; i++, rpnt++) {
+ int res;
+
+ symtab_index = ELF32_R_SYM (rpnt->r_info);
+
+ debug_sym (symtab, strtab, symtab_index);
+ debug_reloc (symtab, strtab, rpnt);
+
+ res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
+
+ if (res == 0)
+ continue;
+
+ _dl_dprintf (2, "\n%s: ", _dl_progname);
+
+ if (symtab_index)
+ _dl_dprintf (2, "symbol '%s': ",
+ strtab + symtab[symtab_index].st_name);
+
+ if (unlikely (res < 0)) {
+ int reloc_type = ELF32_R_TYPE (rpnt->r_info);
+#if defined (__SUPPORT_LD_DEBUG__)
+ _dl_dprintf (2, "can't handle reloc type %s\n",
+ _dl_reltypes (reloc_type));
+#else
+ _dl_dprintf (2, "can't handle reloc type %x\n", reloc_type);
+#endif
+ _dl_exit (-res);
+ }
+ if (unlikely (res > 0)) {
+ _dl_dprintf (2, "can't resolve symbol\n");
+ return res;
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+_dl_do_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
+ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
+{
+ int reloc_type;
+ int symtab_index;
+ char *symname;
+ Elf32_Sym *sym;
+ Elf32_Addr *reloc_addr;
+ Elf32_Addr symbol_addr;
+#if defined (__SUPPORT_LD_DEBUG__)
+ Elf32_Addr old_val;
+#endif
+
+ reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE (rpnt->r_info);
+ symtab_index = ELF32_R_SYM (rpnt->r_info);
+ sym = &symtab[symtab_index];
+ symbol_addr = 0;
+ symname = strtab + sym->st_name;
+
+ if (symtab_index) {
+ symbol_addr = (Elf32_Addr)
+ _dl_find_hash (symname, scope, tpnt,
+ elf_machine_type_class (reloc_type));
+
+ /*
+ * We want to allow undefined references to weak symbols - this might
+ * have been intentional. We should not be linking local symbols
+ * here, so all bases should be covered.
+ */
+ if (unlikely (!symbol_addr &&
+ ELF32_ST_BIND (sym->st_info) != STB_WEAK)) {
+ _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
+ _dl_progname, symname);
+ _dl_exit (1);
+ }
+ }
+
+#if defined (__SUPPORT_LD_DEBUG__)
+ old_val = *reloc_addr;
+#endif
+
+ switch (reloc_type) {
+ case R_XTENSA_NONE:
+ break;
+
+ case R_XTENSA_GLOB_DAT:
+ case R_XTENSA_JMP_SLOT:
+ *reloc_addr = symbol_addr + rpnt->r_addend;
+ break;
+
+ case R_XTENSA_RTLD:
+ if (rpnt->r_addend == 1) {
+ /* Grab the function pointer stashed at the beginning of the
+ GOT by the GOT_INIT function. */
+ *reloc_addr = *(Elf32_Addr *) tpnt->dynamic_info[DT_PLTGOT];
+ } else if (rpnt->r_addend == 2) {
+ /* Store the link map for the object. */
+ *reloc_addr = (Elf32_Addr) tpnt;
+ } else {
+ _dl_exit (1);
+ }
+ break;
+
+ case R_XTENSA_RELATIVE:
+ *reloc_addr += tpnt->loadaddr + rpnt->r_addend;
+ break;
+
+ default:
+ return -1; /* Calls _dl_exit(1). */
+ }
+#if defined (__SUPPORT_LD_DEBUG__)
+ if (_dl_debug_reloc && _dl_debug_detail)
+ _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %x",
+ old_val, *reloc_addr, reloc_addr);
+#endif
+
+ return 0;
+}
+
+
+static int
+_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
+ ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
+{
+ int reloc_type;
+ Elf32_Addr *reloc_addr;
+#if defined (__SUPPORT_LD_DEBUG__)
+ Elf32_Addr old_val;
+#endif
+
+ reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + rpnt->r_offset);
+ reloc_type = ELF32_R_TYPE (rpnt->r_info);
+
+#if defined (__SUPPORT_LD_DEBUG__)
+ old_val = *reloc_addr;
+#endif
+
+ switch (reloc_type) {
+ case R_XTENSA_JMP_SLOT:
+ /* Perform a RELATIVE reloc on the GOT entry that transfers
+ to the stub function. */
+ *reloc_addr += tpnt->loadaddr;
+ break;
+ case R_XTENSA_NONE:
+ break;
+ default:
+ _dl_exit (1);
+ }
+
+#if defined (__SUPPORT_LD_DEBUG__)
+ if (_dl_debug_reloc && _dl_debug_detail)
+ _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %x",
+ old_val, *reloc_addr, reloc_addr);
+#endif
+ return 0;
+
+}
+
+void
+_dl_parse_lazy_relocation_information (struct dyn_elf *rpnt,
+ unsigned long rel_addr,
+ unsigned long rel_size)
+{
+ (void) _dl_parse (rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
+}
+
+int
+_dl_parse_relocation_information (struct dyn_elf *rpnt,
+ unsigned long rel_addr,
+ unsigned long rel_size)
+{
+ return _dl_parse (rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size,
+ _dl_do_reloc);
+}
diff --git a/ldso/ldso/xtensa/resolve.S b/ldso/ldso/xtensa/resolve.S
new file mode 100644
index 000000000..fb298391c
--- /dev/null
+++ b/ldso/ldso/xtensa/resolve.S
@@ -0,0 +1,61 @@
+/* Xtensa dynamic resolver.
+ Parts copied from glibc/sysdeps/xtensa/dl-trampoline.S
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#define MIN_FRAME_SIZE 32
+
+#ifdef __XTENSA_EB__
+#define XTENSA_IMM12_FLD_OFFSET 8
+#else /* __XTENSA_EL__ */
+#define XTENSA_IMM12_FLD_OFFSET 12
+#endif /* __XTENSA_EL__ */
+
+ .text
+ .align 4
+ .global _dl_linux_resolve
+ .type _dl_linux_resolve, @function
+_dl_linux_resolve:
+ /* Fix up the high 2 bits of the return address. */
+ mov a14, a0 // save a0 temporarily
+ _call0 0f
+ .align 4
+0: extui a13, a0, 30, 2
+ slli a13, a13, 30
+ mov a0, a14 // restore a0
+ slli a12, a0, 2
+ srli a12, a12, 2
+ or a12, a12, a13
+
+ /* Call the fixup function. */
+ movi a8, _dl_linux_resolver
+ callx8 a8
+
+ /* Extract the target's frame size from the ENTRY instruction. */
+ l32i a11, a10, 0
+ extui a11, a11, XTENSA_IMM12_FLD_OFFSET, 12
+ slli a11, a11, 3
+
+ addi a11, a11, -MIN_FRAME_SIZE
+ sub a11, sp, a11
+ movsp sp, a11
+
+ /* Jump to the next instruction past the ENTRY. */
+ addi a10, a10, 3
+ jx a10
+ .size _dl_linux_resolve, . - _dl_linux_resolve