Skip to content

Commit ffa34d5

Browse files
eukarpovjon-turney
authored andcommitted
Cygwin: aarch64: Add runtime pseudo relocation
The patch adds runtime pseudo relocation handling for 12-bit and 21-bit relocations. The 26-bit relocation is handled using a jump stub generated by the linker.
1 parent 1e463a9 commit ffa34d5

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed

winsup/cygwin/pseudo-reloc.cc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)