2 * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
4 * Lots of code copied from ../i386/elfinterp.c, so:
5 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
6 * David Engel, Hongjiu Lu and Mitch D'Souza
7 * Copyright (C) 2001-2002, Erik Andersen
10 * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
14 #define ARC_PLT_SIZE 12
17 _dl_linux_resolver(struct elf_resolve *tpnt, unsigned int plt_pc)
19 ELF_RELOC *this_reloc, *rel_base;
20 char *strtab, *symname, *new_addr;
23 unsigned int *got_addr;
24 unsigned long plt_base;
27 /* start of .rela.plt */
28 rel_base = (ELF_RELOC *)(tpnt->dynamic_info[DT_JMPREL]);
30 /* starts of .plt (addr of PLT0) */
31 plt_base = tpnt->dynamic_info[DT_PLTGOT];
34 * compute the idx of the yet-unresolved PLT entry in .plt
35 * Same idx will be used to find the relo entry in .rela.plt
37 plt_idx = (plt_pc - plt_base)/ARC_PLT_SIZE - 2; /* ignoring 2 dummy PLTs */
39 this_reloc = rel_base + plt_idx;
41 symtab_index = ELF_R_SYM(this_reloc->r_info);
42 symtab = (ElfW(Sym) *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
43 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]);
44 symname= strtab + symtab[symtab_index].st_name;
46 /* relo-offset to fixup, shd be a .got entry */
47 got_addr = (unsigned int *)(this_reloc->r_offset + tpnt->loadaddr);
49 /* Get the address of the GOT entry */
50 new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt,
51 ELF_RTYPE_CLASS_PLT, NULL);
53 if (unlikely(!new_addr)) {
54 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
59 #if defined __SUPPORT_LD_DEBUG__
60 if (_dl_debug_bindings) {
61 _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
63 _dl_dprintf(_dl_debug_file, "\n\tpatched %x ==> %pc @ %pl\n",
64 *got_addr, new_addr, got_addr);
67 if (!_dl_debug_nofixups)
68 *got_addr = (unsigned int)new_addr;
70 /* Update the .got entry with the runtime address of symbol */
71 *got_addr = (unsigned int)new_addr;
75 * Return the new addres, where the asm trampoline will jump to
76 * after re-setting up the orig args
78 return (unsigned long) new_addr;
83 _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
84 ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
89 unsigned long *reloc_addr;
90 unsigned long symbol_addr;
91 #if defined __SUPPORT_LD_DEBUG__
92 unsigned long old_val = 0;
94 struct symbol_ref sym_ref;
96 reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset);
97 reloc_type = ELF_R_TYPE(rpnt->r_info);
98 symtab_index = ELF_R_SYM(rpnt->r_info);
101 sym_ref.sym = &symtab[symtab_index];
104 #if defined __SUPPORT_LD_DEBUG__
106 old_val = *reloc_addr;
110 symname = strtab + symtab[symtab_index].st_name;
111 symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
112 elf_machine_type_class(reloc_type), &sym_ref);
115 * We want to allow undefined references to weak symbols,
116 * this might have been intentional. We should not be linking
117 * local symbols here, so all bases should be covered.
120 if (unlikely(!symbol_addr
121 && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
122 /* Non-fatal if called from dlopen, hence different ret code */
125 } else if (reloc_type == R_ARC_RELATIVE ) {
126 *reloc_addr += tpnt->loadaddr;
130 switch (reloc_type) {
132 *reloc_addr += symbol_addr + rpnt->r_addend;
135 *reloc_addr += symbol_addr + rpnt->r_addend - (unsigned long) reloc_addr;
139 *reloc_addr = symbol_addr;
142 _dl_memcpy((void *) reloc_addr,(void *) symbol_addr,
143 symtab[symtab_index].st_size);
150 #if defined __SUPPORT_LD_DEBUG__
151 if (_dl_debug_detail)
152 _dl_dprintf(_dl_debug_file,"\tpatched: %lx ==> %lx @ %pl: addend %x ",
153 old_val, *reloc_addr, reloc_addr, rpnt->r_addend);
160 _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
164 unsigned long *reloc_addr;
165 #if defined __SUPPORT_LD_DEBUG__
166 unsigned long old_val;
169 reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset);
170 reloc_type = ELF_R_TYPE(rpnt->r_info);
172 #if defined __SUPPORT_LD_DEBUG__
173 old_val = *reloc_addr;
176 switch (reloc_type) {
178 *reloc_addr += tpnt->loadaddr;
184 #if defined __SUPPORT_LD_DEBUG__
185 if (_dl_debug_reloc && _dl_debug_detail)
186 _dl_dprintf(_dl_debug_file, "\tpatched: %lx ==> %lx @ %pl\n",
187 old_val, *reloc_addr, reloc_addr);
196 static int _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
197 unsigned long rel_addr, unsigned long rel_size, int type)
206 /* Now parse the relocation information */
207 rpnt = (ELF_RELOC *)(intptr_t) (rel_addr);
208 rel_size = rel_size / sizeof(ELF_RELOC);
210 symtab = (ElfW(Sym) *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
211 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]);
213 for (i = 0; i < rel_size; i++, rpnt++) {
215 symtab_index = ELF_R_SYM(rpnt->r_info);
217 debug_sym(symtab,strtab,symtab_index);
218 debug_reloc(symtab,strtab,rpnt);
220 /* constant propagation subsumes the 'if' */
221 if (type == ___DO_LAZY)
222 res = _dl_do_lazy_reloc(tpnt, scope, rpnt);
224 res = _dl_do_reloc(tpnt, scope, rpnt, symtab, strtab);
230 if (unlikely(res != 0)) {
232 int reloc_type = ELF_R_TYPE(rpnt->r_info);
233 #if defined __SUPPORT_LD_DEBUG__
234 _dl_dprintf(2, "can't handle reloc type %s\n ",
235 _dl_reltypes(reloc_type));
237 _dl_dprintf(2, "can't handle reloc type %x\n",
242 _dl_dprintf(2, "can't resolve symbol\n");
243 /* Fall thru to return res */
251 _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
252 unsigned long rel_addr,
253 unsigned long rel_size)
255 /* This func is called for processing .rela.plt of loaded module(s)
256 * The relo entries handled are JMP_SLOT type for fixing up .got slots
257 * for external function calls.
258 * This function doesn't resolve the slots: that is done lazily at
259 * runtime. The build linker (at least thats what happens for ARC) had
260 * pre-init the .got slots to point to PLT0. All that is done here is
261 * to fix them up to point to load value of PLT0 (as opposed to the
263 * On ARC, the loadaddr of dyn exec is zero, thus elfaddr == loadaddr
264 * Thus there is no point in adding "0" to values and un-necessarily
265 * stir up the caches and TLB.
266 * For ldso processing busybox binary, this skips over 380 relo entries
268 if (rpnt->dyn->loadaddr != 0)
269 _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, ___DO_LAZY);
273 _dl_parse_relocation_information(struct dyn_elf *rpnt,
274 struct r_scope_elem *scope,
275 unsigned long rel_addr,
276 unsigned long rel_size)
278 return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, ___DO_NOW);