1 /* vi: set sw=8 ts=8: */
3 * ldso/ldso/sh64/elfinterp.c
5 * SuperH (sh64) ELF shared library loader suppport
7 * Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. The name of the above contributors may not be
17 * used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #ifdef __SUPPORT_LD_DEBUG__
34 static const char *_dl_reltypes_tab[] = {
35 /* SHcompact relocs */
36 [0] = "R_SH_NONE", "R_SH_DIR32",
37 "R_SH_REL32", "R_SH_DIR8WPN",
38 [4] = "R_SH_IND12W", "R_SH_DIR8WPL",
39 "R_SH_DIR8WPZ", "R_SH_DIR8BP",
40 [8] = "R_SH_DIR8W", "R_SH_DIR8L",
41 [25] = "R_SH_SWITCH16", "R_SH_SWITCH32",
42 "R_SH_USES", "R_SH_COUNT",
43 [29] = "R_SH_ALIGN", "R_SH_CODE",
44 "R_SH_DATA", "R_SH_LABEL",
45 [33] = "R_SH_SWITCH8", "R_SH_GNU_VTINHERIT",
47 [160] = "R_SH_GOT32", "R_SH_PLT32",
48 "R_SH_COPY", "R_SH_GLOB_DAT",
49 [164] = "R_SH_JMP_SLOT", "R_SH_RELATIVE",
50 "R_SH_GOTOFF", "R_SH_GOTPC",
53 [45] = "R_SH_DIR5U", "R_SH_DIR6U",
54 "R_SH_DIR6S", "R_SH_DIR10S",
55 [49] = "R_SH_DIR10SW", "R_SH_DIR10SL",
57 [169] = "R_SH_GOT_LOW16", "R_SH_GOT_MEDLOW16",
58 "R_SH_GOT_MEDHI16", "R_SH_GOT_HI16",
59 [173] = "R_SH_GOTPLT_LOW16", "R_SH_GOTPLT_MEDLOW16",
60 "R_SH_GOTPLT_MEDHI16", "R_SH_GOTPLT_HI16",
61 [177] = "R_SH_PLT_LOW16", "R_SH_PLT_MEDLOW16",
62 "R_SH_PLT_MEDHI16", "R_SH_PLT_HI16",
63 [181] = "R_SH_GOTOFF_LOW16", "R_SH_GOTOFF_MEDLOW16",
64 "R_SH_GOTOFF_MEDHI16", "R_SH_GOTOFF_HI16",
65 [185] = "R_SH_GOTPC_LOW16", "R_SH_GOTPC_MEDLOW16",
66 "R_SH_GOTPC_MEDHI16", "R_SH_GOTPC_HI16",
67 [189] = "R_SH_GOT10BY4", "R_SH_GOTPLT10BY4",
68 "R_SH_GOT10BY8", "R_SH_GOTPLT10BY8",
69 [193] = "R_SH_COPY64", "R_SH_GLOB_DAT64",
70 "R_SH_JMP_SLOT64", "R_SH_RELATIVE64",
71 [197] = "R_SH_RELATIVE_LOW16", "R_SH_RELATIVE_MEDLOW16",
72 "R_SH_RELATIVE_MEDHI16","R_SH_RELATIVE_HI16",
73 [242] = "R_SH_SHMEDIA_CODE", "R_SH_PT_16",
74 "R_SH_IMMS16", "R_SH_IMMU16",
75 [246] = "R_SH_IMM_LOW16", "R_SH_IMM_LOW16_PCREL",
76 "R_SH_IMM_MEDLOW16", "R_SH_IMM_MEDLOW16_PCREL",
77 [250] = "R_SH_IMM_MEDHI16", "R_SH_IMM_MEDHI16_PCREL",
78 "R_SH_IMM_HI16", "R_SH_IMM_HI16_PCREL",
79 [254] = "R_SH_64", "R_SH_64_PCREL",
82 static const char *_dl_reltypes(int type)
88 tabsize = sizeof(_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0]);
89 str = _dl_reltypes_tab[type];
91 if (type >= tabsize || str == NULL)
92 str =_dl_simple_ltoa(buf, (unsigned long)(type));
97 static void debug_sym(Elf32_Sym *symtab, char *strtab, int symtab_index)
99 if (!_dl_debug_symbols || !symtab_index)
102 _dl_dprintf(_dl_debug_file,
103 "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
104 strtab + symtab[symtab_index].st_name,
105 symtab[symtab_index].st_value,
106 symtab[symtab_index].st_size,
107 symtab[symtab_index].st_info,
108 symtab[symtab_index].st_other,
109 symtab[symtab_index].st_shndx);
112 static void debug_reloc(Elf32_Sym *symtab, char *strtab, ELF_RELOC *rpnt)
114 if (!_dl_debug_reloc)
117 if (_dl_debug_symbols) {
118 _dl_dprintf(_dl_debug_file, "\n\t");
123 symtab_index = ELF32_R_SYM(rpnt->r_info);
124 sym = symtab_index ? strtab + symtab[symtab_index].st_name
127 _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
130 _dl_dprintf(_dl_debug_file, "%s\toffset=%x",
131 _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
134 #ifdef ELF_USES_RELOCA
135 _dl_dprintf(_dl_debug_file, "\taddend=%x", rpnt->r_addend);
138 _dl_dprintf(_dl_debug_file, "\n");
141 #endif /* __SUPPORT_LD_DEBUG__ */
143 /* Program to load an ELF binary on a linux system, and run it.
144 References to symbols in sharable libraries can be resolved by either
145 an ELF sharable library or a linux style of shared library. */
147 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
148 I ever taken any courses on internals. This program was developed using
149 information available through the book "UNIX SYSTEM V RELEASE 4,
150 Programmers guide: Ansi C and Programming Support Tools", which did
151 a more than adequate job of explaining everything required to get this
154 extern int _dl_linux_resolve(void);
156 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
159 ELF_RELOC *this_reloc;
166 unsigned long instr_addr;
169 rel_addr = (char *)(tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
171 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
172 reloc_type = ELF32_R_TYPE(this_reloc->r_info);
173 symtab_index = ELF32_R_SYM(this_reloc->r_info);
175 symtab = (Elf32_Sym *)(intptr_t)
176 (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
177 strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
178 symname = strtab + symtab[symtab_index].st_name;
180 if (reloc_type != R_SH_JMP_SLOT) {
181 _dl_dprintf(2, "%s: Incorrect relocation type in jump reloc\n",
186 /* Address of jump instruction to fix up */
187 instr_addr = ((unsigned long)this_reloc->r_offset +
188 (unsigned long)tpnt->loadaddr);
189 got_addr = (char **)instr_addr;
192 /* Get the address of the GOT entry */
193 new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver);
195 new_addr = _dl_find_hash(symname, NULL, NULL, resolver);
198 return (unsigned long)new_addr;
200 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
201 _dl_progname, symname);
205 #ifdef __SUPPORT_LD_DEBUG__
206 if ((unsigned long)got_addr < 0x20000000) {
207 if (_dl_debug_bindings) {
208 _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
211 if (_dl_debug_detail)
212 _dl_dprintf(_dl_debug_file,
213 "\n\tpatched %x ==> %x @ %x\n",
214 *got_addr, new_addr, got_addr);
218 if (!_dl_debug_nofixups)
219 *got_addr = new_addr;
221 *got_addr = new_addr;
224 return (unsigned long)new_addr;
227 static int _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
228 unsigned long rel_addr, unsigned long rel_size,
229 int (*reloc_fnc)(struct elf_resolve *tpnt,
230 struct dyn_elf *scope,
231 ELF_RELOC *rpnt, Elf32_Sym *symtab,
240 /* Now parse the relocation information */
241 rpnt = (ELF_RELOC *)(intptr_t)(rel_addr + tpnt->loadaddr);
242 rel_size = rel_size / sizeof(ELF_RELOC);
244 symtab = (Elf32_Sym *)(intptr_t)
245 (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
246 strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
248 for (i = 0; i < rel_size; i++, rpnt++) {
251 symtab_index = ELF32_R_SYM(rpnt->r_info);
253 /* When the dynamic linker bootstrapped itself, it resolved
254 some symbols. Make sure we do not do them again */
255 if (!symtab_index && tpnt->libtype == program_interpreter)
257 if (symtab_index && tpnt->libtype == program_interpreter &&
258 _dl_symbol(strtab + symtab[symtab_index].st_name))
261 #ifdef __SUPPORT_LD_DEBUG__
262 debug_sym(symtab,strtab,symtab_index);
263 debug_reloc(symtab,strtab,rpnt);
266 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
270 _dl_dprintf(2, "\n%s: ",_dl_progname);
273 _dl_dprintf(2, "symbol '%s': ",
274 strtab + symtab[symtab_index].st_name);
277 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
279 _dl_dprintf(2, "can't handle reloc type "
280 #ifdef __SUPPORT_LD_DEBUG__
281 "%s\n", _dl_reltypes(reloc_type)
288 } else if (res > 0) {
289 _dl_dprintf(2, "can't resolve symbol\n");
298 static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
299 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
302 int symtab_index, lsb;
304 unsigned long *reloc_addr;
305 unsigned long symbol_addr;
306 #ifdef __SUPPORT_LD_DEBUG__
307 unsigned long old_val;
310 reloc_type = ELF32_R_TYPE(rpnt->r_info);
311 symtab_index = ELF32_R_SYM(rpnt->r_info);
313 lsb = symtab[symtab_index].st_other & 4;
314 symname = strtab + symtab[symtab_index].st_name;
315 reloc_addr = (unsigned long *)(intptr_t)
316 (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
321 symbol_addr = (unsigned long)_dl_find_hash(symname, scope,
322 (reloc_type == R_SH_JMP_SLOT ? tpnt : NULL),
326 * We want to allow undefined references to weak symbols - this
327 * might have been intentional. We should not be linking local
328 * symbols here, so all bases should be covered.
330 stb = ELF32_ST_BIND(symtab[symtab_index].st_info);
332 if (stb == STB_GLOBAL && !symbol_addr) {
333 #ifdef __SUPPORT_LD_DEBUG__
334 _dl_dprintf(2, "\tglobal symbol '%s' "
335 "already defined in '%s'\n",
336 symname, tpnt->libname);
342 #ifdef __SUPPORT_LD_DEBUG__
343 old_val = *reloc_addr;
346 switch (reloc_type) {
350 /* handled later on */
355 *reloc_addr = (symbol_addr + rpnt->r_addend) | lsb;
358 *reloc_addr = symbol_addr + rpnt->r_addend -
359 (unsigned long)reloc_addr;
362 *reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
364 case R_SH_RELATIVE_LOW16:
365 case R_SH_RELATIVE_MEDLOW16:
367 unsigned long word, value;
369 word = (unsigned long)reloc_addr & ~0x3fffc00;
370 value = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
372 if (reloc_type == R_SH_RELATIVE_MEDLOW16)
375 word |= (value & 0xffff) << 10;
381 case R_SH_IMM_MEDLOW16:
383 unsigned long word, value;
385 word = (unsigned long)reloc_addr & ~0x3fffc00;
386 value = (symbol_addr + rpnt->r_addend) | lsb;
388 if (reloc_type == R_SH_IMM_MEDLOW16)
391 word |= (value & 0xffff) << 10;
396 case R_SH_IMM_LOW16_PCREL:
397 case R_SH_IMM_MEDLOW16_PCREL:
399 unsigned long word, value;
401 word = (unsigned long)reloc_addr & ~0x3fffc00;
402 value = symbol_addr + rpnt->r_addend -
403 (unsigned long)reloc_addr;
405 if (reloc_type == R_SH_IMM_MEDLOW16_PCREL)
408 word |= (value & 0xffff) << 10;
414 return -1; /*call _dl_exit(1) */
417 #ifdef __SUPPORT_LD_DEBUG__
418 if (_dl_debug_reloc && _dl_debug_detail)
419 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x",
420 old_val, *reloc_addr, reloc_addr);
426 static int _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
427 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
429 int reloc_type, symtab_index, lsb;
430 unsigned long *reloc_addr;
431 #ifdef __SUPPORT_LD_DEBUG__
432 unsigned long old_val;
435 reloc_type = ELF32_R_TYPE(rpnt->r_info);
436 symtab_index = ELF32_R_SYM(rpnt->r_info);
437 lsb = symtab[symtab_index].st_other & 4;
438 reloc_addr = (unsigned long *)(intptr_t)
439 (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
441 #ifdef __SUPPORT_LD_DEBUG__
442 old_val = *reloc_addr;
445 switch (reloc_type) {
449 *reloc_addr += (unsigned long)tpnt->loadaddr | lsb;
452 return -1; /*call _dl_exit(1) */
455 #ifdef __SUPPORT_LD_DEBUG__
456 if (_dl_debug_reloc && _dl_debug_detail)
457 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x",
458 old_val, *reloc_addr, reloc_addr);
464 /* This is done as a separate step, because there are cases where
465 information is first copied and later initialized. This results in
466 the wrong information being copied. Someone at Sun was complaining about
467 a bug in the handling of _COPY by SVr4, and this may in fact be what he
468 was talking about. Sigh. */
470 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
472 static int _dl_do_copy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
473 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
477 unsigned long *reloc_addr;
478 unsigned long symbol_addr;
482 reloc_addr = (unsigned long *)(intptr_t)
483 (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
484 reloc_type = ELF32_R_TYPE(rpnt->r_info);
486 if (reloc_type != R_SH_COPY)
489 symtab_index = ELF32_R_SYM(rpnt->r_info);
491 symname = strtab + symtab[symtab_index].st_name;
494 symbol_addr = (unsigned long)
495 _dl_find_hash(symname, scope, NULL, copyrel);
502 #ifdef __SUPPORT_LD_DEBUG__
504 _dl_dprintf(_dl_debug_file,
505 "\n%s move %x bytes from %x to %x",
506 symname, symtab[symtab_index].st_size,
507 symbol_addr, symtab[symtab_index].st_value);
510 _dl_memcpy((char *)symtab[symtab_index].st_value,
511 (char *)symbol_addr, symtab[symtab_index].st_size);
517 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
518 unsigned long rel_addr, unsigned long rel_size, int type)
520 (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
523 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
524 unsigned long rel_addr, unsigned long rel_size, int type)
526 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
529 int _dl_parse_copy_information(struct dyn_elf *rpnt,
530 unsigned long rel_addr, unsigned long rel_size, int type)
532 return _dl_parse(rpnt->dyn, rpnt->next, rel_addr, rel_size, _dl_do_copy_reloc);