Jon Turney <[email protected]> wrote: > Thanks! I applied this. > > I believe this file is also present in the MinGW-w64 runtime, so you > should submit this change to that project as well.
Thanks. Yes, there is a similar implementation in MinGW (not upstreamed yet). https://github.com/eukarpov/mingw-windows-arm64/commit/a7b86e4867d47434c00b1542a4219e8864acd71c Unfortunately the previous patch was incorrectly encoded. Here is the correct version. Regards, Evgeny
From: "Evgeny Karpov" <[email protected]> Subject: [PATCH] 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. --- winsup/cygwin/pseudo-reloc.cc | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/winsup/cygwin/pseudo-reloc.cc b/winsup/cygwin/pseudo-reloc.cc index 5a0eab936..fdc2a5d1b 100644 --- a/winsup/cygwin/pseudo-reloc.cc +++ b/winsup/cygwin/pseudo-reloc.cc @@ -199,6 +199,9 @@ do_pseudo_reloc (void * start, void * end, void * base) ptrdiff_t reloc_target = (ptrdiff_t) ((char *)end - (char*)start); runtime_pseudo_reloc_v2 *v2_hdr = (runtime_pseudo_reloc_v2 *) start; runtime_pseudo_reloc_item_v2 *r; +#ifdef __aarch64__ + uint32_t opcode; +#endif /* A valid relocation list will contain at least one entry, and * one v1 data structure (the smallest one) requires two DWORDs. @@ -307,6 +310,13 @@ do_pseudo_reloc (void * start, void * end, void * base) if ((reldata & 0x8000) != 0) reldata |= ~((ptrdiff_t) 0xffff); break; +#ifdef __aarch64__ + case 12: + case 21: + opcode = (*((unsigned int *)reloc_target)); + reldata = 0; + break; +#endif case 32: reldata = (ptrdiff_t) (*((unsigned int *)reloc_target)); #if defined (__x86_64__) || defined (_WIN64) @@ -339,6 +349,31 @@ do_pseudo_reloc (void * start, void * end, void * base) case 16: __write_memory ((void *) reloc_target, &reldata, 2); break; +#ifdef __aarch64__ + case 12: + /* Replace add Xn, Xn, :lo12:label with ldr Xn, [Xn, :lo12:__imp__func]. + That loads the address of _func into Xn. */ + opcode = 0xf9400000 | (opcode & 0x3ff); // ldr + reldata = ((ptrdiff_t) base + r->sym) & ((1 << 12) - 1); + reldata >>= 3; + opcode |= reldata << 10; + __write_memory ((void *) reloc_target, &opcode, 4); + break; + case 21: + /* Replace adrp Xn, label with adrp Xn, __imp__func. */ + opcode &= 0x9f00001f; + reldata = (((ptrdiff_t) base + r->sym) >> 12) + - (((ptrdiff_t) base + r->target) >> 12); + reldata &= (1 << 21) - 1; + opcode |= (reldata & 3) << 29; + reldata >>= 2; + opcode |= reldata << 5; + __write_memory ((void *) reloc_target, &opcode, 4); + break; + /* A note regarding 26 bits relocation. + A single opcode is not sufficient for 26 bits relocation in dynamic linking. + The linker generates a jump stub instead. */ +#endif case 32: #if defined (__CYGWIN__) && defined (__x86_64__) if (reldata > (ptrdiff_t) __INT32_MAX__ -- 2.39.5
