1 /* vi: set sw=4 ts=4: */
2 /* SuperH ELF shared library loader suppport
4 * Copyright (C) 2002, Stefan Allius <allius@atecom.com> and
5 * Eddie C. Dost <ecd@atecom.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. The name of the above contributors may not be
15 * used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #if defined (__SUPPORT_LD_DEBUG__)
32 static const char *_dl_reltypes_tab[] =
34 [0] "R_SH_NONE", "R_SH_DIR32", "R_SH_REL32", "R_SH_DIR8WPN",
35 [4] "R_SH_IND12W", "R_SH_DIR8WPL", "R_SH_DIR8WPZ", "R_SH_DIR8BP",
36 [8] "R_SH_DIR8W", "R_SH_DIR8L",
37 [25] "R_SH_SWITCH16","R_SH_SWITCH32","R_SH_USES",
38 [28] "R_SH_COUNT", "R_SH_ALIGN", "R_SH_CODE", "R_SH_DATA",
39 [32] "R_SH_LABEL", "R_SH_SWITCH8", "R_SH_GNU_VTINHERIT","R_SH_GNU_VTENTRY",
40 [160] "R_SH_GOT32", "R_SH_PLT32", "R_SH_COPY", "R_SH_GLOB_DAT",
41 [164] "R_SH_JMP_SLOT","R_SH_RELATIVE","R_SH_GOTOFF", "R_SH_GOTPC",
45 _dl_reltypes(int type)
50 if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
51 NULL == (str = _dl_reltypes_tab[type]))
53 str =_dl_simple_ltoa( buf, (unsigned long)(type));
59 void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
64 _dl_dprintf(_dl_debug_file, "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
65 strtab + symtab[symtab_index].st_name,
66 symtab[symtab_index].st_value,
67 symtab[symtab_index].st_size,
68 symtab[symtab_index].st_info,
69 symtab[symtab_index].st_other,
70 symtab[symtab_index].st_shndx);
75 static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
81 symtab_index = ELF32_R_SYM(rpnt->r_info);
82 sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
85 _dl_dprintf(_dl_debug_file, "\n\t");
87 _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
89 #ifdef ELF_USES_RELOCA
90 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
91 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
95 _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
96 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
103 /* Program to load an ELF binary on a linux system, and run it.
104 References to symbols in sharable libraries can be resolved by either
105 an ELF sharable library or a linux style of shared library. */
107 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
108 I ever taken any courses on internals. This program was developed using
109 information available through the book "UNIX SYSTEM V RELEASE 4,
110 Programmers guide: Ansi C and Programming Support Tools", which did
111 a more than adequate job of explaining everything required to get this
114 extern int _dl_linux_resolve(void);
116 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
119 ELF_RELOC *this_reloc;
126 unsigned long instr_addr;
129 rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
131 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
132 reloc_type = ELF32_R_TYPE(this_reloc->r_info);
133 symtab_index = ELF32_R_SYM(this_reloc->r_info);
135 symtab = (Elf32_Sym *)(intptr_t) tpnt->dynamic_info[DT_SYMTAB];
136 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
137 symname = strtab + symtab[symtab_index].st_name;
139 if (unlikely(reloc_type != R_SH_JMP_SLOT)) {
140 _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
145 /* Address of jump instruction to fix up */
146 instr_addr = ((unsigned long) this_reloc->r_offset +
147 (unsigned long) tpnt->loadaddr);
148 got_addr = (char **) instr_addr;
151 /* Get the address of the GOT entry */
152 new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
153 if (unlikely(!new_addr)) {
154 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
158 #if defined (__SUPPORT_LD_DEBUG__)
159 if ((unsigned long) got_addr < 0x20000000)
161 if (_dl_debug_bindings)
163 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
164 if(_dl_debug_detail) _dl_dprintf(_dl_debug_file,
165 "\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
168 if (!_dl_debug_nofixups) {
169 *got_addr = new_addr;
172 *got_addr = new_addr;
175 return (unsigned long) new_addr;
180 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
181 unsigned long rel_addr, unsigned long rel_size,
182 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
183 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
190 /* Now parse the relocation information */
192 rpnt = (ELF_RELOC *)(intptr_t) rel_addr;
193 rel_size = rel_size / sizeof(ELF_RELOC);
195 symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB];
196 strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
198 for (i = 0; i < rel_size; i++, rpnt++) {
201 symtab_index = ELF32_R_SYM(rpnt->r_info);
202 #if defined (__SUPPORT_LD_DEBUG__)
203 debug_sym(symtab,strtab,symtab_index);
204 debug_reloc(symtab,strtab,rpnt);
207 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
209 if (res==0) continue;
211 _dl_dprintf(2, "\n%s: ",_dl_progname);
214 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
216 if (unlikely(res <0))
218 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
219 #if defined (__SUPPORT_LD_DEBUG__)
220 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
222 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
226 if (unlikely(res >0))
228 _dl_dprintf(2, "can't resolve symbol\n");
237 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
238 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
243 unsigned long *reloc_addr;
244 unsigned long symbol_addr;
245 #if defined (__SUPPORT_LD_DEBUG__)
246 unsigned long old_val;
249 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
250 reloc_type = ELF32_R_TYPE(rpnt->r_info);
251 symtab_index = ELF32_R_SYM(rpnt->r_info);
253 symname = strtab + symtab[symtab_index].st_name;
256 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
257 elf_machine_type_class(reloc_type));
260 * We want to allow undefined references to weak symbols - this might
261 * have been intentional. We should not be linking local symbols
262 * here, so all bases should be covered.
264 if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
265 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
266 _dl_progname, strtab + symtab[symtab_index].st_name);
272 #if defined (__SUPPORT_LD_DEBUG__)
273 old_val = *reloc_addr;
275 switch (reloc_type) {
280 #if defined (__SUPPORT_LD_DEBUG__)
282 _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
283 symname, symtab[symtab_index].st_size,
284 symbol_addr, reloc_addr);
286 _dl_memcpy((char *) reloc_addr, (char *) symbol_addr, symtab[symtab_index].st_size);
288 return 0; /* no further LD_DEBUG messages for copy relocs */
292 *reloc_addr = symbol_addr + rpnt->r_addend;
295 *reloc_addr = symbol_addr + rpnt->r_addend -
296 (unsigned long) reloc_addr;
299 *reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend;
302 return -1; /*call _dl_exit(1) */
304 #if defined (__SUPPORT_LD_DEBUG__)
305 if(_dl_debug_reloc && _dl_debug_detail)
306 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
314 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
315 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
318 unsigned long *reloc_addr;
319 #if defined (__SUPPORT_LD_DEBUG__)
320 unsigned long old_val;
326 reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
327 reloc_type = ELF32_R_TYPE(rpnt->r_info);
329 #if defined (__SUPPORT_LD_DEBUG__)
330 old_val = *reloc_addr;
332 switch (reloc_type) {
336 *reloc_addr += (unsigned long) tpnt->loadaddr;
339 return -1; /*call _dl_exit(1) */
341 #if defined (__SUPPORT_LD_DEBUG__)
342 if(_dl_debug_reloc && _dl_debug_detail)
343 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
349 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
350 unsigned long rel_addr, unsigned long rel_size)
352 (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
355 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
356 unsigned long rel_addr, unsigned long rel_size)
358 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);