arm64-link.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #ifdef TARGET_DEFS_ONLY
  2. #define EM_TCC_TARGET EM_AARCH64
  3. #define R_DATA_32 R_AARCH64_ABS32
  4. #define R_DATA_PTR R_AARCH64_ABS64
  5. #define R_JMP_SLOT R_AARCH64_JUMP_SLOT
  6. #define R_GLOB_DAT R_AARCH64_GLOB_DAT
  7. #define R_COPY R_AARCH64_COPY
  8. #define R_RELATIVE R_AARCH64_RELATIVE
  9. #define R_NUM R_AARCH64_NUM
  10. #define ELF_START_ADDR 0x00400000
  11. #define ELF_PAGE_SIZE 0x1000
  12. #define PCRELATIVE_DLLPLT 1
  13. #define RELOCATE_DLLPLT 1
  14. #else /* !TARGET_DEFS_ONLY */
  15. #include "tcc.h"
  16. /* Returns 1 for a code relocation, 0 for a data relocation. For unknown
  17. relocations, returns -1. */
  18. int code_reloc (int reloc_type)
  19. {
  20. switch (reloc_type) {
  21. case R_AARCH64_ABS32:
  22. case R_AARCH64_ABS64:
  23. case R_AARCH64_PREL32:
  24. case R_AARCH64_MOVW_UABS_G0_NC:
  25. case R_AARCH64_MOVW_UABS_G1_NC:
  26. case R_AARCH64_MOVW_UABS_G2_NC:
  27. case R_AARCH64_MOVW_UABS_G3:
  28. case R_AARCH64_ADR_PREL_PG_HI21:
  29. case R_AARCH64_ADD_ABS_LO12_NC:
  30. case R_AARCH64_ADR_GOT_PAGE:
  31. case R_AARCH64_LD64_GOT_LO12_NC:
  32. case R_AARCH64_GLOB_DAT:
  33. case R_AARCH64_COPY:
  34. return 0;
  35. case R_AARCH64_JUMP26:
  36. case R_AARCH64_CALL26:
  37. case R_AARCH64_JUMP_SLOT:
  38. return 1;
  39. }
  40. tcc_error ("Unknown relocation type: %d", reloc_type);
  41. return -1;
  42. }
  43. /* Returns an enumerator to describe whether and when the relocation needs a
  44. GOT and/or PLT entry to be created. See tcc.h for a description of the
  45. different values. */
  46. int gotplt_entry_type (int reloc_type)
  47. {
  48. switch (reloc_type) {
  49. case R_AARCH64_PREL32:
  50. case R_AARCH64_MOVW_UABS_G0_NC:
  51. case R_AARCH64_MOVW_UABS_G1_NC:
  52. case R_AARCH64_MOVW_UABS_G2_NC:
  53. case R_AARCH64_MOVW_UABS_G3:
  54. case R_AARCH64_ADR_PREL_PG_HI21:
  55. case R_AARCH64_ADD_ABS_LO12_NC:
  56. case R_AARCH64_GLOB_DAT:
  57. case R_AARCH64_JUMP_SLOT:
  58. case R_AARCH64_COPY:
  59. return NO_GOTPLT_ENTRY;
  60. case R_AARCH64_ABS32:
  61. case R_AARCH64_ABS64:
  62. case R_AARCH64_JUMP26:
  63. case R_AARCH64_CALL26:
  64. return AUTO_GOTPLT_ENTRY;
  65. case R_AARCH64_ADR_GOT_PAGE:
  66. case R_AARCH64_LD64_GOT_LO12_NC:
  67. return ALWAYS_GOTPLT_ENTRY;
  68. }
  69. tcc_error ("Unknown relocation type: %d", reloc_type);
  70. return -1;
  71. }
  72. ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
  73. {
  74. Section *plt = s1->plt;
  75. uint8_t *p;
  76. unsigned plt_offset;
  77. if (s1->output_type == TCC_OUTPUT_DLL)
  78. tcc_error("DLLs unimplemented!");
  79. if (plt->data_offset == 0) {
  80. section_ptr_add(plt, 32);
  81. }
  82. plt_offset = plt->data_offset;
  83. p = section_ptr_add(plt, 16);
  84. write32le(p, got_offset);
  85. write32le(p + 4, (uint64_t) got_offset >> 32);
  86. return plt_offset;
  87. }
  88. /* relocate the PLT: compute addresses and offsets in the PLT now that final
  89. address for PLT and GOT are known (see fill_program_header) */
  90. ST_FUNC void relocate_plt(TCCState *s1)
  91. {
  92. uint8_t *p, *p_end;
  93. if (!s1->plt)
  94. return;
  95. p = s1->plt->data;
  96. p_end = p + s1->plt->data_offset;
  97. if (p < p_end) {
  98. uint64_t plt = s1->plt->sh_addr;
  99. uint64_t got = s1->got->sh_addr;
  100. uint64_t off = (got >> 12) - (plt >> 12);
  101. if ((off + ((uint32_t)1 << 20)) >> 21)
  102. tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt);
  103. write32le(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
  104. write32le(p + 4, (0x90000010 | // adrp x16,...
  105. (off & 0x1ffffc) << 3 | (off & 3) << 29));
  106. write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...]
  107. (got & 0xff8) << 7));
  108. write32le(p + 12, (0x91000210 | // add x16,x16,#...
  109. (got & 0xfff) << 10));
  110. write32le(p + 16, 0xd61f0220); // br x17
  111. write32le(p + 20, 0xd503201f); // nop
  112. write32le(p + 24, 0xd503201f); // nop
  113. write32le(p + 28, 0xd503201f); // nop
  114. p += 32;
  115. while (p < p_end) {
  116. uint64_t pc = plt + (p - s1->plt->data);
  117. uint64_t addr = got + read64le(p);
  118. uint64_t off = (addr >> 12) - (pc >> 12);
  119. if ((off + ((uint32_t)1 << 20)) >> 21)
  120. tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
  121. write32le(p, (0x90000010 | // adrp x16,...
  122. (off & 0x1ffffc) << 3 | (off & 3) << 29));
  123. write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
  124. (addr & 0xff8) << 7));
  125. write32le(p + 8, (0x91000210 | // add x16,x16,#...
  126. (addr & 0xfff) << 10));
  127. write32le(p + 12, 0xd61f0220); // br x17
  128. p += 16;
  129. }
  130. }
  131. }
  132. void relocate_init(Section *sr) {}
  133. void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
  134. {
  135. int sym_index = ELFW(R_SYM)(rel->r_info);
  136. #ifdef DEBUG_RELOC
  137. ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
  138. #endif
  139. switch(type) {
  140. case R_AARCH64_ABS64:
  141. write64le(ptr, val);
  142. return;
  143. case R_AARCH64_ABS32:
  144. write32le(ptr, val);
  145. return;
  146. case R_AARCH64_PREL32:
  147. write32le(ptr, val - addr);
  148. return;
  149. case R_AARCH64_MOVW_UABS_G0_NC:
  150. write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
  151. (val & 0xffff) << 5));
  152. return;
  153. case R_AARCH64_MOVW_UABS_G1_NC:
  154. write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
  155. (val >> 16 & 0xffff) << 5));
  156. return;
  157. case R_AARCH64_MOVW_UABS_G2_NC:
  158. write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
  159. (val >> 32 & 0xffff) << 5));
  160. return;
  161. case R_AARCH64_MOVW_UABS_G3:
  162. write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
  163. (val >> 48 & 0xffff) << 5));
  164. return;
  165. case R_AARCH64_ADR_PREL_PG_HI21: {
  166. uint64_t off = (val >> 12) - (addr >> 12);
  167. if ((off + ((uint64_t)1 << 20)) >> 21)
  168. tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
  169. write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
  170. (off & 0x1ffffc) << 3 | (off & 3) << 29));
  171. return;
  172. }
  173. case R_AARCH64_ADD_ABS_LO12_NC:
  174. write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
  175. (val & 0xfff) << 10));
  176. return;
  177. case R_AARCH64_JUMP26:
  178. case R_AARCH64_CALL26:
  179. #ifdef DEBUG_RELOC
  180. printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
  181. (char *) symtab_section->link->data + sym->st_name);
  182. #endif
  183. if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc)
  184. tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed"
  185. " (val=%lx, addr=%lx)", val, addr);
  186. write32le(ptr, (0x14000000 |
  187. (uint32_t)(type == R_AARCH64_CALL26) << 31 |
  188. ((val - addr) >> 2 & 0x3ffffff)));
  189. return;
  190. case R_AARCH64_ADR_GOT_PAGE: {
  191. uint64_t off =
  192. (((s1->got->sh_addr +
  193. s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12));
  194. if ((off + ((uint64_t)1 << 20)) >> 21)
  195. tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed");
  196. write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
  197. (off & 0x1ffffc) << 3 | (off & 3) << 29));
  198. return;
  199. }
  200. case R_AARCH64_LD64_GOT_LO12_NC:
  201. write32le(ptr,
  202. ((read32le(ptr) & 0xfff803ff) |
  203. ((s1->got->sh_addr +
  204. s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7));
  205. return;
  206. case R_AARCH64_COPY:
  207. return;
  208. case R_AARCH64_GLOB_DAT:
  209. case R_AARCH64_JUMP_SLOT:
  210. /* They don't need addend */
  211. #ifdef DEBUG_RELOC
  212. printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr,
  213. val - rel->r_addend,
  214. (char *) symtab_section->link->data + sym->st_name);
  215. #endif
  216. write64le(ptr, val - rel->r_addend);
  217. return;
  218. case R_AARCH64_RELATIVE:
  219. #ifdef TCC_TARGET_PE
  220. add32le(ptr, val - s1->pe_imagebase);
  221. #endif
  222. /* do nothing */
  223. return;
  224. default:
  225. fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
  226. type, (unsigned)addr, ptr, (unsigned)val);
  227. return;
  228. }
  229. }
  230. #endif /* !TARGET_DEFS_ONLY */