dl-machine-x86_64.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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. * dl-machine-x86_64.h
  17. *
  18. * This files contain architecture-specific implementation of ELF dynamic
  19. * relocation function.
  20. * The source code is imported and modified from the GNU C Library.
  21. */
  22. #ifndef dl_machine_h
  23. #define dl_machine_h
  24. #define ELF_MACHINE_NAME "x86_64"
  25. #include <sys/param.h>
  26. #include <sysdep.h>
  27. #include <sysdeps/generic/ldsodefs.h>
  28. #include "pal_internal.h"
  29. /* Return nonzero iff ELF header is compatible with the running host. */
  30. static inline bool __attribute__ ((unused))
  31. elf_machine_matches_host (const Elf64_Ehdr *ehdr)
  32. {
  33. return ehdr->e_machine == EM_X86_64;
  34. }
  35. /* Return the link-time address of _DYNAMIC. Conveniently, this is the
  36. first element of the GOT. This must be inlined in a function which
  37. uses global data. */
  38. static inline Elf64_Addr __attribute__ ((unused))
  39. elf_machine_dynamic (void)
  40. {
  41. Elf64_Addr addr;
  42. /* This works because we have our GOT address available in the small PIC
  43. model. */
  44. addr = (Elf64_Addr) &_DYNAMIC;
  45. return addr;
  46. }
  47. #define XSTRINGIFY(x) STRINGIFY(x)
  48. #define STRINGIFY(x) #x
  49. /* Return the run-time load address of the shared object. */
  50. static inline Elf64_Addr __attribute__ ((unused))
  51. elf_machine_load_address (void)
  52. {
  53. Elf64_Addr addr;
  54. /* The easy way is just the same as on x86:
  55. leaq _dl_start, %0
  56. leaq _dl_start(%%rip), %1
  57. subq %0, %1
  58. but this does not work with binutils since we then have
  59. a R_X86_64_32S relocation in a shared lib.
  60. Instead we store the address of _dl_start in the data section
  61. and compare it with the current value that we can get via
  62. an RIP relative addressing mode. Note that this is the address
  63. of _dl_start before any relocation performed at runtime. In case
  64. the binary is prelinked the resulting "address" is actually a
  65. load offset which is zero if the binary was loaded at the address
  66. it is prelinked for. */
  67. asm ("leaq " XSTRINGIFY(_ENTRY) "(%%rip), %0\n\t"
  68. "subq 1f(%%rip), %0\n\t"
  69. ".section\t.data.rel.ro\n"
  70. "1:\t.quad " XSTRINGIFY(_ENTRY) "\n\t"
  71. ".previous\n\t"
  72. : "=r" (addr) : : "cc");
  73. return addr;
  74. }
  75. /* The x86-64 never uses Elf64_Rel relocations. */
  76. #define ELF_MACHINE_NO_REL 1
  77. /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
  78. MAP is the object containing the reloc. */
  79. //#define DEBUG_RELOC
  80. static void
  81. elf_machine_rela (Elf64_Dyn **l_info, Elf64_Addr l_addr,
  82. Elf64_Rela *reloc, Elf64_Sym *sym, void *const reloc_addr_arg,
  83. bool rel, bool rel_relative)
  84. {
  85. Elf64_Addr *const reloc_addr = reloc_addr_arg;
  86. const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info);
  87. const char * __attribute__ ((unused)) strtab =
  88. (const void *) D_PTR (l_info[DT_STRTAB]);
  89. #ifdef DEBUG_RELOC
  90. #define elf_machine_rela_debug(r_type, sym, value) \
  91. ({ if (strtab && sym && sym->st_name) \
  92. printf(#r_type ": %s\n", strtab + sym->st_name); \
  93. else if (value) \
  94. printf(#r_type ": %p\n", value); \
  95. else \
  96. printf(#r_type "\n", value); \
  97. })
  98. #else
  99. #define elf_machine_rela_debug(...) ({})
  100. #endif
  101. if (__builtin_expect (r_type == R_X86_64_RELATIVE, 0))
  102. {
  103. /* This is defined in rtld.c, but nowhere in the static libc.a;
  104. make the reference weak so static programs can still link.
  105. This declaration cannot be done when compiling rtld.c
  106. (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
  107. common defn for _dl_rtld_map, which is incompatible with a
  108. weak decl in the same file. */
  109. if (rel_relative)
  110. {
  111. #ifndef RTLD_BOOTSTRAP
  112. elf_machine_rela_debug (R_X86_64_RELATIVE, sym, 0);
  113. *reloc_addr = l_addr + reloc->r_addend;
  114. #endif
  115. }
  116. return;
  117. }
  118. if (__builtin_expect (r_type == R_X86_64_NONE, 0))
  119. {
  120. elf_machine_rela_debug (R_X86_64_NONE, sym, 0);
  121. return;
  122. }
  123. #ifdef RTLD_BOOTSTRAP
  124. Elf64_Addr value = (sym == NULL ? 0 : l_addr + sym->st_value);
  125. #define SYM (sym)
  126. #else
  127. Elf64_Sym *refsym = sym;
  128. Elf64_Addr sym_map = RESOLVE_MAP(&strtab, &sym);
  129. #define SYM (sym ? : refsym)
  130. if (!sym_map)
  131. sym_map = l_addr;
  132. Elf64_Addr value = sym_map + (sym == NULL ? refsym->st_value : sym->st_value);
  133. /* We do a very special relocation for loaded libraries */
  134. if (!rel) {
  135. if (sym && refsym && refsym != sym) {
  136. refsym->st_info = sym->st_info;
  137. refsym->st_size = sym->st_size;
  138. if (__builtin_expect (ELFW(ST_TYPE) (sym->st_info)
  139. == STT_GNU_IFUNC, 0)
  140. && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1))
  141. {
  142. value = ((Elf64_Addr (*) (void)) value) ();
  143. refsym->st_info ^= ELFW(ST_TYPE)(sym->st_info);
  144. refsym->st_info |= STT_FUNC;
  145. }
  146. refsym->st_value = value - l_addr;
  147. } else {
  148. return;
  149. }
  150. }
  151. #endif
  152. if (sym != NULL
  153. && __builtin_expect (ELFW(ST_TYPE) (sym->st_info)
  154. == STT_GNU_IFUNC, 0)
  155. && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1))
  156. value = ((Elf64_Addr (*) (void)) value) ();
  157. /* In the libc loader, they guaranteed that only R_ARCH_RELATIVE,
  158. R_ARCH_GLOB_DAT, R_ARCH_JUMP_SLOT appear in ld.so. We observed
  159. the same thing in libpal.so, so we are gonna to make the same
  160. assumption */
  161. switch (r_type)
  162. {
  163. case R_X86_64_GLOB_DAT:
  164. elf_machine_rela_debug (R_X86_64_GLOB_DAT, SYM, value);
  165. *reloc_addr = value + reloc->r_addend;
  166. break;
  167. case R_X86_64_JUMP_SLOT:
  168. elf_machine_rela_debug (R_X86_64_JUMP_SLOT, SYM, value);
  169. *reloc_addr = value + reloc->r_addend;
  170. break;
  171. #ifndef RTLD_BOOTSTRAP
  172. case R_X86_64_64:
  173. elf_machine_rela_debug (R_X86_64_64, SYM, value);
  174. *reloc_addr = value + reloc->r_addend;
  175. break;
  176. case R_X86_64_32:
  177. elf_machine_rela_debug (R_X86_64_32, SYM, value);
  178. value += reloc->r_addend;
  179. *(Elf64_Addr *) reloc_addr = value;
  180. break;
  181. /* Not needed for dl-conflict.c. */
  182. case R_X86_64_PC32:
  183. elf_machine_rela_debug (R_X86_64_PC32, SYM, value);
  184. value += reloc->r_addend - (Elf64_Addr) reloc_addr;
  185. *(Elf64_Addr *) reloc_addr = value;
  186. break;
  187. case R_X86_64_COPY:
  188. elf_machine_rela_debug (R_X86_64_COPY, SYM, value);
  189. size_t sym_size = sym ? sym->st_size : 0;
  190. size_t ref_size = refsym ? refsym->st_size : 0;
  191. memcpy (reloc_addr_arg, (void *) value, MIN (sym_size,
  192. ref_size));
  193. break;
  194. case R_X86_64_IRELATIVE:
  195. elf_machine_rela_debug (R_X86_64_IRELATIVE, SYM, value);
  196. value = sym_map + reloc->r_addend;
  197. value = ((Elf64_Addr (*) (void)) value) ();
  198. *reloc_addr = value;
  199. break;
  200. #endif
  201. default:
  202. return;
  203. }
  204. if (!rel)
  205. /* We have relocated the symbol, we don't want the
  206. interpreter to relocate it again. */
  207. reloc->r_info ^= ELF64_R_TYPE (reloc->r_info);
  208. }
  209. static void
  210. elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc,
  211. void *const reloc_addr_arg)
  212. {
  213. Elf64_Addr *const reloc_addr = reloc_addr_arg;
  214. assert (ELF64_R_TYPE (reloc->r_info) == R_X86_64_RELATIVE);
  215. *reloc_addr = l_addr + reloc->r_addend;
  216. }
  217. #endif /* !dl_machine_h */