elfinterp.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /* vi: set sw=4 ts=4: */
  2. /* Run an ELF binary on a linux system.
  3. Copyright (C) 2002, Steven J. Hill (sjhill@realitydiluted.com)
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  15. /* Program to load an ELF binary on a linux system, and run it.
  16. References to symbols in sharable libraries can be resolved by either
  17. an ELF sharable library or a linux style of shared library. */
  18. /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
  19. I ever taken any courses on internals. This program was developed using
  20. information available through the book "UNIX SYSTEM V RELEASE 4,
  21. Programmers guide: Ansi C and Programming Support Tools", which did
  22. a more than adequate job of explaining everything required to get this
  23. working. */
  24. extern int _dl_linux_resolve(void);
  25. #define OFFSET_GP_GOT 0x7ff0
  26. unsigned long _dl_linux_resolver(unsigned long sym_index,
  27. unsigned long old_gpreg)
  28. {
  29. unsigned long *got = (unsigned long *) (old_gpreg - OFFSET_GP_GOT);
  30. struct elf_resolve *tpnt = (struct elf_resolve *) got[1];
  31. Elf32_Sym *sym;
  32. char *strtab;
  33. unsigned long local_gotno;
  34. unsigned long gotsym;
  35. unsigned long value;
  36. gotsym = tpnt->mips_gotsym;
  37. local_gotno = tpnt->mips_local_gotno;
  38. sym = ((Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr)) +
  39. sym_index;
  40. strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
  41. value = (unsigned long) _dl_find_hash(strtab + sym->st_name,
  42. tpnt->symbol_scope, tpnt, 1);
  43. *(got + local_gotno + sym_index - gotsym) = value;
  44. #ifdef DL_DEBUG
  45. _dl_dprintf(2, "---RESOLVER---\n");
  46. _dl_dprintf(2, "SYMTAB INDEX: %i\n", sym_index);
  47. _dl_dprintf(2, " GOTSYM: %i\n", gotsym);
  48. _dl_dprintf(2, " LOCAL GOTNO: %i\n", local_gotno);
  49. _dl_dprintf(2, " VALUE: %x\n", value);
  50. _dl_dprintf(2, " SYMBOL: %s\n\n", strtab + sym->st_name);
  51. #endif
  52. return value;
  53. }
  54. void _dl_parse_lazy_relocation_information(struct elf_resolve *tpnt,
  55. unsigned long rel_addr, unsigned long rel_size, int type)
  56. {
  57. /* Nothing to do */
  58. return;
  59. }
  60. int _dl_parse_copy_information(struct dyn_elf *xpnt, unsigned long rel_addr,
  61. unsigned long rel_size, int type)
  62. {
  63. /* Nothing to do */
  64. return 0;
  65. }
  66. int _dl_parse_relocation_information(struct elf_resolve *tpnt,
  67. unsigned long rel_addr, unsigned long rel_size, int type)
  68. {
  69. Elf32_Sym *symtab;
  70. Elf32_Rel *rpnt;
  71. char *strtab;
  72. unsigned long *got;
  73. unsigned long *reloc_addr;
  74. unsigned long symbol_addr;
  75. int i, reloc_type, symtab_index;
  76. /* Now parse the relocation information */
  77. rel_size = rel_size / sizeof(Elf32_Rel);
  78. rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadaddr);
  79. symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
  80. strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
  81. got = (unsigned long *) (tpnt->dynamic_info[DT_PLTGOT] + tpnt->loadaddr);
  82. for (i = 0; i < rel_size; i++, rpnt++) {
  83. reloc_addr = (unsigned long *) (tpnt->loadaddr +
  84. (unsigned long) rpnt->r_offset);
  85. reloc_type = ELF32_R_TYPE(rpnt->r_info);
  86. symtab_index = ELF32_R_SYM(rpnt->r_info);
  87. symbol_addr = 0;
  88. if (!symtab_index && tpnt->libtype == program_interpreter)
  89. continue;
  90. switch (reloc_type) {
  91. case R_MIPS_REL32:
  92. if (symtab_index) {
  93. if (symtab_index < tpnt->mips_gotsym)
  94. *reloc_addr +=
  95. symtab[symtab_index].st_value +
  96. (unsigned long) tpnt->loadaddr;
  97. else {
  98. *reloc_addr += got[symtab_index + tpnt->mips_local_gotno -
  99. tpnt->mips_gotsym];
  100. }
  101. }
  102. else {
  103. *reloc_addr += (unsigned long) tpnt->loadaddr;
  104. }
  105. break;
  106. case R_MIPS_NONE:
  107. break;
  108. default:
  109. _dl_dprintf(2, "%s: can't handle reloc type ", _dl_progname);
  110. if (symtab_index)
  111. _dl_dprintf(2, "'%s'\n", strtab + symtab[symtab_index].st_name);
  112. _dl_exit(1);
  113. };
  114. };
  115. return 0;
  116. }
  117. void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
  118. {
  119. Elf32_Sym *sym;
  120. char *strtab;
  121. unsigned long i;
  122. unsigned long *got_entry;
  123. for (; tpnt ; tpnt = tpnt->next) {
  124. /* We don't touch the dynamic linker */
  125. if (tpnt->libtype == program_interpreter)
  126. continue;
  127. /* Setup the loop variables */
  128. got_entry = (unsigned long *) (tpnt->loadaddr +
  129. tpnt->dynamic_info[DT_PLTGOT]) + tpnt->mips_local_gotno;
  130. sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] +
  131. (unsigned long) tpnt->loadaddr) + tpnt->mips_gotsym;
  132. strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] +
  133. (unsigned long) tpnt->loadaddr);
  134. i = tpnt->mips_symtabno - tpnt->mips_gotsym;
  135. /* Relocate the global GOT entries for the object */
  136. while(i--) {
  137. if (sym->st_shndx == SHN_UNDEF) {
  138. if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && sym->st_value)
  139. *got_entry = sym->st_value + (unsigned long) tpnt->loadaddr;
  140. else {
  141. *got_entry = (unsigned long) _dl_find_hash(strtab +
  142. sym->st_name, tpnt->symbol_scope, NULL, 1);
  143. }
  144. }
  145. else if (sym->st_shndx == SHN_COMMON) {
  146. *got_entry = (unsigned long) _dl_find_hash(strtab +
  147. sym->st_name, tpnt->symbol_scope, NULL, 1);
  148. }
  149. else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
  150. *got_entry != sym->st_value)
  151. *got_entry += (unsigned long) tpnt->loadaddr;
  152. else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) {
  153. if (sym->st_other == 0)
  154. *got_entry += (unsigned long) tpnt->loadaddr;
  155. }
  156. else {
  157. *got_entry = (unsigned long) _dl_find_hash(strtab +
  158. sym->st_name, tpnt->symbol_scope, NULL, 1);
  159. }
  160. #ifdef DL_DEBUG
  161. if (*got_entry == 0)
  162. _dl_dprintf(2,"ZERO: %s\n", strtab + sym->st_name);
  163. #endif
  164. got_entry++;
  165. sym++;
  166. }
  167. }
  168. }