dynamic_link.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
  2. /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
  3. /* Copyright (C) 2014 OSCAR lab, Stony Brook University
  4. This file is part of Graphene Library OS.
  5. Graphene Library OS is free software: you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation, either version 3 of the
  8. License, or (at your option) any later version.
  9. Graphene Library OS is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. /*
  16. * dynamic_link.h
  17. *
  18. * This files contain inline functions for dynamic linking.
  19. * The source code is imported and modified from the GNU C Library.
  20. */
  21. #include <pal_rtld.h>
  22. #include <elf/elf.h>
  23. #include <dl-machine-x86_64.h>
  24. /* We pass reloc_addr as a pointer to void, as opposed to a pointer to
  25. ElfW(Addr), because not all architectures can assume that the
  26. relocated address is properly aligned, whereas the compiler is
  27. entitled to assume that a pointer to a type is properly aligned for
  28. the type. Even if we cast the pointer back to some other type with
  29. less strict alignment requirements, the compiler might still
  30. remember that the pointer was originally more aligned, thereby
  31. optimizing away alignment tests or using word instructions for
  32. copying memory, breaking the very code written to handle the
  33. unaligned cases. */
  34. #if ! ELF_MACHINE_NO_REL
  35. static inline void __attribute__((always_inline))
  36. elf_machine_rel (ElfW(Dyn) ** l_info, ElfW(Addr) l_addr,
  37. ElfW(Rel) *reloc, ElfW(Sym) *sym, void *const reloc_addr,
  38. bool rel, bool rel_relative);
  39. static inline void __attribute__((always_inline))
  40. elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
  41. void *const reloc_addr);
  42. #endif
  43. #if ! ELF_MACHINE_NO_RELA
  44. static inline void __attribute__((always_inline))
  45. elf_machine_rela (ElfW(Dyn) ** l_info, ElfW(Addr) l_addr,
  46. ElfW(Rela) *reloc, ElfW(Sym) *sym, void *const reloc_addr,
  47. bool rel, bool rel_relative);
  48. static inline void __attribute__((always_inline))
  49. elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
  50. void *const reloc_addr);
  51. #endif
  52. /* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
  53. static inline
  54. void __attribute__ ((unused, always_inline))
  55. elf_get_dynamic_info (ElfW(Dyn) *dyn, ElfW(Dyn) **l_info, ElfW(Addr) l_addr)
  56. {
  57. #if __ELF_NATIVE_CLASS == 32
  58. typedef Elf32_Word d_tag_utype;
  59. #elif __ELF_NATIVE_CLASS == 64
  60. typedef Elf64_Xword d_tag_utype;
  61. #endif
  62. while (dyn->d_tag != DT_NULL) {
  63. if ((d_tag_utype) dyn->d_tag < DT_NUM)
  64. l_info[dyn->d_tag] = dyn;
  65. else if (dyn->d_tag >= DT_LOPROC &&
  66. dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)
  67. l_info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;
  68. else if ((d_tag_utype) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)
  69. l_info[VERSYMIDX (dyn->d_tag)] = dyn;
  70. else if ((d_tag_utype) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
  71. l_info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
  72. + DT_VERSIONTAGNUM] = dyn;
  73. else if ((d_tag_utype) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
  74. l_info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
  75. + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn;
  76. else if ((d_tag_utype) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
  77. l_info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
  78. + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
  79. ++dyn;
  80. }
  81. if (l_addr != 0) {
  82. # define ADJUST_DYN_INFO(tag) \
  83. do { \
  84. if (l_info[tag]) \
  85. l_info[tag]->d_un.d_ptr += l_addr; \
  86. } while(0);
  87. ADJUST_DYN_INFO (DT_HASH);
  88. ADJUST_DYN_INFO (DT_PLTGOT);
  89. ADJUST_DYN_INFO (DT_STRTAB);
  90. ADJUST_DYN_INFO (DT_SYMTAB);
  91. # if ! ELF_MACHINE_NO_RELA
  92. ADJUST_DYN_INFO (DT_RELA);
  93. # endif
  94. # if ! ELF_MACHINE_NO_REL
  95. ADJUST_DYN_INFO (DT_REL);
  96. # endif
  97. ADJUST_DYN_INFO (DT_JMPREL);
  98. ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
  99. ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
  100. + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
  101. # undef ADJUST_DYN_INFO
  102. }
  103. /* Then a bunch of assertion, we could kind of ignore them */
  104. if (l_info[DT_PLTREL]) {
  105. #if ELF_MACHINE_NO_RELA
  106. assert (l_info[DT_PLTREL]->d_un.d_val == DT_REL);
  107. #elif ELF_MACHINE_NO_REL
  108. assert (l_info[DT_PLTREL]->d_un.d_val == DT_RELA);
  109. #else
  110. assert (l_info[DT_PLTREL]->d_un.d_val == DT_REL
  111. || l_info[DT_PLTREL]->d_un.d_val == DT_RELA);
  112. #endif
  113. }
  114. #if ! ELF_MACHINE_NO_RELA
  115. if (l_info[DT_RELA])
  116. assert (l_info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
  117. # endif
  118. # if ! ELF_MACHINE_NO_REL
  119. if (l_info[DT_REL])
  120. assert (l_info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
  121. #endif
  122. #ifdef RTLD_BOOTSTRAP
  123. /* Only the bind now flags are allowed. */
  124. assert (!l_info[VERSYMIDX (DT_FLAGS_1)]
  125. || l_info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val == DF_1_NOW);
  126. assert (!l_info[DT_FLAGS]
  127. || l_info[DT_FLAGS]->d_un.d_val == DF_BIND_NOW);
  128. /* Flags must not be set for ld.so. */
  129. assert (!l_info[DT_RUNPATH]);
  130. assert (!l_info[DT_RPATH]);
  131. #endif
  132. }
  133. #ifdef RTLD_BOOTSTRAP
  134. # define ELF_DURING_STARTUP (1)
  135. #else
  136. # define ELF_DURING_STARTUP (0)
  137. #endif
  138. /* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
  139. These functions are almost identical, so we use cpp magic to avoid
  140. duplicating their code. It cannot be done in a more general function
  141. because we must be able to completely inline. */
  142. /* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
  143. range. Note that according to the ELF spec, this is completely legal!
  144. But conditionally define things so that on machines we know this will
  145. not happen we do something more optimal. */
  146. #ifdef ELF_MACHINE_PLTREL_OVERLAP
  147. /* ELF_MACHINE_PLTREL_OVERLAP is only used for s390, powerpc and sparc.
  148. We will keep it for now */
  149. static void
  150. _elf_dynamic_do_reloc(int dt_reloc, int dt_reloc_sz,
  151. void (*do_reloc) (ElfW(Dyn) **, ElfW(Addr),
  152. ElfW(Addr), ElfW(Addr),
  153. bool, bool),
  154. ElfW(Dyn) **l_info, ElfW(Addr) l_addr,
  155. bool rel, bool rel_relative)
  156. {
  157. struct { ElfW(Addr) start, size; } ranges[3];
  158. int ranges_index;
  159. ranges[0].size = ranges[1].size = ranges[2].size = 0;
  160. if (l_info[dt_reloc]) {
  161. ranges[0].start = D_PTR (l_info[dt_reloc]);
  162. ranges[0].size = l_info[dt_reloc_sz]->d_un.d_val;
  163. }
  164. for (ranges_index = 0; ranges_index < 3; ++ranges_index)
  165. (*do_reloc) (l_info, l_addr,
  166. ranges[ranges_index].start,
  167. ranges[ranges_index].size,
  168. lazy, rel, rel_relative);
  169. }
  170. #else
  171. /* Now this part is for our x86s machines */
  172. static void __attribute__((unused))
  173. _elf_dynamic_do_reloc(int dt_reloc, int dt_reloc_sz,
  174. void (*do_reloc) (ElfW(Dyn) **, ElfW(Addr),
  175. ElfW(Addr), ElfW(Addr),
  176. bool, bool),
  177. ElfW(Dyn) **l_info, ElfW(Addr) l_addr,
  178. bool rel, bool rel_relative)
  179. {
  180. struct { ElfW(Addr) start, size; } ranges[2];
  181. ranges[0].size = ranges[1].size = 0;
  182. ranges[0].start = ranges[1].start = 0;
  183. if (l_info[dt_reloc]) {
  184. ranges[0].start = D_PTR (l_info[dt_reloc]);
  185. ranges[0].size = l_info[dt_reloc_sz]->d_un.d_val;
  186. }
  187. if (l_info[DT_PLTREL]
  188. && l_info[DT_PLTREL]->d_un.d_val == dt_reloc) {
  189. ElfW(Addr) start = D_PTR (l_info[DT_JMPREL]);
  190. if (!ELF_DURING_STARTUP &&
  191. /* This test does not only detect whether the relocation
  192. sections are in the right order, it also checks whether
  193. there is a DT_REL/DT_RELA section. */
  194. ranges[0].start + ranges[0].size != start) {
  195. ranges[1].start = start;
  196. ranges[1].size = l_info[DT_PLTRELSZ]->d_un.d_val;
  197. } else {
  198. /* Combine processing the sections. */
  199. assert (ranges[0].start + ranges[0].size == start);
  200. ranges[0].size += l_info[DT_PLTRELSZ]->d_un.d_val;
  201. }
  202. }
  203. /* This is interesting, don't make it lazy. */
  204. if (ELF_DURING_STARTUP) {
  205. (*do_reloc) (l_info, l_addr,
  206. ranges[0].start, ranges[0].size,
  207. rel, rel_relative);
  208. } else {
  209. int ranges_index;
  210. for (ranges_index = 0; ranges_index < 2; ++ranges_index)
  211. (*do_reloc) (l_info, l_addr,
  212. ranges[ranges_index].start,
  213. ranges[ranges_index].size,
  214. rel, rel_relative);
  215. }
  216. }
  217. #endif
  218. #define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, l_info, l_addr, \
  219. do_rel, do_rel_relative) \
  220. _elf_dynamic_do_reloc(DT_##RELOC, DT_##RELOC##SZ, \
  221. &elf_dynamic_do_##reloc, \
  222. l_info, l_addr, \
  223. do_rel, do_rel_relative)
  224. #if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
  225. # define _ELF_CHECK_REL 0
  226. #else
  227. # define _ELF_CHECK_REL 1
  228. #endif
  229. #if ! ELF_MACHINE_NO_REL
  230. # include "do-rel.h"
  231. # define ELF_DYNAMIC_DO_REL(l_info, l_addr, rel, rel_relative) \
  232. _ELF_DYNAMIC_DO_RELOC (REL, rel, l_info, l_addr, rel, rel_relative)
  233. #else
  234. /* nothing to do */
  235. # define ELF_DYNAMIC_DO_REL(l_info, l_addr, rel, rel_relative)
  236. #endif
  237. #if ! ELF_MACHINE_NO_RELA
  238. # define DO_RELA
  239. # include "do-rel.h"
  240. # define ELF_DYNAMIC_DO_RELA(l_info, l_addr, rel, rel_relative) \
  241. _ELF_DYNAMIC_DO_RELOC (RELA, rela, l_info, l_addr, rel, rel_relative)
  242. #else
  243. /* nothing to do */
  244. # define ELF_DYNAMIC_DO_RELA(l_info, l_addr, rel, relative)
  245. #endif
  246. /* This can't just be an inline function because GCC is too dumb
  247. to inline functions containing inlines themselves. */
  248. # define ELF_DYNAMIC_RELOCATE(l_info, l_addr) \
  249. do { \
  250. ELF_DYNAMIC_DO_REL (l_info, l_addr, true, true); \
  251. ELF_DYNAMIC_DO_RELA(l_info, l_addr, true, true); \
  252. } while (0)
  253. # define ELF_DYNAMIC_SCAN(l_info, l_addr) \
  254. do { \
  255. ELF_DYNAMIC_DO_REL (l_info, l_addr, false, false); \
  256. ELF_DYNAMIC_DO_RELA(l_info, l_addr, false, false); \
  257. } while (0)