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 struct funcdesc_value volatile *__attribute__((__visibility__("hidden")))
41 _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
43 ELF_RELOC *this_reloc;
48 struct elf_resolve *new_tpnt;
50 struct funcdesc_value funcval;
51 struct funcdesc_value volatile *got_entry;
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 = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
60 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
61 symname= strtab + symtab[symtab_index].st_name;
63 /* Address of GOT entry fix up */
64 got_entry = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
66 /* Get the address to be used to fill in the GOT entry. */
67 new_addr = _dl_lookup_hash(symname, tpnt->symbol_scope, NULL, 0, &new_tpnt);
69 new_addr = _dl_lookup_hash(symname, NULL, NULL, 0, &new_tpnt);
71 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
72 _dl_progname, symname);
77 funcval.entry_point = new_addr;
78 funcval.got_value = new_tpnt->loadaddr.got_value;
80 #if defined (__SUPPORT_LD_DEBUG__)
81 if (_dl_debug_bindings) {
82 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
84 _dl_dprintf(_dl_debug_file,
85 "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n",
86 got_entry->entry_point, got_entry->got_value,
87 funcval.entry_point, funcval.got_value,
90 if (1 || !_dl_debug_nofixups) {
101 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
102 unsigned long rel_addr, unsigned long rel_size,
103 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
104 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
112 /* Now parse the relocation information */
113 rpnt = (ELF_RELOC *) rel_addr;
114 rel_size = rel_size / sizeof(ELF_RELOC);
116 symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
117 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
119 for (i = 0; i < rel_size; i++, rpnt++) {
122 symtab_index = ELF_R_SYM(rpnt->r_info);
123 debug_sym(symtab,strtab,symtab_index);
124 debug_reloc(symtab,strtab,rpnt);
126 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
128 if (res==0) continue;
130 _dl_dprintf(2, "\n%s: ",_dl_progname);
133 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
136 int reloc_type = ELF_R_TYPE(rpnt->r_info);
137 #if defined (__SUPPORT_LD_DEBUG__)
138 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
140 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
144 _dl_dprintf(2, "can't resolve symbol\n");
152 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
153 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
158 unsigned long reloc_value = 0, *reloc_addr;
159 struct { unsigned long v; } __attribute__((__packed__))
161 unsigned long symbol_addr;
162 struct elf_resolve *symbol_tpnt;
163 struct funcdesc_value funcval;
164 #if defined (__SUPPORT_LD_DEBUG__)
165 unsigned long old_val;
168 reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
169 __asm__ ("" : "=r" (reloc_addr_packed) : "0" (reloc_addr));
170 reloc_type = ELF_R_TYPE(rpnt->r_info);
171 symtab_index = ELF_R_SYM(rpnt->r_info);
173 symname = strtab + symtab[symtab_index].st_name;
175 if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
176 symbol_addr = (unsigned long) DL_RELOC_ADDR(tpnt->loadaddr, symtab[symtab_index].st_value);
180 symbol_addr = (unsigned long)
181 _dl_lookup_hash(symname, scope, NULL, 0, &symbol_tpnt);
184 * We want to allow undefined references to weak symbols - this might
185 * have been intentional. We should not be linking local symbols
186 * here, so all bases should be covered.
189 if (!symbol_addr && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
190 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
191 _dl_progname, strtab + symtab[symtab_index].st_name);
196 #if defined (__SUPPORT_LD_DEBUG__)
197 if (_dl_debug_reloc && _dl_debug_detail)
199 if ((long)reloc_addr_packed & 3)
200 old_val = reloc_addr_packed->v;
202 old_val = *reloc_addr;
207 switch (reloc_type) {
210 case R_BFIN_byte4_data:
211 if ((long)reloc_addr_packed & 3)
212 reloc_value = reloc_addr_packed->v += symbol_addr;
214 reloc_value = *reloc_addr += symbol_addr;
216 case R_BFIN_FUNCDESC_VALUE:
217 funcval.entry_point = (void*)symbol_addr;
218 /* The addend of FUNCDESC_VALUE
219 relocations referencing global
220 symbols must be ignored, because it
221 may hold the address of a lazy PLT
223 if (ELF_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL)
224 funcval.entry_point += *reloc_addr;
225 reloc_value = (unsigned long)funcval.entry_point;
228 = symbol_tpnt->loadaddr.got_value;
230 funcval.got_value = 0;
231 __asm__ ("%0 = %2; %1 = %H2;"
232 : "=m" (*(struct funcdesc_value *)reloc_addr), "=m" (((long *)reloc_addr)[1])
235 case R_BFIN_FUNCDESC:
236 if ((long)reloc_addr_packed & 3)
237 reloc_value = reloc_addr_packed->v;
239 reloc_value = *reloc_addr;
241 reloc_value = (unsigned long)_dl_funcdesc_for
242 ((char *)symbol_addr + reloc_value,
243 symbol_tpnt->loadaddr.got_value);
246 if ((long)reloc_addr_packed & 3)
247 reloc_addr_packed->v = reloc_value;
249 *reloc_addr = reloc_value;
254 #if defined (__SUPPORT_LD_DEBUG__)
255 if (_dl_debug_reloc && _dl_debug_detail) {
256 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_value, reloc_addr);
257 switch (reloc_type) {
258 case R_BFIN_FUNCDESC_VALUE:
259 _dl_dprintf(_dl_debug_file, " got %x", ((struct funcdesc_value *)reloc_value)->got_value);
261 case R_BFIN_FUNCDESC:
264 _dl_dprintf(_dl_debug_file, " funcdesc (%x,%x)",
265 ((struct funcdesc_value *)reloc_value)->entry_point,
266 ((struct funcdesc_value *)reloc_value)->got_value);
276 _dl_do_lazy_reloc (struct elf_resolve *tpnt,
277 struct dyn_elf *scope __attribute__((unused)),
278 ELF_RELOC *rpnt, ElfW(Sym) *symtab __attribute__((unused)),
279 char *strtab __attribute__((unused)))
282 struct funcdesc_value volatile *reloc_addr;
283 struct funcdesc_value funcval;
284 #if defined (__SUPPORT_LD_DEBUG__)
285 unsigned long old_val;
288 reloc_addr = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
289 reloc_type = ELF_R_TYPE(rpnt->r_info);
291 #if defined (__SUPPORT_LD_DEBUG__)
292 old_val = (unsigned long)reloc_addr->entry_point;
294 switch (reloc_type) {
297 case R_BFIN_FUNCDESC_VALUE:
298 funcval = *reloc_addr;
299 funcval.entry_point = DL_RELOC_ADDR(tpnt->loadaddr, funcval.entry_point);
300 funcval.got_value = tpnt->loadaddr.got_value;
301 *reloc_addr = funcval;
306 #if defined (__SUPPORT_LD_DEBUG__)
307 if (_dl_debug_reloc && _dl_debug_detail)
308 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_addr->entry_point, reloc_addr);
315 _dl_parse_lazy_relocation_information
316 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
318 _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
322 _dl_parse_relocation_information
323 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
325 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
328 /* We don't have copy relocs. */
331 _dl_parse_copy_information
332 (struct dyn_elf *rpnt __attribute__((unused)),
333 unsigned long rel_addr __attribute__((unused)),
334 unsigned long rel_size __attribute__((unused)))
340 # include "../../libc/sysdeps/linux/bfin/crtreloc.c"