@@ -199,6 +199,9 @@ do_pseudo_reloc (void * start, void * end, void * base)
199199 ptrdiff_t reloc_target = (ptrdiff_t ) ((char *)end - (char *)start);
200200 runtime_pseudo_reloc_v2 *v2_hdr = (runtime_pseudo_reloc_v2 *) start;
201201 runtime_pseudo_reloc_item_v2 *r;
202+ #ifdef __aarch64__
203+ uint32_t opcode;
204+ #endif
202205
203206 /* A valid relocation list will contain at least one entry, and
204207 * one v1 data structure (the smallest one) requires two DWORDs.
@@ -307,6 +310,13 @@ do_pseudo_reloc (void * start, void * end, void * base)
307310 if ((reldata & 0x8000 ) != 0 )
308311 reldata |= ~((ptrdiff_t ) 0xffff );
309312 break ;
313+ #ifdef __aarch64__
314+ case 12 :
315+ case 21 :
316+ opcode = (*((unsigned int *)reloc_target));
317+ reldata = 0 ;
318+ break ;
319+ #endif
310320 case 32 :
311321 reldata = (ptrdiff_t ) (*((unsigned int *)reloc_target));
312322#if defined (__x86_64__) || defined (_WIN64)
@@ -339,6 +349,31 @@ do_pseudo_reloc (void * start, void * end, void * base)
339349 case 16 :
340350 __write_memory ((void *) reloc_target, &reldata, 2 );
341351 break ;
352+ #ifdef __aarch64__
353+ case 12 :
354+ /* Replace add Xn, Xn, :lo12:label with ldr Xn, [Xn, :lo12:__imp__func].
355+ That loads the address of _func into Xn. */
356+ opcode = 0xf9400000 | (opcode & 0x3ff ); // ldr
357+ reldata = ((ptrdiff_t ) base + r->sym ) & ((1 << 12 ) - 1 );
358+ reldata >>= 3 ;
359+ opcode |= reldata << 10 ;
360+ __write_memory ((void *) reloc_target, &opcode, 4 );
361+ break ;
362+ case 21 :
363+ /* Replace adrp Xn, label with adrp Xn, __imp__func. */
364+ opcode &= 0x9f00001f ;
365+ reldata = (((ptrdiff_t ) base + r->sym ) >> 12 )
366+ - (((ptrdiff_t ) base + r->target ) >> 12 );
367+ reldata &= (1 << 21 ) - 1 ;
368+ opcode |= (reldata & 3 ) << 29 ;
369+ reldata >>= 2 ;
370+ opcode |= reldata << 5 ;
371+ __write_memory ((void *) reloc_target, &opcode, 4 );
372+ break ;
373+ /* A note regarding 26 bits relocation.
374+ A single opcode is not sufficient for 26 bits relocation in dynamic linking.
375+ The linker generates a jump stub instead. */
376+ #endif
342377 case 32 :
343378#if defined (__CYGWIN__) && defined (__x86_64__)
344379 if (reldata > (ptrdiff_t ) __INT32_MAX__
0 commit comments