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, write to
24 the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
27 #include <sys/cdefs.h> /* __attribute_used__ */
29 /* Program to load an ELF binary on a linux system, and run it.
30 References to symbols in sharable libraries can be resolved by either
31 an ELF sharable library or a linux style of shared library. */
33 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
34 I ever taken any courses on internals. This program was developed using
35 information available through the book "UNIX SYSTEM V RELEASE 4,
36 Programmers guide: Ansi C and Programming Support Tools", which did
37 a more than adequate job of explaining everything required to get this
40 __attribute__((__visibility__("hidden")))
41 struct funcdesc_value volatile *
42 _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
44 ELF_RELOC *this_reloc;
50 struct funcdesc_value funcval;
51 struct funcdesc_value volatile *got_entry;
53 struct symbol_ref sym_ref;
55 rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
57 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
58 symtab_index = ELF_R_SYM(this_reloc->r_info);
60 symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
61 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
62 sym_ref.sym = &symtab[symtab_index];
64 symname= strtab + symtab[symtab_index].st_name;
66 /* Address of GOT entry fix up */
67 got_entry = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
69 /* Get the address to be used to fill in the GOT entry. */
70 new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, NULL, 0, &sym_ref);
72 new_addr = _dl_find_hash(symname, NULL, NULL, 0, &sym_ref);
74 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
75 _dl_progname, symname);
80 funcval.entry_point = new_addr;
81 funcval.got_value = sym_ref.tpnt->loadaddr.got_value;
83 #if defined (__SUPPORT_LD_DEBUG__)
84 if (_dl_debug_bindings) {
85 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
87 _dl_dprintf(_dl_debug_file,
88 "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n",
89 got_entry->entry_point, got_entry->got_value,
90 funcval.entry_point, funcval.got_value,
93 if (1 || !_dl_debug_nofixups) {
104 _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
105 unsigned long rel_addr, unsigned long rel_size,
106 int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
107 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
115 /* Now parse the relocation information */
116 rpnt = (ELF_RELOC *) rel_addr;
117 rel_size = rel_size / sizeof(ELF_RELOC);
119 symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
120 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
122 for (i = 0; i < rel_size; i++, rpnt++) {
125 symtab_index = ELF_R_SYM(rpnt->r_info);
126 debug_sym(symtab,strtab,symtab_index);
127 debug_reloc(symtab,strtab,rpnt);
129 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
131 if (res==0) continue;
133 _dl_dprintf(2, "\n%s: ",_dl_progname);
136 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
139 int reloc_type = ELF_R_TYPE(rpnt->r_info);
140 #if defined (__SUPPORT_LD_DEBUG__)
141 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
143 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
147 _dl_dprintf(2, "can't resolve symbol\n");
155 _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope,
156 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
161 unsigned long reloc_value = 0, *reloc_addr;
162 struct { unsigned long v; } __attribute__((__packed__))
164 unsigned long symbol_addr;
165 struct elf_resolve *symbol_tpnt;
166 struct funcdesc_value funcval;
167 #if defined (__SUPPORT_LD_DEBUG__)
168 unsigned long old_val;
170 struct symbol_ref sym_ref;
172 reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
173 __asm__ ("" : "=r" (reloc_addr_packed) : "0" (reloc_addr));
174 reloc_type = ELF_R_TYPE(rpnt->r_info);
175 symtab_index = ELF_R_SYM(rpnt->r_info);
177 sym_ref.sym = &symtab[symtab_index];
179 symname = strtab + symtab[symtab_index].st_name;
181 if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
182 symbol_addr = (unsigned long) DL_RELOC_ADDR(tpnt->loadaddr, symtab[symtab_index].st_value);
186 symbol_addr = (unsigned long)
187 _dl_find_hash(symname, scope, NULL, 0, &sym_ref);
190 * We want to allow undefined references to weak symbols - this might
191 * have been intentional. We should not be linking local symbols
192 * here, so all bases should be covered.
195 if (!symbol_addr && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
196 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
197 _dl_progname, symname);
200 if (_dl_trace_prelink)
201 _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
202 &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"