elfinterp.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*
  2. * Copyright (C) 2016 Andes Technology, Inc.
  3. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  4. */
  5. /* NDS32 ELF shared library loader suppport
  6. *
  7. * Copyright (C) 2001-2004 Erik Andersen
  8. *
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  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.
  19. *
  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
  30. * SUCH DAMAGE.
  31. */
  32. /* Program to load an ELF binary on a linux system, and run it.
  33. References to symbols in sharable libraries can be resolved by either
  34. an ELF sharable library or a linux style of shared library. */
  35. /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
  36. I ever taken any courses on internals. This program was developed using
  37. information available through the book "UNIX SYSTEM V RELEASE 4,
  38. Programmers guide: Ansi C and Programming Support Tools", which did
  39. a more than adequate job of explaining everything required to get this
  40. working. */
  41. #include "ldso.h"
  42. #if defined(USE_TLS) && USE_TLS
  43. #include "dl-tls.h"
  44. #include "tlsdeschtab.h"
  45. #endif
  46. extern int _dl_linux_resolve(void);
  47. unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
  48. {
  49. int reloc_type;
  50. ELF_RELOC *this_reloc;
  51. char *strtab;
  52. char *symname;
  53. Elf32_Sym *symtab;
  54. ELF_RELOC *rel_addr;
  55. int symtab_index;
  56. char *new_addr;
  57. char **got_addr;
  58. unsigned long instr_addr;
  59. rel_addr = (ELF_RELOC *) tpnt->dynamic_info[DT_JMPREL];
  60. this_reloc = rel_addr + reloc_entry/sizeof(ELF_RELOC);
  61. reloc_type = ELF32_R_TYPE(this_reloc->r_info);
  62. symtab_index = ELF32_R_SYM(this_reloc->r_info);
  63. symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
  64. strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
  65. symname = strtab + symtab[symtab_index].st_name;
  66. if (unlikely(reloc_type != R_NDS32_JMP_SLOT)) {
  67. _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
  68. _dl_progname);
  69. _dl_exit(1);
  70. }
  71. /* Address of jump instruction to fix up */
  72. instr_addr = ((unsigned long) this_reloc->r_offset +
  73. (unsigned long) tpnt->loadaddr);
  74. got_addr = (char **) instr_addr;
  75. /* Get the address of the GOT entry */
  76. new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt,
  77. ELF_RTYPE_CLASS_PLT, NULL);
  78. if (unlikely(!new_addr)) {
  79. _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
  80. _dl_progname, symname);
  81. _dl_exit(1);
  82. }
  83. #if defined (__SUPPORT_LD_DEBUG__)
  84. if ((unsigned long) got_addr < 0x40000000)
  85. {
  86. if (_dl_debug_bindings)
  87. {
  88. _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
  89. if (_dl_debug_detail) _dl_dprintf(_dl_debug_file,
  90. "\tpatch %x ==> %x @ %x", (unsigned int)*got_addr, (unsigned int)new_addr, (unsigned int)got_addr);
  91. }
  92. }
  93. if (!_dl_debug_nofixups) {
  94. *got_addr = new_addr;
  95. }
  96. #else
  97. *got_addr = new_addr;
  98. #endif
  99. return (unsigned long) new_addr;
  100. }
  101. static int
  102. _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
  103. unsigned long rel_addr, unsigned long rel_size,
  104. int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
  105. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
  106. {
  107. int symtab_index;
  108. int i;
  109. char *strtab;
  110. int goof = 0;
  111. ElfW(Sym) *symtab;
  112. ELF_RELOC *rpnt;
  113. /* Now parse the relocation information */
  114. rpnt = (ELF_RELOC *) rel_addr;
  115. rel_size = rel_size / sizeof(ELF_RELOC);
  116. symtab = (Elf32_Sym *) tpnt->dynamic_info[DT_SYMTAB];
  117. strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
  118. for (i = 0; i < rel_size; i++, rpnt++) {
  119. int res;
  120. symtab_index = ELF32_R_SYM(rpnt->r_info);
  121. debug_sym(symtab,strtab,symtab_index);
  122. debug_reloc(symtab,strtab,rpnt);
  123. res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
  124. if (res==0) continue;
  125. _dl_dprintf(2, "\n%s: ",_dl_progname);
  126. if (symtab_index)
  127. _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
  128. if (unlikely(res <0))
  129. {
  130. int reloc_type = ELF32_R_TYPE(rpnt->r_info);
  131. _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
  132. _dl_exit(-res);
  133. }
  134. if (unlikely(res >0))
  135. {
  136. _dl_dprintf(2, "can't resolve symbol\n");
  137. goof += res;
  138. }
  139. }
  140. return goof;
  141. }
  142. static int
  143. _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
  144. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
  145. {
  146. int reloc_type;
  147. int symtab_index;
  148. char *symname = NULL;
  149. #if defined USE_TLS && USE_TLS
  150. struct elf_resolve *tls_tpnt = NULL;
  151. #endif
  152. unsigned long *reloc_addr;
  153. unsigned long symbol_addr;
  154. int goof = 0;
  155. struct symbol_ref sym_ref;
  156. reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
  157. reloc_type = ELF32_R_TYPE(rpnt->r_info);
  158. symtab_index = ELF32_R_SYM(rpnt->r_info);
  159. symbol_addr = 0;
  160. sym_ref.sym = &symtab[symtab_index];
  161. sym_ref.tpnt = NULL;
  162. if (symtab_index) {
  163. symname = strtab + symtab[symtab_index].st_name;
  164. symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt,
  165. elf_machine_type_class(reloc_type), &sym_ref);
  166. /*
  167. * We want to allow undefined references to weak symbols - this might
  168. * have been intentional. We should not be linking local symbols
  169. * here, so all bases should be covered.
  170. */
  171. if (!symbol_addr
  172. && (ELF32_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS)
  173. && (ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
  174. _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
  175. _dl_progname, symname);
  176. _dl_exit (1);
  177. }
  178. if (_dl_trace_prelink) {
  179. _dl_debug_lookup(symname, tpnt, &symtab[symtab_index],
  180. &sym_ref, elf_machine_type_class(reloc_type));
  181. }
  182. #if defined USE_TLS && USE_TLS
  183. tls_tpnt = sym_ref.tpnt;
  184. #endif
  185. }
  186. #if defined USE_TLS && USE_TLS
  187. /* In case of a TLS reloc, tls_tpnt NULL means we have an 'anonymous'
  188. symbol. This is the case for a static tls variable, so the lookup
  189. module is just that one is referencing the tls variable. */
  190. if (!tls_tpnt)
  191. tls_tpnt = tpnt;
  192. #endif
  193. #define COPY_UNALIGNED_WORD(swp, twp) \
  194. { \
  195. __typeof (swp) __tmp = __builtin_nds32_unaligned_load_w ((unsigned int*)&swp); \
  196. __builtin_nds32_unaligned_store_w ((unsigned int *)twp, __tmp); \
  197. }
  198. #if defined (__SUPPORT_LD_DEBUG__)
  199. {
  200. unsigned long old_val = 0;
  201. if(reloc_type != R_NDS32_NONE)
  202. old_val = *reloc_addr;
  203. #endif
  204. symbol_addr += rpnt->r_addend ;
  205. switch (reloc_type) {
  206. case R_NDS32_NONE:
  207. break;
  208. case R_NDS32_32:
  209. case R_NDS32_GLOB_DAT:
  210. case R_NDS32_JMP_SLOT:
  211. *reloc_addr = symbol_addr;
  212. break;
  213. case R_NDS32_32_RELA:
  214. COPY_UNALIGNED_WORD (symbol_addr, reloc_addr);
  215. break;
  216. #undef COPY_UNALIGNED_WORD
  217. case R_NDS32_RELATIVE:
  218. *reloc_addr = (unsigned long) tpnt->loadaddr + rpnt->r_addend;
  219. break;
  220. case R_NDS32_COPY:
  221. _dl_memcpy((void *) reloc_addr,
  222. (void *) symbol_addr, symtab[symtab_index].st_size);
  223. break;
  224. #if defined USE_TLS && USE_TLS
  225. case R_NDS32_TLS_TPOFF:
  226. CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
  227. *reloc_addr = (symbol_addr + tls_tpnt->l_tls_offset);
  228. break;
  229. case R_NDS32_TLS_DESC:
  230. {
  231. struct tlsdesc volatile *td =
  232. (struct tlsdesc volatile *)reloc_addr;
  233. #ifndef SHARED
  234. CHECK_STATIC_TLS((struct link_map *) tls_tpnt);
  235. #else
  236. if (!TRY_STATIC_TLS ((struct link_map *) tls_tpnt))
  237. {
  238. td->argument.pointer = _dl_make_tlsdesc_dynamic((struct link_map *) tls_tpnt, symbol_addr);
  239. td->entry = _dl_tlsdesc_dynamic;
  240. }
  241. else
  242. #endif
  243. {
  244. td->argument.value = symbol_addr + tls_tpnt->l_tls_offset;
  245. td->entry = _dl_tlsdesc_return;
  246. }
  247. }
  248. break;
  249. #endif
  250. default:
  251. return -1; /*call _dl_exit(1) */
  252. }
  253. #if defined (__SUPPORT_LD_DEBUG__)
  254. if (_dl_debug_reloc && _dl_debug_detail)
  255. _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", (unsigned int)old_val, (unsigned int)*reloc_addr, (unsigned int)reloc_addr);
  256. }
  257. #endif
  258. return goof;
  259. }
  260. static int
  261. _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
  262. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
  263. {
  264. int reloc_type;
  265. unsigned long *reloc_addr;
  266. reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
  267. reloc_type = ELF32_R_TYPE(rpnt->r_info);
  268. #if defined (__SUPPORT_LD_DEBUG__)
  269. {
  270. unsigned long old_val = *reloc_addr;
  271. #endif
  272. switch (reloc_type) {
  273. case R_NDS32_NONE:
  274. break;
  275. case R_NDS32_JMP_SLOT:
  276. *reloc_addr += (unsigned long) tpnt->loadaddr;
  277. break;
  278. default:
  279. return -1; /*call _dl_exit(1) */
  280. }
  281. #if defined (__SUPPORT_LD_DEBUG__)
  282. if (_dl_debug_reloc && _dl_debug_detail)
  283. _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", (unsigned int)old_val, (unsigned int)*reloc_addr, (unsigned int)reloc_addr);
  284. }
  285. #endif
  286. return 0;
  287. }
  288. void
  289. _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
  290. unsigned long rel_addr,
  291. unsigned long rel_size)
  292. {
  293. _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
  294. }
  295. int
  296. _dl_parse_relocation_information(struct dyn_elf *rpnt,
  297. struct r_scope_elem *scope,
  298. unsigned long rel_addr,
  299. unsigned long rel_size)
  300. {
  301. return _dl_parse(rpnt->dyn, scope, rel_addr,
  302. rel_size, _dl_do_reloc);
  303. }