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, ELF_RTYPE_CLASS_PLT);
195 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
196 _dl_progname, symname);
200 #ifdef __SUPPORT_LD_DEBUG__
201 if ((unsigned long)got_addr < 0x20000000) {
202 if (_dl_debug_bindings) {
203 _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
206 if (_dl_debug_detail)
207 _dl_dprintf(_dl_debug_file,
208 "\n\tpatched %x ==> %x @ %x\n",
209 *got_addr, new_addr, got_addr);
213 if (!_dl_debug_nofixups)
214 *got_addr = new_addr;
216 *got_addr = new_addr;
219 return (unsigned long)new_addr;
222 static int _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
223 unsigned long rel_addr, unsigned long rel_size,
224 int (*reloc_fnc)(struct elf_resolve *tpnt,
225 struct dyn_elf *scope,
226 ELF_RELOC *rpnt, Elf32_Sym *symtab,
235 /* Now parse the relocation information */
236 rpnt = (ELF_RELOC *)(intptr_t)(rel_addr + tpnt->loadaddr);
237 rel_size = rel_size / sizeof(ELF_RELOC);
239 symtab = (Elf32_Sym *)(intptr_t)
240 (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
241 strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
243 for (i = 0; i < rel_size; i++, rpnt++) {
246 symtab_index = ELF32_R_SYM(rpnt->r_info);
248 /* When the dynamic linker bootstrapped itself, it resolved
249 some symbols. Make sure we do not do them again */
250 if (!symtab_index && tpnt->libtype == program_interpreter)
252 if (symtab_index && tpnt->libtype == program_interpreter &&
253 _dl_symbol(strtab + symtab[symtab_index].st_name))
256 #ifdef __SUPPORT_LD_DEBUG__
257 debug_sym(symtab,strtab,symtab_index);
258 debug_reloc(symtab,strtab,rpnt);
261 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
265 _dl_dprintf(2, "\n%s: ",_dl_progname);
268 _dl_dprintf(2, "symbol '%s': ",
269 strtab + symtab[symtab_index].st_name);
272 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
274 _dl_dprintf(2, "can't handle reloc type "
275 #ifdef __SUPPORT_LD_DEBUG__
276 "%s\n", _dl_reltypes(reloc_type)
283 } else if (res > 0) {
284 _dl_dprintf(2, "can't resolve symbol\n");
293 static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
294 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
297 int symtab_index, lsb;
299 unsigned long *reloc_addr;
300 unsigned long symbol_addr;
301 #ifdef __SUPPORT_LD_DEBUG__
302 unsigned long old_val;
305 reloc_type = ELF32_R_TYPE(rpnt->r_info);
306 symtab_index = ELF32_R_SYM(rpnt->r_info);
308 lsb = symtab[symtab_index].st_other & 4;
309 symname = strtab + symtab[symtab_index].st_name;
310 reloc_addr = (unsigned long *)(intptr_t)
311 (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
316 symbol_addr = (unsigned long)_dl_find_hash(symname, scope,
317 elf_machine_type_class(reloc_type));
320 * We want to allow undefined references to weak symbols - this
321 * might have been intentional. We should not be linking local
322 * symbols here, so all bases should be covered.
324 stb = ELF32_ST_BIND(symtab[symtab_index].st_info);
326 if (stb == STB_GLOBAL && !symbol_addr) {
327 #ifdef __SUPPORT_LD_DEBUG__
328 _dl_dprintf(2, "\tglobal symbol '%s' "
329 "already defined in '%s'\n",
330 symname, tpnt->libname);
336 #ifdef __SUPPORT_LD_DEBUG__
337 old_val = *reloc_addr;
340 switch (reloc_type) {
344 /* handled later on */
349 *reloc_addr = (symbol_addr + rpnt->r_addend) | lsb;
352 *reloc_addr = symbol_addr + rpnt->r_addend -
353 (unsigned long)reloc_addr;
356 *reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
358 case R_SH_RELATIVE_LOW16:
359 case R_SH_RELATIVE_MEDLOW16:
361 unsigned long word, value;
363 word = (unsigned long)reloc_addr & ~0x3fffc00;
364 value = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
366 if (reloc_type == R_SH_RELATIVE_MEDLOW16)
369 word |= (value & 0xffff) << 10;
375 case R_SH_IMM_MEDLOW16:
377 unsigned long word, value;
379 word = (unsigned long)reloc_addr & ~0x3fffc00;
380 value = (symbol_addr + rpnt->r_addend) | lsb;
382 if (reloc_type == R_SH_IMM_MEDLOW16)
385 word |= (value & 0xffff) << 10;
390 case R_SH_IMM_LOW16_PCREL:
391 case R_SH_IMM_MEDLOW16_PCREL:
393 unsigned long word, value;
395 word = (unsigned long)reloc_addr & ~0x3fffc00;
396 value = symbol_addr + rpnt->r_addend -
397 (unsigned long)reloc_addr;
399 if (reloc_type == R_SH_IMM_MEDLOW16_PCREL)
402 word |= (value & 0xffff) << 10;
408 return -1; /*call _dl_exit(1) */
411 #ifdef __SUPPORT_LD_DEBUG__
412 if (_dl_debug_reloc && _dl_debug_detail)
413 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x",
414 old_val, *reloc_addr, reloc_addr);
420 static int _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
421 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
423 int reloc_type, symtab_index, lsb;
424 unsigned long *reloc_addr;
425 #ifdef __SUPPORT_LD_DEBUG__
426 unsigned long old_val;
429 reloc_type = ELF32_R_TYPE(rpnt->r_info);
430 symtab_index = ELF32_R_SYM(rpnt->r_info);
431 lsb = symtab[symtab_index].st_other & 4;
432 reloc_addr = (unsigned long *)(intptr_t)
433 (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
435 #ifdef __SUPPORT_LD_DEBUG__
436 old_val = *reloc_addr;
439 switch (reloc_type) {
443 *reloc_addr += (unsigned long)tpnt->loadaddr | lsb;
446 return -1; /*call _dl_exit(1) */
449 #ifdef __SUPPORT_LD_DEBUG__
450 if (_dl_debug_reloc && _dl_debug_detail)
451 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x",
452 old_val, *reloc_addr, reloc_addr);
458 /* This is done as a separate step, because there are cases where
459 information is first copied and later initialized. This results in
460 the wrong information being copied. Someone at Sun was complaining about
461 a bug in the handling of _COPY by SVr4, and this may in fact be what he
462 was talking about. Sigh. */
464 /* No, there are cases where the SVr4 linker fails to emit COPY relocs
466 static int _dl_do_copy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
467 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
471 unsigned long *reloc_addr;
472 unsigned long symbol_addr;
476 reloc_addr = (unsigned long *)(intptr_t)
477 (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
478 reloc_type = ELF32_R_TYPE(rpnt->r_info);
480 if (reloc_type != R_SH_COPY)
483 symtab_index = ELF32_R_SYM(rpnt->r_info);
485 symname = strtab + symtab[symtab_index].st_name;
488 symbol_addr = (unsigned long)
489 _dl_find_hash(symname, scope, ELF_RTYPE_CLASS_COPY);
496 #ifdef __SUPPORT_LD_DEBUG__
498 _dl_dprintf(_dl_debug_file,
499 "\n%s move %x bytes from %x to %x",
500 symname, symtab[symtab_index].st_size,
501 symbol_addr, symtab[symtab_index].st_value);
504 _dl_memcpy((char *)symtab[symtab_index].st_value,
505 (char *)symbol_addr, symtab[symtab_index].st_size);
511 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
512 unsigned long rel_addr, unsigned long rel_size, int type)
514 (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
517 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
518 unsigned long rel_addr, unsigned long rel_size, int type)
520 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
523 int _dl_parse_copy_information(struct dyn_elf *rpnt,
524 unsigned long rel_addr, unsigned long rel_size, int type)
526 return _dl_parse(rpnt->dyn, rpnt->next, rel_addr, rel_size, _dl_do_copy_reloc);