dl-inlines.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /* Copyright (C) 2003, 2004 Red Hat, Inc.
  2. * Contributed by Alexandre Oliva <aoliva@redhat.com>
  3. * Copyright (C) 2006-2011 Analog Devices, Inc.
  4. *
  5. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  6. */
  7. #include <inline-hashtab.h>
  8. static __always_inline void htab_delete(struct funcdesc_ht *htab);
  9. /* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete load map. */
  10. static __always_inline void
  11. __dl_init_loadaddr_map(struct elf32_fdpic_loadaddr *loadaddr, Elf32_Addr dl_boot_got_pointer,
  12. struct elf32_fdpic_loadmap *map)
  13. {
  14. if (map->version != 0) {
  15. SEND_EARLY_STDERR("Invalid loadmap version number\n");
  16. _dl_exit(-1);
  17. }
  18. if (map->nsegs == 0) {
  19. SEND_EARLY_STDERR("Invalid segment count in loadmap\n");
  20. _dl_exit(-1);
  21. }
  22. loadaddr->got_value = (void *)dl_boot_got_pointer;
  23. loadaddr->map = map;
  24. }
  25. /*
  26. * Figure out how many LOAD segments there are in the given headers,
  27. * and allocate a block for the load map big enough for them.
  28. * got_value will be properly initialized later on, with INIT_GOT.
  29. */
  30. static __always_inline int
  31. __dl_init_loadaddr(struct elf32_fdpic_loadaddr *loadaddr, Elf32_Phdr *ppnt,
  32. int pcnt)
  33. {
  34. int count = 0, i;
  35. size_t size;
  36. for (i = 0; i < pcnt; i++)
  37. if (ppnt[i].p_type == PT_LOAD)
  38. count++;
  39. loadaddr->got_value = 0;
  40. size = sizeof(struct elf32_fdpic_loadmap) +
  41. (sizeof(struct elf32_fdpic_loadseg) * count);
  42. loadaddr->map = _dl_malloc(size);
  43. if (!loadaddr->map)
  44. _dl_exit(-1);
  45. loadaddr->map->version = 0;
  46. loadaddr->map->nsegs = 0;
  47. return count;
  48. }
  49. /* Incrementally initialize a load map. */
  50. static __always_inline void
  51. __dl_init_loadaddr_hdr(struct elf32_fdpic_loadaddr loadaddr, void *addr,
  52. Elf32_Phdr *phdr, int maxsegs)
  53. {
  54. struct elf32_fdpic_loadseg *segdata;
  55. if (loadaddr.map->nsegs == maxsegs)
  56. _dl_exit(-1);
  57. segdata = &loadaddr.map->segs[loadaddr.map->nsegs++];
  58. segdata->addr = (Elf32_Addr)addr;
  59. segdata->p_vaddr = phdr->p_vaddr;
  60. segdata->p_memsz = phdr->p_memsz;
  61. #if defined(__SUPPORT_LD_DEBUG__)
  62. if (_dl_debug)
  63. _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n",
  64. loadaddr.map->nsegs - 1,
  65. segdata->p_vaddr, segdata->addr, segdata->p_memsz);
  66. #endif
  67. }
  68. /* Replace an existing entry in the load map. */
  69. static __always_inline void
  70. __dl_update_loadaddr_hdr(struct elf32_fdpic_loadaddr loadaddr, void *addr,
  71. Elf32_Phdr *phdr)
  72. {
  73. struct elf32_fdpic_loadseg *segdata;
  74. void *oldaddr;
  75. int i;
  76. for (i = 0; i < loadaddr.map->nsegs; i++)
  77. if (loadaddr.map->segs[i].p_vaddr == phdr->p_vaddr &&
  78. loadaddr.map->segs[i].p_memsz == phdr->p_memsz)
  79. break;
  80. if (i == loadaddr.map->nsegs)
  81. _dl_exit(-1);
  82. segdata = loadaddr.map->segs + i;
  83. oldaddr = (void *)segdata->addr;
  84. _dl_munmap(oldaddr, segdata->p_memsz);
  85. segdata->addr = (Elf32_Addr)addr;
  86. #if defined (__SUPPORT_LD_DEBUG__)
  87. if (_dl_debug)
  88. _dl_dprintf(_dl_debug_file, "%i: changed mapping %x at %x (old %x), size %x\n",
  89. loadaddr.map->nsegs - 1,
  90. segdata->p_vaddr, segdata->addr, oldaddr, segdata->p_memsz);
  91. #endif
  92. }
  93. #ifndef __dl_loadaddr_unmap
  94. static __always_inline void
  95. __dl_loadaddr_unmap(struct elf32_fdpic_loadaddr loadaddr,
  96. struct funcdesc_ht *funcdesc_ht)
  97. {
  98. int i;
  99. for (i = 0; i < loadaddr.map->nsegs; i++)
  100. _dl_munmap((void *)loadaddr.map->segs[i].addr,
  101. loadaddr.map->segs[i].p_memsz);
  102. /*
  103. * _dl_unmap is only called for dlopen()ed libraries, for which
  104. * calling free() is safe, or before we've completed the initial
  105. * relocation, in which case calling free() is probably pointless,
  106. * but still safe.
  107. */
  108. _dl_free(loadaddr.map);
  109. if (funcdesc_ht)
  110. htab_delete(funcdesc_ht);
  111. }
  112. #endif
  113. /* Figure out whether the given address is in one of the mapped segments. */
  114. static __always_inline int
  115. __dl_addr_in_loadaddr(void *p, struct elf32_fdpic_loadaddr loadaddr)
  116. {
  117. struct elf32_fdpic_loadmap *map = loadaddr.map;
  118. int c;
  119. for (c = 0; c < map->nsegs; c++)
  120. if ((void *)map->segs[c].addr <= p &&
  121. (char *)p < (char *)map->segs[c].addr + map->segs[c].p_memsz)
  122. return 1;
  123. return 0;
  124. }
  125. static int
  126. hash_pointer(void *p)
  127. {
  128. return (int) ((long)p >> 3);
  129. }
  130. static int
  131. eq_pointer(void *p, void *q)
  132. {
  133. struct funcdesc_value *entry = p;
  134. return entry->entry_point == q;
  135. }
  136. static __always_inline void *
  137. _dl_funcdesc_for (void *entry_point, void *got_value)
  138. {
  139. struct elf_resolve *tpnt = ((void**)got_value)[2];
  140. struct funcdesc_ht *ht = tpnt->funcdesc_ht;
  141. struct funcdesc_value **entry;
  142. _dl_assert(got_value == tpnt->loadaddr.got_value);
  143. if (!ht) {
  144. ht = htab_create();
  145. if (!ht)
  146. return (void*)-1;
  147. tpnt->funcdesc_ht = ht;
  148. }
  149. entry = htab_find_slot(ht, entry_point, 1, hash_pointer, eq_pointer);
  150. if (entry == NULL)
  151. _dl_exit(1);
  152. if (*entry) {
  153. _dl_assert((*entry)->entry_point == entry_point);
  154. return _dl_stabilize_funcdesc(*entry);
  155. }
  156. *entry = _dl_malloc(sizeof(**entry));
  157. (*entry)->entry_point = entry_point;
  158. (*entry)->got_value = got_value;
  159. return _dl_stabilize_funcdesc(*entry);
  160. }
  161. static __always_inline void const *
  162. _dl_lookup_address(void const *address)
  163. {
  164. struct elf_resolve *rpnt;
  165. struct funcdesc_value const *fd;
  166. /* Make sure we don't make assumptions about its alignment. */
  167. __asm__ ("" : "+r" (address));
  168. if ((Elf32_Addr)address & 7)
  169. /* It's not a function descriptor. */
  170. return address;
  171. fd = address;
  172. for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
  173. if (!rpnt->funcdesc_ht)
  174. continue;
  175. if (fd->got_value != rpnt->loadaddr.got_value)
  176. continue;
  177. address = htab_find_slot(rpnt->funcdesc_ht, (void *)fd->entry_point, 0,
  178. hash_pointer, eq_pointer);
  179. if (address && *(struct funcdesc_value *const*)address == fd) {
  180. address = (*(struct funcdesc_value *const*)address)->entry_point;
  181. break;
  182. } else
  183. address = fd;
  184. }
  185. return address;
  186. }