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, tpnt->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 dyn_elf *scope,
105 unsigned long rel_addr, unsigned long rel_size,
106 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *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 dyn_elf *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 symbol_tpnt = sym_ref.tpnt;
203 #if defined (__SUPPORT_LD_DEBUG__)
204 if (_dl_debug_reloc && _dl_debug_detail)
206 if ((long)reloc_addr_packed & 3)
207 old_val = reloc_addr_packed->v;
209 old_val = *reloc_addr;
214 switch (reloc_type) {
217 case R_BFIN_BYTE4_DATA:
218 if ((long)reloc_addr_packed & 3)
219 reloc_value = reloc_addr_packed->v += symbol_addr;
221 reloc_value = *reloc_addr += symbol_addr;
223 case R_BFIN_FUNCDESC_VALUE:
224 funcval.entry_point = (void*)symbol_addr;
225 /* The addend of FUNCDESC_VALUE
226 relocations referencing global
227 symbols must be ignored, because it
228 may hold the address of a lazy PLT
230 if (ELF_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL)
231 funcval.entry_point += *reloc_addr;
232 reloc_value = (unsigned long)funcval.entry_point;
235 = symbol_tpnt->loadaddr.got_value;
237 funcval.got_value = 0;
238 __asm__ ("%0 = %2; %1 = %H2;"
239 : "=m" (*(struct funcdesc_value *)reloc_addr), "=m" (((long *)reloc_addr)[1])
242 case R_BFIN_FUNCDESC:
243 if ((long)reloc_addr_packed & 3)
244 reloc_value = reloc_addr_packed->v;
246 reloc_value = *reloc_addr;
248 reloc_value = (unsigned long)_dl_funcdesc_for
249 ((char *)symbol_addr + reloc_value,
250 symbol_tpnt->loadaddr.got_value);
253 if ((long)reloc_addr_packed & 3)
254 reloc_addr_packed->v = reloc_value;
256 *reloc_addr = reloc_value;
261 #if defined (__SUPPORT_LD_DEBUG__)
262 if (_dl_debug_reloc && _dl_debug_detail) {
263 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_value, reloc_addr);
264 switch (reloc_type) {
265 case R_BFIN_FUNCDESC_VALUE:
266 _dl_dprintf(_dl_debug_file, " got %x", ((struct funcdesc_value *)reloc_value)->got_value);
268 case R_BFIN_FUNCDESC:
271 _dl_dprintf(_dl_debug_file, " funcdesc (%x,%x)",
272 ((struct funcdesc_value *)reloc_value)->entry_point,
273 ((struct funcdesc_value *)reloc_value)->got_value);
283 _dl_do_lazy_reloc (struct elf_resolve *tpnt,
284 struct dyn_elf *scope __attribute__((unused)),
285 ELF_RELOC *rpnt, ElfW(Sym) *symtab __attribute__((unused)),
286 char *strtab __attribute__((unused)))
289 struct funcdesc_value volatile *reloc_addr;
290 struct funcdesc_value funcval;
291 #if defined (__SUPPORT_LD_DEBUG__)
292 unsigned long old_val;
295 reloc_addr = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
296 reloc_type = ELF_R_TYPE(rpnt->r_info);
298 #if defined (__SUPPORT_LD_DEBUG__)
299 old_val = (unsigned long)reloc_addr->entry_point;
301 switch (reloc_type) {
304 case R_BFIN_FUNCDESC_VALUE:
305 funcval = *reloc_addr;
306 funcval.entry_point = (void *) DL_RELOC_ADDR(tpnt->loadaddr, funcval.entry_point);
307 funcval.got_value = tpnt->loadaddr.got_value;
308 *reloc_addr = funcval;
313 #if defined (__SUPPORT_LD_DEBUG__)
314 if (_dl_debug_reloc && _dl_debug_detail)
315 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, reloc_addr->entry_point, reloc_addr);
322 _dl_parse_lazy_relocation_information
323 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
325 _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
329 _dl_parse_relocation_information
330 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
332 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
335 /* We don't have copy relocs. */
338 _dl_parse_copy_information
339 (struct dyn_elf *rpnt __attribute__((unused)),
340 unsigned long rel_addr __attribute__((unused)),
341 unsigned long rel_size __attribute__((unused)))
347 # include "../../libc/sysdeps/linux/bfin/crtreloc.c"