diff --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp --- a/lld/MachO/Arch/ARM64.cpp +++ b/lld/MachO/Arch/ARM64.cpp @@ -189,6 +189,7 @@ void applyAdrpAdd(const OptimizationHint &); void applyAdrpAdrp(const OptimizationHint &); void applyAdrpLdr(const OptimizationHint &); + void applyAdrpLdrGot(const OptimizationHint &); private: uint8_t *buf; @@ -424,6 +425,19 @@ writeLiteralLdr(buf + hint.offset0 + hint.delta[0], ldr, delta); } +// GOT loads are emitted by the compiler as a pair of adrp and ldr instructions, +// but they may be changed to adrp+add by relaxGotLoad(). This hint performs +// the AdrpLdr or AdrpAdd transformation depending on whether it was relaxed. +void OptimizationHintContext::applyAdrpLdrGot(const OptimizationHint &hint) { + uint32_t ins2 = read32le(buf + hint.offset0 + hint.delta[0]); + Add add; + Ldr ldr; + if (parseAdd(ins2, add)) + applyAdrpAdd(hint); + else if (parseLdr(ins2, ldr)) + applyAdrpLdr(hint); +} + void ARM64::applyOptimizationHints(uint8_t *buf, const ConcatInputSection *isec, ArrayRef relocTargets) const { assert(isec); @@ -452,7 +466,7 @@ ctx1.applyAdrpAdd(hint); break; case LOH_ARM64_ADRP_LDR_GOT: - // TODO: Implement this as well + ctx1.applyAdrpLdrGot(hint); break; } } diff --git a/lld/test/MachO/loh-adrp-ldr-got.s b/lld/test/MachO/loh-adrp-ldr-got.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/loh-adrp-ldr-got.s @@ -0,0 +1,35 @@ +# REQUIRES: aarch64 + +# RUN: rm -rf %t; split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/obj.s -o %t/obj.o +# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/dylib.s -o %t/dylib.o +# RUN: %lld -arch arm64 -dylib -o %t/libdylib.dylib %t/dylib.o +# RUN: %lld -arch arm64 %t/obj.o %t/libdylib.dylib -o %t/AdrpLdrGot +# RUN: llvm-objdump -d --macho %t/AdrpLdrGot | FileCheck %s + +#--- obj.s +.text +.globl _main +# CHECK-LABEL: _main: +_main: +## The referenced symbol is local +L1: adrp x0, _local@GOTPAGE +L2: ldr x0, [x0, _local@GOTPAGEOFF] +# CHECK-NEXT: adr x0 +# CHECK-NEXT: nop + +## The referenced symbol is in a dylib +L3: adrp x1, _external@GOTPAGE +L4: ldr x1, [x1, _external@GOTPAGEOFF] +# CHECK-NEXT: nop +# CHECK-NEXT: ldr x1 + +_local: + nop + +.loh AdrpLdrGot L1, L2 +.loh AdrpLdrGot L3, L4 + +#--- dylib.s +.globl _external +_external: