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 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
33 I ever taken any courses on internals. This program was developed using
34 information available through the book "UNIX SYSTEM V RELEASE 4,
35 Programmers guide: Ansi C and Programming Support Tools", which did
36 a more than adequate job of explaining everything required to get this
39 __attribute__((__visibility__("hidden")))
40 struct funcdesc_value volatile *
41 _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
43 ELF_RELOC *this_reloc;
49 struct funcdesc_value funcval;
50 struct funcdesc_value volatile *got_entry;
52 struct symbol_ref sym_ref;
54 rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
56 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
57 symtab_index = ELF_R_SYM(this_reloc->r_info);
59 symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
60 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
61 sym_ref.sym = &symtab[symtab_index];
63 symname= strtab + symtab[symtab_index].st_name;
65 /* Address of GOT entry fix up */
66 got_entry = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
68 /* Get the address to be used to fill in the GOT entry. */
69 new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, NULL, 0, &sym_ref);
71 new_addr = _dl_find_hash(symname, NULL, NULL, 0, &sym_ref);
73 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
74 _dl_progname, symname);
79 funcval.entry_point = new_addr;
80 funcval.got_value = sym_ref.tpnt->loadaddr.got_value;
82 #if defined (__SUPPORT_LD_DEBUG__)
83 if (_dl_debug_bindings) {
84 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
86 _dl_dprintf(_dl_debug_file,
87 "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n",
88 got_entry->entry_point, got_entry->got_value,
89 funcval.entry_point, funcval.got_value,
92 if (1 || !_dl_debug_nofixups) {
103 _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
104 unsigned long rel_addr, unsigned long rel_size,
105 int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
106 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
114 /* Now parse the relocation information */
115 rpnt = (ELF_RELOC *) rel_addr;
116 rel_size = rel_size / sizeof(ELF_RELOC);
118 symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
119 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
121 for (i = 0; i < rel_size; i++, rpnt++) {
124 symtab_index = ELF_R_SYM(rpnt->r_info);
125 debug_sym(symtab,strtab,symtab_index);
126 debug_reloc(symtab,strtab,rpnt);
128 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
130 if (res==0) continue;
132 _dl_dprintf(2, "\n%s: ",_dl_progname);
135 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
138 int reloc_type = ELF_R_TYPE(rpnt->r_info);
139 #if defined (__SUPPORT_LD_DEBUG__)
140 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
142 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
146 _dl_dprintf(2, "can't resolve symbol\n");
154 _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope,
155 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
160 unsigned long reloc_value = 0, *reloc_addr;
161 struct { unsigned long v; } __attribute__((__packed__))
163 unsigned long symbol_addr;
164 struct elf_resolve *symbol_tpnt;
165 struct funcdesc_value funcval;
166 #if defined (__SUPPORT_LD_DEBUG__)
167 unsigned long old_val;
169 struct symbol_ref sym_ref;
171 reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
172 __asm__ ("" : "=r" (reloc_addr_packed) : "0" (reloc_addr));
173 reloc_type = ELF_R_TYPE(rpnt->r_info);
174 symtab_index = ELF_R_SYM(rpnt->r_info);
176 sym_ref.sym = &symtab[symtab_index];
178 symname = strtab + symtab[symtab_index].st_name;
180 if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
181 symbol_addr = (unsigned long) DL_RELOC_ADDR(tpnt->loadaddr, symtab[symtab_index].st_value);
185 symbol_addr = (unsigned long)
186 _dl_find_hash(symname, scope, NULL, 0, &sym_ref);
189 * We want to allow undefined references to weak symbols - this might
190 * have been intentional. We should not be linking local symbols
191 * here, so all bases should be covered.
194 if (!symbol_addr && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
195 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
196 _dl_progname, symname);
199 if (_dl_trace_prelink) {
200 _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
201 &sym_ref, elf_machine_type_class(reloc_type));
203 symbol_tpnt = sym_ref.tpnt;
206 #if defined (__SUPPORT_LD_DEBUG__)
207 if (_dl_debug_reloc && _dl_debug_detail)
209 if ((long)reloc_addr_packed & 3)
210 old_val = reloc_addr_packed->v;
212 old_val = *reloc_addr;
217 switch (reloc_type) {
220 case R_BFIN_BYTE4_DATA:
221 if ((long)reloc_addr_packed & 3)
222 reloc_value = reloc_addr_packed->v += symbol_addr;
224 reloc_value = *reloc_addr += symbol_addr;
226 case R_BFIN_FUNCDESC_VALUE:
227 funcval.entry_point = (void*)symbol_addr;
228 /* The addend of FUNCDESC_VALUE
229 relocations referencing global
230 symbols must be ignored, because it
231 may hold the address of a lazy PLT
233 if (ELF_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL)
234 funcval.entry_point += *reloc_addr;
235 reloc_value = (unsigned long)funcval.entry_point;
238 = symbol_tpnt->loadaddr.got_value;
240 funcval.got_value = 0;
241 __asm__ ("%0 = %2; %1 = %H2;"
242 : "=m" (*(struct funcdesc_value *)reloc_addr), "=m" (((long *)reloc_addr)[1])
245 case R_BFIN_FUNCDESC:
246 if ((long)reloc_addr_packed & 3)
247 reloc_value = reloc_addr_packed->v;
249 reloc_value = *reloc_addr;
251 reloc_value = (unsigned long)_dl_funcdesc_for
252 ((char *)symbol_addr + reloc_value,
253 symbol_tpnt->loadaddr.got_value);
256 if ((long)reloc_addr_packed & 3)
257 reloc_addr_packed->v = reloc_value;
259 *reloc_addr = reloc_value;
264 #if defined (__SUPPORT_LD_DEBUG__)
265 if (_dl_debug_reloc && _dl_debug_detail) {
266 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_value, reloc_addr);
267 switch (reloc_type) {
268 case R_BFIN_FUNCDESC_VALUE:
269 _dl_dprintf(_dl_debug_file, " got %x", ((struct funcdesc_value *)reloc_value)->got_value);
271 case R_BFIN_FUNCDESC:
274 _dl_dprintf(_dl_debug_file, " funcdesc (%x,%x)",
275 ((struct funcdesc_value *)reloc_value)->entry_point,
276 ((struct funcdesc_value *)reloc_value)->got_value);
286 _dl_do_lazy_reloc (struct elf_resolve *tpnt,
287 struct r_scope_elem *scope __attribute__((unused)),
288 ELF_RELOC *rpnt, ElfW(Sym) *symtab __attribute__((unused)),
289 char *strtab __attribute__((unused)))
292 struct funcdesc_value volatile *reloc_addr;
293 struct funcdesc_value funcval;
294 #if defined (__SUPPORT_LD_DEBUG__)
295 unsigned long old_val;
298 reloc_addr = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
299 reloc_type = ELF_R_TYPE(rpnt->r_info);
301 #if defined (__SUPPORT_LD_DEBUG__)
302 old_val = (unsigned long)reloc_addr->entry_point;
304 switch (reloc_type) {
307 case R_BFIN_FUNCDESC_VALUE:
308 funcval = *reloc_addr;
309 funcval.entry_point = (void *) DL_RELOC_ADDR(tpnt->loadaddr, funcval.entry_point);
310 funcval.got_value = tpnt->loadaddr.got_value;
311 *reloc_addr = funcval;
316 #if defined (__SUPPORT_LD_DEBUG__)
317 if (_dl_debug_reloc && _dl_debug_detail)
318 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, reloc_addr->entry_point, reloc_addr);
325 _dl_parse_lazy_relocation_information
326 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
328 _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
332 _dl_parse_relocation_information
333 (struct dyn_elf *rpnt, struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size)
335 return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
338 /* We don't have copy relocs. */
341 _dl_parse_copy_information
342 (struct dyn_elf *rpnt __attribute__((unused)),
343 unsigned long rel_addr __attribute__((unused)),
344 unsigned long rel_size __attribute__((unused)))
350 # include "../../libc/sysdeps/linux/bfin/crtreloc.c"