elfinterp.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /* Blackfin ELF shared library loader suppport
  2. Copyright (C) 2003, 2004 Red Hat, Inc.
  3. Contributed by Alexandre Oliva <aoliva@redhat.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
  8. All rights reserved.
  9. This file is part of uClibc.
  10. uClibc is free software; you can redistribute it and/or modify it
  11. under the terms of the GNU Lesser General Public License as
  12. published by the Free Software Foundation; either version 2.1 of the
  13. License, or (at your option) any later version.
  14. uClibc is distributed in the hope that it will be useful, but WITHOUT
  15. ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. Library General Public License for more details.
  18. You should have received a copy of the GNU Lesser General Public
  19. License along with uClibc; see the file COPYING.LIB. If not, see
  20. <http://www.gnu.org/licenses/>. */
  21. #include <sys/cdefs.h> /* __attribute_used__ */
  22. /* Program to load an ELF binary on a linux system, and run it.
  23. References to symbols in sharable libraries can be resolved by either
  24. an ELF sharable library or a linux style of shared library. */
  25. __attribute__((__visibility__("hidden")))
  26. struct funcdesc_value volatile *
  27. _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
  28. {
  29. ELF_RELOC *this_reloc;
  30. char *strtab;
  31. ElfW(Sym) *symtab;
  32. int symtab_index;
  33. char *rel_addr;
  34. char *new_addr;
  35. struct funcdesc_value funcval;
  36. struct funcdesc_value volatile *got_entry;
  37. char *symname;
  38. struct symbol_ref sym_ref;
  39. rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
  40. this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
  41. symtab_index = ELF_R_SYM(this_reloc->r_info);
  42. symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
  43. strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
  44. sym_ref.sym = &symtab[symtab_index];
  45. sym_ref.tpnt = NULL;
  46. symname= strtab + symtab[symtab_index].st_name;
  47. /* Address of GOT entry fix up */
  48. got_entry = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, this_reloc->r_offset);
  49. /* Get the address to be used to fill in the GOT entry. */
  50. new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, NULL, 0, &sym_ref);
  51. if (!new_addr) {
  52. new_addr = _dl_find_hash(symname, NULL, NULL, 0, &sym_ref);
  53. if (!new_addr) {
  54. _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
  55. _dl_progname, symname);
  56. _dl_exit(1);
  57. }
  58. }
  59. funcval.entry_point = new_addr;
  60. funcval.got_value = sym_ref.tpnt->loadaddr.got_value;
  61. #if defined (__SUPPORT_LD_DEBUG__)
  62. if (_dl_debug_bindings) {
  63. _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
  64. if (_dl_debug_detail)
  65. _dl_dprintf(_dl_debug_file,
  66. "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n",
  67. got_entry->entry_point, got_entry->got_value,
  68. funcval.entry_point, funcval.got_value,
  69. got_entry);
  70. }
  71. if (1 || !_dl_debug_nofixups) {
  72. *got_entry = funcval;
  73. }
  74. #else
  75. *got_entry = funcval;
  76. #endif
  77. return got_entry;
  78. }
  79. static int
  80. _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
  81. unsigned long rel_addr, unsigned long rel_size,
  82. int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
  83. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
  84. {
  85. unsigned int i;
  86. char *strtab;
  87. ElfW(Sym) *symtab;
  88. ELF_RELOC *rpnt;
  89. int symtab_index;
  90. /* Now parse the relocation information */
  91. rpnt = (ELF_RELOC *) rel_addr;
  92. rel_size = rel_size / sizeof(ELF_RELOC);
  93. symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
  94. strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
  95. for (i = 0; i < rel_size; i++, rpnt++) {
  96. int res;
  97. symtab_index = ELF_R_SYM(rpnt->r_info);
  98. debug_sym(symtab,strtab,symtab_index);
  99. debug_reloc(symtab,strtab,rpnt);
  100. res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
  101. if (res==0) continue;
  102. _dl_dprintf(2, "\n%s: ",_dl_progname);
  103. if (symtab_index)
  104. _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
  105. if (res <0) {
  106. int reloc_type = ELF_R_TYPE(rpnt->r_info);
  107. _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
  108. _dl_exit(-res);
  109. } else if (res >0) {
  110. _dl_dprintf(2, "can't resolve symbol\n");
  111. return res;
  112. }
  113. }
  114. return 0;
  115. }
  116. static int
  117. _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope,
  118. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
  119. {
  120. int reloc_type;
  121. int symtab_index;
  122. char *symname;
  123. unsigned long reloc_value = 0, *reloc_addr;
  124. struct { unsigned long v; } __attribute__((__packed__))
  125. *reloc_addr_packed;
  126. unsigned long symbol_addr;
  127. struct elf_resolve *symbol_tpnt;
  128. struct funcdesc_value funcval;
  129. #if defined (__SUPPORT_LD_DEBUG__)
  130. unsigned long old_val;
  131. #endif
  132. struct symbol_ref sym_ref;
  133. reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
  134. __asm__ ("" : "=r" (reloc_addr_packed) : "0" (reloc_addr));
  135. reloc_type = ELF_R_TYPE(rpnt->r_info);
  136. symtab_index = ELF_R_SYM(rpnt->r_info);
  137. symbol_addr = 0;
  138. sym_ref.sym = &symtab[symtab_index];
  139. sym_ref.tpnt = NULL;
  140. symname = strtab + symtab[symtab_index].st_name;
  141. if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
  142. symbol_addr = (unsigned long) DL_RELOC_ADDR(tpnt->loadaddr, symtab[symtab_index].st_value);
  143. symbol_tpnt = tpnt;
  144. } else {
  145. symbol_addr = (unsigned long)
  146. _dl_find_hash(symname, scope, NULL, 0, &sym_ref);
  147. /*
  148. * We want to allow undefined references to weak symbols - this might
  149. * have been intentional. We should not be linking local symbols
  150. * here, so all bases should be covered.
  151. */
  152. if (!symbol_addr && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
  153. _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
  154. _dl_progname, symname);
  155. _dl_exit (1);
  156. }
  157. if (_dl_trace_prelink) {
  158. _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
  159. &sym_ref, elf_machine_type_class(reloc_type));
  160. }
  161. symbol_tpnt = sym_ref.tpnt;
  162. }
  163. #if defined (__SUPPORT_LD_DEBUG__)
  164. if (_dl_debug_reloc && _dl_debug_detail)
  165. {
  166. if ((long)reloc_addr_packed & 3)
  167. old_val = reloc_addr_packed->v;
  168. else
  169. old_val = *reloc_addr;
  170. }
  171. else
  172. old_val = 0;
  173. #endif
  174. switch (reloc_type) {
  175. case R_BFIN_UNUSED0:
  176. break;
  177. case R_BFIN_BYTE4_DATA:
  178. if ((long)reloc_addr_packed & 3)
  179. reloc_value = reloc_addr_packed->v += symbol_addr;
  180. else
  181. reloc_value = *reloc_addr += symbol_addr;
  182. break;
  183. case R_BFIN_FUNCDESC_VALUE:
  184. funcval.entry_point = (void*)symbol_addr;
  185. /* The addend of FUNCDESC_VALUE
  186. relocations referencing global
  187. symbols must be ignored, because it
  188. may hold the address of a lazy PLT
  189. entry. */
  190. if (ELF_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL)
  191. funcval.entry_point += *reloc_addr;
  192. reloc_value = (unsigned long)funcval.entry_point;
  193. if (symbol_addr)
  194. funcval.got_value
  195. = symbol_tpnt->loadaddr.got_value;
  196. else
  197. funcval.got_value = 0;
  198. __asm__ ("%0 = %2; %1 = %H2;"
  199. : "=m" (*(struct funcdesc_value *)reloc_addr), "=m" (((long *)reloc_addr)[1])
  200. : "d" (funcval));
  201. break;
  202. case R_BFIN_FUNCDESC:
  203. if ((long)reloc_addr_packed & 3)
  204. reloc_value = reloc_addr_packed->v;
  205. else
  206. reloc_value = *reloc_addr;
  207. if (symbol_addr)
  208. reloc_value = (unsigned long)_dl_funcdesc_for
  209. ((char *)symbol_addr + reloc_value,
  210. symbol_tpnt->loadaddr.got_value);
  211. else
  212. reloc_value = 0;
  213. if ((long)reloc_addr_packed & 3)
  214. reloc_addr_packed->v = reloc_value;
  215. else
  216. *reloc_addr = reloc_value;
  217. break;
  218. default:
  219. return -1;
  220. }
  221. #if defined (__SUPPORT_LD_DEBUG__)
  222. if (_dl_debug_reloc && _dl_debug_detail) {
  223. _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_value, reloc_addr);
  224. switch (reloc_type) {
  225. case R_BFIN_FUNCDESC_VALUE:
  226. _dl_dprintf(_dl_debug_file, " got %x", ((struct funcdesc_value *)reloc_value)->got_value);
  227. break;
  228. case R_BFIN_FUNCDESC:
  229. if (! reloc_value)
  230. break;
  231. _dl_dprintf(_dl_debug_file, " funcdesc (%x,%x)",
  232. ((struct funcdesc_value *)reloc_value)->entry_point,
  233. ((struct funcdesc_value *)reloc_value)->got_value);
  234. break;
  235. }
  236. }
  237. #endif
  238. return 0;
  239. }
  240. static int
  241. _dl_do_lazy_reloc (struct elf_resolve *tpnt,
  242. struct r_scope_elem *scope __attribute__((unused)),
  243. ELF_RELOC *rpnt, ElfW(Sym) *symtab __attribute__((unused)),
  244. char *strtab __attribute__((unused)))
  245. {
  246. int reloc_type;
  247. struct funcdesc_value volatile *reloc_addr;
  248. struct funcdesc_value funcval;
  249. #if defined (__SUPPORT_LD_DEBUG__)
  250. unsigned long old_val;
  251. #endif
  252. reloc_addr = (struct funcdesc_value *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset);
  253. reloc_type = ELF_R_TYPE(rpnt->r_info);
  254. #if defined (__SUPPORT_LD_DEBUG__)
  255. old_val = (unsigned long)reloc_addr->entry_point;
  256. #endif
  257. switch (reloc_type) {
  258. case R_BFIN_UNUSED0:
  259. break;
  260. case R_BFIN_FUNCDESC_VALUE:
  261. funcval = *reloc_addr;
  262. funcval.entry_point = (void *) DL_RELOC_ADDR(tpnt->loadaddr, funcval.entry_point);
  263. funcval.got_value = tpnt->loadaddr.got_value;
  264. *reloc_addr = funcval;
  265. break;
  266. default:
  267. return -1;
  268. }
  269. #if defined (__SUPPORT_LD_DEBUG__)
  270. if (_dl_debug_reloc && _dl_debug_detail)
  271. _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, reloc_addr->entry_point, reloc_addr);
  272. #endif
  273. return 0;
  274. }
  275. void
  276. _dl_parse_lazy_relocation_information
  277. (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
  278. {
  279. _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
  280. }
  281. int
  282. _dl_parse_relocation_information
  283. (struct dyn_elf *rpnt, struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size)
  284. {
  285. return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
  286. }
  287. /* We don't have copy relocs. */
  288. int
  289. _dl_parse_copy_information
  290. (struct dyn_elf *rpnt __attribute__((unused)),
  291. unsigned long rel_addr __attribute__((unused)),
  292. unsigned long rel_size __attribute__((unused)))
  293. {
  294. return 0;
  295. }
  296. #ifndef IS_IN_libdl
  297. # include "../../libc/sysdeps/linux/bfin/crtreloc.c"
  298. #endif