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
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
;
42 struct funcdesc_value funcval
;
43 struct funcdesc_value
volatile *got_entry
;
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
];
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
);
64 new_addr
= _dl_find_hash(symname
, NULL
, NULL
, 0, &sym_ref
);
66 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
67 _dl_progname
, symname
);
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
);
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
,
85 if (1 || !_dl_debug_nofixups
) {
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
))
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
++) {
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
);
128 _dl_dprintf(2, "symbol '%s': ", strtab
+ symtab
[symtab_index
].st_name
);
131 int reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
132 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type
);
135 _dl_dprintf(2, "can't resolve symbol\n");
143 _dl_do_reloc (struct elf_resolve
*tpnt
,struct r_scope_elem
*scope
,
144 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
149 unsigned long reloc_value
= 0, *reloc_addr
;
150 struct { unsigned long v
; } __attribute__((__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
;
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
);
165 sym_ref
.sym
= &symtab
[symtab_index
];
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
);
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
);
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
;
201 old_val
= *reloc_addr
;
206 switch (reloc_type
) {
209 case R_BFIN_BYTE4_DATA
:
210 if ((long)reloc_addr_packed
& 3)
211 reloc_value
= reloc_addr_packed
->v
+= symbol_addr
;
213 reloc_value
= *reloc_addr
+= symbol_addr
;
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
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
;
227 = symbol_tpnt
->loadaddr
.got_value
;
229 funcval
.got_value
= 0;
230 __asm__ ("%0 = %2; %1 = %H2;"
231 : "=m" (*(struct funcdesc_value
*)reloc_addr
), "=m" (((long *)reloc_addr
)[1])
234 case R_BFIN_FUNCDESC
:
235 if ((long)reloc_addr_packed
& 3)
236 reloc_value
= reloc_addr_packed
->v
;
238 reloc_value
= *reloc_addr
;
240 reloc_value
= (unsigned long)_dl_funcdesc_for
241 ((char *)symbol_addr
+ reloc_value
,
242 symbol_tpnt
->loadaddr
.got_value
);
245 if ((long)reloc_addr_packed
& 3)
246 reloc_addr_packed
->v
= reloc_value
;
248 *reloc_addr
= reloc_value
;
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
);
260 case R_BFIN_FUNCDESC
:
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
);
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
)))
281 struct funcdesc_value
volatile *reloc_addr
;
282 struct funcdesc_value funcval
;
283 #if defined (__SUPPORT_LD_DEBUG__)
284 unsigned long old_val
;
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
;
293 switch (reloc_type
) {
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
;
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
);
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
)))
339 # include "../../libc/sysdeps/linux/bfin/crtreloc.c"