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
10 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
13 #include <sys/cdefs.h> /* __attribute_used__ */
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
;
29 struct funcdesc_value funcval
;
30 struct funcdesc_value
volatile *got_entry
;
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
];
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
);
51 new_addr
= _dl_find_hash(symname
, NULL
, NULL
, 0, &sym_ref
);
53 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
54 _dl_progname
, symname
);
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
);
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
,
73 if (!_dl_debug_nofixups
) {
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
))
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
++) {
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
);
116 _dl_dprintf(2, "symbol '%s': ", strtab
+ symtab
[symtab_index
].st_name
);
120 int reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
121 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type
);
126 _dl_dprintf(2, "can't resolve symbol\n");
134 _dl_do_reloc (struct elf_resolve
*tpnt
,struct r_scope_elem
*scope
,
135 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
140 unsigned long reloc_value
= 0, *reloc_addr
;
141 struct { unsigned long v
; } __attribute__((__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
;
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
);
156 sym_ref
.sym
= &symtab
[symtab_index
];
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
);
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
);
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
;
188 old_val
= *reloc_addr
;
193 switch (reloc_type
) {
197 if ((long)reloc_addr_packed
& 3)
198 reloc_value
= reloc_addr_packed
->v
+= symbol_addr
;
200 reloc_value
= *reloc_addr
+= symbol_addr
;
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
210 (symtab
[symtab_index
].st_info
)
212 funcval
.entry_point
+= *reloc_addr
;
213 reloc_value
= (unsigned long)funcval
.entry_point
;
216 = symbol_tpnt
->loadaddr
.got_value
;
218 funcval
.got_value
= 0;
219 __asm__ ("std%I0\t%1, %M0"
220 : "=m" (*(struct funcdesc_value
*)reloc_addr
)
224 if ((long)reloc_addr_packed
& 3)
225 reloc_value
= reloc_addr_packed
->v
;
227 reloc_value
= *reloc_addr
;
229 reloc_value
= (unsigned long)_dl_funcdesc_for
230 ((char *)symbol_addr
+ reloc_value
,
231 symbol_tpnt
->loadaddr
.got_value
);
234 if ((long)reloc_addr_packed
& 3)
235 reloc_addr_packed
->v
= reloc_value
;
237 *reloc_addr
= reloc_value
;
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
);
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
);
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
)))
270 struct funcdesc_value
volatile *reloc_addr
;
271 struct funcdesc_value funcval
;
272 #if defined (__SUPPORT_LD_DEBUG__)
273 unsigned long old_val
;
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
;
283 switch (reloc_type
) {
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
;
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
);
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
)))
329 # include "../../libc/sysdeps/linux/frv/crtreloc.c"