elfinterp.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /* TI C64X DSBT ELF shared library loader suppport
  2. * Copyright (C) 2010 Texas Instruments Incorporated
  3. * Contributed by Mark Salter <msalter@redhat.com>
  4. *
  5. * Borrowed heavily from frv arch:
  6. * Copyright (C) 2003, 2004 Red Hat, Inc.
  7. * Contributed by Alexandre Oliva <aoliva@redhat.com>
  8. * Lots of code copied from ../i386/elfinterp.c, so:
  9. * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
  10. * David Engel, Hongjiu Lu and Mitch D'Souza
  11. * Copyright (C) 2001-2002, Erik Andersen
  12. * All rights reserved.
  13. *
  14. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  15. */
  16. #include <features.h>
  17. /* Program to load an ELF binary on a linux system, and run it.
  18. References to symbols in sharable libraries can be resolved by either
  19. an ELF sharable library or a linux style of shared library. */
  20. extern void __c6x_cache_sync(unsigned long start, unsigned long end)
  21. attribute_hidden;
  22. static void
  23. _dl_c6x_flush_relocs(struct elf32_dsbt_loadmap *map)
  24. {
  25. unsigned long s, e;
  26. s = map->segs[0].addr;
  27. e = s + map->segs[0].p_memsz;
  28. __c6x_cache_sync(s, e);
  29. s = map->segs[1].addr;
  30. e = s + map->segs[1].p_memsz;
  31. __c6x_cache_sync(s, e);
  32. }
  33. attribute_hidden
  34. char *
  35. _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
  36. {
  37. ELF_RELOC *this_reloc;
  38. char *strtab;
  39. ElfW(Sym) *symtab;
  40. int symtab_index;
  41. char *rel_addr;
  42. char *new_addr;
  43. char **got_addr;
  44. char *symname;
  45. rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
  46. this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
  47. symtab_index = ELF_R_SYM(this_reloc->r_info);
  48. symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
  49. strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
  50. symname = strtab + symtab[symtab_index].st_name;
  51. /* Address of GOT entry fix up */
  52. got_addr = (char **) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
  53. /* Get the address to be used to fill in the GOT entry. */
  54. new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
  55. if (unlikely(!new_addr)) {
  56. _dl_dprintf(2, "%s: can't resolve symbol '%s' in lib '%s'.\n", _dl_progname, symname, tpnt->libname);
  57. _dl_exit(1);
  58. }
  59. #if defined (__SUPPORT_LD_DEBUG__)
  60. if (_dl_debug_bindings) {
  61. _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
  62. if (_dl_debug_detail)
  63. _dl_dprintf(_dl_debug_file,
  64. "\n\tpatched %x ==> %x @ %x\n",
  65. *got_addr, new_addr, got_addr);
  66. }
  67. if (!_dl_debug_nofixups) {
  68. *got_addr = new_addr;
  69. }
  70. #else
  71. *got_addr = new_addr;
  72. #endif
  73. return new_addr;
  74. }
  75. static int
  76. _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
  77. unsigned long rel_addr, unsigned long rel_size,
  78. int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
  79. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
  80. {
  81. unsigned int i;
  82. char *strtab;
  83. ElfW(Sym) *symtab;
  84. ELF_RELOC *rpnt;
  85. int symtab_index;
  86. /* Now parse the relocation information */
  87. rpnt = (ELF_RELOC *)rel_addr;
  88. rel_size = rel_size / sizeof(ELF_RELOC);
  89. symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB];
  90. strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
  91. for (i = 0; i < rel_size; i++, rpnt++) {
  92. int res;
  93. symtab_index = ELF_R_SYM(rpnt->r_info);
  94. debug_sym(symtab,strtab,symtab_index);
  95. debug_reloc(symtab,strtab,rpnt);
  96. res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
  97. if (res==0) continue;
  98. _dl_dprintf(2, "\n%s: ",_dl_progname);
  99. if (symtab_index)
  100. _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
  101. if (res <0) {
  102. int reloc_type = ELF_R_TYPE(rpnt->r_info);
  103. _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
  104. _dl_exit(-res);
  105. } else if (res >0) {
  106. _dl_dprintf(2, "can't resolve symbol\n");
  107. return res;
  108. }
  109. }
  110. _dl_c6x_flush_relocs(tpnt->loadaddr.map);
  111. return 0;
  112. }
  113. static int
  114. _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope,
  115. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
  116. {
  117. int reloc_type;
  118. int symtab_index;
  119. char *symname;
  120. unsigned long *reloc_addr;
  121. unsigned long symbol_addr, sym_val;
  122. long reloc_addend;
  123. unsigned long old_val, new_val = 0;
  124. struct symbol_ref sym_ref;
  125. struct elf_resolve *symbol_tpnt;
  126. reloc_addr = (unsigned long *)(intptr_t)
  127. DL_RELOC_ADDR (tpnt->loadaddr, rpnt->r_offset);
  128. reloc_type = ELF_R_TYPE(rpnt->r_info);
  129. reloc_addend = rpnt->r_addend;
  130. symtab_index = ELF_R_SYM(rpnt->r_info);
  131. symbol_addr = 0;
  132. symname = strtab + symtab[symtab_index].st_name;
  133. sym_ref.sym = &symtab[symtab_index];
  134. sym_ref.tpnt = NULL;
  135. if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
  136. symbol_addr = (unsigned long)
  137. DL_RELOC_ADDR (tpnt->loadaddr, symtab[symtab_index].st_value);
  138. symbol_tpnt = tpnt;
  139. } else {
  140. symbol_addr = (unsigned long) _dl_find_hash(symname,
  141. scope, NULL, elf_machine_type_class(reloc_type),
  142. &sym_ref);
  143. /*
  144. * We want to allow undefined references to weak symbols - this might
  145. * have been intentional. We should not be linking local symbols
  146. * here, so all bases should be covered.
  147. */
  148. if (!symbol_addr && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
  149. _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
  150. _dl_progname, strtab + symtab[symtab_index].st_name);
  151. _dl_exit (1);
  152. }
  153. symbol_tpnt = sym_ref.tpnt;
  154. }
  155. old_val = *reloc_addr;
  156. sym_val = symbol_addr + reloc_addend;
  157. switch (reloc_type) {
  158. case R_C6000_NONE:
  159. break;
  160. case R_C6000_ABS32:
  161. case R_C6000_JUMP_SLOT:
  162. new_val = sym_val;
  163. *reloc_addr = sym_val;
  164. break;
  165. case R_C6000_DSBT_INDEX:
  166. new_val = (old_val & ~0x007fff00) | ((symbol_tpnt->dsbt_index & 0x7fff) << 8);
  167. *reloc_addr = new_val;
  168. break;
  169. case R_C6000_ABS_L16:
  170. new_val = (old_val & ~0x007fff80) | ((sym_val & 0xffff) << 7);
  171. *reloc_addr = new_val;
  172. break;
  173. case R_C6000_ABS_H16:
  174. new_val = (old_val & ~0x007fff80) | ((sym_val >> 9) & 0x007fff80);
  175. *reloc_addr = new_val;
  176. break;
  177. case R_C6000_PCR_S21:
  178. new_val = sym_val - (((unsigned long)reloc_addr) & ~31);
  179. *reloc_addr = (old_val & ~0x0fffff80) | (((new_val >> 2) & 0x1fffff) << 7);
  180. break;
  181. case R_C6000_COPY:
  182. if (symbol_addr) {
  183. #if defined (__SUPPORT_LD_DEBUG__)
  184. if (_dl_debug_move)
  185. _dl_dprintf(_dl_debug_file,
  186. "\n%s move %d bytes from %x to %x",
  187. symname, symtab[symtab_index].st_size,
  188. symbol_addr, reloc_addr);
  189. #endif
  190. _dl_memcpy((char *)reloc_addr,
  191. (char *)symbol_addr,
  192. symtab[symtab_index].st_size);
  193. }
  194. return 0;
  195. default:
  196. return -1; /*call _dl_exit(1) */
  197. }
  198. #if defined (__SUPPORT_LD_DEBUG__)
  199. if (_dl_debug_reloc && _dl_debug_detail && reloc_type != R_C6000_NONE) {
  200. _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, new_val, reloc_addr);
  201. }
  202. #endif
  203. return 0;
  204. }
  205. static int
  206. _dl_do_lazy_reloc (struct elf_resolve *tpnt,
  207. struct r_scope_elem *scope attribute_unused,
  208. ELF_RELOC *rpnt, ElfW(Sym) *symtab attribute_unused,
  209. char *strtab attribute_unused)
  210. {
  211. int reloc_type;
  212. unsigned long *reloc_addr;
  213. unsigned long old_val;
  214. reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
  215. reloc_type = ELF_R_TYPE(rpnt->r_info);
  216. old_val = *reloc_addr;
  217. switch (reloc_type) {
  218. case R_C6000_NONE:
  219. break;
  220. case R_C6000_JUMP_SLOT:
  221. *reloc_addr = DL_RELOC_ADDR(tpnt->loadaddr, old_val);
  222. break;
  223. default:
  224. return -1;
  225. }
  226. #if defined (__SUPPORT_LD_DEBUG__)
  227. if (_dl_debug_reloc && _dl_debug_detail)
  228. _dl_dprintf(_dl_debug_file, "\n\tpatched: %x ==> %x @ %x\n",
  229. old_val, *reloc_addr, reloc_addr);
  230. #endif
  231. return 0;
  232. }
  233. void
  234. _dl_parse_lazy_relocation_information
  235. (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
  236. {
  237. _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
  238. }
  239. int
  240. _dl_parse_relocation_information
  241. (struct dyn_elf *rpnt, struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size)
  242. {
  243. return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
  244. }
  245. /* We don't have copy relocs. */
  246. int
  247. _dl_parse_copy_information
  248. (struct dyn_elf *rpnt,
  249. unsigned long rel_addr,
  250. unsigned long rel_size)
  251. {
  252. return 0;
  253. }