Xtensa support for uClibc [2/9]

Chris Zankel chris at zankel.net
Thu Dec 6 20:49:42 UTC 2007


Add support for Xtensa to uClibc [2/9]: Dynamic loader support.

---

diff -Nurd uClibc-0.9.29.orig/ldso/ldso/xtensa/dl-debug.h uClibc-0.9.29/ldso/ldso/xtensa/dl-debug.h
--- uClibc-0.9.29.orig/ldso/ldso/xtensa/dl-debug.h	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/ldso/ldso/xtensa/dl-debug.h	2007-12-04 11:38:14.000000000 -0800
@@ -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 -Nurd uClibc-0.9.29.orig/ldso/ldso/xtensa/dl-startup.h uClibc-0.9.29/ldso/ldso/xtensa/dl-startup.h
--- uClibc-0.9.29.orig/ldso/ldso/xtensa/dl-startup.h	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/ldso/ldso/xtensa/dl-startup.h	2007-12-04 11:38:14.000000000 -0800
@@ -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 -Nurd uClibc-0.9.29.orig/ldso/ldso/xtensa/dl-syscalls.h uClibc-0.9.29/ldso/ldso/xtensa/dl-syscalls.h
--- uClibc-0.9.29.orig/ldso/ldso/xtensa/dl-syscalls.h	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/ldso/ldso/xtensa/dl-syscalls.h	2007-12-04 11:38:00.000000000 -0800
@@ -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 -Nurd uClibc-0.9.29.orig/ldso/ldso/xtensa/dl-sysdep.h uClibc-0.9.29/ldso/ldso/xtensa/dl-sysdep.h
--- uClibc-0.9.29.orig/ldso/ldso/xtensa/dl-sysdep.h	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/ldso/ldso/xtensa/dl-sysdep.h	2007-12-04 11:38:00.000000000 -0800
@@ -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 -Nurd uClibc-0.9.29.orig/ldso/ldso/xtensa/elfinterp.c uClibc-0.9.29/ldso/ldso/xtensa/elfinterp.c
--- uClibc-0.9.29.orig/ldso/ldso/xtensa/elfinterp.c	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/ldso/ldso/xtensa/elfinterp.c	2007-12-04 11:38:14.000000000 -0800
@@ -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 -Nurd uClibc-0.9.29.orig/ldso/ldso/xtensa/resolve.S uClibc-0.9.29/ldso/ldso/xtensa/resolve.S
--- uClibc-0.9.29.orig/ldso/ldso/xtensa/resolve.S	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/ldso/ldso/xtensa/resolve.S	2007-12-04 11:38:00.000000000 -0800
@@ -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



More information about the uClibc mailing list