elfinterp.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /* ARM ELF shared library loader suppport
  2. *
  3. * Copyright (C) 2001-2004 Erik Andersen
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. The name of the above contributors may not be
  13. * used to endorse or promote products derived from this software
  14. * without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
  17. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
  20. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  22. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26. * SUCH DAMAGE.
  27. */
  28. /* Program to load an ELF binary on a linux system, and run it.
  29. References to symbols in sharable libraries can be resolved by either
  30. an ELF sharable library or a linux style of shared library. */
  31. #include "ldso.h"
  32. extern int _dl_linux_resolve(void);
  33. unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
  34. {
  35. ELF_RELOC *this_reloc;
  36. char *strtab;
  37. char *symname;
  38. ElfW(Sym) *symtab;
  39. ELF_RELOC *rel_addr;
  40. int symtab_index;
  41. unsigned long new_addr;
  42. char **got_addr;
  43. unsigned long instr_addr;
  44. rel_addr = (ELF_RELOC *) tpnt->dynamic_info[DT_JMPREL];
  45. this_reloc = rel_addr + reloc_entry;
  46. symtab_index = ELF_R_SYM(this_reloc->r_info);
  47. symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
  48. strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
  49. symname = strtab + symtab[symtab_index].st_name;
  50. /* Address of jump instruction to fix up */
  51. instr_addr = ((unsigned long) this_reloc->r_offset +
  52. (unsigned long) tpnt->loadaddr);
  53. got_addr = (char **) instr_addr;
  54. /* Get the address of the GOT entry */
  55. new_addr = (unsigned long)_dl_find_hash(symname, &_dl_loaded_modules->symbol_scope,
  56. tpnt, ELF_RTYPE_CLASS_PLT, NULL);
  57. if (unlikely(!new_addr)) {
  58. _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
  59. _dl_progname, symname);
  60. _dl_exit(1);
  61. }
  62. #if defined (__SUPPORT_LD_DEBUG__)
  63. # if !defined __SUPPORT_LD_DEBUG_EARLY__
  64. if ((unsigned long) got_addr < 0x40000000)
  65. # endif
  66. {
  67. if (_dl_debug_bindings)
  68. {
  69. _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
  70. if (_dl_debug_detail) _dl_dprintf(_dl_debug_file,
  71. "\tpatch %x ==> %x @ %x", *got_addr, new_addr, got_addr);
  72. }
  73. }
  74. if (!_dl_debug_nofixups) {
  75. *got_addr = (char *)new_addr;
  76. }
  77. #else
  78. *got_addr = (char *)new_addr;
  79. #endif
  80. return new_addr;
  81. }
  82. static int
  83. _dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
  84. unsigned long rel_addr, unsigned long rel_size,
  85. int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
  86. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
  87. {
  88. int i;
  89. char *strtab;
  90. int goof = 0;
  91. ElfW(Sym) *symtab;
  92. ELF_RELOC *rpnt;
  93. int symtab_index;
  94. /* Now parse the relocation information */
  95. rpnt = (ELF_RELOC *) rel_addr;
  96. rel_size = rel_size / sizeof(ELF_RELOC);
  97. symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
  98. strtab = (char *) tpnt->dynamic_info[DT_STRTAB];
  99. for (i = 0; i < rel_size; i++, rpnt++) {
  100. int res;
  101. symtab_index = ELF_R_SYM(rpnt->r_info);
  102. debug_sym(symtab,strtab,symtab_index);
  103. debug_reloc(symtab,strtab,rpnt);
  104. res = reloc_fnc (tpnt, scope, rpnt, symtab, strtab);
  105. if (res==0) continue;
  106. _dl_dprintf(2, "\n%s: ",_dl_progname);
  107. if (symtab_index)
  108. _dl_dprintf(2, "symbol '%s': ", strtab + symtab[symtab_index].st_name);
  109. if (unlikely(res <0))
  110. {
  111. int reloc_type = ELF_R_TYPE(rpnt->r_info);
  112. _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type);
  113. _dl_exit(-res);
  114. }
  115. if (unlikely(res >0))
  116. {
  117. _dl_dprintf(2, "can't resolve symbol\n");
  118. goof += res;
  119. }
  120. }
  121. return goof;
  122. }
  123. #if 0
  124. static unsigned long
  125. fix_bad_pc24 (unsigned long *const reloc_addr, unsigned long value)
  126. {
  127. static void *fix_page;
  128. static unsigned int fix_offset;
  129. unsigned int *fix_address;
  130. if (! fix_page)
  131. {
  132. fix_page = _dl_mmap (NULL, PAGE_SIZE , PROT_READ | PROT_WRITE | PROT_EXEC,
  133. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  134. fix_offset = 0;
  135. }
  136. fix_address = (unsigned int *)(fix_page + fix_offset);
  137. fix_address[0] = 0xe51ff004; /* ldr pc, [pc, #-4] */
  138. fix_address[1] = value;
  139. fix_offset += 8;
  140. if (fix_offset >= PAGE_SIZE)
  141. fix_page = NULL;
  142. return (unsigned long)fix_address;
  143. }
  144. #endif
  145. static int
  146. _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope,
  147. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
  148. {
  149. int reloc_type;
  150. int symtab_index;
  151. char *symname;
  152. unsigned long *reloc_addr;
  153. unsigned long symbol_addr;
  154. struct symbol_ref sym_ref;
  155. struct elf_resolve *def_mod = 0;
  156. int goof = 0;
  157. reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
  158. reloc_type = ELF_R_TYPE(rpnt->r_info);
  159. symtab_index = ELF_R_SYM(rpnt->r_info);
  160. symbol_addr = 0;
  161. sym_ref.sym = &symtab[symtab_index];
  162. sym_ref.tpnt = NULL;
  163. symname = strtab + symtab[symtab_index].st_name;
  164. if (symtab_index) {
  165. symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt,
  166. elf_machine_type_class(reloc_type), &sym_ref);
  167. /*
  168. * We want to allow undefined references to weak symbols - this might
  169. * have been intentional. We should not be linking local symbols
  170. * here, so all bases should be covered.
  171. */
  172. if (!symbol_addr && (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS)
  173. && (ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
  174. /* This may be non-fatal if called from dlopen. */
  175. return 1;
  176. }
  177. if (_dl_trace_prelink) {
  178. _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
  179. &sym_ref, elf_machine_type_class(reloc_type));
  180. }
  181. def_mod = sym_ref.tpnt;
  182. } else {
  183. /*
  184. * Relocs against STN_UNDEF are usually treated as using a
  185. * symbol value of zero, and using the module containing the
  186. * reloc itself.
  187. */
  188. symbol_addr = symtab[symtab_index].st_value;
  189. def_mod = tpnt;
  190. }
  191. #if defined (__SUPPORT_LD_DEBUG__)
  192. {
  193. unsigned long old_val = *reloc_addr;
  194. #endif
  195. switch (reloc_type) {
  196. case R_ARM_NONE:
  197. break;
  198. case R_ARM_ABS32:
  199. *reloc_addr += symbol_addr;
  200. break;
  201. case R_ARM_PC24:
  202. #if 0
  203. {
  204. unsigned long addend;
  205. long newvalue, topbits;
  206. addend = *reloc_addr & 0x00ffffff;
  207. if (addend & 0x00800000) addend |= 0xff000000;
  208. newvalue = symbol_addr - (unsigned long)reloc_addr + (addend << 2);
  209. topbits = newvalue & 0xfe000000;
  210. if (topbits != 0xfe000000 && topbits != 0x00000000)
  211. {
  212. newvalue = fix_bad_pc24(reloc_addr, symbol_addr)
  213. - (unsigned long)reloc_addr + (addend << 2);
  214. topbits = newvalue & 0xfe000000;
  215. if (unlikely(topbits != 0xfe000000 && topbits != 0x00000000))
  216. {
  217. _dl_dprintf(2,"symbol '%s': R_ARM_PC24 relocation out of range.",
  218. symtab[symtab_index].st_name);
  219. _dl_exit(1);
  220. }
  221. }
  222. newvalue >>= 2;
  223. symbol_addr = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
  224. *reloc_addr = symbol_addr;
  225. break;
  226. }
  227. #else
  228. _dl_dprintf(2,"R_ARM_PC24: Compile shared libraries with -fPIC!\n");
  229. _dl_exit(1);
  230. #endif
  231. case R_ARM_GLOB_DAT:
  232. case R_ARM_JUMP_SLOT:
  233. *reloc_addr = symbol_addr;
  234. break;
  235. case R_ARM_RELATIVE:
  236. *reloc_addr += (unsigned long) tpnt->loadaddr;
  237. break;
  238. case R_ARM_COPY:
  239. _dl_memcpy((void *) reloc_addr,
  240. (void *) symbol_addr, symtab[symtab_index].st_size);
  241. break;
  242. #if defined USE_TLS && USE_TLS
  243. case R_ARM_TLS_DTPMOD32:
  244. *reloc_addr = def_mod->l_tls_modid;
  245. break;
  246. case R_ARM_TLS_DTPOFF32:
  247. *reloc_addr += symbol_addr;
  248. break;
  249. case R_ARM_TLS_TPOFF32:
  250. CHECK_STATIC_TLS ((struct link_map *) def_mod);
  251. *reloc_addr += (symbol_addr + def_mod->l_tls_offset);
  252. break;
  253. #endif
  254. default:
  255. return -1; /*call _dl_exit(1) */
  256. }
  257. #if defined (__SUPPORT_LD_DEBUG__)
  258. if (_dl_debug_reloc && _dl_debug_detail)
  259. _dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
  260. }
  261. #endif
  262. return goof;
  263. }
  264. static int
  265. _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
  266. ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
  267. {
  268. int reloc_type;
  269. unsigned long *reloc_addr;
  270. reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
  271. reloc_type = ELF_R_TYPE(rpnt->r_info);
  272. #if defined (__SUPPORT_LD_DEBUG__)
  273. {
  274. unsigned long old_val = *reloc_addr;
  275. #endif
  276. switch (reloc_type) {
  277. case R_ARM_NONE:
  278. break;
  279. case R_ARM_JUMP_SLOT:
  280. *reloc_addr += (unsigned long) tpnt->loadaddr;
  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, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
  288. }
  289. #endif
  290. return 0;
  291. }
  292. void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
  293. unsigned long rel_addr, unsigned long rel_size)
  294. {
  295. (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
  296. }
  297. int _dl_parse_relocation_information(struct dyn_elf *rpnt,
  298. struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size)
  299. {
  300. return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
  301. }