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)
44 ELF_RELOC *this_reloc;
49 struct elf_resolve *new_tpnt;
51 struct funcdesc_value funcval;
52 struct funcdesc_value volatile *got_entry;
55 rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
57 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
58 reloc_type = ELF_R_TYPE(this_reloc->r_info);
59 symtab_index = ELF_R_SYM(this_reloc->r_info);
61 symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
62 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
63 symname= strtab + symtab[symtab_index].st_name;
65 if (reloc_type != R_BFIN_FUNCDESC_VALUE) {
66 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
71 /* Address of GOT entry fix up */
72 got_entry = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
74 /* Get the address to be used to fill in the GOT entry. */
75 new_addr = _dl_lookup_hash(symname, tpnt->symbol_scope, NULL, 0, &new_tpnt);
77 new_addr = _dl_lookup_hash(symname, NULL, NULL, 0, &new_tpnt);
79 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
80 _dl_progname, symname);
85 funcval.entry_point = new_addr;
86 funcval.got_value = new_tpnt->loadaddr.got_value;
88 #if defined (__SUPPORT_LD_DEBUG__)
89 if (_dl_debug_bindings) {
90 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
92 _dl_dprintf(_dl_debug_file,
93 "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n",
94 got_entry->entry_point, got_entry->got_value,
95 funcval.entry_point, funcval.got_value,
98 if (1 || !_dl_debug_nofixups) {
102 *got_entry = funcval;
109 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
110 unsigned long rel_addr, unsigned long rel_size,
111 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
112 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
120 /* Now parse the relocation information */
121 rpnt = (ELF_RELOC *) rel_addr;
122 rel_size = rel_size / sizeof(ELF_RELOC);
124 symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
125 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
127 for (i = 0; i < rel_size; i++, rpnt++) {
130 symtab_index = ELF_R_SYM(rpnt->r_info);
131 debug_sym(symtab,strtab,symtab_index);
132 debug_reloc(symtab,strtab,rpnt);
134 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
136 if (res==0) continue;
138 _dl_dprintf(2, "\n%s: ",_dl_progname);
141 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
144 int reloc_type = ELF_R_TYPE(rpnt->r_info);
145 #if defined (__SUPPORT_LD_DEBUG__)
146 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
148 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
152 _dl_dprintf(2, "can't resolve symbol\n");
160 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
161 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
166 unsigned long reloc_value = 0, *reloc_addr;
167 struct { unsigned long v; } __attribute__((__packed__))
169 unsigned long symbol_addr;
170 struct elf_resolve *symbol_tpnt;
171 struct funcdesc_value funcval;
172 #if defined (__SUPPORT_LD_DEBUG__)
173 unsigned long old_val;
176 reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
177 __asm__ ("" : "=r" (reloc_addr_packed) : "0" (reloc_addr));
178 reloc_type = ELF_R_TYPE(rpnt->r_info);
179 symtab_index = ELF_R_SYM(rpnt->r_info);
181 symname = strtab + symtab[symtab_index].st_name;
183 if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
184 symbol_addr = (unsigned long) DL_RELOC_ADDR(tpnt->loadaddr, symtab[symtab_index].st_value);
188 symbol_addr = (unsigned long)
189 _dl_lookup_hash(symname, scope, NULL, 0, &symbol_tpnt);
192 * We want to allow undefined references to weak symbols - this might
193 * have been intentional. We should not be linking local symbols
194 * here, so all bases should be covered.
197 if (!symbol_addr && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
198 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
199 _dl_progname, strtab + symtab[symtab_index].st_name);
204 #if defined (__SUPPORT_LD_DEBUG__)
205 if (_dl_debug_reloc && _dl_debug_detail)
207 if ((long)reloc_addr_packed & 3)
208 old_val = reloc_addr_packed->v;
210 old_val = *reloc_addr;
215 switch (reloc_type) {
218 case R_BFIN_byte4_data:
219 if ((long)reloc_addr_packed & 3)
220 reloc_value = reloc_addr_packed->v += symbol_addr;
222 reloc_value = *reloc_addr += symbol_addr;
224 case R_BFIN_FUNCDESC_VALUE:
225 funcval.entry_point = (void*)symbol_addr;
226 /* The addend of FUNCDESC_VALUE
227 relocations referencing global
228 symbols must be ignored, because it
229 may hold the address of a lazy PLT
231 if (ELF_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL)
232 funcval.entry_point += *reloc_addr;
233 reloc_value = (unsigned long)funcval.entry_point;
236 = symbol_tpnt->loadaddr.got_value;
238 funcval.got_value = 0;
239 __asm__ ("%0 = %2; %1 = %H2;"
240 : "=m" (*(struct funcdesc_value *)reloc_addr), "=m" (((long *)reloc_addr)[1])
243 case R_BFIN_FUNCDESC:
244 if ((long)reloc_addr_packed & 3)
245 reloc_value = reloc_addr_packed->v;
247 reloc_value = *reloc_addr;
249 reloc_value = (unsigned long)_dl_funcdesc_for
250 ((char *)symbol_addr + reloc_value,
251 symbol_tpnt->loadaddr.got_value);
254 if ((long)reloc_addr_packed & 3)
255 reloc_addr_packed->v = reloc_value;
257 *reloc_addr = reloc_value;
262 #if defined (__SUPPORT_LD_DEBUG__)
263 if (_dl_debug_reloc && _dl_debug_detail) {
264 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_value, reloc_addr);
265 switch (reloc_type) {
266 case R_BFIN_FUNCDESC_VALUE:
267 _dl_dprintf(_dl_debug_file, " got %x", ((struct funcdesc_value *)reloc_value)->got_value);
269 case R_BFIN_FUNCDESC:
272 _dl_dprintf(_dl_debug_file, " funcdesc (%x,%x)",
273 ((struct funcdesc_value *)reloc_value)->entry_point,
274 ((struct funcdesc_value *)reloc_value)->got_value);
284 _dl_do_lazy_reloc (struct elf_resolve *tpnt,
285 struct dyn_elf *scope __attribute__((unused)),
286 ELF_RELOC *rpnt, ElfW(Sym) *symtab __attribute__((unused)),
287 char *strtab __attribute__((unused)))
290 struct funcdesc_value volatile *reloc_addr;
291 struct funcdesc_value funcval;
292 #if defined (__SUPPORT_LD_DEBUG__)
293 unsigned long old_val;
296 reloc_addr = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
297 reloc_type = ELF_R_TYPE(rpnt->r_info);
299 #if defined (__SUPPORT_LD_DEBUG__)
300 old_val = (unsigned long)reloc_addr->entry_point;
302 switch (reloc_type) {
305 case R_BFIN_FUNCDESC_VALUE:
306 funcval = *reloc_addr;
307 funcval.entry_point = DL_RELOC_ADDR(tpnt->loadaddr, funcval.entry_point);
308 funcval.got_value = tpnt->loadaddr.got_value;
309 *reloc_addr = funcval;
314 #if defined (__SUPPORT_LD_DEBUG__)
315 if (_dl_debug_reloc && _dl_debug_detail)
316 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_addr->entry_point, reloc_addr);
323 _dl_parse_lazy_relocation_information
324 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
326 _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
330 _dl_parse_relocation_information
331 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
333 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
336 /* We don't have copy relocs. */
339 _dl_parse_copy_information
340 (struct dyn_elf *rpnt __attribute__((unused)),
341 unsigned long rel_addr __attribute__((unused)),
342 unsigned long rel_size __attribute__((unused)))
348 # include "../../libc/sysdeps/linux/bfin/crtreloc.c"