elfinterp.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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. 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, write to
  20. the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
  21. USA. */
  22. #include <sys/cdefs.h> /* __attribute_used__ */
  23. #if defined (__SUPPORT_LD_DEBUG__)
  24. static const char *_dl_reltypes_tab[] =
  25. {
  26. [0] "R_FRV_NONE", "R_FRV_32",
  27. [2] "R_FRV_LABEL16", "R_FRV_LABEL24",
  28. [4] "R_FRV_LO16", "R_FRV_HI16",
  29. [6] "R_FRV_GPREL12", "R_FRV_GPRELU12",
  30. [8] "R_FRV_GPREL32", "R_FRV_GPRELHI", "R_FRV_GPRELLO",
  31. [11] "R_FRV_GOT12", "R_FRV_GOTHI", "R_FRV_GOTLO",
  32. [14] "R_FRV_FUNCDESC",
  33. [15] "R_FRV_FUNCDESC_GOT12", "R_FRV_FUNCDESC_GOTHI", "R_FRV_FUNCDESC_GOTLO",
  34. [18] "R_FRV_FUNCDESC_VALUE", "R_FRV_FUNCDESC_GOTOFF12",
  35. [20] "R_FRV_FUNCDESC_GOTOFFHI", "R_FRV_FUNCDESC_GOTOFFLO",
  36. [22] "R_FRV_GOTOFF12", "R_FRV_GOTOFFHI", "R_FRV_GOTOFFLO",
  37. #if 0
  38. [200] "R_FRV_GNU_VTINHERIT", "R_FRV_GNU_VTENTRY"
  39. #endif
  40. };
  41. static const char *
  42. _dl_reltypes(int type)
  43. {
  44. static char buf[22];
  45. const char *str;
  46. if (type >= (int)(sizeof (_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0])) ||
  47. NULL == (str = _dl_reltypes_tab[type]))
  48. {
  49. str =_dl_simple_ltoa( buf, (unsigned long)(type));
  50. }
  51. return str;
  52. }
  53. static
  54. void debug_sym(Elf32_Sym *symtab,char *strtab,int symtab_index)
  55. {
  56. if(_dl_debug_symbols)
  57. {
  58. if(symtab_index){
  59. _dl_dprintf(_dl_debug_file, "\n%s\n\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
  60. strtab + symtab[symtab_index].st_name,
  61. symtab[symtab_index].st_value,
  62. symtab[symtab_index].st_size,
  63. symtab[symtab_index].st_info,
  64. symtab[symtab_index].st_other,
  65. symtab[symtab_index].st_shndx);
  66. }
  67. }
  68. }
  69. static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
  70. {
  71. if(_dl_debug_reloc)
  72. {
  73. int symtab_index;
  74. const char *sym;
  75. symtab_index = ELF32_R_SYM(rpnt->r_info);
  76. sym = symtab_index ? strtab + symtab[symtab_index].st_name : "sym=0x0";
  77. if(_dl_debug_symbols)
  78. _dl_dprintf(_dl_debug_file, "\n\t");
  79. else
  80. _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
  81. #ifdef ELF_USES_RELOCA
  82. _dl_dprintf(_dl_debug_file, "%s\toffset=%x\taddend=%x",
  83. _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
  84. rpnt->r_offset,
  85. rpnt->r_addend);
  86. #else
  87. _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
  88. _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
  89. rpnt->r_offset);
  90. #endif
  91. }
  92. }
  93. #endif
  94. /* Program to load an ELF binary on a linux system, and run it.
  95. References to symbols in sharable libraries can be resolved by either
  96. an ELF sharable library or a linux style of shared library. */
  97. /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
  98. I ever taken any courses on internals. This program was developed using
  99. information available through the book "UNIX SYSTEM V RELEASE 4,
  100. Programmers guide: Ansi C and Programming Support Tools", which did
  101. a more than adequate job of explaining everything required to get this
  102. working. */
  103. struct funcdesc_value volatile *__attribute__((__visibility__("hidden")))
  104. _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry)
  105. {
  106. int reloc_type;
  107. ELF_RELOC *this_reloc;
  108. char *strtab;
  109. Elf32_Sym *symtab;
  110. int symtab_index;
  111. char *rel_addr;
  112. struct elf_resolve *new_tpnt;
  113. char *new_addr;
  114. struct funcdesc_value funcval;
  115. struct funcdesc_value volatile *got_entry;
  116. char *symname;
  117. rel_addr = DL_RELOC_ADDR (tpnt->dynamic_info[DT_JMPREL],
  118. tpnt->loadaddr);
  119. this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
  120. reloc_type = ELF32_R_TYPE(this_reloc->r_info);
  121. symtab_index = ELF32_R_SYM(this_reloc->r_info);
  122. symtab = (Elf32_Sym *)(intptr_t)
  123. DL_RELOC_ADDR (tpnt->dynamic_info[DT_SYMTAB],
  124. tpnt->loadaddr);
  125. strtab = DL_RELOC_ADDR (tpnt->dynamic_info[DT_STRTAB], tpnt->loadaddr);
  126. symname= strtab + symtab[symtab_index].st_name;
  127. if (reloc_type != R_FRV_FUNCDESC_VALUE) {
  128. _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
  129. _dl_progname);
  130. _dl_exit(1);
  131. }
  132. /* Address of GOT entry fix up */
  133. got_entry = (struct funcdesc_value *)
  134. DL_RELOC_ADDR (this_reloc->r_offset, tpnt->loadaddr);
  135. /* Get the address to be used to fill in the GOT entry. */
  136. new_addr = _dl_find_hash_mod(symname, tpnt->symbol_scope, NULL, 0,
  137. &new_tpnt);
  138. if (!new_addr) {
  139. new_addr = _dl_find_hash_mod(symname, NULL, NULL, 0,
  140. &new_tpnt);
  141. if (!new_addr) {
  142. _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
  143. _dl_progname, symname);
  144. _dl_exit(1);
  145. }
  146. }
  147. funcval.entry_point = new_addr;
  148. funcval.got_value = new_tpnt->loadaddr.got_value;
  149. #if defined (__SUPPORT_LD_DEBUG__)
  150. if (_dl_debug_bindings)
  151. {
  152. _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
  153. if(_dl_debug_detail)
  154. _dl_dprintf(_dl_debug_file,
  155. "\n\tpatched (%x,%x) ==> (%x,%x) @ %x\n",
  156. got_entry->entry_point, got_entry->got_value,
  157. funcval.entry_point, funcval.got_value,
  158. got_entry);
  159. }
  160. if (!_dl_debug_nofixups) {
  161. *got_entry = funcval;
  162. }
  163. #else
  164. *got_entry = funcval;
  165. #endif
  166. return got_entry;
  167. }
  168. static int
  169. _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
  170. unsigned long rel_addr, unsigned long rel_size,
  171. int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
  172. ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
  173. {
  174. unsigned int i;
  175. char *strtab;
  176. Elf32_Sym *symtab;
  177. ELF_RELOC *rpnt;
  178. int symtab_index;
  179. /* Now parse the relocation information */
  180. rpnt = (ELF_RELOC *)(intptr_t) DL_RELOC_ADDR (rel_addr, tpnt->loadaddr);
  181. rel_size = rel_size / sizeof(ELF_RELOC);
  182. symtab = (Elf32_Sym *)(intptr_t)
  183. DL_RELOC_ADDR (tpnt->dynamic_info[DT_SYMTAB], tpnt->loadaddr);
  184. strtab = DL_RELOC_ADDR (tpnt->dynamic_info[DT_STRTAB], tpnt->loadaddr);
  185. for (i = 0; i < rel_size; i++, rpnt++) {
  186. int res;
  187. symtab_index = ELF32_R_SYM(rpnt->r_info);
  188. #if defined (__SUPPORT_LD_DEBUG__)
  189. debug_sym(symtab,strtab,symtab_index);
  190. debug_reloc(symtab,strtab,rpnt);
  191. #endif
  192. res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
  193. if (res==0) continue;
  194. _dl_dprintf(2, "\n%s: ",_dl_progname);
  195. if (symtab_index)
  196. _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
  197. if (res <0)
  198. {
  199. int reloc_type = ELF32_R_TYPE(rpnt->r_info);
  200. #if defined (__SUPPORT_LD_DEBUG__)
  201. _dl_dprintf(2, "can't handle reloc type %s\n ", _dl_reltypes(reloc_type));
  202. #else
  203. _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
  204. #endif
  205. _dl_exit(-res);
  206. }
  207. else if (res >0)
  208. {
  209. _dl_dprintf(2, "can't resolve symbol\n");
  210. return res;
  211. }
  212. }
  213. return 0;
  214. }
  215. static int
  216. _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
  217. ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
  218. {
  219. int reloc_type;
  220. int symtab_index;
  221. char *symname;
  222. unsigned long reloc_value = 0, *reloc_addr;
  223. struct { unsigned long v; } __attribute__((__packed__))
  224. *reloc_addr_packed;
  225. unsigned long symbol_addr;
  226. struct elf_resolve *symbol_tpnt;
  227. struct funcdesc_value funcval;
  228. #if defined (__SUPPORT_LD_DEBUG__)
  229. unsigned long old_val;
  230. #endif
  231. reloc_addr = (unsigned long *)(intptr_t)
  232. DL_RELOC_ADDR (rpnt->r_offset, tpnt->loadaddr);
  233. asm ("" : "=r" (reloc_addr_packed) : "0" (reloc_addr));
  234. reloc_type = ELF32_R_TYPE(rpnt->r_info);
  235. symtab_index = ELF32_R_SYM(rpnt->r_info);
  236. symbol_addr = 0;
  237. symname = strtab + symtab[symtab_index].st_name;
  238. if (ELF32_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
  239. symbol_addr = (unsigned long)
  240. DL_RELOC_ADDR (symtab[symtab_index].st_value,
  241. tpnt->loadaddr);
  242. symbol_tpnt = tpnt;
  243. } else {
  244. symbol_addr = (unsigned long)
  245. _dl_find_hash_mod(symname, scope, NULL, 0, &symbol_tpnt);
  246. /*
  247. * We want to allow undefined references to weak symbols - this might
  248. * have been intentional. We should not be linking local symbols
  249. * here, so all bases should be covered.
  250. */
  251. if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) {
  252. _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
  253. _dl_progname, strtab + symtab[symtab_index].st_name);
  254. _dl_exit (1);
  255. }
  256. }
  257. #if defined (__SUPPORT_LD_DEBUG__)
  258. if (_dl_debug_reloc && _dl_debug_detail)
  259. {
  260. if ((long)reloc_addr_packed & 3)
  261. old_val = reloc_addr_packed->v;
  262. else
  263. old_val = *reloc_addr;
  264. }
  265. else
  266. old_val = 0;
  267. #endif
  268. switch (reloc_type) {
  269. case R_FRV_NONE:
  270. break;
  271. case R_FRV_32:
  272. if ((long)reloc_addr_packed & 3)
  273. reloc_value = reloc_addr_packed->v += symbol_addr;
  274. else
  275. reloc_value = *reloc_addr += symbol_addr;
  276. break;
  277. case R_FRV_FUNCDESC_VALUE:
  278. funcval.entry_point = (void*)symbol_addr;
  279. /* The addend of FUNCDESC_VALUE
  280. relocations referencing global
  281. symbols must be ignored, because it
  282. may hold the address of a lazy PLT
  283. entry. */
  284. if (ELF32_ST_BIND
  285. (symtab[symtab_index].st_info)
  286. == STB_LOCAL)
  287. funcval.entry_point += *reloc_addr;
  288. reloc_value = (unsigned long)funcval.entry_point;
  289. if (symbol_addr)
  290. funcval.got_value
  291. = symbol_tpnt->loadaddr.got_value;
  292. else
  293. funcval.got_value = 0;
  294. asm ("std%I0\t%1, %M0"
  295. : "=m" (*(struct funcdesc_value *)reloc_addr)
  296. : "e" (funcval));
  297. break;
  298. case R_FRV_FUNCDESC:
  299. if ((long)reloc_addr_packed & 3)
  300. reloc_value = reloc_addr_packed->v;
  301. else
  302. reloc_value = *reloc_addr;
  303. if (symbol_addr)
  304. reloc_value = (unsigned long)_dl_funcdesc_for
  305. ((char *)symbol_addr + reloc_value,
  306. symbol_tpnt->loadaddr.got_value);
  307. else
  308. reloc_value = 0;
  309. if ((long)reloc_addr_packed & 3)
  310. reloc_addr_packed->v = reloc_value;
  311. else
  312. *reloc_addr = reloc_value;
  313. break;
  314. default:
  315. return -1; /*call _dl_exit(1) */
  316. }
  317. #if defined (__SUPPORT_LD_DEBUG__)
  318. if(_dl_debug_reloc && _dl_debug_detail) {
  319. _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_value, reloc_addr);
  320. switch (reloc_type) {
  321. case R_FRV_FUNCDESC_VALUE:
  322. _dl_dprintf(_dl_debug_file, " got %x", ((struct funcdesc_value *)reloc_value)->got_value);
  323. break;
  324. case R_FRV_FUNCDESC:
  325. if (! reloc_value)
  326. break;
  327. _dl_dprintf(_dl_debug_file, " funcdesc (%x,%x)",
  328. ((struct funcdesc_value *)reloc_value)->entry_point,
  329. ((struct funcdesc_value *)reloc_value)->got_value);
  330. break;
  331. }
  332. }
  333. #endif
  334. return 0;
  335. }
  336. static int
  337. _dl_do_lazy_reloc (struct elf_resolve *tpnt,
  338. struct dyn_elf *scope __attribute_used__,
  339. ELF_RELOC *rpnt, Elf32_Sym *symtab __attribute_used__,
  340. char *strtab __attribute_used__)
  341. {
  342. int reloc_type;
  343. struct funcdesc_value volatile *reloc_addr;
  344. struct funcdesc_value funcval;
  345. #if defined (__SUPPORT_LD_DEBUG__)
  346. unsigned long old_val;
  347. #endif
  348. reloc_addr = (struct funcdesc_value *)(intptr_t)
  349. DL_RELOC_ADDR (rpnt->r_offset, tpnt->loadaddr);
  350. reloc_type = ELF32_R_TYPE(rpnt->r_info);
  351. #if defined (__SUPPORT_LD_DEBUG__)
  352. old_val = (unsigned long)reloc_addr->entry_point;
  353. #endif
  354. switch (reloc_type) {
  355. case R_FRV_NONE:
  356. break;
  357. case R_FRV_FUNCDESC_VALUE:
  358. funcval = *reloc_addr;
  359. funcval.entry_point =
  360. DL_RELOC_ADDR (funcval.entry_point,
  361. tpnt->loadaddr);
  362. funcval.got_value = tpnt->loadaddr.got_value;
  363. *reloc_addr = funcval;
  364. break;
  365. default:
  366. return -1; /*call _dl_exit(1) */
  367. }
  368. #if defined (__SUPPORT_LD_DEBUG__)
  369. if(_dl_debug_reloc && _dl_debug_detail)
  370. _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, reloc_addr->entry_point, reloc_addr);
  371. #endif
  372. return 0;
  373. }
  374. void
  375. _dl_parse_lazy_relocation_information
  376. (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
  377. {
  378. _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
  379. }
  380. int
  381. _dl_parse_relocation_information
  382. (struct dyn_elf *rpnt, unsigned long rel_addr, unsigned long rel_size)
  383. {
  384. return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
  385. }
  386. /* We don't have copy relocs. */
  387. int
  388. _dl_parse_copy_information
  389. (struct dyn_elf *rpnt __attribute_used__,
  390. unsigned long rel_addr __attribute_used__,
  391. unsigned long rel_size __attribute_used__)
  392. {
  393. return 0;
  394. }
  395. #ifndef LIBDL
  396. # include "../../libc/sysdeps/linux/frv/crtreloc.c"
  397. #endif