| From b064bc18c30c334d3111c3db45b8d38ec35ad045 Mon Sep 17 00:00:00 2001 |
| From: Peter Collingbourne <peter@pcc.me.uk> |
| Date: Thu, 23 Jun 2022 21:47:14 -0700 |
| Subject: [PATCH] ELF: Do not relax ADRP/LDR -> ADRP/ADD for absolute symbols |
| in PIC. |
| |
| GOT references to absolute symbols can't be relaxed to use ADRP/ADD in |
| position-independent code because these instructions produce a relative |
| address. |
| |
| Differential Revision: https://reviews.llvm.org/D128492 |
| --- |
| lld/ELF/Arch/AArch64.cpp | 5 +++++ |
| lld/test/ELF/aarch64-adrp-ldr-got-symbols.s | 22 +++++++++++++++++++-- |
| 2 files changed, 25 insertions(+), 2 deletions(-) |
| |
| diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp |
| index 3b32ac56512..1949169d644 100644 |
| --- a/lld/ELF/Arch/AArch64.cpp |
| +++ b/lld/ELF/Arch/AArch64.cpp |
| @@ -693,6 +693,11 @@ bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel, |
| return false; |
| |
| Symbol &sym = *adrpRel.sym; |
| + // GOT references to absolute symbols can't be relaxed to use ADRP/ADD in |
| + // position-independent code because these instructions produce a relative |
| + // address. |
| + if (config->isPic && !cast<Defined>(sym).section) |
| + return false; |
| // Check if the address difference is within 4GB range. |
| int64_t val = |
| getAArch64Page(sym.getVA()) - getAArch64Page(secAddr + adrpRel.offset); |
| diff --git a/lld/test/ELF/aarch64-adrp-ldr-got-symbols.s b/lld/test/ELF/aarch64-adrp-ldr-got-symbols.s |
| index 145cf1c2ceb..3f2f4e953d7 100644 |
| --- a/lld/test/ELF/aarch64-adrp-ldr-got-symbols.s |
| +++ b/lld/test/ELF/aarch64-adrp-ldr-got-symbols.s |
| @@ -5,8 +5,9 @@ |
| # RUN: rm -rf %t && split-file %s %t |
| |
| # RUN: llvm-mc -filetype=obj -triple=aarch64 %t/symbols.s -o %t/symbols.o |
| +# RUN: llvm-mc -filetype=obj -triple=aarch64 %t/abs.s -o %t/abs.o |
| |
| -# RUN: ld.lld -shared -T %t/linker.t %t/symbols.o -o %t/symbols.so |
| +# RUN: ld.lld -shared -T %t/linker.t %t/symbols.o %t/abs.o -o %t/symbols.so |
| # RUN: llvm-objdump --no-show-raw-insn -d %t/symbols.so | \ |
| # RUN: FileCheck --check-prefix=LIB %s |
| |
| @@ -26,7 +27,11 @@ LIB-NEXT: ldr x2 |
| LIB-NEXT: adrp x3 |
| LIB-NEXT: ldr x3 |
| |
| -# RUN: ld.lld -T %t/linker.t -z undefs %t/symbols.o -o %t/symbols |
| +## Symbol 'abs_sym' is absolute, no relaxations should be applied. |
| +LIB-NEXT: adrp x4 |
| +LIB-NEXT: ldr x4 |
| + |
| +# RUN: ld.lld -T %t/linker.t -z undefs %t/symbols.o %t/abs.o -o %t/symbols |
| # RUN: llvm-objdump --no-show-raw-insn -d %t/symbols | \ |
| # RUN: FileCheck --check-prefix=EXE %s |
| |
| @@ -34,6 +39,10 @@ LIB-NEXT: ldr x3 |
| EXE: adrp x1 |
| EXE-NEXT: add x1 |
| |
| +## Symbol 'abs_sym' is absolute, relaxations may be applied in -no-pie mode. |
| +EXE: adrp x4 |
| +EXE-NEXT: add x4 |
| + |
| ## The linker script ensures that .rodata and .text are sufficiently (>1MB) |
| ## far apart so that the adrp + ldr pair cannot be relaxed to adr + nop. |
| #--- linker.t |
| @@ -42,6 +51,13 @@ SECTIONS { |
| .text 0x300100: { *(.text) } |
| } |
| |
| +# This symbol is defined in a separate file to prevent the definition from |
| +# being folded into the instructions that reference it. |
| +#--- abs.s |
| +.global abs_sym |
| +.hidden abs_sym |
| +abs_sym = 0x1000 |
| + |
| #--- symbols.s |
| .rodata |
| .hidden hidden_sym |
| @@ -68,3 +84,5 @@ _start: |
| ldr x2, [x2, #:got_lo12:undefined_sym] |
| adrp x3, :got:ifunc_sym |
| ldr x3, [x3, #:got_lo12:ifunc_sym] |
| + adrp x4, :got:abs_sym |
| + ldr x4, [x4, #:got_lo12:abs_sym] |
| -- |
| 2.37.0.170.g444d1eabd0-goog |
| |