1 /* TI C64X DSBT ELF shared library loader suppport
2 * Copyright (C) 2010 Texas Instruments Incorporated
3 * Contributed by Mark Salter <msalter@redhat.com>
5 * Borrowed heavily from frv arch:
6 * Copyright (C) 2003, 2004 Red Hat, Inc.
7 * Contributed by Alexandre Oliva <aoliva@redhat.com>
8 * Lots of code copied from ../i386/elfinterp.c, so:
9 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
10 * David Engel, Hongjiu Lu and Mitch D'Souza
11 * Copyright (C) 2001-2002, Erik Andersen
12 * All rights reserved.
14 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
19 /* Program to load an ELF binary on a linux system, and run it.
20 References to symbols in sharable libraries can be resolved by either
21 an ELF sharable library or a linux style of shared library. */
23 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
24 I ever taken any courses on internals. This program was developed using
25 information available through the book "UNIX SYSTEM V RELEASE 4,
26 Programmers guide: Ansi C and Programming Support Tools", which did
27 a more than adequate job of explaining everything required to get this
30 extern void __c6x_cache_sync(unsigned long start, unsigned long end)
34 _dl_c6x_flush_relocs(struct elf32_dsbt_loadmap *map)
37 s = map->segs[0].addr;
38 e = s + map->segs[0].p_memsz;
39 __c6x_cache_sync(s, e);
40 s = map->segs[1].addr;
41 e = s + map->segs[1].p_memsz;
42 __c6x_cache_sync(s, e);
48 _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
50 ELF_RELOC *this_reloc;
59 rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
61 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
62 symtab_index = ELF_R_SYM(this_reloc->r_info);
64 symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
65 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
66 symname = strtab + symtab[symtab_index].st_name;
68 /* Address of GOT entry fix up */
69 got_addr = (char **) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
71 /* Get the address to be used to fill in the GOT entry. */
72 new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt,
73 ELF_RTYPE_CLASS_PLT, NULL);
74 if (unlikely(!new_addr)) {
75 _dl_dprintf(2, "%s: can't resolve symbol '%s' in lib '%s'.\n", _dl_progname, symname, tpnt->libname);
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\n",
86 *got_addr, new_addr, got_addr);
88 if (!_dl_debug_nofixups) {
99 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
100 unsigned long rel_addr, unsigned long rel_size,
101 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
102 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
110 /* Now parse the relocation information */
111 rpnt = (ELF_RELOC *)rel_addr;
112 rel_size = rel_size / sizeof(ELF_RELOC);
114 symtab = (Elf32_Sym *)tpnt->dynamic_info[DT_SYMTAB];
115 strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
117 for (i = 0; i < rel_size; i++, rpnt++) {
120 symtab_index = ELF32_R_SYM(rpnt->r_info);
121 debug_sym(symtab,strtab,symtab_index);
122 debug_reloc(symtab,strtab,rpnt);
124 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
126 if (res==0) continue;
128 _dl_dprintf(2, "\n%s: ",_dl_progname);
131 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
134 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
135 #if defined (__SUPPORT_LD_DEBUG__)
136 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
138 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
142 _dl_dprintf(2, "can't resolve symbol\n");
146 _dl_c6x_flush_relocs(tpnt->loadaddr.map);
151 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
152 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
157 unsigned long *reloc_addr;
158 unsigned long symbol_addr, sym_val;
160 unsigned long old_val, new_val;
162 reloc_addr = (unsigned long *)(intptr_t)
163 DL_RELOC_ADDR (tpnt->loadaddr, rpnt->r_offset);
165 reloc_type = ELF32_R_TYPE(rpnt->r_info);
166 reloc_addend = rpnt->r_addend;
167 symtab_index = ELF32_R_SYM(rpnt->r_info);
169 symname = strtab + symtab[symtab_index].st_name;
171 if (ELF32_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
172 symbol_addr = (unsigned long)
173 DL_RELOC_ADDR (tpnt->loadaddr, symtab[symtab_index].st_value);
175 symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
176 scope, tpnt, elf_machine_type_class(reloc_type),
179 * We want to allow undefined references to weak symbols - this might
180 * have been intentional. We should not be linking local symbols
181 * here, so all bases should be covered.
184 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
185 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
186 _dl_progname, strtab + symtab[symtab_index].st_name);
190 old_val = *reloc_addr;
191 sym_val = symbol_addr + reloc_addend;
193 switch (reloc_type) {
197 case R_C6000_JUMP_SLOT:
199 *reloc_addr = sym_val;
201 case R_C6000_ABS_L16:
202 new_val = (old_val & ~0x007fff80) | ((sym_val & 0xffff) << 7);
203 *reloc_addr = new_val;
205 case R_C6000_ABS_H16:
206 new_val = (old_val & ~0x007fff80) | ((sym_val >> 9) & 0x007fff80);
207 *reloc_addr = new_val;
209 case R_C6000_PCR_S21:
210 new_val = sym_val - (((unsigned long)reloc_addr) & ~31);
211 *reloc_addr = (old_val & ~0x0fffff80) | (((new_val >> 2) & 0x1fffff) << 7);
215 #if defined (__SUPPORT_LD_DEBUG__)
217 _dl_dprintf(_dl_debug_file,
218 "\n%s move %d bytes from %x to %x",
219 symname, symtab[symtab_index].st_size,
220 symbol_addr, reloc_addr);
223 _dl_memcpy((char *)reloc_addr,
225 symtab[symtab_index].st_size);
229 return -1; /*call _dl_exit(1) */
231 #if defined (__SUPPORT_LD_DEBUG__)
232 if (_dl_debug_reloc && _dl_debug_detail && reloc_type != R_C6000_NONE) {
233 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, new_val, reloc_addr);
240 _dl_do_lazy_reloc (struct elf_resolve *tpnt,
241 struct dyn_elf *scope attribute_unused,
242 ELF_RELOC *rpnt, ElfW(Sym) *symtab attribute_unused,
243 char *strtab attribute_unused)
246 unsigned long *reloc_addr;
247 unsigned long old_val;
249 reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
250 reloc_type = ELF_R_TYPE(rpnt->r_info);
252 old_val = *reloc_addr;
254 switch (reloc_type) {
257 case R_C6000_JUMP_SLOT:
258 *reloc_addr = DL_RELOC_ADDR(tpnt->loadaddr, old_val);
264 #if defined (__SUPPORT_LD_DEBUG__)
265 if (_dl_debug_reloc && _dl_debug_detail)
266 _dl_dprintf(_dl_debug_file, "\n\tpatched: %x ==> %x @ %x\n",
267 old_val, *reloc_addr, reloc_addr);
274 _dl_parse_lazy_relocation_information
275 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
277 _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
281 _dl_parse_relocation_information
282 (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
284 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
287 /* We don't have copy relocs. */
289 _dl_parse_copy_information
290 (struct dyn_elf *rpnt,
291 unsigned long rel_addr,
292 unsigned long rel_size)