aot_reloc_aarch64.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. * Copyright (C) 2020 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "aot_reloc.h"
  6. #define R_AARCH64_MOVW_UABS_G0 263
  7. #define R_AARCH64_MOVW_UABS_G0_NC 264
  8. #define R_AARCH64_MOVW_UABS_G1 265
  9. #define R_AARCH64_MOVW_UABS_G1_NC 266
  10. #define R_AARCH64_MOVW_UABS_G2 267
  11. #define R_AARCH64_MOVW_UABS_G2_NC 268
  12. #define R_AARCH64_MOVW_UABS_G3 269
  13. #define R_AARCH64_MOVW_SABS_G0 270
  14. #define R_AARCH64_MOVW_SABS_G1 271
  15. #define R_AARCH64_MOVW_SABS_G2 272
  16. #define R_AARCH64_ADR_PREL_LO19 273
  17. #define R_AARCH64_ADR_PREL_LO21 274
  18. #define R_AARCH64_ADR_PREL_PG_HI21 275
  19. #define R_AARCH64_ADR_PREL_PG_HI21_NC 276
  20. #define R_AARCH64_ADD_ABS_LO12_NC 277
  21. #define R_AARCH64_LDST8_ABS_LO12_NC 278
  22. #define R_AARCH64_LDST16_ABS_LO12_NC 284
  23. #define R_AARCH64_LDST32_ABS_LO12_NC 285
  24. #define R_AARCH64_LDST64_ABS_LO12_NC 286
  25. #define R_AARCH64_LDST128_ABS_LO12_NC 299
  26. #define R_AARCH64_JUMP26 282
  27. #define R_AARCH64_CALL26 283
  28. /* clang-format off */
  29. static SymbolMap target_sym_map[] = {
  30. REG_COMMON_SYMBOLS
  31. };
  32. /* clang-format on */
  33. static void
  34. set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
  35. {
  36. if (error_buf != NULL)
  37. snprintf(error_buf, error_buf_size, "%s", string);
  38. }
  39. SymbolMap *
  40. get_target_symbol_map(uint32 *sym_num)
  41. {
  42. *sym_num = sizeof(target_sym_map) / sizeof(SymbolMap);
  43. return target_sym_map;
  44. }
  45. void
  46. get_current_target(char *target_buf, uint32 target_buf_size)
  47. {
  48. const char *s = BUILD_TARGET;
  49. size_t s_size = sizeof(BUILD_TARGET);
  50. char *d = target_buf;
  51. /* Set to "aarch64v8" by default if sub version isn't specified */
  52. if (strcmp(s, "AARCH64") == 0) {
  53. s = "aarch64v8";
  54. s_size = 9; /* strlen("aarch64v8"); */
  55. }
  56. if (target_buf_size < s_size) {
  57. s_size = target_buf_size;
  58. }
  59. while (--s_size) {
  60. if (*s >= 'A' && *s <= 'Z')
  61. *d++ = *s++ + 'a' - 'A';
  62. else
  63. *d++ = *s++;
  64. }
  65. /* Ensure the string is null byte ('\0') terminated */
  66. *d = '\0';
  67. }
  68. static uint32
  69. get_plt_item_size(void)
  70. {
  71. /* 6*4 bytes instructions and 8 bytes symbol address */
  72. return 32;
  73. }
  74. void
  75. init_plt_table(uint8 *plt)
  76. {
  77. uint32 i, num = sizeof(target_sym_map) / sizeof(SymbolMap);
  78. for (i = 0; i < num; i++) {
  79. uint32 *p = (uint32 *)plt;
  80. *p++ = 0xf81f0ffe; /* str x30, [sp, #-16]! */
  81. *p++ = 0x100000be; /* adr x30, #20; symbol addr is PC + 5 instructions
  82. below */
  83. *p++ = 0xf94003de; /* ldr x30, [x30] */
  84. *p++ = 0xd63f03c0; /* blr x30 */
  85. *p++ = 0xf84107fe; /* ldr x30, [sp], #16 */
  86. *p++ = 0xd61f03c0; /* br x30 */
  87. /* symbol addr */
  88. *(uint64 *)p = (uint64)(uintptr_t)target_sym_map[i].symbol_addr;
  89. p += 2;
  90. plt += get_plt_item_size();
  91. }
  92. }
  93. uint32
  94. get_plt_table_size()
  95. {
  96. return get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap));
  97. }
  98. #define SIGN_EXTEND_TO_INT64(val, bits, val_ext) \
  99. do { \
  100. int64 m = (int64)((uint64)1 << (bits - 1)); \
  101. val_ext = ((int64)val ^ m) - m; \
  102. } while (0)
  103. #define Page(expr) ((expr) & ~0xFFF)
  104. static bool
  105. check_reloc_offset(uint32 target_section_size, uint64 reloc_offset,
  106. uint32 reloc_data_size, char *error_buf,
  107. uint32 error_buf_size)
  108. {
  109. if (!(reloc_offset < (uint64)target_section_size
  110. && reloc_offset + reloc_data_size <= (uint64)target_section_size)) {
  111. set_error_buf(error_buf, error_buf_size,
  112. "AOT module load failed: invalid relocation offset.");
  113. return false;
  114. }
  115. return true;
  116. }
  117. bool
  118. apply_relocation(AOTModule *module, uint8 *target_section_addr,
  119. uint32 target_section_size, uint64 reloc_offset,
  120. int64 reloc_addend, uint32 reloc_type, void *symbol_addr,
  121. int32 symbol_index, char *error_buf, uint32 error_buf_size)
  122. {
  123. switch (reloc_type) {
  124. case R_AARCH64_CALL26:
  125. case R_AARCH64_JUMP26:
  126. {
  127. void *S, *P = (void *)(target_section_addr + reloc_offset);
  128. int64 X, A, initial_addend;
  129. int32 insn, imm26;
  130. CHECK_RELOC_OFFSET(sizeof(int32));
  131. insn = *(int32 *)P;
  132. imm26 = insn & 0x3FFFFFF;
  133. SIGN_EXTEND_TO_INT64(imm26 << 2, 28, initial_addend);
  134. A = initial_addend;
  135. A += (int64)reloc_addend;
  136. if (symbol_index < 0) {
  137. /* Symbol address itself is an AOT function.
  138. * Apply relocation with the symbol directly.
  139. * Suppose the symbol address is in +-128MB relative
  140. * to the relocation address.
  141. */
  142. S = symbol_addr;
  143. }
  144. else {
  145. uint8 *plt;
  146. if (reloc_addend > 0) {
  147. set_error_buf(
  148. error_buf, error_buf_size,
  149. "AOT module load failed: relocate to plt table "
  150. "with reloc addend larger than 0 is unsupported.");
  151. return false;
  152. }
  153. /* Symbol address is not an AOT function,
  154. * but a function of runtime or native. Its address is
  155. * beyond of the +-128MB space. Apply relocation with
  156. * the PLT which branch to the target symbol address.
  157. */
  158. S = plt = (uint8 *)module->code + module->code_size
  159. - get_plt_table_size()
  160. + get_plt_item_size() * symbol_index;
  161. }
  162. /* S + A - P */
  163. X = (int64)S + A - (int64)P;
  164. /* Check overflow: +-128MB */
  165. if (X > (128 * BH_MB) || X < (-128 * BH_MB)) {
  166. set_error_buf(error_buf, error_buf_size,
  167. "AOT module load failed: "
  168. "target address out of range.");
  169. return false;
  170. }
  171. /* write the imm26 back to instruction */
  172. *(int32 *)P = (insn & 0xFC000000) | ((int32)((X >> 2) & 0x3FFFFFF));
  173. break;
  174. }
  175. case R_AARCH64_MOVW_UABS_G0:
  176. case R_AARCH64_MOVW_UABS_G0_NC:
  177. case R_AARCH64_MOVW_UABS_G1:
  178. case R_AARCH64_MOVW_UABS_G1_NC:
  179. case R_AARCH64_MOVW_UABS_G2:
  180. case R_AARCH64_MOVW_UABS_G2_NC:
  181. case R_AARCH64_MOVW_UABS_G3:
  182. {
  183. void *S = symbol_addr,
  184. *P = (void *)(target_section_addr + reloc_offset);
  185. int64 X, A, initial_addend;
  186. int32 insn, imm16;
  187. CHECK_RELOC_OFFSET(sizeof(int32));
  188. insn = *(int32 *)P;
  189. imm16 = (insn >> 5) & 0xFFFF;
  190. SIGN_EXTEND_TO_INT64(imm16, 16, initial_addend);
  191. A = initial_addend;
  192. A += (int64)reloc_addend;
  193. /* S + A */
  194. X = (int64)S + A;
  195. /* No need to check overflow for this relocation type */
  196. switch (reloc_type) {
  197. case R_AARCH64_MOVW_UABS_G0:
  198. if (X < 0 || X >= (1LL << 16))
  199. goto overflow_check_fail;
  200. break;
  201. case R_AARCH64_MOVW_UABS_G1:
  202. if (X < 0 || X >= (1LL << 32))
  203. goto overflow_check_fail;
  204. break;
  205. case R_AARCH64_MOVW_UABS_G2:
  206. if (X < 0 || X >= (1LL << 48))
  207. goto overflow_check_fail;
  208. break;
  209. default:
  210. break;
  211. }
  212. /* write the imm16 back to bits[5:20] of instruction */
  213. switch (reloc_type) {
  214. case R_AARCH64_MOVW_UABS_G0:
  215. case R_AARCH64_MOVW_UABS_G0_NC:
  216. *(int32 *)P =
  217. (insn & 0xFFE0001F) | ((int32)((X & 0xFFFF) << 5));
  218. break;
  219. case R_AARCH64_MOVW_UABS_G1:
  220. case R_AARCH64_MOVW_UABS_G1_NC:
  221. *(int32 *)P = (insn & 0xFFE0001F)
  222. | ((int32)(((X >> 16) & 0xFFFF) << 5));
  223. break;
  224. case R_AARCH64_MOVW_UABS_G2:
  225. case R_AARCH64_MOVW_UABS_G2_NC:
  226. *(int32 *)P = (insn & 0xFFE0001F)
  227. | ((int32)(((X >> 32) & 0xFFFF) << 5));
  228. break;
  229. case R_AARCH64_MOVW_UABS_G3:
  230. *(int32 *)P = (insn & 0xFFE0001F)
  231. | ((int32)(((X >> 48) & 0xFFFF) << 5));
  232. break;
  233. default:
  234. bh_assert(0);
  235. break;
  236. }
  237. break;
  238. }
  239. case R_AARCH64_ADR_PREL_PG_HI21:
  240. case R_AARCH64_ADR_PREL_PG_HI21_NC:
  241. {
  242. void *S = symbol_addr,
  243. *P = (void *)(target_section_addr + reloc_offset);
  244. int64 X, A, initial_addend;
  245. int32 insn, immhi19, immlo2, imm21;
  246. CHECK_RELOC_OFFSET(sizeof(int32));
  247. insn = *(int32 *)P;
  248. immhi19 = (insn >> 5) & 0x7FFFF;
  249. immlo2 = (insn >> 29) & 0x3;
  250. imm21 = (immhi19 << 2) | immlo2;
  251. SIGN_EXTEND_TO_INT64(imm21 << 12, 33, initial_addend);
  252. A = initial_addend;
  253. A += (int64)reloc_addend;
  254. /* Page(S+A) - Page(P) */
  255. X = Page((int64)S + A) - Page((int64)P);
  256. /* Check overflow: +-4GB */
  257. if (reloc_type == R_AARCH64_ADR_PREL_PG_HI21
  258. && (X > ((int64)4 * BH_GB) || X < ((int64)-4 * BH_GB)))
  259. goto overflow_check_fail;
  260. /* write the imm21 back to instruction */
  261. immhi19 = (int32)(((X >> 12) >> 2) & 0x7FFFF);
  262. immlo2 = (int32)((X >> 12) & 0x3);
  263. *(int32 *)P = (insn & 0x9F00001F) | (immlo2 << 29) | (immhi19 << 5);
  264. break;
  265. }
  266. case R_AARCH64_ADD_ABS_LO12_NC:
  267. {
  268. void *S = symbol_addr,
  269. *P = (void *)(target_section_addr + reloc_offset);
  270. int64 X, A, initial_addend;
  271. int32 insn, imm12;
  272. CHECK_RELOC_OFFSET(sizeof(int32));
  273. insn = *(int32 *)P;
  274. imm12 = (insn >> 10) & 0xFFF;
  275. SIGN_EXTEND_TO_INT64(imm12, 12, initial_addend);
  276. A = initial_addend;
  277. A += (int64)reloc_addend;
  278. /* S + A */
  279. X = (int64)S + A;
  280. /* No need to check overflow for this relocation type */
  281. /* write the imm12 back to instruction */
  282. *(int32 *)P = (insn & 0xFFC003FF) | ((int32)((X & 0xFFF) << 10));
  283. break;
  284. }
  285. case R_AARCH64_LDST8_ABS_LO12_NC:
  286. case R_AARCH64_LDST16_ABS_LO12_NC:
  287. case R_AARCH64_LDST32_ABS_LO12_NC:
  288. case R_AARCH64_LDST64_ABS_LO12_NC:
  289. case R_AARCH64_LDST128_ABS_LO12_NC:
  290. {
  291. void *S = symbol_addr,
  292. *P = (void *)(target_section_addr + reloc_offset);
  293. int64 X, A, initial_addend;
  294. int32 insn, imm12;
  295. CHECK_RELOC_OFFSET(sizeof(int32));
  296. insn = *(int32 *)P;
  297. imm12 = (insn >> 10) & 0xFFF;
  298. SIGN_EXTEND_TO_INT64(imm12, 12, initial_addend);
  299. A = initial_addend;
  300. A += (int64)reloc_addend;
  301. /* S + A */
  302. X = (int64)S + A;
  303. /* No need to check overflow for this relocation type */
  304. /* write the imm12 back to instruction */
  305. switch (reloc_type) {
  306. case R_AARCH64_LDST8_ABS_LO12_NC:
  307. *(int32 *)P =
  308. (insn & 0xFFC003FF) | ((int32)((X & 0xFFF) << 10));
  309. break;
  310. case R_AARCH64_LDST16_ABS_LO12_NC:
  311. *(int32 *)P = (insn & 0xFFC003FF)
  312. | ((int32)(((X & 0xFFF) >> 1) << 10));
  313. break;
  314. case R_AARCH64_LDST32_ABS_LO12_NC:
  315. *(int32 *)P = (insn & 0xFFC003FF)
  316. | ((int32)(((X & 0xFFF) >> 2) << 10));
  317. break;
  318. case R_AARCH64_LDST64_ABS_LO12_NC:
  319. *(int32 *)P = (insn & 0xFFC003FF)
  320. | ((int32)(((X & 0xFFF) >> 3) << 10));
  321. break;
  322. case R_AARCH64_LDST128_ABS_LO12_NC:
  323. *(int32 *)P = (insn & 0xFFC003FF)
  324. | ((int32)(((X & 0xFFF) >> 4) << 10));
  325. break;
  326. default:
  327. bh_assert(0);
  328. break;
  329. }
  330. break;
  331. }
  332. default:
  333. if (error_buf != NULL)
  334. snprintf(error_buf, error_buf_size,
  335. "Load relocation section failed: "
  336. "invalid relocation type %d.",
  337. reloc_type);
  338. return false;
  339. }
  340. return true;
  341. overflow_check_fail:
  342. set_error_buf(error_buf, error_buf_size,
  343. "AOT module load failed: "
  344. "target address out of range.");
  345. return false;
  346. }