remove the not useful disclaimer
[uclibc-ng.git] / ldso / ldso / bfin / elfinterp.c
blob6549b77f2a0d9ea44f4ecaa5c99c427b3ce464c7
1 /* Blackfin ELF shared library loader suppport
2 Copyright (C) 2003, 2004 Red Hat, Inc.
3 Contributed by Alexandre Oliva <aoliva@redhat.com>
4 Lots of code copied from ../i386/elfinterp.c, so:
5 Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
6 David Engel, Hongjiu Lu and Mitch D'Souza
7 Copyright (C) 2001-2002, Erik Andersen
8 All rights reserved.
10 This file is part of uClibc.
12 uClibc is free software; you can redistribute it and/or modify it
13 under the terms of the GNU Lesser General Public License as
14 published by the Free Software Foundation; either version 2.1 of the
15 License, or (at your option) any later version.
17 uClibc is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Library General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public
23 License along with uClibc; see the file COPYING.LIB. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #include <sys/cdefs.h> /* __attribute_used__ */
28 /* Program to load an ELF binary on a linux system, and run it.
29 References to symbols in sharable libraries can be resolved by either
30 an ELF sharable library or a linux style of shared library. */
32 __attribute__((__visibility__("hidden")))
33 struct funcdesc_value volatile *
34 _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
36 ELF_RELOC *this_reloc;
37 char *strtab;
38 ElfW(Sym) *symtab;
39 int symtab_index;
40 char *rel_addr;
41 char *new_addr;
42 struct funcdesc_value funcval;
43 struct funcdesc_value volatile *got_entry;
44 char *symname;
45 struct symbol_ref sym_ref;
47 rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
49 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
50 symtab_index = ELF_R_SYM(this_reloc->r_info);
52 symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
53 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
54 sym_ref.sym = &symtab[symtab_index];
55 sym_ref.tpnt = NULL;
56 symname= strtab + symtab[symtab_index].st_name;
58 /* Address of GOT entry fix up */
59 got_entry = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
61 /* Get the address to be used to fill in the GOT entry. */
62 new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, NULL, 0, &sym_ref);
63 if (!new_addr) {
64 new_addr = _dl_find_hash(symname, NULL, NULL, 0, &sym_ref);
65 if (!new_addr) {
66 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
67 _dl_progname, symname);
68 _dl_exit(1);
72 funcval.entry_point = new_addr;
73 funcval.got_value = sym_ref.tpnt->loadaddr.got_value;
75 #if defined (__SUPPORT_LD_DEBUG__)
76 if (_dl_debug_bindings) {
77 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
78 if (_dl_debug_detail)
79 _dl_dprintf(_dl_debug_file,
80 "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n",
81 got_entry->entry_point, got_entry->got_value,
82 funcval.entry_point, funcval.got_value,
83 got_entry);
85 if (1 || !_dl_debug_nofixups) {
86 *got_entry = funcval;
88 #else
89 *got_entry = funcval;
90 #endif
92 return got_entry;
95 static int
96 _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
97 unsigned long rel_addr, unsigned long rel_size,
98 int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
99 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
101 unsigned int i;
102 char *strtab;
103 ElfW(Sym) *symtab;
104 ELF_RELOC *rpnt;
105 int symtab_index;
107 /* Now parse the relocation information */
108 rpnt = (ELF_RELOC *) rel_addr;
109 rel_size = rel_size / sizeof(ELF_RELOC);
111 symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
112 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
114 for (i = 0; i < rel_size; i++, rpnt++) {
115 int res;
117 symtab_index = ELF_R_SYM(rpnt->r_info);
118 debug_sym(symtab,strtab,symtab_index);
119 debug_reloc(symtab,strtab,rpnt);
121 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
123 if (res==0) continue;
125 _dl_dprintf(2, "\n%s: ",_dl_progname);
127 if (symtab_index)
128 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
130 if (res <0) {
131 int reloc_type = ELF_R_TYPE(rpnt->r_info);
132 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
133 _dl_exit(-res);
134 } else if (res >0) {
135 _dl_dprintf(2, "can't resolve symbol\n");
136 return res;
139 return 0;
142 static int
143 _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope,
144 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
146 int reloc_type;
147 int symtab_index;
148 char *symname;
149 unsigned long reloc_value = 0, *reloc_addr;
150 struct { unsigned long v; } __attribute__((__packed__))
151 *reloc_addr_packed;
152 unsigned long symbol_addr;
153 struct elf_resolve *symbol_tpnt;
154 struct funcdesc_value funcval;
155 #if defined (__SUPPORT_LD_DEBUG__)
156 unsigned long old_val;
157 #endif
158 struct symbol_ref sym_ref;
160 reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
161 __asm__ ("" : "=r" (reloc_addr_packed) : "0" (reloc_addr));
162 reloc_type = ELF_R_TYPE(rpnt->r_info);
163 symtab_index = ELF_R_SYM(rpnt->r_info);
164 symbol_addr = 0;
165 sym_ref.sym = &symtab[symtab_index];
166 sym_ref.tpnt = NULL;
167 symname = strtab + symtab[symtab_index].st_name;
169 if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
170 symbol_addr = (unsigned long) DL_RELOC_ADDR(tpnt->loadaddr, symtab[symtab_index].st_value);
171 symbol_tpnt = tpnt;
172 } else {
174 symbol_addr = (unsigned long)
175 _dl_find_hash(symname, scope, NULL, 0, &sym_ref);
178 * We want to allow undefined references to weak symbols - this might
179 * have been intentional. We should not be linking local symbols
180 * here, so all bases should be covered.
183 if (!symbol_addr && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
184 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
185 _dl_progname, symname);
186 _dl_exit (1);
188 if (_dl_trace_prelink) {
189 _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
190 &sym_ref, elf_machine_type_class(reloc_type));
192 symbol_tpnt = sym_ref.tpnt;
195 #if defined (__SUPPORT_LD_DEBUG__)
196 if (_dl_debug_reloc && _dl_debug_detail)
198 if ((long)reloc_addr_packed & 3)
199 old_val = reloc_addr_packed->v;
200 else
201 old_val = *reloc_addr;
203 else
204 old_val = 0;
205 #endif
206 switch (reloc_type) {
207 case R_BFIN_UNUSED0:
208 break;
209 case R_BFIN_BYTE4_DATA:
210 if ((long)reloc_addr_packed & 3)
211 reloc_value = reloc_addr_packed->v += symbol_addr;
212 else
213 reloc_value = *reloc_addr += symbol_addr;
214 break;
215 case R_BFIN_FUNCDESC_VALUE:
216 funcval.entry_point = (void*)symbol_addr;
217 /* The addend of FUNCDESC_VALUE
218 relocations referencing global
219 symbols must be ignored, because it
220 may hold the address of a lazy PLT
221 entry. */
222 if (ELF_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL)
223 funcval.entry_point += *reloc_addr;
224 reloc_value = (unsigned long)funcval.entry_point;
225 if (symbol_addr)
226 funcval.got_value
227 = symbol_tpnt->loadaddr.got_value;
228 else
229 funcval.got_value = 0;
230 __asm__ ("%0 = %2; %1 = %H2;"
231 : "=m" (*(struct funcdesc_value *)reloc_addr), "=m" (((long *)reloc_addr)[1])
232 : "d" (funcval));
233 break;
234 case R_BFIN_FUNCDESC:
235 if ((long)reloc_addr_packed & 3)
236 reloc_value = reloc_addr_packed->v;
237 else
238 reloc_value = *reloc_addr;
239 if (symbol_addr)
240 reloc_value = (unsigned long)_dl_funcdesc_for
241 ((char *)symbol_addr + reloc_value,
242 symbol_tpnt->loadaddr.got_value);
243 else
244 reloc_value = 0;
245 if ((long)reloc_addr_packed & 3)
246 reloc_addr_packed->v = reloc_value;
247 else
248 *reloc_addr = reloc_value;
249 break;
250 default:
251 return -1;
253 #if defined (__SUPPORT_LD_DEBUG__)
254 if (_dl_debug_reloc && _dl_debug_detail) {
255 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_value, reloc_addr);
256 switch (reloc_type) {
257 case R_BFIN_FUNCDESC_VALUE:
258 _dl_dprintf(_dl_debug_file, " got %x", ((struct funcdesc_value *)reloc_value)->got_value);
259 break;
260 case R_BFIN_FUNCDESC:
261 if (! reloc_value)
262 break;
263 _dl_dprintf(_dl_debug_file, " funcdesc (%x,%x)",
264 ((struct funcdesc_value *)reloc_value)->entry_point,
265 ((struct funcdesc_value *)reloc_value)->got_value);
266 break;
269 #endif
271 return 0;
274 static int
275 _dl_do_lazy_reloc (struct elf_resolve *tpnt,
276 struct r_scope_elem *scope __attribute__((unused)),
277 ELF_RELOC *rpnt, ElfW(Sym) *symtab __attribute__((unused)),
278 char *strtab __attribute__((unused)))
280 int reloc_type;
281 struct funcdesc_value volatile *reloc_addr;
282 struct funcdesc_value funcval;
283 #if defined (__SUPPORT_LD_DEBUG__)
284 unsigned long old_val;
285 #endif
287 reloc_addr = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
288 reloc_type = ELF_R_TYPE(rpnt->r_info);
290 #if defined (__SUPPORT_LD_DEBUG__)
291 old_val = (unsigned long)reloc_addr->entry_point;
292 #endif
293 switch (reloc_type) {
294 case R_BFIN_UNUSED0:
295 break;
296 case R_BFIN_FUNCDESC_VALUE:
297 funcval = *reloc_addr;
298 funcval.entry_point = (void *) DL_RELOC_ADDR(tpnt->loadaddr, funcval.entry_point);
299 funcval.got_value = tpnt->loadaddr.got_value;
300 *reloc_addr = funcval;
301 break;
302 default:
303 return -1;
305 #if defined (__SUPPORT_LD_DEBUG__)
306 if (_dl_debug_reloc && _dl_debug_detail)
307 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, reloc_addr->entry_point, reloc_addr);
308 #endif
309 return 0;
313 void
314 _dl_parse_lazy_relocation_information
315 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
317 _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
321 _dl_parse_relocation_information
322 (struct dyn_elf *rpnt, struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size)
324 return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
327 /* We don't have copy relocs. */
330 _dl_parse_copy_information
331 (struct dyn_elf *rpnt __attribute__((unused)),
332 unsigned long rel_addr __attribute__((unused)),
333 unsigned long rel_size __attribute__((unused)))
335 return 0;
338 #ifndef IS_IN_libdl
339 # include "../../libc/sysdeps/linux/bfin/crtreloc.c"
340 #endif