elfinterp.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
  3. *
  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
  8. * All rights reserved.
  9. *
  10. * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
  11. */
  12. #include "ldso.h"
  13. #ifdef __A7__
  14. #define ARC_PLT_SIZE 12
  15. #else
  16. #define ARC_PLT_SIZE 16
  17. #endif
  18. unsigned long
  19. _dl_linux_resolver(struct elf_resolve *tpnt, unsigned int plt_pc)
  20. {
  21. ELF_RELOC *this_reloc, *rel_base;
  22. char *strtab, *symname, *new_addr;
  23. ElfW(Sym) *symtab;
  24. int symtab_index;
  25. unsigned int *got_addr;
  26. unsigned long plt_base;
  27. int plt_idx;
  28. /* start of .rela.plt */
  29. rel_base = (ELF_RELOC *)(tpnt->dynamic_info[DT_JMPREL]);
  30. /* starts of .plt (addr of PLT0) */
  31. plt_base = tpnt->dynamic_info[DT_PLTGOT];
  32. /*
  33. * compute the idx of the yet-unresolved PLT entry in .plt
  34. * Same idx will be used to find the relo entry in .rela.plt
  35. */
  36. plt_idx = (plt_pc - plt_base)/ARC_PLT_SIZE - 2; /* ignoring 2 dummy PLTs */
  37. this_reloc = rel_base + plt_idx;
  38. symtab_index = ELF_R_SYM(this_reloc->r_info);
  39. symtab = (ElfW(Sym) *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
  40. strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]);
  41. symname= strtab + symtab[symtab_index].st_name;
  42. /* relo-offset to fixup, shd be a .got entry */
  43. got_addr = (unsigned int *)(this_reloc->r_offset + tpnt->loadaddr);
  44. /* Get the address of the GOT entry */
  45. new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt,
  46. ELF_RTYPE_CLASS_PLT, NULL);
  47. if (unlikely(!new_addr)) {
  48. _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
  49. _dl_exit(1);
  50. }
  51. #if defined __SUPPORT_LD_DEBUG__
  52. if (_dl_debug_bindings) {
  53. _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
  54. if (_dl_debug_detail)
  55. _dl_dprintf(_dl_debug_file, "\n\tpatched %x ==> %pc @ %pl\n",
  56. *got_addr, new_addr, got_addr);
  57. }
  58. if (!_dl_debug_nofixups)
  59. *got_addr = (unsigned int)new_addr;
  60. #else
  61. /* Update the .got entry with the runtime address of symbol */
  62. *got_addr = (unsigned int)new_addr;
  63. #endif
  64. /*
  65. * Return the new addres, where the asm trampoline will jump to
  66. * after re-setting up the orig args
  67. */
  68. return (unsigned long) new_addr;
  69. }
  70. static int
  71. _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
  72. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
  73. {
  74. int reloc_type;
  75. int symtab_index;
  76. char *symname;
  77. unsigned long *reloc_addr;
  78. unsigned long symbol_addr;
  79. #if defined __SUPPORT_LD_DEBUG__
  80. unsigned long old_val = 0;
  81. #endif
  82. struct symbol_ref sym_ref;
  83. struct elf_resolve *tls_tpnt = NULL;
  84. reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset);
  85. reloc_type = ELF_R_TYPE(rpnt->r_info);
  86. symtab_index = ELF_R_SYM(rpnt->r_info);
  87. symbol_addr = 0;
  88. sym_ref.sym = &symtab[symtab_index];
  89. sym_ref.tpnt = NULL;
  90. #if defined __SUPPORT_LD_DEBUG__
  91. if (reloc_addr)
  92. old_val = *reloc_addr;
  93. #endif
  94. if (symtab_index) {
  95. symname = strtab + symtab[symtab_index].st_name;
  96. symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
  97. elf_machine_type_class(reloc_type), &sym_ref);
  98. /*
  99. * We want to allow undefined references to weak symbols,
  100. * this might have been intentional. We should not be linking
  101. * local symbols here, so all bases should be covered.
  102. */
  103. if (unlikely(!symbol_addr
  104. && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK
  105. && ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS)) {
  106. /* Non-fatal if called from dlopen, hence different ret code */
  107. return 1;
  108. }
  109. tls_tpnt = sym_ref.tpnt;
  110. } else if (reloc_type == R_ARC_RELATIVE ) {
  111. *reloc_addr += tpnt->loadaddr;
  112. goto log_entry;
  113. }
  114. #if defined USE_TLS && USE_TLS
  115. /* In case of a TLS reloc, tls_tpnt NULL means we have an 'anonymous'
  116. symbol. This is the case for a static tls variable, so the lookup
  117. module is just that one is referencing the tls variable. */
  118. if (!tls_tpnt)
  119. tls_tpnt = tpnt;
  120. #endif
  121. switch (reloc_type) {
  122. case R_ARC_32:
  123. *reloc_addr += symbol_addr + rpnt->r_addend;
  124. break;
  125. case R_ARC_PC32:
  126. *reloc_addr += symbol_addr + rpnt->r_addend - (unsigned long) reloc_addr;
  127. break;
  128. case R_ARC_GLOB_DAT:
  129. case R_ARC_JMP_SLOT:
  130. *reloc_addr = symbol_addr;
  131. break;
  132. case R_ARC_COPY:
  133. _dl_memcpy((void *) reloc_addr,(void *) symbol_addr,
  134. symtab[symtab_index].st_size);
  135. break;
  136. #if defined USE_TLS && USE_TLS
  137. case R_ARC_TLS_DTPMOD:
  138. *reloc_addr = tls_tpnt->l_tls_modid;
  139. break;
  140. case R_ARC_TLS_DTPOFF:
  141. *reloc_addr = symbol_addr;
  142. break;
  143. case R_ARC_TLS_TPOFF:
  144. CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
  145. *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend;
  146. break;
  147. #endif
  148. default:
  149. return -1;
  150. }
  151. log_entry:
  152. #if defined __SUPPORT_LD_DEBUG__
  153. if (_dl_debug_detail)
  154. _dl_dprintf(_dl_debug_file,"\tpatched: %lx ==> %lx @ %pl: addend %x ",
  155. old_val, *reloc_addr, reloc_addr, rpnt->r_addend);
  156. #endif
  157. return 0;
  158. }
  159. static int
  160. _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
  161. ELF_RELOC *rpnt)
  162. {
  163. int reloc_type;
  164. unsigned long *reloc_addr;
  165. #if defined __SUPPORT_LD_DEBUG__
  166. unsigned long old_val;
  167. #endif
  168. reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset);
  169. reloc_type = ELF_R_TYPE(rpnt->r_info);
  170. #if defined __SUPPORT_LD_DEBUG__
  171. old_val = *reloc_addr;
  172. #endif
  173. switch (reloc_type) {
  174. case R_ARC_JMP_SLOT:
  175. *reloc_addr += tpnt->loadaddr;
  176. break;
  177. default:
  178. return -1;
  179. }
  180. #if defined __SUPPORT_LD_DEBUG__
  181. if (_dl_debug_reloc && _dl_debug_detail)
  182. _dl_dprintf(_dl_debug_file, "\tpatched: %lx ==> %lx @ %pl\n",
  183. old_val, *reloc_addr, reloc_addr);
  184. #endif
  185. return 0;
  186. }
  187. #define ___DO_LAZY 1
  188. #define ___DO_NOW 2
  189. static int _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
  190. unsigned long rel_addr, unsigned long rel_size, int type)
  191. {
  192. unsigned int i;
  193. char *strtab;
  194. ElfW(Sym) *symtab;
  195. ELF_RELOC *rpnt;
  196. int symtab_index;
  197. int res = 0;
  198. /* Now parse the relocation information */
  199. rpnt = (ELF_RELOC *)(intptr_t) (rel_addr);
  200. rel_size = rel_size / sizeof(ELF_RELOC);
  201. symtab = (ElfW(Sym) *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
  202. strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]);
  203. for (i = 0; i < rel_size; i++, rpnt++) {
  204. symtab_index = ELF_R_SYM(rpnt->r_info);
  205. debug_sym(symtab,strtab,symtab_index);
  206. debug_reloc(symtab,strtab,rpnt);
  207. /* constant propagation subsumes the 'if' */
  208. if (type == ___DO_LAZY)
  209. res = _dl_do_lazy_reloc(tpnt, scope, rpnt);
  210. else
  211. res = _dl_do_reloc(tpnt, scope, rpnt, symtab, strtab);
  212. if (res != 0)
  213. break;
  214. }
  215. if (unlikely(res != 0)) {
  216. if (res < 0) {
  217. int reloc_type = ELF_R_TYPE(rpnt->r_info);
  218. #if defined __SUPPORT_LD_DEBUG__
  219. _dl_dprintf(2, "can't handle reloc type %s\n ",
  220. _dl_reltypes(reloc_type));
  221. #else
  222. _dl_dprintf(2, "can't handle reloc type %x\n",
  223. reloc_type);
  224. #endif
  225. _dl_exit(-res);
  226. } else {
  227. _dl_dprintf(2, "can't resolve symbol\n");
  228. /* Fall thru to return res */
  229. }
  230. }
  231. return res;
  232. }
  233. void
  234. _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
  235. unsigned long rel_addr,
  236. unsigned long rel_size)
  237. {
  238. /* This func is called for processing .rela.plt of loaded module(s)
  239. * The relo entries handled are JMP_SLOT type for fixing up .got slots
  240. * for external function calls.
  241. * This function doesn't resolve the slots: that is done lazily at
  242. * runtime. The build linker (at least thats what happens for ARC) had
  243. * pre-init the .got slots to point to PLT0. All that is done here is
  244. * to fix them up to point to load value of PLT0 (as opposed to the
  245. * build value).
  246. * On ARC, the loadaddr of dyn exec is zero, thus elfaddr == loadaddr
  247. * Thus there is no point in adding "0" to values and un-necessarily
  248. * stir up the caches and TLB.
  249. * For ldso processing busybox binary, this skips over 380 relo entries
  250. */
  251. if (rpnt->dyn->loadaddr != 0)
  252. _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, ___DO_LAZY);
  253. }
  254. int
  255. _dl_parse_relocation_information(struct dyn_elf *rpnt,
  256. struct r_scope_elem *scope,
  257. unsigned long rel_addr,
  258. unsigned long rel_size)
  259. {
  260. return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, ___DO_NOW);
  261. }