aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRadek Bartoň <radek.barton@microsoft.com>2025-07-19 19:17:12 +0200
committerJeremy Drake <cygwin@jdrake.com>2025-07-25 16:20:02 -0700
commitfaac5b9fa147f0415357b947c86dbe2e98ab91ac (patch)
treecb555194610a50302a7da1b5f08521b3b047840b
parent038afec1ef9e1f083fa23dea46a2304c260896da (diff)
downloadnewlib-master.zip
newlib-master.tar.gz
newlib-master.tar.bz2
Cygwin: mkimport: implement AArch64 +/-4GB relocationsHEADmastermain
Based on https://sourceware.org/pipermail/cygwin-patches/2025q3/014154.html suggestion, this patch implements +/-4GB relocations for AArch64 in the mkimport script by using adrp and ldr instructions. This change required update in winsup/cygwin/mm/malloc_wrapper.cc where those instructions are decoded to get target import address. Signed-off-by: Radek Bartoň <radek.barton@microsoft.com>
-rw-r--r--winsup/cygwin/mm/malloc_wrapper.cc34
-rwxr-xr-xwinsup/cygwin/scripts/mkimport7
2 files changed, 30 insertions, 11 deletions
diff --git a/winsup/cygwin/mm/malloc_wrapper.cc b/winsup/cygwin/mm/malloc_wrapper.cc
index 863d308..9444cb4 100644
--- a/winsup/cygwin/mm/malloc_wrapper.cc
+++ b/winsup/cygwin/mm/malloc_wrapper.cc
@@ -51,16 +51,32 @@ import_address (void *imp)
__try
{
#if defined(__aarch64__)
- // If opcode is an adr instruction.
- uint32_t opcode = *(uint32_t *) imp;
- if ((opcode & 0x9f000000) == 0x10000000)
+ /* If first three instructions of the imp are:
+ adrp x16, X
+ ldr x16, [x16, #:lo12:X]
+ br x16
+ References:
+ - https://www.scs.stanford.edu/~zyedidia/arm64/adrp.html
+ - https://www.scs.stanford.edu/~zyedidia/arm64/ldr_imm_gen.html
+ - https://www.scs.stanford.edu/~zyedidia/arm64/br.html
+ NOTE: This implementation assumes that the relocation table is made of
+ those specific AArch64 instructions as generated by the
+ winsup/cygwin/scripts/mkimport script. Please, keep it in sync. */
+ uint32_t opcode1 = *((uint32_t *) imp);
+ uint32_t opcode2 = *(((uint32_t *) imp) + 1);
+ uint32_t opcode3 = *(((uint32_t *) imp) + 2);
+ if (((opcode1 & 0x9f00001f) == 0x90000010) &&
+ ((opcode2 & 0xffc003ff) == 0xf9400210) &&
+ (opcode3 == 0xd61f0200))
{
- uint32_t immhi = (opcode >> 5) & 0x7ffff;
- uint32_t immlo = (opcode >> 29) & 0x3;
- int64_t sign_extend = (0l - (immhi >> 18)) << 21;
- int64_t imm = sign_extend | (immhi << 2) | immlo;
- uintptr_t jmpto = *(uintptr_t *) ((uint8_t *) imp + imm);
- return (void *) jmpto;
+ uint32_t immhi = (opcode1 >> 5) & 0x7ffff;
+ uint32_t immlo = (opcode1 >> 29) & 0x3;
+ uint32_t imm12 = ((opcode2 >> 10) & 0xfff) * 8; // 64 bit scale
+ int64_t sign_extend = (0l - ((int64_t) immhi >> 32)) << 33; // sign extend from 33 to 64 bits
+ int64_t imm = sign_extend | (((immhi << 2) | immlo) << 12);
+ int64_t base = (int64_t) imp & ~0xfff;
+ uintptr_t* jmpto = (uintptr_t *) (base + imm + imm12);
+ return (void *) *jmpto;
}
#else
if (*((uint16_t *) imp) == 0x25ff)
diff --git a/winsup/cygwin/scripts/mkimport b/winsup/cygwin/scripts/mkimport
index 0c1bcaf..5583099 100755
--- a/winsup/cygwin/scripts/mkimport
+++ b/winsup/cygwin/scripts/mkimport
@@ -73,8 +73,11 @@ EOF
.extern $imp_sym
.global $glob_sym
$glob_sym:
- adr x16, $imp_sym
- ldr x16, [x16]
+ # NOTE: Using instructions that are used by MSVC and LLVM. Binutils are
+ # using adrp/add/ldr-0-offset though. Please, keep it in sync with
+ # import_address implementation in winsup/cygwin/mm/malloc_wrapper.cc.
+ adrp x16, $imp_sym
+ ldr x16, [x16, #:lo12:$imp_sym]
br x16
EOF
} else {