@@ -192,6 +192,79 @@ static SymbolMap target_sym_map[] = {
192192 /* clang-format on */
193193};
194194
195+ /*
196+ * Cache entries for matching R_RISCV_PCREL_HI20 with its corresponding
197+ * R_RISCV_PCREL_LO12_{I,S}. The relocation table is typically ordered by
198+ * increasing offset, so only a small number of "in-flight" HI20 entries are
199+ * expected at any moment; 8 is a conservative fixed bound.
200+ */
201+ #define PCREL_CACHE_SIZE 8
202+
203+ typedef struct {
204+ uintptr_t hi20_addr ;
205+ uintptr_t cached_offset ;
206+ } pcrel_cache_entry_t ;
207+
208+ static pcrel_cache_entry_t pcrel_cache [PCREL_CACHE_SIZE ];
209+ static int pcrel_cache_count = 0 ;
210+
211+ void
212+ aot_reloc_reset_cache (void )
213+ {
214+ int i ;
215+ for (i = 0 ; i < PCREL_CACHE_SIZE ; i ++ ) {
216+ pcrel_cache [i ].hi20_addr = 0 ;
217+ pcrel_cache [i ].cached_offset = 0 ;
218+ }
219+ pcrel_cache_count = 0 ;
220+ }
221+
222+ static bool
223+ add_hi20_to_cache (uintptr_t hi20_reloc_addr , uintptr_t hi20_offset )
224+ {
225+ int i ;
226+
227+ for (i = 0 ; i < PCREL_CACHE_SIZE ; i ++ ) {
228+ if (pcrel_cache [i ].hi20_addr == 0 ) {
229+ pcrel_cache [i ].hi20_addr = hi20_reloc_addr ;
230+ pcrel_cache [i ].cached_offset = hi20_offset ;
231+ pcrel_cache_count ++ ;
232+ return true;
233+ }
234+ }
235+
236+ return false;
237+ }
238+
239+ static uintptr_t
240+ find_hi20_in_cache (uintptr_t hi20_reloc_addr )
241+ {
242+ int i ;
243+
244+ for (i = 0 ; i < PCREL_CACHE_SIZE ; i ++ ) {
245+ if (pcrel_cache [i ].hi20_addr == hi20_reloc_addr ) {
246+ pcrel_cache [i ].hi20_addr = 0 ;
247+ pcrel_cache [i ].cached_offset = 0 ;
248+ pcrel_cache_count -- ;
249+ return pcrel_cache [i ].cached_offset ;
250+ }
251+ }
252+ return 0 ;
253+ }
254+
255+ static inline bool
256+ valid_hi20_imm (long imm_hi )
257+ {
258+ #if __riscv_xlen == 64
259+ long hi = imm_hi & ((1 << 20 ) - 1 );
260+ long sign = - ((imm_hi >> 19 ) & 1 );
261+ hi = ((hi << 12 ) | sign << 32 ) >> 12 ;
262+ return imm_hi == hi ;
263+ #else
264+ return true;
265+ #endif
266+ }
267+
195268static void
196269set_error_buf (char * error_buf , uint32 error_buf_size , const char * string )
197270{
@@ -257,17 +330,17 @@ rv_add_val(uint16 *addr, uint32 val)
257330/**
258331 * Get imm_hi and imm_lo from given integer
259332 *
260- * @param imm given integer, signed 32bit
333+ * @param imm given integer (intptr_t, 32-bit on RV32, 64-bit on RV64)
261334 * @param imm_hi signed 20bit
262335 * @param imm_lo signed 12bit
263336 *
264337 */
265338static void
266- rv_calc_imm (int32 imm , int32 * imm_hi , int32 * imm_lo )
339+ rv_calc_imm (intptr_t imm , int32 * imm_hi , int32 * imm_lo )
267340{
268- int32 lo ;
269- int32 hi = imm / 4096 ;
270- int32 r = imm % 4096 ;
341+ intptr_t lo ;
342+ intptr_t hi = imm / 4096 ;
343+ intptr_t r = imm % 4096 ;
271344
272345 if (2047 < r ) {
273346 hi ++ ;
@@ -278,8 +351,8 @@ rv_calc_imm(int32 imm, int32 *imm_hi, int32 *imm_lo)
278351
279352 lo = imm - (hi * 4096 );
280353
281- * imm_lo = lo ;
282- * imm_hi = hi ;
354+ * imm_lo = ( int32 ) lo ;
355+ * imm_hi = ( int32 ) hi ;
283356}
284357
285358uint32
@@ -325,10 +398,7 @@ typedef struct RelocTypeStrMap {
325398 char * reloc_str ;
326399} RelocTypeStrMap ;
327400
328- #define RELOC_TYPE_MAP (reloc_type ) \
329- { \
330- reloc_type, #reloc_type \
331- }
401+ #define RELOC_TYPE_MAP (reloc_type ) { reloc_type, #reloc_type }
332402
333403static RelocTypeStrMap reloc_type_str_maps [] = {
334404 RELOC_TYPE_MAP (R_RISCV_32 ), RELOC_TYPE_MAP (R_RISCV_64 ),
@@ -436,6 +506,21 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
436506
437507 rv_calc_imm (val , & imm_hi , & imm_lo );
438508
509+ if (reloc_type == R_RISCV_PCREL_HI20 ) {
510+ if (!valid_hi20_imm (imm_hi )) {
511+ set_error_buf (error_buf , error_buf_size ,
512+ "AOT module load failed: invalid HI20 "
513+ "immediate for RV64" );
514+ return false;
515+ }
516+ if (!add_hi20_to_cache ((uintptr_t )addr , (uintptr_t )val )) {
517+ set_error_buf (error_buf , error_buf_size ,
518+ "AOT module load failed: PCREL relocation "
519+ "cache overflow." );
520+ return false;
521+ }
522+ }
523+
439524 rv_add_val ((uint16 * )addr , (imm_hi << 12 ));
440525 if ((rv_get_val ((uint16 * )(addr + 4 )) & 0x7f ) == RV_OPCODE_SW ) {
441526 /* Adjust imm for SW : S-type */
@@ -453,15 +538,20 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
453538
454539 case R_RISCV_HI20 : /* S + A */
455540 {
456- val = (int32 )((intptr_t )symbol_addr + (intptr_t )reloc_addend );
457-
458541 CHECK_RELOC_OFFSET (sizeof (uint32 ));
459- if (val != ((intptr_t )symbol_addr + (intptr_t )reloc_addend )) {
460- goto fail_addr_out_of_range ;
542+
543+ intptr_t val = (intptr_t )symbol_addr + (intptr_t )reloc_addend ;
544+ int32_t imm_hi , imm_lo ;
545+ rv_calc_imm (val , & imm_hi , & imm_lo );
546+
547+ if (!valid_hi20_imm (imm_hi )) {
548+ set_error_buf (
549+ error_buf , error_buf_size ,
550+ "AOT module load failed: invalid HI20 immediate for RV64" );
551+ return false;
461552 }
462553
463554 insn = rv_get_val ((uint16 * )addr );
464- rv_calc_imm (val , & imm_hi , & imm_lo );
465555 insn = (insn & 0x00000fff ) | (imm_hi << 12 );
466556 rv_set_val ((uint16 * )addr , insn );
467557 break ;
@@ -470,62 +560,59 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr,
470560 case R_RISCV_PCREL_LO12_I : /* S - P */
471561 case R_RISCV_PCREL_LO12_S : /* S - P */
472562 {
473- /* Already handled in R_RISCV_PCREL_HI20, it should be skipped for
474- * most cases. But it is still needed for some special cases, e.g.
475- * ```
476- * label:
477- * auipc t0, %pcrel_hi(symbol) # R_RISCV_PCREL_HI20 (symbol)
478- * lui t1, 1
479- * lw t2, t0, %pcrel_lo(label) # R_RISCV_PCREL_LO12_I (label)
480- * add t2, t2, t1
481- * sw t2, t0, %pcrel_lo(label) # R_RISCV_PCREL_LO12_S (label)
482- * ```
483- * In this case, the R_RISCV_PCREL_LO12_I/S relocation should be
484- * handled after R_RISCV_PCREL_HI20 relocation.
485- *
486- * So, if the R_RISCV_PCREL_LO12_I/S relocation is not followed by
487- * R_RISCV_PCREL_HI20 relocation, it should be handled here but
488- * not implemented yet.
489- */
490-
491- if ((uintptr_t )addr - (uintptr_t )symbol_addr
492- - (uintptr_t )reloc_addend
493- != 4 ) {
494- goto fail_addr_out_of_range ;
563+ uintptr_t cached_offset ;
564+
565+ cached_offset = find_hi20_in_cache ((uintptr_t )addr - 4 );
566+
567+ if (cached_offset != 0 ) {
568+ val = (int32 )cached_offset ;
569+ }
570+ else {
571+ val = (int32 )(intptr_t )((uint8 * )symbol_addr + reloc_addend
572+ - addr - 4 );
573+ }
574+
575+ CHECK_RELOC_OFFSET (sizeof (uint32 ));
576+
577+ rv_calc_imm (val , & imm_hi , & imm_lo );
578+
579+ if (reloc_type == R_RISCV_PCREL_LO12_I ) {
580+ rv_add_val ((uint16 * )addr , ((int32 )imm_lo << 20 ));
581+ }
582+ else {
583+ val = (((int32 )imm_lo >> 5 ) << 25 )
584+ + (((int32 )imm_lo & 0x1f ) << 7 );
585+ rv_add_val ((uint16 * )addr , val );
495586 }
496587 break ;
497588 }
498589
499590 case R_RISCV_LO12_I : /* S + A */
500591 {
501-
502- val = (int32 )((intptr_t )symbol_addr + (intptr_t )reloc_addend );
503-
504592 CHECK_RELOC_OFFSET (sizeof (uint32 ));
505593
506- if (val != (intptr_t )symbol_addr + (intptr_t )reloc_addend ) {
507- goto fail_addr_out_of_range ;
508- }
509-
510594 addr = target_section_addr + reloc_offset ;
511595 insn = rv_get_val ((uint16 * )addr );
596+
597+ intptr_t val = (intptr_t )symbol_addr + (intptr_t )reloc_addend ;
598+ int32_t imm_hi , imm_lo ;
512599 rv_calc_imm (val , & imm_hi , & imm_lo );
600+
513601 insn = (insn & 0x000fffff ) | (imm_lo << 20 );
514602 rv_set_val ((uint16 * )addr , insn );
515603 break ;
516604 }
517605
518606 case R_RISCV_LO12_S :
519607 {
520- val = (int32 )((intptr_t )symbol_addr + (intptr_t )reloc_addend );
521-
522608 CHECK_RELOC_OFFSET (sizeof (uint32 ));
523- if (val != ((intptr_t )symbol_addr + (intptr_t )reloc_addend )) {
524- goto fail_addr_out_of_range ;
525- }
526609
527610 addr = target_section_addr + reloc_offset ;
611+
612+ intptr_t val = (intptr_t )symbol_addr + (intptr_t )reloc_addend ;
613+ int32_t imm_hi , imm_lo ;
528614 rv_calc_imm (val , & imm_hi , & imm_lo );
615+
529616 val = (((int32 )imm_lo >> 5 ) << 25 ) + (((int32 )imm_lo & 0x1f ) << 7 );
530617 rv_add_val ((uint16 * )addr , val );
531618 break ;
0 commit comments