elfinterp.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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 @ %p\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_NONE:
  123. break;
  124. case R_ARC_32:
  125. *reloc_addr += symbol_addr + rpnt->r_addend;
  126. break;
  127. case R_ARC_PC32:
  128. *reloc_addr += symbol_addr + rpnt->r_addend - (unsigned long) reloc_addr;
  129. break;
  130. case R_ARC_GLOB_DAT:
  131. case R_ARC_JMP_SLOT:
  132. *reloc_addr = symbol_addr;
  133. break;
  134. case R_ARC_COPY:
  135. _dl_memcpy((void *) reloc_addr,(void *) symbol_addr,
  136. symtab[symtab_index].st_size);
  137. break;
  138. #if defined USE_TLS && USE_TLS
  139. case R_ARC_TLS_DTPMOD:
  140. *reloc_addr = tls_tpnt->l_tls_modid;
  141. break;
  142. case R_ARC_TLS_DTPOFF:
  143. *reloc_addr = symbol_addr;
  144. break;
  145. case R_ARC_TLS_TPOFF:
  146. CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
  147. *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend;
  148. break;
  149. #endif
  150. default:
  151. return -1;
  152. }
  153. log_entry:
  154. #if defined __SUPPORT_LD_DEBUG__
  155. if (_dl_debug_detail && (reloc_type != R_ARC_NONE))
  156. _dl_dprintf(_dl_debug_file,"\tpatched: %x ==> %x @ %x",
  157. old_val, *reloc_addr, reloc_addr);
  158. #endif
  159. return 0;
  160. }
  161. static int
  162. _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
  163. ELF_RELOC *rpnt)
  164. {
  165. int reloc_type;
  166. unsigned long *reloc_addr;
  167. #if defined __SUPPORT_LD_DEBUG__
  168. unsigned long old_val;
  169. #endif
  170. reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset);
  171. reloc_type = ELF_R_TYPE(rpnt->r_info);
  172. #if defined __SUPPORT_LD_DEBUG__
  173. old_val = *reloc_addr;
  174. #endif
  175. switch (reloc_type) {
  176. case R_ARC_NONE:
  177. break;
  178. case R_ARC_JMP_SLOT:
  179. *reloc_addr += tpnt->loadaddr;
  180. break;
  181. default:
  182. return -1;
  183. }
  184. #if defined __SUPPORT_LD_DEBUG__
  185. if (_dl_debug_reloc && _dl_debug_detail && (reloc_type != R_ARC_NONE))
  186. _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
  187. old_val, *reloc_addr, reloc_addr);
  188. #endif
  189. return 0;
  190. }
  191. #define ___DO_LAZY 1
  192. #define ___DO_NOW 2
  193. static int _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
  194. unsigned long rel_addr, unsigned long rel_size, int type)
  195. {
  196. unsigned int i;
  197. char *strtab;
  198. ElfW(Sym) *symtab;
  199. ELF_RELOC *rpnt;
  200. int symtab_index;
  201. int res = 0;
  202. /* Now parse the relocation information */
  203. rpnt = (ELF_RELOC *)(intptr_t) (rel_addr);
  204. rel_size = rel_size / sizeof(ELF_RELOC);
  205. symtab = (ElfW(Sym) *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
  206. strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]);
  207. for (i = 0; i < rel_size; i++, rpnt++) {
  208. symtab_index = ELF_R_SYM(rpnt->r_info);
  209. debug_sym(symtab,strtab,symtab_index);
  210. debug_reloc(symtab,strtab,rpnt);
  211. /* constant propagation subsumes the 'if' */
  212. if (type == ___DO_LAZY)
  213. res = _dl_do_lazy_reloc(tpnt, scope, rpnt);
  214. else
  215. res = _dl_do_reloc(tpnt, scope, rpnt, symtab, strtab);
  216. if (res != 0)
  217. break;
  218. }
  219. if (unlikely(res != 0)) {
  220. if (res < 0) {
  221. int reloc_type = ELF_R_TYPE(rpnt->r_info);
  222. _dl_dprintf(2, "can't handle reloc type %x\n",
  223. reloc_type);
  224. _dl_exit(-res);
  225. } else {
  226. _dl_dprintf(2, "can't resolve symbol\n");
  227. /* Fall thru to return res */
  228. }
  229. }
  230. return res;
  231. }
  232. void
  233. _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
  234. unsigned long rel_addr,
  235. unsigned long rel_size)
  236. {
  237. /* This func is called for processing .rela.plt of loaded module(s)
  238. * The relo entries handled are JMP_SLOT type for fixing up .got slots
  239. * for external function calls.
  240. * This function doesn't resolve the slots: that is done lazily at
  241. * runtime. The build linker (at least thats what happens for ARC) had
  242. * pre-init the .got slots to point to PLT0. All that is done here is
  243. * to fix them up to point to load value of PLT0 (as opposed to the
  244. * build value).
  245. * On ARC, the loadaddr of dyn exec is zero, thus elfaddr == loadaddr
  246. * Thus there is no point in adding "0" to values and un-necessarily
  247. * stir up the caches and TLB.
  248. * For ldso processing busybox binary, this skips over 380 relo entries
  249. */
  250. if (rpnt->dyn->loadaddr != 0)
  251. _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, ___DO_LAZY);
  252. }
  253. int
  254. _dl_parse_relocation_information(struct dyn_elf *rpnt,
  255. struct r_scope_elem *scope,
  256. unsigned long rel_addr,
  257. unsigned long rel_size)
  258. {
  259. return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, ___DO_NOW);
  260. }