remove the not useful disclaimer
[uclibc-ng.git] / ldso / ldso / frv / elfinterp.c
blob66ee05124dfe621065038f52c7b7a8388ff12cdf
1 /* FR-V FDPIC 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 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
13 #include <sys/cdefs.h> /* __attribute_used__ */
14 #include <features.h>
16 /* Program to load an ELF binary on a linux system, and run it.
17 References to symbols in sharable libraries can be resolved by either
18 an ELF sharable library or a linux style of shared library. */
20 struct funcdesc_value volatile attribute_hidden *
21 _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
23 ELF_RELOC *this_reloc;
24 char *strtab;
25 ElfW(Sym) *symtab;
26 int symtab_index;
27 char *rel_addr;
28 char *new_addr;
29 struct funcdesc_value funcval;
30 struct funcdesc_value volatile *got_entry;
31 char *symname;
32 struct symbol_ref sym_ref;
34 rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
36 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
37 symtab_index = ELF_R_SYM(this_reloc->r_info);
39 symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
40 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
41 sym_ref.sym = &symtab[symtab_index];
42 sym_ref.tpnt = NULL;
43 symname= strtab + symtab[symtab_index].st_name;
45 /* Address of GOT entry fix up */
46 got_entry = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
48 /* Get the address to be used to fill in the GOT entry. */
49 new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, NULL, 0, &sym_ref);
50 if (!new_addr) {
51 new_addr = _dl_find_hash(symname, NULL, NULL, 0, &sym_ref);
52 if (!new_addr) {
53 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
54 _dl_progname, symname);
55 _dl_exit(1);
59 funcval.entry_point = new_addr;
60 funcval.got_value = sym_ref.tpnt->loadaddr.got_value;
62 #if defined (__SUPPORT_LD_DEBUG__)
63 if (_dl_debug_bindings)
65 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
66 if (_dl_debug_detail)
67 _dl_dprintf(_dl_debug_file,
68 "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n",
69 got_entry->entry_point, got_entry->got_value,
70 funcval.entry_point, funcval.got_value,
71 got_entry);
73 if (!_dl_debug_nofixups) {
74 *got_entry = funcval;
76 #else
77 *got_entry = funcval;
78 #endif
80 return got_entry;
83 static int
84 _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
85 unsigned long rel_addr, unsigned long rel_size,
86 int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
87 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
89 unsigned int i;
90 char *strtab;
91 ElfW(Sym) *symtab;
92 ELF_RELOC *rpnt;
93 int symtab_index;
95 /* Now parse the relocation information */
96 rpnt = (ELF_RELOC *) rel_addr;
97 rel_size = rel_size / sizeof(ELF_RELOC);
99 symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
100 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
102 for (i = 0; i < rel_size; i++, rpnt++) {
103 int res;
105 symtab_index = ELF_R_SYM(rpnt->r_info);
106 debug_sym(symtab,strtab,symtab_index);
107 debug_reloc(symtab,strtab,rpnt);
109 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
111 if (res==0) continue;
113 _dl_dprintf(2, "\n%s: ",_dl_progname);
115 if (symtab_index)
116 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
118 if (res <0)
120 int reloc_type = ELF_R_TYPE(rpnt->r_info);
121 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
122 _dl_exit(-res);
124 else if (res >0)
126 _dl_dprintf(2, "can't resolve symbol\n");
127 return res;
130 return 0;
133 static int
134 _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope,
135 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
137 int reloc_type;
138 int symtab_index;
139 char *symname;
140 unsigned long reloc_value = 0, *reloc_addr;
141 struct { unsigned long v; } __attribute__((__packed__))
142 *reloc_addr_packed;
143 unsigned long symbol_addr;
144 struct elf_resolve *symbol_tpnt;
145 struct funcdesc_value funcval;
146 #if defined (__SUPPORT_LD_DEBUG__)
147 unsigned long old_val;
148 #endif
149 struct symbol_ref sym_ref;
151 reloc_addr = (unsigned long *) DL_RELOC_ADDR (tpnt->loadaddr, rpnt->r_offset);
152 __asm__ ("" : "=r" (reloc_addr_packed) : "0" (reloc_addr));
153 reloc_type = ELF_R_TYPE(rpnt->r_info);
154 symtab_index = ELF_R_SYM(rpnt->r_info);
155 symbol_addr = 0;
156 sym_ref.sym = &symtab[symtab_index];
157 sym_ref.tpnt = NULL;
158 symname = strtab + symtab[symtab_index].st_name;
160 if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
161 symbol_addr = (unsigned long) DL_RELOC_ADDR(tpnt->loadaddr, symtab[symtab_index].st_value);
162 symbol_tpnt = tpnt;
163 } else {
165 symbol_addr = (unsigned long)
166 _dl_find_hash(symname, scope, NULL, 0, &sym_ref);
169 * We want to allow undefined references to weak symbols - this might
170 * have been intentional. We should not be linking local symbols
171 * here, so all bases should be covered.
174 if (!symbol_addr && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
175 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
176 _dl_progname, strtab + symtab[symtab_index].st_name);
177 _dl_exit (1);
179 symbol_tpnt = sym_ref.tpnt;
182 #if defined (__SUPPORT_LD_DEBUG__)
183 if (_dl_debug_reloc && _dl_debug_detail)
185 if ((long)reloc_addr_packed & 3)
186 old_val = reloc_addr_packed->v;
187 else
188 old_val = *reloc_addr;
190 else
191 old_val = 0;
192 #endif
193 switch (reloc_type) {
194 case R_FRV_NONE:
195 break;
196 case R_FRV_32:
197 if ((long)reloc_addr_packed & 3)
198 reloc_value = reloc_addr_packed->v += symbol_addr;
199 else
200 reloc_value = *reloc_addr += symbol_addr;
201 break;
202 case R_FRV_FUNCDESC_VALUE:
203 funcval.entry_point = (void*)symbol_addr;
204 /* The addend of FUNCDESC_VALUE
205 relocations referencing global
206 symbols must be ignored, because it
207 may hold the address of a lazy PLT
208 entry. */
209 if (ELF_ST_BIND
210 (symtab[symtab_index].st_info)
211 == STB_LOCAL)
212 funcval.entry_point += *reloc_addr;
213 reloc_value = (unsigned long)funcval.entry_point;
214 if (symbol_addr)
215 funcval.got_value
216 = symbol_tpnt->loadaddr.got_value;
217 else
218 funcval.got_value = 0;
219 __asm__ ("std%I0\t%1, %M0"
220 : "=m" (*(struct funcdesc_value *)reloc_addr)
221 : "e" (funcval));
222 break;
223 case R_FRV_FUNCDESC:
224 if ((long)reloc_addr_packed & 3)
225 reloc_value = reloc_addr_packed->v;
226 else
227 reloc_value = *reloc_addr;
228 if (symbol_addr)
229 reloc_value = (unsigned long)_dl_funcdesc_for
230 ((char *)symbol_addr + reloc_value,
231 symbol_tpnt->loadaddr.got_value);
232 else
233 reloc_value = 0;
234 if ((long)reloc_addr_packed & 3)
235 reloc_addr_packed->v = reloc_value;
236 else
237 *reloc_addr = reloc_value;
238 break;
239 default:
240 return -1; /*call _dl_exit(1) */
242 #if defined (__SUPPORT_LD_DEBUG__)
243 if (_dl_debug_reloc && _dl_debug_detail) {
244 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_value, reloc_addr);
245 switch (reloc_type) {
246 case R_FRV_FUNCDESC_VALUE:
247 _dl_dprintf(_dl_debug_file, " got %x", ((struct funcdesc_value *)reloc_value)->got_value);
248 break;
249 case R_FRV_FUNCDESC:
250 if (! reloc_value)
251 break;
252 _dl_dprintf(_dl_debug_file, " funcdesc (%x,%x)",
253 ((struct funcdesc_value *)reloc_value)->entry_point,
254 ((struct funcdesc_value *)reloc_value)->got_value);
255 break;
258 #endif
260 return 0;
263 static int
264 _dl_do_lazy_reloc (struct elf_resolve *tpnt,
265 struct r_scope_elem *scope __attribute__((unused)),
266 ELF_RELOC *rpnt, ElfW(Sym) *symtab __attribute__((unused)),
267 char *strtab __attribute__((unused)))
269 int reloc_type;
270 struct funcdesc_value volatile *reloc_addr;
271 struct funcdesc_value funcval;
272 #if defined (__SUPPORT_LD_DEBUG__)
273 unsigned long old_val;
274 #endif
276 reloc_addr = (struct funcdesc_value *)(intptr_t)
277 DL_RELOC_ADDR (tpnt->loadaddr, rpnt->r_offset);
278 reloc_type = ELF_R_TYPE(rpnt->r_info);
280 #if defined (__SUPPORT_LD_DEBUG__)
281 old_val = (unsigned long)reloc_addr->entry_point;
282 #endif
283 switch (reloc_type) {
284 case R_FRV_NONE:
285 break;
286 case R_FRV_FUNCDESC_VALUE:
287 funcval = *reloc_addr;
288 funcval.entry_point = (void *) DL_RELOC_ADDR(tpnt->loadaddr, funcval.entry_point);
289 funcval.got_value = tpnt->loadaddr.got_value;
290 *reloc_addr = funcval;
291 break;
292 default:
293 return -1; /*call _dl_exit(1) */
295 #if defined (__SUPPORT_LD_DEBUG__)
296 if (_dl_debug_reloc && _dl_debug_detail)
297 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, reloc_addr->entry_point, reloc_addr);
298 #endif
299 return 0;
303 void
304 _dl_parse_lazy_relocation_information
305 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
307 _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
311 _dl_parse_relocation_information
312 (struct dyn_elf *rpnt, struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size)
314 return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
317 /* We don't have copy relocs. */
320 _dl_parse_copy_information
321 (struct dyn_elf *rpnt __attribute__((unused)),
322 unsigned long rel_addr __attribute__((unused)),
323 unsigned long rel_size __attribute__((unused)))
325 return 0;
328 #ifndef IS_IN_libdl
329 # include "../../libc/sysdeps/linux/frv/crtreloc.c"
330 #endif