1 /* vi: set sw=4 ts=4: */
2 /* ARM ELF shared library loader suppport
4 * Copyright (C) 2001-2004 Erik Andersen
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. The name of the above contributors may not be
14 * used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 /* Program to load an ELF binary on a linux system, and run it.
31 References to symbols in sharable libraries can be resolved by either
32 an ELF sharable library or a linux style of shared library. */
34 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
35 I ever taken any courses on internals. This program was developed using
36 information available through the book "UNIX SYSTEM V RELEASE 4,
37 Programmers guide: Ansi C and Programming Support Tools", which did
38 a more than adequate job of explaining everything required to get this
43 extern int _dl_linux_resolve(void);
45 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
47 ELF_RELOC *this_reloc;
53 unsigned long new_addr;
55 unsigned long instr_addr;
57 rel_addr = (ELF_RELOC *) tpnt->dynamic_info[DT_JMPREL];
59 this_reloc = rel_addr + reloc_entry;
60 symtab_index = ELF32_R_SYM(this_reloc->r_info);
62 symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
63 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
64 symname = strtab + symtab[symtab_index].st_name;
66 /* Address of jump instruction to fix up */
67 instr_addr = ((unsigned long) this_reloc->r_offset +
68 (unsigned long) tpnt->loadaddr);
69 got_addr = (char **) instr_addr;
71 /* Get the address of the GOT entry */
72 new_addr = _dl_find_hash(symname, tpnt->symbol_scope,
73 tpnt, ELF_RTYPE_CLASS_PLT, NULL);
74 if (unlikely(!new_addr)) {
75 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
76 _dl_progname, symname);
79 #if defined (__SUPPORT_LD_DEBUG__)
80 #if !defined __SUPPORT_LD_DEBUG_EARLY__
81 if ((unsigned long) got_addr < 0x40000000)
84 if (_dl_debug_bindings)
86 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
87 if (_dl_debug_detail) _dl_dprintf(_dl_debug_file,
88 "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
91 if (!_dl_debug_nofixups) {
92 *got_addr = (char *)new_addr;
95 *got_addr = (char *)new_addr;
102 _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
103 unsigned long rel_addr, unsigned long rel_size,
104 int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
105 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
114 /* Now parse the relocation information */
115 rpnt = (ELF_RELOC *) rel_addr;
116 rel_size = rel_size / sizeof(ELF_RELOC);
118 symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
119 strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
121 for (i = 0; i < rel_size; i++, rpnt++) {
124 symtab_index = ELF32_R_SYM(rpnt->r_info);
126 debug_sym(symtab,strtab,symtab_index);
127 debug_reloc(symtab,strtab,rpnt);
129 res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
131 if (res==0) continue;
133 _dl_dprintf(2, "\n%s: ",_dl_progname);
136 _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
138 if (unlikely(res <0))
140 int reloc_type = ELF32_R_TYPE(rpnt->r_info);
141 #if defined (__SUPPORT_LD_DEBUG__)
142 _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
144 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
148 if (unlikely(res >0))
150 _dl_dprintf(2, "can't resolve symbol\n");
159 fix_bad_pc24 (unsigned long *const reloc_addr, unsigned long value)
161 static void *fix_page;
162 static unsigned int fix_offset;
163 unsigned int *fix_address;
166 fix_page = _dl_mmap (NULL, PAGE_SIZE , PROT_READ | PROT_WRITE | PROT_EXEC,
167 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
171 fix_address = (unsigned int *)(fix_page + fix_offset);
172 fix_address[0] = 0xe51ff004; /* ldr pc, [pc, #-4] */
173 fix_address[1] = value;
176 if (fix_offset >= PAGE_SIZE)
179 return (unsigned long)fix_address;
184 _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
185 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
189 unsigned long *reloc_addr;
190 unsigned long symbol_addr;
191 const Elf32_Sym *def = 0;
192 struct symbol_ref sym_ref;
193 struct elf_resolve *def_mod = 0;
196 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
198 reloc_type = ELF32_R_TYPE(rpnt->r_info);
199 symtab_index = ELF32_R_SYM(rpnt->r_info);
201 sym_ref.sym = &symtab[symtab_index];
205 symbol_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
206 scope, tpnt, elf_machine_type_class(reloc_type), &sym_ref);
209 * We want to allow undefined references to weak symbols - this might
210 * have been intentional. We should not be linking local symbols
211 * here, so all bases should be covered.
213 if (!symbol_addr && (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS)
214 && (ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
215 /* This may be non-fatal if called from dlopen. */
219 def_mod = sym_ref.tpnt;
222 * Relocs against STN_UNDEF are usually treated as using a
223 * symbol value of zero, and using the module containing the
226 symbol_addr = symtab[symtab_index].st_value;
230 #if defined (__SUPPORT_LD_DEBUG__)
232 unsigned long old_val = *reloc_addr;
234 switch (reloc_type) {
238 *reloc_addr += symbol_addr;
243 unsigned long addend;
244 long newvalue, topbits;
246 addend = *reloc_addr & 0x00ffffff;
247 if (addend & 0x00800000) addend |= 0xff000000;
249 newvalue = symbol_addr - (unsigned long)reloc_addr + (addend << 2);
250 topbits = newvalue & 0xfe000000;
251 if (topbits != 0xfe000000 && topbits != 0x00000000)
253 newvalue = fix_bad_pc24(reloc_addr, symbol_addr)
254 - (unsigned long)reloc_addr + (addend << 2);
255 topbits = newvalue & 0xfe000000;
256 if (unlikely(topbits != 0xfe000000 && topbits != 0x00000000))
258 _dl_dprintf(2,"symbol '%s': R_ARM_PC24 relocation out of range.",
259 symtab[symtab_index].st_name);
264 symbol_addr = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
265 *reloc_addr = symbol_addr;
269 _dl_dprintf(2,"R_ARM_PC24: Compile shared libraries with -fPIC!\n");
273 case R_ARM_JUMP_SLOT:
274 *reloc_addr = symbol_addr;
277 *reloc_addr += (unsigned long) tpnt->loadaddr;
280 _dl_memcpy((void *) reloc_addr,
281 (void *) symbol_addr, symtab[symtab_index].st_size);
283 #if defined USE_TLS && USE_TLS
284 case R_ARM_TLS_DTPMOD32:
285 *reloc_addr = def_mod->l_tls_modid;
288 case R_ARM_TLS_DTPOFF32:
289 *reloc_addr += symbol_addr;
292 case R_ARM_TLS_TPOFF32:
293 CHECK_STATIC_TLS ((struct link_map *) def_mod);
294 *reloc_addr += (symbol_addr + def_mod->l_tls_offset);
298 return -1; /*call _dl_exit(1) */
300 #if defined (__SUPPORT_LD_DEBUG__)
301 if (_dl_debug_reloc && _dl_debug_detail)
302 _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
311 _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
312 ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
315 unsigned long *reloc_addr;
317 reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
318 reloc_type = ELF32_R_TYPE(rpnt->r_info);
320 #if defined (__SUPPORT_LD_DEBUG__)
322 unsigned long old_val = *reloc_addr;
324 switch (reloc_type) {
327 case R_ARM_JUMP_SLOT:
328 *reloc_addr += (unsigned long) tpnt->loadaddr;
331 return -1; /*call _dl_exit(1) */
333 #if defined (__SUPPORT_LD_DEBUG__)
334 if (_dl_debug_reloc && _dl_debug_detail)
335 _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
343 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
344 unsigned long rel_addr, unsigned long rel_size)
346 (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
349 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
350 unsigned long rel_addr, unsigned long rel_size)
352 return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);