elfinterp.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /* vi: set sw=8 ts=8: */
  2. /*
  3. * ldso/ldso/sh64/elfinterp.c
  4. *
  5. * SuperH (sh64) ELF shared library loader suppport
  6. *
  7. * Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org>
  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. #ifdef __SUPPORT_LD_DEBUG__
  33. static const char *_dl_reltypes_tab[] = {
  34. /* SHcompact relocs */
  35. [0] = "R_SH_NONE", "R_SH_DIR32",
  36. "R_SH_REL32", "R_SH_DIR8WPN",
  37. [4] = "R_SH_IND12W", "R_SH_DIR8WPL",
  38. "R_SH_DIR8WPZ", "R_SH_DIR8BP",
  39. [8] = "R_SH_DIR8W", "R_SH_DIR8L",
  40. [25] = "R_SH_SWITCH16", "R_SH_SWITCH32",
  41. "R_SH_USES", "R_SH_COUNT",
  42. [29] = "R_SH_ALIGN", "R_SH_CODE",
  43. "R_SH_DATA", "R_SH_LABEL",
  44. [33] = "R_SH_SWITCH8", "R_SH_GNU_VTINHERIT",
  45. "R_SH_GNU_VTENTRY",
  46. [160] = "R_SH_GOT32", "R_SH_PLT32",
  47. "R_SH_COPY", "R_SH_GLOB_DAT",
  48. [164] = "R_SH_JMP_SLOT", "R_SH_RELATIVE",
  49. "R_SH_GOTOFF", "R_SH_GOTPC",
  50. /* SHmedia relocs */
  51. [45] = "R_SH_DIR5U", "R_SH_DIR6U",
  52. "R_SH_DIR6S", "R_SH_DIR10S",
  53. [49] = "R_SH_DIR10SW", "R_SH_DIR10SL",
  54. "R_SH_DIR10SQ",
  55. [169] = "R_SH_GOT_LOW16", "R_SH_GOT_MEDLOW16",
  56. "R_SH_GOT_MEDHI16", "R_SH_GOT_HI16",
  57. [173] = "R_SH_GOTPLT_LOW16", "R_SH_GOTPLT_MEDLOW16",
  58. "R_SH_GOTPLT_MEDHI16", "R_SH_GOTPLT_HI16",
  59. [177] = "R_SH_PLT_LOW16", "R_SH_PLT_MEDLOW16",
  60. "R_SH_PLT_MEDHI16", "R_SH_PLT_HI16",
  61. [181] = "R_SH_GOTOFF_LOW16", "R_SH_GOTOFF_MEDLOW16",
  62. "R_SH_GOTOFF_MEDHI16", "R_SH_GOTOFF_HI16",
  63. [185] = "R_SH_GOTPC_LOW16", "R_SH_GOTPC_MEDLOW16",
  64. "R_SH_GOTPC_MEDHI16", "R_SH_GOTPC_HI16",
  65. [189] = "R_SH_GOT10BY4", "R_SH_GOTPLT10BY4",
  66. "R_SH_GOT10BY8", "R_SH_GOTPLT10BY8",
  67. [193] = "R_SH_COPY64", "R_SH_GLOB_DAT64",
  68. "R_SH_JMP_SLOT64", "R_SH_RELATIVE64",
  69. [197] = "R_SH_RELATIVE_LOW16", "R_SH_RELATIVE_MEDLOW16",
  70. "R_SH_RELATIVE_MEDHI16","R_SH_RELATIVE_HI16",
  71. [242] = "R_SH_SHMEDIA_CODE", "R_SH_PT_16",
  72. "R_SH_IMMS16", "R_SH_IMMU16",
  73. [246] = "R_SH_IMM_LOW16", "R_SH_IMM_LOW16_PCREL",
  74. "R_SH_IMM_MEDLOW16", "R_SH_IMM_MEDLOW16_PCREL",
  75. [250] = "R_SH_IMM_MEDHI16", "R_SH_IMM_MEDHI16_PCREL",
  76. "R_SH_IMM_HI16", "R_SH_IMM_HI16_PCREL",
  77. [254] = "R_SH_64", "R_SH_64_PCREL",
  78. };
  79. static const char *_dl_reltypes(int type)
  80. {
  81. static char buf[22];
  82. const char *str;
  83. int tabsize;
  84. tabsize = sizeof(_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0]);
  85. str = _dl_reltypes_tab[type];
  86. if (type >= tabsize || str == NULL)
  87. str =_dl_simple_ltoa(buf, (unsigned long)(type));
  88. return str;
  89. }
  90. static void debug_sym(Elf32_Sym *symtab, char *strtab, int symtab_index)
  91. {
  92. if (!_dl_debug_symbols || !symtab_index)
  93. return;
  94. _dl_dprintf(_dl_debug_file,
  95. "\n%s\tvalue=%x\tsize=%x\tinfo=%x\tother=%x\tshndx=%x",
  96. strtab + symtab[symtab_index].st_name,
  97. symtab[symtab_index].st_value,
  98. symtab[symtab_index].st_size,
  99. symtab[symtab_index].st_info,
  100. symtab[symtab_index].st_other,
  101. symtab[symtab_index].st_shndx);
  102. }
  103. static void debug_reloc(Elf32_Sym *symtab, char *strtab, ELF_RELOC *rpnt)
  104. {
  105. if (!_dl_debug_reloc)
  106. return;
  107. if (_dl_debug_symbols) {
  108. _dl_dprintf(_dl_debug_file, "\n\t");
  109. } else {
  110. int symtab_index;
  111. const char *sym;
  112. symtab_index = ELF32_R_SYM(rpnt->r_info);
  113. sym = symtab_index ? strtab + symtab[symtab_index].st_name
  114. : "sym=0x0";
  115. _dl_dprintf(_dl_debug_file, "\n%s\n\t", sym);
  116. }
  117. _dl_dprintf(_dl_debug_file, "%s\toffset=%x",
  118. _dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
  119. rpnt->r_offset);
  120. #ifdef ELF_USES_RELOCA
  121. _dl_dprintf(_dl_debug_file, "\taddend=%x", rpnt->r_addend);
  122. #endif
  123. _dl_dprintf(_dl_debug_file, "\n");
  124. }
  125. #endif /* __SUPPORT_LD_DEBUG__ */
  126. /* Program to load an ELF binary on a linux system, and run it.
  127. References to symbols in sharable libraries can be resolved by either
  128. an ELF sharable library or a linux style of shared library. */
  129. /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
  130. I ever taken any courses on internals. This program was developed using
  131. information available through the book "UNIX SYSTEM V RELEASE 4,
  132. Programmers guide: Ansi C and Programming Support Tools", which did
  133. a more than adequate job of explaining everything required to get this
  134. working. */
  135. extern int _dl_linux_resolve(void);
  136. unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
  137. {
  138. int reloc_type;
  139. ELF_RELOC *this_reloc;
  140. char *strtab;
  141. Elf32_Sym *symtab;
  142. int symtab_index;
  143. char *rel_addr;
  144. char *new_addr;
  145. char **got_addr;
  146. unsigned long instr_addr;
  147. char *symname;
  148. rel_addr = (char *)(tpnt->dynamic_info[DT_JMPREL] + tpnt->loadaddr);
  149. this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
  150. reloc_type = ELF32_R_TYPE(this_reloc->r_info);
  151. symtab_index = ELF32_R_SYM(this_reloc->r_info);
  152. symtab = (Elf32_Sym *)(intptr_t)
  153. (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
  154. strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
  155. symname = strtab + symtab[symtab_index].st_name;
  156. if (reloc_type != R_SH_JMP_SLOT) {
  157. _dl_dprintf(2, "%s: Incorrect relocation type in jump reloc\n",
  158. _dl_progname);
  159. _dl_exit(1);
  160. }
  161. /* Address of jump instruction to fix up */
  162. instr_addr = ((unsigned long)this_reloc->r_offset +
  163. (unsigned long)tpnt->loadaddr);
  164. got_addr = (char **)instr_addr;
  165. /* Get the address of the GOT entry */
  166. new_addr = _dl_find_hash(symname, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
  167. if (!new_addr) {
  168. _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
  169. _dl_progname, symname);
  170. _dl_exit(1);
  171. }
  172. #ifdef __SUPPORT_LD_DEBUG__
  173. if ((unsigned long)got_addr < 0x20000000) {
  174. if (_dl_debug_bindings) {
  175. _dl_dprintf(_dl_debug_file, "\nresolve function: %s",
  176. symname);
  177. if (_dl_debug_detail)
  178. _dl_dprintf(_dl_debug_file,
  179. "\n\tpatched %x ==> %x @ %x\n",
  180. *got_addr, new_addr, got_addr);
  181. }
  182. }
  183. if (!_dl_debug_nofixups)
  184. *got_addr = new_addr;
  185. #else
  186. *got_addr = new_addr;
  187. #endif
  188. return (unsigned long)new_addr;
  189. }
  190. static int _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
  191. unsigned long rel_addr, unsigned long rel_size,
  192. int (*reloc_fnc)(struct elf_resolve *tpnt,
  193. struct dyn_elf *scope,
  194. ELF_RELOC *rpnt, Elf32_Sym *symtab,
  195. char *strtab))
  196. {
  197. unsigned int i;
  198. char *strtab;
  199. Elf32_Sym *symtab;
  200. ELF_RELOC *rpnt;
  201. int symtab_index;
  202. /* Now parse the relocation information */
  203. rpnt = (ELF_RELOC *)(intptr_t)(rel_addr + tpnt->loadaddr);
  204. rel_size = rel_size / sizeof(ELF_RELOC);
  205. symtab = (Elf32_Sym *)(intptr_t)
  206. (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
  207. strtab = (char *)(tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
  208. for (i = 0; i < rel_size; i++, rpnt++) {
  209. int res;
  210. symtab_index = ELF32_R_SYM(rpnt->r_info);
  211. /* When the dynamic linker bootstrapped itself, it resolved
  212. some symbols. Make sure we do not do them again */
  213. if (!symtab_index && tpnt->libtype == program_interpreter)
  214. continue;
  215. if (symtab_index && tpnt->libtype == program_interpreter &&
  216. _dl_symbol(strtab + symtab[symtab_index].st_name))
  217. continue;
  218. #ifdef __SUPPORT_LD_DEBUG__
  219. debug_sym(symtab,strtab,symtab_index);
  220. debug_reloc(symtab,strtab,rpnt);
  221. #endif
  222. res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
  223. if (res == 0)
  224. continue;
  225. _dl_dprintf(2, "\n%s: ",_dl_progname);
  226. if (symtab_index)
  227. _dl_dprintf(2, "symbol '%s': ",
  228. strtab + symtab[symtab_index].st_name);
  229. if (res < 0) {
  230. int reloc_type = ELF32_R_TYPE(rpnt->r_info);
  231. _dl_dprintf(2, "can't handle reloc type "
  232. #ifdef __SUPPORT_LD_DEBUG__
  233. "%s\n", _dl_reltypes(reloc_type)
  234. #else
  235. "%x\n", reloc_type
  236. #endif
  237. );
  238. _dl_exit(-res);
  239. } else if (res > 0) {
  240. _dl_dprintf(2, "can't resolve symbol\n");
  241. return res;
  242. }
  243. }
  244. return 0;
  245. }
  246. static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
  247. ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
  248. {
  249. int reloc_type;
  250. int symtab_index, lsb;
  251. char *symname;
  252. unsigned long *reloc_addr;
  253. unsigned long symbol_addr;
  254. #ifdef __SUPPORT_LD_DEBUG__
  255. unsigned long old_val;
  256. #endif
  257. reloc_type = ELF32_R_TYPE(rpnt->r_info);
  258. symtab_index = ELF32_R_SYM(rpnt->r_info);
  259. symbol_addr = 0;
  260. lsb = symtab[symtab_index].st_other & 4;
  261. symname = strtab + symtab[symtab_index].st_name;
  262. reloc_addr = (unsigned long *)(intptr_t)
  263. (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
  264. if (symtab_index) {
  265. int stb;
  266. symbol_addr = (unsigned long)_dl_find_hash(symname, scope,
  267. elf_machine_type_class(reloc_type));
  268. /*
  269. * We want to allow undefined references to weak symbols - this
  270. * might have been intentional. We should not be linking local
  271. * symbols here, so all bases should be covered.
  272. */
  273. stb = ELF32_ST_BIND(symtab[symtab_index].st_info);
  274. if (stb == STB_GLOBAL && !symbol_addr) {
  275. #ifdef __SUPPORT_LD_DEBUG__
  276. _dl_dprintf(2, "\tglobal symbol '%s' "
  277. "already defined in '%s'\n",
  278. symname, tpnt->libname);
  279. #endif
  280. return 0;
  281. }
  282. }
  283. #ifdef __SUPPORT_LD_DEBUG__
  284. old_val = *reloc_addr;
  285. #endif
  286. switch (reloc_type) {
  287. case R_SH_NONE:
  288. break;
  289. case R_SH_COPY:
  290. /* handled later on */
  291. break;
  292. case R_SH_DIR32:
  293. case R_SH_GLOB_DAT:
  294. case R_SH_JMP_SLOT:
  295. *reloc_addr = (symbol_addr + rpnt->r_addend) | lsb;
  296. break;
  297. case R_SH_REL32:
  298. *reloc_addr = symbol_addr + rpnt->r_addend -
  299. (unsigned long)reloc_addr;
  300. break;
  301. case R_SH_RELATIVE:
  302. *reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
  303. break;
  304. case R_SH_RELATIVE_LOW16:
  305. case R_SH_RELATIVE_MEDLOW16:
  306. {
  307. unsigned long word, value;
  308. word = (unsigned long)reloc_addr & ~0x3fffc00;
  309. value = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
  310. if (reloc_type == R_SH_RELATIVE_MEDLOW16)
  311. value >>= 16;
  312. word |= (value & 0xffff) << 10;
  313. *reloc_addr = word;
  314. break;
  315. }
  316. case R_SH_IMM_LOW16:
  317. case R_SH_IMM_MEDLOW16:
  318. {
  319. unsigned long word, value;
  320. word = (unsigned long)reloc_addr & ~0x3fffc00;
  321. value = (symbol_addr + rpnt->r_addend) | lsb;
  322. if (reloc_type == R_SH_IMM_MEDLOW16)
  323. value >>= 16;
  324. word |= (value & 0xffff) << 10;
  325. *reloc_addr = word;
  326. break;
  327. }
  328. case R_SH_IMM_LOW16_PCREL:
  329. case R_SH_IMM_MEDLOW16_PCREL:
  330. {
  331. unsigned long word, value;
  332. word = (unsigned long)reloc_addr & ~0x3fffc00;
  333. value = symbol_addr + rpnt->r_addend -
  334. (unsigned long)reloc_addr;
  335. if (reloc_type == R_SH_IMM_MEDLOW16_PCREL)
  336. value >>= 16;
  337. word |= (value & 0xffff) << 10;
  338. *reloc_addr = word;
  339. break;
  340. }
  341. default:
  342. return -1; /*call _dl_exit(1) */
  343. }
  344. #ifdef __SUPPORT_LD_DEBUG__
  345. if (_dl_debug_reloc && _dl_debug_detail)
  346. _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x",
  347. old_val, *reloc_addr, reloc_addr);
  348. #endif
  349. return 0;
  350. }
  351. static int _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
  352. ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
  353. {
  354. int reloc_type, symtab_index, lsb;
  355. unsigned long *reloc_addr;
  356. #ifdef __SUPPORT_LD_DEBUG__
  357. unsigned long old_val;
  358. #endif
  359. reloc_type = ELF32_R_TYPE(rpnt->r_info);
  360. symtab_index = ELF32_R_SYM(rpnt->r_info);
  361. lsb = symtab[symtab_index].st_other & 4;
  362. reloc_addr = (unsigned long *)(intptr_t)
  363. (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
  364. #ifdef __SUPPORT_LD_DEBUG__
  365. old_val = *reloc_addr;
  366. #endif
  367. switch (reloc_type) {
  368. case R_SH_NONE:
  369. break;
  370. case R_SH_JMP_SLOT:
  371. *reloc_addr += (unsigned long)tpnt->loadaddr | lsb;
  372. break;
  373. default:
  374. return -1; /*call _dl_exit(1) */
  375. }
  376. #ifdef __SUPPORT_LD_DEBUG__
  377. if (_dl_debug_reloc && _dl_debug_detail)
  378. _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x",
  379. old_val, *reloc_addr, reloc_addr);
  380. #endif
  381. return 0;
  382. }
  383. /* This is done as a separate step, because there are cases where
  384. information is first copied and later initialized. This results in
  385. the wrong information being copied. Someone at Sun was complaining about
  386. a bug in the handling of _COPY by SVr4, and this may in fact be what he
  387. was talking about. Sigh. */
  388. /* No, there are cases where the SVr4 linker fails to emit COPY relocs
  389. at all */
  390. static int _dl_do_copy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
  391. ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
  392. {
  393. int reloc_type;
  394. int symtab_index;
  395. unsigned long *reloc_addr;
  396. unsigned long symbol_addr;
  397. char *symname;
  398. int goof = 0;
  399. reloc_addr = (unsigned long *)(intptr_t)
  400. (tpnt->loadaddr + (unsigned long)rpnt->r_offset);
  401. reloc_type = ELF32_R_TYPE(rpnt->r_info);
  402. if (reloc_type != R_SH_COPY)
  403. return 0;
  404. symtab_index = ELF32_R_SYM(rpnt->r_info);
  405. symbol_addr = 0;
  406. symname = strtab + symtab[symtab_index].st_name;
  407. if (symtab_index) {
  408. symbol_addr = (unsigned long)
  409. _dl_find_hash(symname, scope, ELF_RTYPE_CLASS_COPY);
  410. if (!symbol_addr)
  411. goof++;
  412. }
  413. if (!goof) {
  414. #ifdef __SUPPORT_LD_DEBUG__
  415. if (_dl_debug_move)
  416. _dl_dprintf(_dl_debug_file,
  417. "\n%s move %x bytes from %x to %x",
  418. symname, symtab[symtab_index].st_size,
  419. symbol_addr, symtab[symtab_index].st_value);
  420. #endif
  421. _dl_memcpy((char *)symtab[symtab_index].st_value,
  422. (char *)symbol_addr, symtab[symtab_index].st_size);
  423. }
  424. return goof;
  425. }
  426. void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
  427. unsigned long rel_addr, unsigned long rel_size, int type)
  428. {
  429. (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
  430. }
  431. int _dl_parse_relocation_information(struct dyn_elf *rpnt,
  432. unsigned long rel_addr, unsigned long rel_size, int type)
  433. {
  434. return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
  435. }
  436. int _dl_parse_copy_information(struct dyn_elf *rpnt,
  437. unsigned long rel_addr, unsigned long rel_size, int type)
  438. {
  439. return _dl_parse(rpnt->dyn, rpnt->next, rel_addr, rel_size, _dl_do_copy_reloc);
  440. }