elf-x86-amd64.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * ELF object format helpers - x86:amd64
  3. *
  4. * Copyright (C) 2004-2007 Michael Urman
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
  19. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. * POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <util.h>
  28. #include <libyasm.h>
  29. #define YASM_OBJFMT_ELF_INTERNAL
  30. #include "elf.h"
  31. #include "elf-machine.h"
  32. static elf_machine_ssym elf_x86_amd64_ssyms[] = {
  33. {"pltoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLTOFF64, 64},
  34. {"plt", ELF_SSYM_SYM_RELATIVE, R_X86_64_PLT32, 32},
  35. {"gotplt", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPLT64, 64},
  36. {"gotoff", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTOFF64, 64},
  37. {"gotpcrel", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOTPCREL, 32},
  38. {"tlsgd", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
  39. R_X86_64_TLSGD, 32},
  40. {"tlsld", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
  41. R_X86_64_TLSLD, 32},
  42. {"gottpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
  43. R_X86_64_GOTTPOFF, 32},
  44. {"tpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
  45. R_X86_64_TPOFF32, 32},
  46. {"dtpoff", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
  47. R_X86_64_DTPOFF32, 32},
  48. {"got", ELF_SSYM_SYM_RELATIVE, R_X86_64_GOT32, 32},
  49. {"tlsdesc", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
  50. R_X86_64_GOTPC32_TLSDESC, 32},
  51. {"tlscall", ELF_SSYM_SYM_RELATIVE|ELF_SSYM_THREAD_LOCAL,
  52. R_X86_64_TLSDESC_CALL, 32}
  53. };
  54. static int
  55. elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt)
  56. {
  57. if (wrt) {
  58. const elf_machine_ssym *ssym = (elf_machine_ssym *)
  59. yasm_symrec_get_data(wrt, &elf_ssym_symrec_data);
  60. if (!ssym || val != ssym->size)
  61. return 0;
  62. return 1;
  63. }
  64. return (val&(val-1)) ? 0 : ((val & (8|16|32|64)) != 0);
  65. }
  66. static void
  67. elf_x86_amd64_write_symtab_entry(unsigned char *bufp,
  68. elf_symtab_entry *entry,
  69. yasm_intnum *value_intn,
  70. yasm_intnum *size_intn)
  71. {
  72. YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0);
  73. YASM_WRITE_8(bufp, ELF64_ST_INFO(entry->bind, entry->type));
  74. YASM_WRITE_8(bufp, ELF64_ST_OTHER(entry->vis));
  75. if (entry->sect) {
  76. elf_secthead *shead =
  77. yasm_section_get_data(entry->sect, &elf_section_data);
  78. if (!shead)
  79. yasm_internal_error(N_("symbol references section without data"));
  80. YASM_WRITE_16_L(bufp, shead->index);
  81. } else {
  82. YASM_WRITE_16_L(bufp, entry->index);
  83. }
  84. YASM_WRITE_64I_L(bufp, value_intn);
  85. YASM_WRITE_64I_L(bufp, size_intn);
  86. }
  87. static void
  88. elf_x86_amd64_write_secthead(unsigned char *bufp, elf_secthead *shead)
  89. {
  90. YASM_WRITE_32_L(bufp, shead->name ? shead->name->index : 0);
  91. YASM_WRITE_32_L(bufp, shead->type);
  92. YASM_WRITE_64Z_L(bufp, shead->flags);
  93. YASM_WRITE_64Z_L(bufp, 0); /* vmem address */
  94. YASM_WRITE_64Z_L(bufp, shead->offset);
  95. YASM_WRITE_64I_L(bufp, shead->size);
  96. YASM_WRITE_32_L(bufp, shead->link);
  97. YASM_WRITE_32_L(bufp, shead->info);
  98. YASM_WRITE_64Z_L(bufp, shead->align);
  99. YASM_WRITE_64Z_L(bufp, shead->entsize);
  100. }
  101. static void
  102. elf_x86_amd64_write_secthead_rel(unsigned char *bufp,
  103. elf_secthead *shead,
  104. elf_section_index symtab_idx,
  105. elf_section_index sindex)
  106. {
  107. yasm_intnum *nreloc;
  108. yasm_intnum *relocsize;
  109. YASM_WRITE_32_L(bufp, shead->rel_name ? shead->rel_name->index : 0);
  110. YASM_WRITE_32_L(bufp, SHT_RELA);
  111. YASM_WRITE_64Z_L(bufp, 0);
  112. YASM_WRITE_64Z_L(bufp, 0);
  113. YASM_WRITE_64Z_L(bufp, shead->rel_offset);
  114. nreloc = yasm_intnum_create_uint(shead->nreloc);
  115. relocsize = yasm_intnum_create_uint(RELOC64A_SIZE);
  116. yasm_intnum_calc(relocsize, YASM_EXPR_MUL, nreloc);
  117. YASM_WRITE_64I_L(bufp, relocsize); /* size */
  118. yasm_intnum_destroy(nreloc);
  119. yasm_intnum_destroy(relocsize);
  120. YASM_WRITE_32_L(bufp, symtab_idx); /* link: symtab index */
  121. YASM_WRITE_32_L(bufp, shead->index); /* info: relocated's index */
  122. YASM_WRITE_64Z_L(bufp, RELOC64_ALIGN); /* align */
  123. YASM_WRITE_64Z_L(bufp, RELOC64A_SIZE); /* entity size */
  124. }
  125. static void
  126. elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn,
  127. elf_reloc_entry *reloc,
  128. unsigned long offset)
  129. {
  130. /* .rela: copy value out as addend, replace original with 0 */
  131. reloc->addend = yasm_intnum_copy(intn);
  132. yasm_intnum_zero(intn);
  133. }
  134. static unsigned int
  135. elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc)
  136. {
  137. if (reloc->wrt) {
  138. const elf_machine_ssym *ssym = (elf_machine_ssym *)
  139. yasm_symrec_get_data(reloc->wrt, &elf_ssym_symrec_data);
  140. if (!ssym || reloc->valsize != ssym->size)
  141. yasm_internal_error(N_("Unsupported WRT"));
  142. /* Force TLS type; this is required by the linker. */
  143. if (ssym->sym_rel & ELF_SSYM_THREAD_LOCAL) {
  144. elf_symtab_entry *esym;
  145. esym = yasm_symrec_get_data(reloc->reloc.sym, &elf_symrec_data);
  146. if (esym)
  147. esym->type = STT_TLS;
  148. }
  149. /* Map PC-relative GOT to appropriate relocation */
  150. if (reloc->rtype_rel && ssym->reloc == R_X86_64_GOT32)
  151. return (unsigned char) R_X86_64_GOTPCREL;
  152. return (unsigned char) ssym->reloc;
  153. } else if (reloc->is_GOT_sym && reloc->valsize == 32) {
  154. return (unsigned char) R_X86_64_GOTPC32;
  155. } else if (reloc->is_GOT_sym && reloc->valsize == 64) {
  156. return (unsigned char) R_X86_64_GOTPC64;
  157. } else if (reloc->rtype_rel) {
  158. switch (reloc->valsize) {
  159. case 8: return (unsigned char) R_X86_64_PC8;
  160. case 16: return (unsigned char) R_X86_64_PC16;
  161. case 32: return (unsigned char) R_X86_64_PC32;
  162. case 64: return (unsigned char) R_X86_64_PC64;
  163. default: yasm_internal_error(N_("Unsupported relocation size"));
  164. }
  165. } else {
  166. switch (reloc->valsize) {
  167. case 8: return (unsigned char) R_X86_64_8;
  168. case 16: return (unsigned char) R_X86_64_16;
  169. case 32: return (unsigned char) R_X86_64_32;
  170. case 64: return (unsigned char) R_X86_64_64;
  171. default: yasm_internal_error(N_("Unsupported relocation size"));
  172. }
  173. }
  174. return 0;
  175. }
  176. static void
  177. elf_x86_amd64_write_reloc(unsigned char *bufp, elf_reloc_entry *reloc,
  178. unsigned int r_type, unsigned int r_sym)
  179. {
  180. YASM_WRITE_64I_L(bufp, reloc->reloc.addr);
  181. /*YASM_WRITE_64_L(bufp, ELF64_R_INFO(r_sym, r_type));*/
  182. YASM_WRITE_64C_L(bufp, r_sym, r_type);
  183. if (reloc->addend)
  184. YASM_WRITE_64I_L(bufp, reloc->addend);
  185. else {
  186. YASM_WRITE_32_L(bufp, 0);
  187. YASM_WRITE_32_L(bufp, 0);
  188. }
  189. }
  190. static void
  191. elf_x86_amd64_write_proghead(unsigned char **bufpp,
  192. elf_offset secthead_addr,
  193. unsigned long secthead_count,
  194. elf_section_index shstrtab_index)
  195. {
  196. unsigned char *bufp = *bufpp;
  197. unsigned char *buf = bufp-4;
  198. YASM_WRITE_8(bufp, ELFCLASS64); /* elf class */
  199. YASM_WRITE_8(bufp, ELFDATA2LSB); /* data encoding :: MSB? */
  200. YASM_WRITE_8(bufp, EV_CURRENT); /* elf version */
  201. YASM_WRITE_8(bufp, ELFOSABI_SYSV); /* os/abi */
  202. YASM_WRITE_8(bufp, 0); /* SYSV v3 ABI=0 */
  203. while (bufp-buf < EI_NIDENT) /* e_ident padding */
  204. YASM_WRITE_8(bufp, 0);
  205. YASM_WRITE_16_L(bufp, ET_REL); /* e_type - object file */
  206. YASM_WRITE_16_L(bufp, EM_X86_64); /* e_machine - or others */
  207. YASM_WRITE_32_L(bufp, EV_CURRENT); /* elf version */
  208. YASM_WRITE_64Z_L(bufp, 0); /* e_entry */
  209. YASM_WRITE_64Z_L(bufp, 0); /* e_phoff */
  210. YASM_WRITE_64Z_L(bufp, secthead_addr); /* e_shoff secthead off */
  211. YASM_WRITE_32_L(bufp, 0); /* e_flags */
  212. YASM_WRITE_16_L(bufp, EHDR64_SIZE); /* e_ehsize */
  213. YASM_WRITE_16_L(bufp, 0); /* e_phentsize */
  214. YASM_WRITE_16_L(bufp, 0); /* e_phnum */
  215. YASM_WRITE_16_L(bufp, SHDR64_SIZE); /* e_shentsize */
  216. YASM_WRITE_16_L(bufp, secthead_count); /* e_shnum */
  217. YASM_WRITE_16_L(bufp, shstrtab_index); /* e_shstrndx */
  218. *bufpp = bufp;
  219. }
  220. const elf_machine_handler
  221. elf_machine_handler_x86_amd64 = {
  222. "x86", "amd64", ".rela",
  223. SYMTAB64_SIZE, SYMTAB64_ALIGN, RELOC64A_SIZE, SHDR64_SIZE, EHDR64_SIZE,
  224. elf_x86_amd64_accepts_reloc,
  225. elf_x86_amd64_write_symtab_entry,
  226. elf_x86_amd64_write_secthead,
  227. elf_x86_amd64_write_secthead_rel,
  228. elf_x86_amd64_handle_reloc_addend,
  229. elf_x86_amd64_map_reloc_info_to_type,
  230. elf_x86_amd64_write_reloc,
  231. elf_x86_amd64_write_proghead,
  232. elf_x86_amd64_ssyms,
  233. sizeof(elf_x86_amd64_ssyms)/sizeof(elf_x86_amd64_ssyms[0]),
  234. 64
  235. };