aot_reloc_riscv.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. /*
  2. * Copyright (C) 2021 XiaoMi Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "aot_reloc.h"
  6. #define R_RISCV_32 1
  7. #define R_RISCV_64 2
  8. #define R_RISCV_CALL 18
  9. #define R_RISCV_CALL_PLT 19
  10. #define R_RISCV_PCREL_HI20 23
  11. #define R_RISCV_PCREL_LO12_I 24
  12. #define R_RISCV_PCREL_LO12_S 25
  13. #define R_RISCV_HI20 26
  14. #define R_RISCV_LO12_I 27
  15. #define R_RISCV_LO12_S 28
  16. #define RV_OPCODE_SW 0x23
  17. #undef NEED_SOFT_FP
  18. #undef NEED_SOFT_DP
  19. #undef NEED_SOFT_I32_MUL
  20. #undef NEED_SOFT_I32_DIV
  21. #undef NEED_SOFT_I64_MUL
  22. #undef NEED_SOFT_I64_DIV
  23. #undef NEED_SOFT_ATOMIC
  24. #ifdef __riscv_flen
  25. #if __riscv_flen == 32
  26. #define NEED_SOFT_DP
  27. #endif
  28. #else
  29. #define NEED_SOFT_FP
  30. #define NEED_SOFT_DP
  31. #endif
  32. #ifndef __riscv_mul
  33. #define NEED_SOFT_I32_MUL
  34. #define NEED_SOFT_I64_MUL
  35. #elif __riscv_xlen == 32
  36. #define NEED_SOFT_I64_MUL
  37. #endif
  38. #ifndef __riscv_div
  39. #define NEED_SOFT_I32_DIV
  40. #define NEED_SOFT_I64_DIV
  41. #elif __riscv_xlen == 32
  42. #define NEED_SOFT_I64_DIV
  43. #endif
  44. #ifndef __riscv_atomic
  45. #define NEED_SOFT_ATOMIC
  46. #endif
  47. /* clang-format off */
  48. void __adddf3(void);
  49. void __addsf3(void);
  50. void __divdf3(void);
  51. void __divdi3(void);
  52. void __divsf3(void);
  53. void __divsi3(void);
  54. void __eqdf2(void);
  55. void __eqsf2(void);
  56. void __extendsfdf2(void);
  57. void __fixdfdi(void);
  58. void __fixdfsi(void);
  59. void __fixsfdi(void);
  60. void __fixsfsi(void);
  61. void __fixunsdfdi(void);
  62. void __fixunsdfsi(void);
  63. void __fixunssfdi(void);
  64. void __fixunssfsi(void);
  65. void __floatdidf(void);
  66. void __floatdisf(void);
  67. void __floatsidf(void);
  68. void __floatsisf(void);
  69. void __floatundidf(void);
  70. void __floatundisf(void);
  71. void __floatunsidf(void);
  72. void __floatunsisf(void);
  73. void __gedf2(void);
  74. void __gesf2(void);
  75. void __gtdf2(void);
  76. void __gtsf2(void);
  77. void __ledf2(void);
  78. void __lesf2(void);
  79. void __ltdf2(void);
  80. void __ltsf2(void);
  81. void __moddi3(void);
  82. void __modsi3(void);
  83. void __muldf3(void);
  84. void __muldi3(void);
  85. void __mulsf3(void);
  86. void __mulsi3(void);
  87. void __nedf2(void);
  88. void __negdf2(void);
  89. void __negsf2(void);
  90. void __nesf2(void);
  91. void __subdf3(void);
  92. void __subsf3(void);
  93. void __truncdfsf2(void);
  94. void __udivdi3(void);
  95. void __udivsi3(void);
  96. void __umoddi3(void);
  97. void __umodsi3(void);
  98. void __unorddf2(void);
  99. void __unordsf2(void);
  100. bool __atomic_compare_exchange_4(volatile void *, void *, unsigned int,
  101. bool, int, int);
  102. void __atomic_store_4(volatile void *, unsigned int, int);
  103. /* clang-format on */
  104. static SymbolMap target_sym_map[] = {
  105. /* clang-format off */
  106. REG_COMMON_SYMBOLS
  107. #ifdef NEED_SOFT_FP
  108. REG_SYM(__addsf3),
  109. REG_SYM(__divsf3),
  110. REG_SYM(__eqsf2),
  111. REG_SYM(__fixsfdi),
  112. REG_SYM(__fixunssfdi),
  113. REG_SYM(__fixunssfsi),
  114. REG_SYM(__floatsidf),
  115. REG_SYM(__gesf2),
  116. REG_SYM(__gtsf2),
  117. REG_SYM(__lesf2),
  118. REG_SYM(__mulsf3),
  119. REG_SYM(__negsf2),
  120. REG_SYM(__nesf2),
  121. REG_SYM(__subsf3),
  122. REG_SYM(__unordsf2),
  123. #elif __riscv_xlen == 32
  124. /* rv32f, support FP instruction but need soft routines
  125. * to convert float and long long
  126. */
  127. REG_SYM(__floatundisf),
  128. REG_SYM(__floatdisf),
  129. #endif
  130. #ifdef NEED_SOFT_DP
  131. REG_SYM(__adddf3),
  132. REG_SYM(__divdf3),
  133. REG_SYM(__eqdf2),
  134. REG_SYM(__extendsfdf2),
  135. REG_SYM(__fixdfdi),
  136. REG_SYM(__fixdfsi),
  137. REG_SYM(__fixunsdfdi),
  138. REG_SYM(__fixunsdfsi),
  139. REG_SYM(__floatdidf),
  140. REG_SYM(__floatsidf),
  141. REG_SYM(__floatundidf),
  142. REG_SYM(__floatunsidf),
  143. REG_SYM(__gedf2),
  144. REG_SYM(__gtdf2),
  145. REG_SYM(__ledf2),
  146. REG_SYM(__ltdf2),
  147. REG_SYM(__muldf3),
  148. REG_SYM(__nedf2),
  149. REG_SYM(__negdf2),
  150. REG_SYM(__subdf3),
  151. REG_SYM(__truncdfsf2),
  152. REG_SYM(__unorddf2),
  153. #elif __riscv_xlen == 32
  154. /* rv32d, support DP instruction but need soft routines
  155. * to convert double and long long
  156. */
  157. REG_SYM(__fixdfdi),
  158. REG_SYM(__floatundidf),
  159. #endif
  160. #ifdef NEED_SOFT_I32_MUL
  161. REG_SYM(__mulsi3),
  162. #endif
  163. #ifdef NEED_SOFT_I32_DIV
  164. REG_SYM(__divsi3),
  165. REG_SYM(__modsi3),
  166. REG_SYM(__udivsi3),
  167. REG_SYM(__umodsi3),
  168. #endif
  169. #ifdef NEED_SOFT_I64_MUL
  170. REG_SYM(__muldi3),
  171. #endif
  172. #ifdef NEED_SOFT_I64_DIV
  173. REG_SYM(__divdi3),
  174. REG_SYM(__moddi3),
  175. REG_SYM(__udivdi3),
  176. REG_SYM(__umoddi3),
  177. #endif
  178. #ifdef NEED_SOFT_ATOMIC
  179. REG_SYM(__atomic_compare_exchange_4),
  180. REG_SYM(__atomic_store_4),
  181. #endif
  182. /* clang-format on */
  183. };
  184. static void
  185. set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
  186. {
  187. if (error_buf != NULL)
  188. snprintf(error_buf, error_buf_size, "%s", string);
  189. }
  190. void
  191. get_current_target(char *target_buf, uint32 target_buf_size)
  192. {
  193. snprintf(target_buf, target_buf_size, "riscv");
  194. }
  195. uint32
  196. get_plt_item_size(void)
  197. {
  198. #if __riscv_xlen == 64
  199. /* auipc + ld + jalr + nop + addr */
  200. return 20;
  201. #else
  202. return 0;
  203. #endif
  204. }
  205. SymbolMap *
  206. get_target_symbol_map(uint32 *sym_num)
  207. {
  208. *sym_num = sizeof(target_sym_map) / sizeof(SymbolMap);
  209. return target_sym_map;
  210. }
  211. /* Get a val from given address */
  212. static uint32
  213. rv_get_val(uint16 *addr)
  214. {
  215. uint32 ret;
  216. ret = *addr | (*(addr + 1)) << 16;
  217. return ret;
  218. }
  219. /* Set a val to given address */
  220. static void
  221. rv_set_val(uint16 *addr, uint32 val)
  222. {
  223. *addr = (val & 0xffff);
  224. *(addr + 1) = (val >> 16);
  225. #ifdef __riscv_zifencei
  226. __asm__ volatile("fence.i");
  227. #else
  228. __asm__ volatile("fence");
  229. #endif
  230. }
  231. /* Add a val to given address */
  232. static void
  233. rv_add_val(uint16 *addr, uint32 val)
  234. {
  235. uint32 cur = rv_get_val(addr);
  236. rv_set_val(addr, cur + val);
  237. }
  238. /**
  239. * Get imm_hi and imm_lo from given integer
  240. *
  241. * @param imm given integer, signed 32bit
  242. * @param imm_hi signed 20bit
  243. * @param imm_lo signed 12bit
  244. *
  245. */
  246. static void
  247. rv_calc_imm(int32 imm, int32 *imm_hi, int32 *imm_lo)
  248. {
  249. int32 lo;
  250. int32 hi = imm / 4096;
  251. int32 r = imm % 4096;
  252. if (2047 < r) {
  253. hi++;
  254. }
  255. else if (r < -2048) {
  256. hi--;
  257. }
  258. lo = imm - (hi * 4096);
  259. *imm_lo = lo;
  260. *imm_hi = hi;
  261. }
  262. uint32
  263. get_plt_table_size()
  264. {
  265. return get_plt_item_size() * (sizeof(target_sym_map) / sizeof(SymbolMap));
  266. }
  267. void
  268. init_plt_table(uint8 *plt)
  269. {
  270. #if __riscv_xlen == 64
  271. uint32 i, num = sizeof(target_sym_map) / sizeof(SymbolMap);
  272. uint8 *p;
  273. for (i = 0; i < num; i++) {
  274. p = plt;
  275. /* auipc t1, 0 */
  276. *(uint16 *)p = 0x0317;
  277. p += 2;
  278. *(uint16 *)p = 0x0000;
  279. p += 2;
  280. /* ld t1, 8(t1) */
  281. *(uint16 *)p = 0x3303;
  282. p += 2;
  283. *(uint16 *)p = 0x00C3;
  284. p += 2;
  285. /* jr t1 */
  286. *(uint16 *)p = 0x8302;
  287. p += 2;
  288. /* nop */
  289. *(uint16 *)p = 0x0001;
  290. p += 2;
  291. bh_memcpy_s(p, 8, &target_sym_map[i].symbol_addr, 8);
  292. p += 8;
  293. plt += get_plt_item_size();
  294. }
  295. #endif
  296. }
  297. typedef struct RelocTypeStrMap {
  298. uint32 reloc_type;
  299. char *reloc_str;
  300. } RelocTypeStrMap;
  301. #define RELOC_TYPE_MAP(reloc_type) \
  302. { \
  303. reloc_type, #reloc_type \
  304. }
  305. static RelocTypeStrMap reloc_type_str_maps[] = {
  306. RELOC_TYPE_MAP(R_RISCV_32), RELOC_TYPE_MAP(R_RISCV_64),
  307. RELOC_TYPE_MAP(R_RISCV_CALL), RELOC_TYPE_MAP(R_RISCV_CALL_PLT),
  308. RELOC_TYPE_MAP(R_RISCV_PCREL_HI20), RELOC_TYPE_MAP(R_RISCV_PCREL_LO12_I),
  309. RELOC_TYPE_MAP(R_RISCV_PCREL_LO12_S), RELOC_TYPE_MAP(R_RISCV_HI20),
  310. RELOC_TYPE_MAP(R_RISCV_LO12_I), RELOC_TYPE_MAP(R_RISCV_LO12_S),
  311. };
  312. static const char *
  313. reloc_type_to_str(uint32 reloc_type)
  314. {
  315. uint32 i;
  316. for (i = 0; i < sizeof(reloc_type_str_maps) / sizeof(RelocTypeStrMap);
  317. i++) {
  318. if (reloc_type_str_maps[i].reloc_type == reloc_type)
  319. return reloc_type_str_maps[i].reloc_str;
  320. }
  321. return "Unknown_Reloc_Type";
  322. }
  323. static bool
  324. check_reloc_offset(uint32 target_section_size, uint64 reloc_offset,
  325. uint32 reloc_data_size, char *error_buf,
  326. uint32 error_buf_size)
  327. {
  328. if (!(reloc_offset < (uint64)target_section_size
  329. && reloc_offset + reloc_data_size <= (uint64)target_section_size)) {
  330. set_error_buf(error_buf, error_buf_size,
  331. "AOT module load failed: invalid relocation offset.");
  332. return false;
  333. }
  334. return true;
  335. }
  336. bool
  337. apply_relocation(AOTModule *module, uint8 *target_section_addr,
  338. uint32 target_section_size, uint64 reloc_offset,
  339. int64 reloc_addend, uint32 reloc_type, void *symbol_addr,
  340. int32 symbol_index, char *error_buf, uint32 error_buf_size)
  341. {
  342. int32 val, imm_hi, imm_lo, insn;
  343. uint8 *addr = target_section_addr + reloc_offset;
  344. char buf[128];
  345. switch (reloc_type) {
  346. case R_RISCV_32:
  347. {
  348. uint32 val_32 =
  349. (uint32)((uintptr_t)symbol_addr + (intptr_t)reloc_addend);
  350. CHECK_RELOC_OFFSET(sizeof(uint32));
  351. if (val_32 != ((uintptr_t)symbol_addr + (intptr_t)reloc_addend)) {
  352. goto fail_addr_out_of_range;
  353. }
  354. rv_set_val((uint16 *)addr, val_32);
  355. break;
  356. }
  357. #if __riscv_xlen == 64
  358. case R_RISCV_64:
  359. {
  360. uint64 val_64 =
  361. (uint64)((intptr_t)symbol_addr + (intptr_t)reloc_addend);
  362. CHECK_RELOC_OFFSET(sizeof(uint64));
  363. if (val_64
  364. != (uint64)((intptr_t)symbol_addr + (intptr_t)reloc_addend)) {
  365. goto fail_addr_out_of_range;
  366. }
  367. bh_memcpy_s(addr, 8, &val_64, 8);
  368. #ifdef __riscv_zifencei
  369. __asm__ volatile("fence.i");
  370. #else
  371. __asm__ volatile("fence");
  372. #endif
  373. break;
  374. }
  375. #endif
  376. case R_RISCV_CALL:
  377. case R_RISCV_CALL_PLT:
  378. case R_RISCV_PCREL_HI20: /* S + A - P */
  379. {
  380. val = (int32)(intptr_t)((uint8 *)symbol_addr + reloc_addend - addr);
  381. CHECK_RELOC_OFFSET(sizeof(uint32));
  382. if (val != (intptr_t)((uint8 *)symbol_addr + reloc_addend - addr)) {
  383. if (symbol_index >= 0) {
  384. /* Call runtime function by plt code */
  385. symbol_addr = (uint8 *)module->code + module->code_size
  386. - get_plt_table_size()
  387. + get_plt_item_size() * symbol_index;
  388. val = (int32)(intptr_t)((uint8 *)symbol_addr - addr);
  389. }
  390. }
  391. if (val != (intptr_t)((uint8 *)symbol_addr + reloc_addend - addr)) {
  392. goto fail_addr_out_of_range;
  393. }
  394. rv_calc_imm(val, &imm_hi, &imm_lo);
  395. rv_add_val((uint16 *)addr, (imm_hi << 12));
  396. if ((rv_get_val((uint16 *)(addr + 4)) & 0x7f) == RV_OPCODE_SW) {
  397. /* Adjust imm for SW : S-type */
  398. val = (((int32)imm_lo >> 5) << 25)
  399. + (((int32)imm_lo & 0x1f) << 7);
  400. rv_add_val((uint16 *)(addr + 4), val);
  401. }
  402. else {
  403. /* Adjust imm for MV(ADDI)/JALR : I-type */
  404. rv_add_val((uint16 *)(addr + 4), ((int32)imm_lo << 20));
  405. }
  406. break;
  407. }
  408. case R_RISCV_HI20: /* S + A */
  409. {
  410. val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend);
  411. CHECK_RELOC_OFFSET(sizeof(uint32));
  412. if (val != ((intptr_t)symbol_addr + (intptr_t)reloc_addend)) {
  413. goto fail_addr_out_of_range;
  414. }
  415. insn = rv_get_val((uint16 *)addr);
  416. rv_calc_imm(val, &imm_hi, &imm_lo);
  417. insn = (insn & 0x00000fff) | (imm_hi << 12);
  418. rv_set_val((uint16 *)addr, insn);
  419. break;
  420. }
  421. case R_RISCV_PCREL_LO12_I: /* S - P */
  422. case R_RISCV_PCREL_LO12_S: /* S - P */
  423. {
  424. /* Already handled in R_RISCV_PCREL_HI20, it should be skipped for
  425. * most cases. But it is still needed for some special cases, e.g.
  426. * ```
  427. * label:
  428. * auipc t0, %pcrel_hi(symbol) # R_RISCV_PCREL_HI20 (symbol)
  429. * lui t1, 1
  430. * lw t2, t0, %pcrel_lo(label) # R_RISCV_PCREL_LO12_I (label)
  431. * add t2, t2, t1
  432. * sw t2, t0, %pcrel_lo(label) # R_RISCV_PCREL_LO12_S (label)
  433. * ```
  434. * In this case, the R_RISCV_PCREL_LO12_I/S relocation should be
  435. * handled after R_RISCV_PCREL_HI20 relocation.
  436. *
  437. * So, if the R_RISCV_PCREL_LO12_I/S relocation is not followed by
  438. * R_RISCV_PCREL_HI20 relocation, it should be handled here but
  439. * not implemented yet.
  440. */
  441. if ((uintptr_t)addr - (uintptr_t)symbol_addr
  442. - (uintptr_t)reloc_addend
  443. != 4) {
  444. goto fail_addr_out_of_range;
  445. }
  446. break;
  447. }
  448. case R_RISCV_LO12_I: /* S + A */
  449. {
  450. val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend);
  451. CHECK_RELOC_OFFSET(sizeof(uint32));
  452. if (val != (intptr_t)symbol_addr + (intptr_t)reloc_addend) {
  453. goto fail_addr_out_of_range;
  454. }
  455. addr = target_section_addr + reloc_offset;
  456. insn = rv_get_val((uint16 *)addr);
  457. rv_calc_imm(val, &imm_hi, &imm_lo);
  458. insn = (insn & 0x000fffff) | (imm_lo << 20);
  459. rv_set_val((uint16 *)addr, insn);
  460. break;
  461. }
  462. case R_RISCV_LO12_S:
  463. {
  464. val = (int32)((intptr_t)symbol_addr + (intptr_t)reloc_addend);
  465. CHECK_RELOC_OFFSET(sizeof(uint32));
  466. if (val != ((intptr_t)symbol_addr + (intptr_t)reloc_addend)) {
  467. goto fail_addr_out_of_range;
  468. }
  469. addr = target_section_addr + reloc_offset;
  470. rv_calc_imm(val, &imm_hi, &imm_lo);
  471. val = (((int32)imm_lo >> 5) << 25) + (((int32)imm_lo & 0x1f) << 7);
  472. rv_add_val((uint16 *)addr, val);
  473. break;
  474. }
  475. default:
  476. if (error_buf != NULL)
  477. snprintf(error_buf, error_buf_size,
  478. "Load relocation section failed: "
  479. "invalid relocation type %" PRIu32 ".",
  480. reloc_type);
  481. return false;
  482. }
  483. return true;
  484. fail_addr_out_of_range:
  485. snprintf(buf, sizeof(buf),
  486. "AOT module load failed: "
  487. "relocation truncated to fit %s failed.",
  488. reloc_type_to_str(reloc_type));
  489. set_error_buf(error_buf, error_buf_size, buf);
  490. return false;
  491. }