1 /* vi: set sw=4 ts=4: */
2 /* Xtensa ELF shared library loader suppport
4 * Copyright (C) 2007 Tensilica Inc.
5 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
6 * David Engel, Hongjiu Lu and Mitch D'Souza
7 * Copyright (C) 2001-2004 Erik Andersen
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. The name of the above contributors may not be
17 * used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
38 ELF_RELOC *this_reloc;
47 rel_addr = (char *) tpnt->dynamic_info[DT_JMPREL];
48 this_reloc = (ELF_RELOC *) (rel_addr + reloc_entry);
49 symtab_index = ELF32_R_SYM (this_reloc->r_info);
51 symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
52 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
53 symname = strtab + symtab[symtab_index].st_name;
55 /* Address of the literal to fix up. */
56 got_addr = (char **) (this_reloc->r_offset + tpnt->loadaddr);
58 /* Get the address of the GOT entry. */
59 new_addr = _dl_find_hash (symname, tpnt->symbol_scope, tpnt,
60 ELF_RTYPE_CLASS_PLT, NULL);
61 if (unlikely (!new_addr)) {
62 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
63 _dl_progname, symname);
67 #if defined (__SUPPORT_LD_DEBUG__)
68 if (_dl_debug_bindings) {
69 _dl_dprintf (_dl_debug_file, "\nresolve function: %s", symname);
71 _dl_dprintf (_dl_debug_file, "\n\tpatched %x ==> %x @ %x\n",
72 *got_addr, new_addr, got_addr);
74 if (!_dl_debug_nofixups)
80 return (unsigned long) new_addr;
85 _dl_parse (struct elf_resolve *tpnt, struct dyn_elf *scope,
86 unsigned long rel_addr, unsigned long rel_size,
87 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
88 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
96 /* Parse the relocation information. */
97 rpnt = (ELF_RELOC *) rel_addr;
98 rel_size /= sizeof (ELF_RELOC);
100 symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
101 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
103 for (i = 0; i < rel_size; i++, rpnt++) {
106 symtab_index = ELF32_R_SYM (rpnt->r_info);
108 debug_sym (symtab, strtab, symtab_index);
109 debug_reloc (symtab, strtab, rpnt);
111 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
116 _dl_dprintf (2, "\n%s: ", _dl_progname);
119 _dl_dprintf (2, "symbol '%s': ",
120 strtab + symtab[symtab_index].st_name);
122 if (unlikely (res < 0)) {
123 int reloc_type = ELF32_R_TYPE (rpnt->r_info);
124 #if defined (__SUPPORT_LD_DEBUG__)
125 _dl_dprintf (2, "can't handle reloc type %s\n",
126 _dl_reltypes (reloc_type));
128 _dl_dprintf (2, "can't handle reloc type %x\n", reloc_type);
132 if (unlikely (res > 0)) {
133 _dl_dprintf (2, "can't resolve symbol\n");
143 _dl_do_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
144 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
149 struct symbol_ref sym_ref;
150 Elf32_Addr *reloc_addr;
151 Elf32_Addr symbol_addr;
152 #if defined (__SUPPORT_LD_DEBUG__)
156 reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + rpnt->r_offset);
157 reloc_type = ELF32_R_TYPE (rpnt->r_info);
158 symtab_index = ELF32_R_SYM (rpnt->r_info);
159 sym_ref.sym = &symtab[symtab_index];
162 symname = strtab + sym_ref.sym->st_name;
165 symbol_addr = (Elf32_Addr)
166 _dl_find_hash (symname, scope, tpnt,
167 elf_machine_type_class (reloc_type), &sym_ref);
170 * We want to allow undefined references to weak symbols - this might
171 * have been intentional. We should not be linking local symbols
172 * here, so all bases should be covered.
174 if (unlikely (!symbol_addr &&
175 ELF32_ST_BIND (sym_ref.sym->st_info) != STB_WEAK)) {
176 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
177 _dl_progname, symname);
182 #if defined (__SUPPORT_LD_DEBUG__)
183 old_val = *reloc_addr;
186 switch (reloc_type) {
190 case R_XTENSA_GLOB_DAT:
191 case R_XTENSA_JMP_SLOT:
192 *reloc_addr = symbol_addr + rpnt->r_addend;
196 if (rpnt->r_addend == 1) {
197 /* Grab the function pointer stashed at the beginning of the
198 GOT by the GOT_INIT function. */
199 *reloc_addr = *(Elf32_Addr *) tpnt->dynamic_info[DT_PLTGOT];
200 } else if (rpnt->r_addend == 2) {
201 /* Store the link map for the object. */
202 *reloc_addr = (Elf32_Addr) tpnt;
208 case R_XTENSA_RELATIVE:
209 *reloc_addr += tpnt->loadaddr + rpnt->r_addend;
213 return -1; /* Calls _dl_exit(1). */
215 #if defined (__SUPPORT_LD_DEBUG__)
216 if (_dl_debug_reloc && _dl_debug_detail)
217 _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
218 old_val, *reloc_addr, reloc_addr);
226 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
227 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
230 Elf32_Addr *reloc_addr;
231 #if defined (__SUPPORT_LD_DEBUG__)
235 reloc_addr = (Elf32_Addr *) (tpnt->loadaddr + rpnt->r_offset);
236 reloc_type = ELF32_R_TYPE (rpnt->r_info);
238 #if defined (__SUPPORT_LD_DEBUG__)
239 old_val = *reloc_addr;
242 switch (reloc_type) {
243 case R_XTENSA_JMP_SLOT:
244 /* Perform a RELATIVE reloc on the GOT entry that transfers
245 to the stub function. */
246 *reloc_addr += tpnt->loadaddr;
254 #if defined (__SUPPORT_LD_DEBUG__)
255 if (_dl_debug_reloc && _dl_debug_detail)
256 _dl_dprintf (_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
257 old_val, *reloc_addr, reloc_addr);
264 _dl_parse_lazy_relocation_information (struct dyn_elf *rpnt,
265 unsigned long rel_addr,
266 unsigned long rel_size)
268 (void) _dl_parse (rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
272 _dl_parse_relocation_information (struct dyn_elf *rpnt,
273 unsigned long rel_addr,
274 unsigned long rel_size)
276 return _dl_parse (rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size,