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, 2004, 2005 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 /* Program to load an ELF binary on a linux system, and run it.
34 References to symbols in sharable libraries can be resolved by either
35 an ELF sharable library or a linux style of shared library. */
37 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
38 I ever taken any courses on internals. This program was developed using
39 information available through the book "UNIX SYSTEM V RELEASE 4,
40 Programmers guide: Ansi C and Programming Support Tools", which did
41 a more than adequate job of explaining everything required to get this
46 extern int _dl_linux_resolve(void);
48 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
50 ELF_RELOC *this_reloc;
57 unsigned long instr_addr;
60 rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
62 this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
63 symtab_index = ELF32_R_SYM(this_reloc->r_info);
65 symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB];
66 strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
67 symname = strtab + symtab[symtab_index].st_name;
69 /* Address of jump instruction to fix up */
70 instr_addr = ((unsigned long)this_reloc->r_offset +
71 (unsigned long)tpnt->loadaddr);
72 got_addr = (char **)instr_addr;
75 /* Get the address of the GOT entry */
76 new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
77 if (unlikely(!new_addr)) {
78 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
79 _dl_progname, symname);
83 #ifdef __SUPPORT_LD_DEBUG__
84 if ((unsigned long)got_addr < 0x20000000) {
85 if (_dl_debug_bindings) {
86 _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
90 _dl_dprintf(_dl_debug_file,
91 "\n\tpatched %x ==> %x @ %x\n",
92 *got_addr, new_addr, got_addr);
96 if (!_dl_debug_nofixups)
102 return (unsigned long)new_addr;
105 static int _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
106 unsigned long rel_addr, unsigned long rel_size,
107 int (*reloc_fnc)(struct elf_resolve *tpnt,
108 struct dyn_elf *scope,
109 ELF_RELOC *rpnt, Elf32_Sym *symtab,
118 /* Now parse the relocation information */
119 rpnt = (ELF_RELOC *)(intptr_t)rel_addr;
120 rel_size = rel_size / sizeof(ELF_RELOC);
122 symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB];
123 strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
125 for (i = 0; i < rel_size; i++, rpnt++) {
128 symtab_index = ELF32_R_SYM(rpnt->r_info);
129 debug_sym(symtab,strtab,symtab_index);
130 debug_reloc(symtab,strtab,rpnt);
132 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
136 _dl_dprintf(2, "\n%s: ",_dl_progname);
139 _dl_dprintf(2, "symbol '%s': ",
140 strtab + symtab[symtab_index].st_name);
142 if (unlikely(res < 0)) {
143 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
145 _dl_dprintf(2, "can't handle reloc type "
146 #ifdef __SUPPORT_LD_DEBUG__
147 "%s\n", _dl_reltypes(reloc_type)
155 if (unlikely(res > 0)) {
156 _dl_dprintf(2, "can't resolve symbol\n");
165 static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
166 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
169 int symtab_index, lsb;
171 unsigned long *reloc_addr;
172 unsigned long symbol_addr;
173 #ifdef __SUPPORT_LD_DEBUG__
174 unsigned long old_val;
176 struct symbol_ref sym_ref;
178 reloc_type = ELF32_R_TYPE(rpnt->r_info);
179 symtab_index = ELF32_R_SYM(rpnt->r_info);
181 lsb = !!(symtab[symtab_index].st_other & STO_SH5_ISA32);
182 sym_ref.sym = &symtab[symtab_index];
184 symname = strtab + symtab[symtab_index].st_name;
185 reloc_addr = (unsigned long *)(intptr_t)
186 (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
191 symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt,
192 elf_machine_type_class(reloc_type), &sym_ref);
195 * We want to allow undefined references to weak symbols - this
196 * might have been intentional. We should not be linking local
197 * symbols here, so all bases should be covered.
199 stb = ELF32_ST_BIND(symtab[symtab_index].st_info);
201 if (stb != STB_WEAK && !symbol_addr) {
202 _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
203 _dl_progname, symname);
208 #ifdef __SUPPORT_LD_DEBUG__
209 old_val = *reloc_addr;
212 switch (reloc_type) {
216 _dl_memcpy((char *)reloc_addr,
217 (char *)symbol_addr, symtab[symtab_index].st_size);
222 *reloc_addr = (symbol_addr + rpnt->r_addend) | lsb;
225 *reloc_addr = symbol_addr + rpnt->r_addend -
226 (unsigned long)reloc_addr;
229 *reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
231 case R_SH_RELATIVE_LOW16:
232 case R_SH_RELATIVE_MEDLOW16:
234 unsigned long word, value;
236 word = (unsigned long)reloc_addr & ~0x3fffc00;
237 value = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
239 if (reloc_type == R_SH_RELATIVE_MEDLOW16)
242 word |= (value & 0xffff) << 10;
248 case R_SH_IMM_MEDLOW16:
250 unsigned long word, value;
252 word = (unsigned long)reloc_addr & ~0x3fffc00;
253 value = (symbol_addr + rpnt->r_addend) | lsb;
255 if (reloc_type == R_SH_IMM_MEDLOW16)
258 word |= (value & 0xffff) << 10;
263 case R_SH_IMM_LOW16_PCREL:
264 case R_SH_IMM_MEDLOW16_PCREL:
266 unsigned long word, value;
268 word = (unsigned long)reloc_addr & ~0x3fffc00;
269 value = symbol_addr + rpnt->r_addend -
270 (unsigned long)reloc_addr;
272 if (reloc_type == R_SH_IMM_MEDLOW16_PCREL)
275 word |= (value & 0xffff) << 10;
281 return -1; /*call _dl_exit(1) */
284 #ifdef __SUPPORT_LD_DEBUG__
285 if (_dl_debug_reloc && _dl_debug_detail)
286 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
287 old_val, *reloc_addr, reloc_addr);
293 static int _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
294 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
296 int reloc_type, symtab_index, lsb;
297 unsigned long *reloc_addr;
298 #ifdef __SUPPORT_LD_DEBUG__
299 unsigned long old_val;
302 reloc_type = ELF32_R_TYPE(rpnt->r_info);
303 symtab_index = ELF32_R_SYM(rpnt->r_info);
304 lsb = !!(symtab[symtab_index].st_other & STO_SH5_ISA32);
305 reloc_addr = (unsigned long *)(intptr_t)
306 (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
308 #ifdef __SUPPORT_LD_DEBUG__
309 old_val = *reloc_addr;
312 switch (reloc_type) {
316 *reloc_addr += (unsigned long)tpnt->loadaddr | lsb;
319 return -1; /*call _dl_exit(1) */
322 #ifdef __SUPPORT_LD_DEBUG__
323 if (_dl_debug_reloc && _dl_debug_detail)
324 _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
325 old_val, *reloc_addr, reloc_addr);
331 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
332 unsigned long rel_addr, unsigned long rel_size)
334 (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
337 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
338 unsigned long rel_addr, unsigned long rel_size)
340 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);