From 124ec188720b6bdea85ade49e7ea195161b12fce Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 5 Jan 2008 10:05:27 +0000 Subject: Chris Zankel writes: The following patches add support for the Xtensa processor architecture to uClibc. They are based on a recent SVN checkout (12/05/2007). The first patch (attached to this post) adds Xtensa support to various shared configuration and make files. The following patches then include the Xtensa specific files and directories. I welcome any feedback and would appreciate it if you could include the patches into the mainline tree. I am certainly committed to maintain the port. Bob Wilson was kind enough to review the patches. Some notes about the architecture: Xtensa is a configurable and extensible processor architecture developed by Tensilica. For more information, please visit: www.linux-xtensa.org. --- ldso/include/dl-string.h | 2 +- ldso/ldso/xtensa/dl-debug.h | 61 +++++++++ ldso/ldso/xtensa/dl-startup.h | 106 +++++++++++++++ ldso/ldso/xtensa/dl-syscalls.h | 7 + ldso/ldso/xtensa/dl-sysdep.h | 132 +++++++++++++++++++ ldso/ldso/xtensa/elfinterp.c | 285 +++++++++++++++++++++++++++++++++++++++++ ldso/ldso/xtensa/resolve.S | 61 +++++++++ 7 files changed, 653 insertions(+), 1 deletion(-) create mode 100644 ldso/ldso/xtensa/dl-debug.h create mode 100644 ldso/ldso/xtensa/dl-startup.h create mode 100644 ldso/ldso/xtensa/dl-syscalls.h create mode 100644 ldso/ldso/xtensa/dl-sysdep.h create mode 100644 ldso/ldso/xtensa/elfinterp.c create mode 100644 ldso/ldso/xtensa/resolve.S (limited to 'ldso') 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 +#include + +/* 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 -- cgit v1.2.3