elfinterp.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /* FR-V FDPIC 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. *
  10. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  11. */
  12. #include <features.h>
  13. /* Program to load an ELF binary on a linux system, and run it.
  14. References to symbols in sharable libraries can be resolved by either
  15. an ELF sharable library or a linux style of shared library. */
  16. /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
  17. I ever taken any courses on internals. This program was developed using
  18. information available through the book "UNIX SYSTEM V RELEASE 4,
  19. Programmers guide: Ansi C and Programming Support Tools", which did
  20. a more than adequate job of explaining everything required to get this
  21. working. */
  22. struct funcdesc_value volatile attribute_hidden *
  23. _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
  24. {
  25. int reloc_type;
  26. ELF_RELOC *this_reloc;
  27. char *strtab;
  28. Elf32_Sym *symtab;
  29. int symtab_index;
  30. char *rel_addr;
  31. struct elf_resolve *new_tpnt;
  32. char *new_addr;
  33. struct funcdesc_value funcval;
  34. struct funcdesc_value volatile *got_entry;
  35. char *symname;
  36. rel_addr = DL_RELOC_ADDR (tpnt->dynamic_info[DT_JMPREL],
  37. tpnt->loadaddr);
  38. this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
  39. reloc_type = ELF32_R_TYPE(this_reloc->r_info);
  40. symtab_index = ELF32_R_SYM(this_reloc->r_info);
  41. symtab = (Elf32_Sym *)(intptr_t)
  42. DL_RELOC_ADDR (tpnt->dynamic_info[DT_SYMTAB],
  43. tpnt->loadaddr);
  44. strtab = DL_RELOC_ADDR (tpnt->dynamic_info[DT_STRTAB], tpnt->loadaddr);
  45. symname= strtab + symtab[symtab_index].st_name;
  46. if (reloc_type != R_FRV_FUNCDESC_VALUE) {
  47. _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
  48. _dl_progname);
  49. _dl_exit(1);
  50. }
  51. /* Address of GOT entry fix up */
  52. got_entry = (struct funcdesc_value *)
  53. DL_RELOC_ADDR (this_reloc->r_offset, tpnt->loadaddr);
  54. /* Get the address to be used to fill in the GOT entry. */
  55. new_addr = _dl_find_hash_mod(symname, tpnt->symbol_scope, NULL, 0,
  56. &new_tpnt);
  57. if (!new_addr) {
  58. new_addr = _dl_find_hash_mod(symname, NULL, NULL, 0,
  59. &new_tpnt);
  60. if (!new_addr) {
  61. _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
  62. _dl_progname, symname);
  63. _dl_exit(1);
  64. }
  65. }
  66. funcval.entry_point = new_addr;
  67. funcval.got_value = new_tpnt->loadaddr.got_value;
  68. #if defined (__SUPPORT_LD_DEBUG__)
  69. if (_dl_debug_bindings)
  70. {
  71. _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
  72. if (_dl_debug_detail)
  73. _dl_dprintf(_dl_debug_file,
  74. "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n",
  75. got_entry->entry_point, got_entry->got_value,
  76. funcval.entry_point, funcval.got_value,
  77. got_entry);
  78. }
  79. if (!_dl_debug_nofixups) {
  80. *got_entry = funcval;
  81. }
  82. #else
  83. *got_entry = funcval;
  84. #endif
  85. return got_entry;
  86. }
  87. static int
  88. _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
  89. unsigned long rel_addr, unsigned long rel_size,
  90. int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
  91. ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
  92. {
  93. unsigned int i;
  94. char *strtab;
  95. Elf32_Sym *symtab;
  96. ELF_RELOC *rpnt;
  97. int symtab_index;
  98. /* Now parse the relocation information */
  99. rpnt = (ELF_RELOC *)(intptr_t) DL_RELOC_ADDR (rel_addr, tpnt->loadaddr);
  100. rel_size = rel_size / sizeof(ELF_RELOC);
  101. symtab = (Elf32_Sym *)(intptr_t)
  102. DL_RELOC_ADDR (tpnt->dynamic_info[DT_SYMTAB], tpnt->loadaddr);
  103. strtab = DL_RELOC_ADDR (tpnt->dynamic_info[DT_STRTAB], tpnt->loadaddr);
  104. for (i = 0; i < rel_size; i++, rpnt++) {
  105. int res;
  106. symtab_index = ELF32_R_SYM(rpnt->r_info);
  107. debug_sym(symtab,strtab,symtab_index);
  108. debug_reloc(symtab,strtab,rpnt);
  109. res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
  110. if (res==0) continue;
  111. _dl_dprintf(2, "\n%s: ",_dl_progname);
  112. if (symtab_index)
  113. _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
  114. if (res <0)
  115. {
  116. int reloc_type = ELF32_R_TYPE(rpnt->r_info);
  117. #if defined (__SUPPORT_LD_DEBUG__)
  118. _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
  119. #else
  120. _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
  121. #endif
  122. _dl_exit(-res);
  123. }
  124. else if (res >0)
  125. {
  126. _dl_dprintf(2, "can't resolve symbol\n");
  127. return res;
  128. }
  129. }
  130. return 0;
  131. }
  132. static int
  133. _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
  134. ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
  135. {
  136. int reloc_type;
  137. int symtab_index;
  138. char *symname;
  139. unsigned long reloc_value = 0, *reloc_addr;
  140. struct { unsigned long v; } __attribute__((__packed__))
  141. *reloc_addr_packed;
  142. unsigned long symbol_addr;
  143. struct elf_resolve *symbol_tpnt;
  144. struct funcdesc_value funcval;
  145. #if defined (__SUPPORT_LD_DEBUG__)
  146. unsigned long old_val;
  147. #endif
  148. reloc_addr = (unsigned long *)(intptr_t)
  149. DL_RELOC_ADDR (rpnt->r_offset, tpnt->loadaddr);
  150. __asm__ ("" : "=r" (reloc_addr_packed) : "0" (reloc_addr));
  151. reloc_type = ELF32_R_TYPE(rpnt->r_info);
  152. symtab_index = ELF32_R_SYM(rpnt->r_info);
  153. symbol_addr = 0;
  154. symname = strtab + symtab[symtab_index].st_name;
  155. if (ELF32_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
  156. symbol_addr = (unsigned long)
  157. DL_RELOC_ADDR (symtab[symtab_index].st_value,
  158. tpnt->loadaddr);
  159. symbol_tpnt = tpnt;
  160. } else {
  161. symbol_addr = (unsigned long)
  162. _dl_find_hash_mod(symname, scope, NULL, 0, &symbol_tpnt);
  163. /*
  164. * We want to allow undefined references to weak symbols - this might
  165. * have been intentional. We should not be linking local symbols
  166. * here, so all bases should be covered.
  167. */
  168. if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
  169. _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
  170. _dl_progname, strtab + symtab[symtab_index].st_name);
  171. _dl_exit (1);
  172. }
  173. }
  174. #if defined (__SUPPORT_LD_DEBUG__)
  175. if (_dl_debug_reloc && _dl_debug_detail)
  176. {
  177. if ((long)reloc_addr_packed & 3)
  178. old_val = reloc_addr_packed->v;
  179. else
  180. old_val = *reloc_addr;
  181. }
  182. else
  183. old_val = 0;
  184. #endif
  185. switch (reloc_type) {
  186. case R_FRV_NONE:
  187. break;
  188. case R_FRV_32:
  189. if ((long)reloc_addr_packed & 3)
  190. reloc_value = reloc_addr_packed->v += symbol_addr;
  191. else
  192. reloc_value = *reloc_addr += symbol_addr;
  193. break;
  194. case R_FRV_FUNCDESC_VALUE:
  195. funcval.entry_point = (void*)symbol_addr;
  196. /* The addend of FUNCDESC_VALUE
  197. relocations referencing global
  198. symbols must be ignored, because it
  199. may hold the address of a lazy PLT
  200. entry. */
  201. if (ELF32_ST_BIND
  202. (symtab[symtab_index].st_info)
  203. == STB_LOCAL)
  204. funcval.entry_point += *reloc_addr;
  205. reloc_value = (unsigned long)funcval.entry_point;
  206. if (symbol_addr)
  207. funcval.got_value
  208. = symbol_tpnt->loadaddr.got_value;
  209. else
  210. funcval.got_value = 0;
  211. __asm__ ("std%I0\t%1, %M0"
  212. : "=m" (*(struct funcdesc_value *)reloc_addr)
  213. : "e" (funcval));
  214. break;
  215. case R_FRV_FUNCDESC:
  216. if ((long)reloc_addr_packed & 3)
  217. reloc_value = reloc_addr_packed->v;
  218. else
  219. reloc_value = *reloc_addr;
  220. if (symbol_addr)
  221. reloc_value = (unsigned long)_dl_funcdesc_for
  222. ((char *)symbol_addr + reloc_value,
  223. symbol_tpnt->loadaddr.got_value);
  224. else
  225. reloc_value = 0;
  226. if ((long)reloc_addr_packed & 3)
  227. reloc_addr_packed->v = reloc_value;
  228. else
  229. *reloc_addr = reloc_value;
  230. break;
  231. default:
  232. return -1; /*call _dl_exit(1) */
  233. }
  234. #if defined (__SUPPORT_LD_DEBUG__)
  235. if (_dl_debug_reloc && _dl_debug_detail) {
  236. _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_value, reloc_addr);
  237. switch (reloc_type) {
  238. case R_FRV_FUNCDESC_VALUE:
  239. _dl_dprintf(_dl_debug_file, " got %x", ((struct funcdesc_value *)reloc_value)->got_value);
  240. break;
  241. case R_FRV_FUNCDESC:
  242. if (! reloc_value)
  243. break;
  244. _dl_dprintf(_dl_debug_file, " funcdesc (%x,%x)",
  245. ((struct funcdesc_value *)reloc_value)->entry_point,
  246. ((struct funcdesc_value *)reloc_value)->got_value);
  247. break;
  248. }
  249. }
  250. #endif
  251. return 0;
  252. }
  253. static int
  254. _dl_do_lazy_reloc (struct elf_resolve *tpnt,
  255. struct dyn_elf *scope __attribute_used__,
  256. ELF_RELOC *rpnt, Elf32_Sym *symtab __attribute_used__,
  257. char *strtab __attribute_used__)
  258. {
  259. int reloc_type;
  260. struct funcdesc_value volatile *reloc_addr;
  261. struct funcdesc_value funcval;
  262. #if defined (__SUPPORT_LD_DEBUG__)
  263. unsigned long old_val;
  264. #endif
  265. reloc_addr = (struct funcdesc_value *)(intptr_t)
  266. DL_RELOC_ADDR (rpnt->r_offset, tpnt->loadaddr);
  267. reloc_type = ELF32_R_TYPE(rpnt->r_info);
  268. #if defined (__SUPPORT_LD_DEBUG__)
  269. old_val = (unsigned long)reloc_addr->entry_point;
  270. #endif
  271. switch (reloc_type) {
  272. case R_FRV_NONE:
  273. break;
  274. case R_FRV_FUNCDESC_VALUE:
  275. funcval = *reloc_addr;
  276. funcval.entry_point =
  277. DL_RELOC_ADDR (funcval.entry_point,
  278. tpnt->loadaddr);
  279. funcval.got_value = tpnt->loadaddr.got_value;
  280. *reloc_addr = funcval;
  281. break;
  282. default:
  283. return -1; /*call _dl_exit(1) */
  284. }
  285. #if defined (__SUPPORT_LD_DEBUG__)
  286. if (_dl_debug_reloc && _dl_debug_detail)
  287. _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_addr->entry_point, reloc_addr);
  288. #endif
  289. return 0;
  290. }
  291. void
  292. _dl_parse_lazy_relocation_information
  293. (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
  294. {
  295. _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
  296. }
  297. int
  298. _dl_parse_relocation_information
  299. (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
  300. {
  301. return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
  302. }
  303. /* We don't have copy relocs. */
  304. int
  305. _dl_parse_copy_information
  306. (struct dyn_elf *rpnt __attribute_used__,
  307. unsigned long rel_addr __attribute_used__,
  308. unsigned long rel_size __attribute_used__)
  309. {
  310. return 0;
  311. }
  312. #ifndef LIBDL
  313. # include "../../libc/sysdeps/linux/frv/crtreloc.c"
  314. #endif