Index: lld/ELF/Arch/AArch64.cpp =================================================================== --- lld/ELF/Arch/AArch64.cpp +++ lld/ELF/Arch/AArch64.cpp @@ -912,7 +912,8 @@ // escape to shared objects. isInIplt indicates a non-preemptible ifunc. Its // address may escape if referenced by a direct relocation. The condition is // conservative. - bool hasBti = btiHeader && (sym.hasFlag(NEEDS_COPY) || sym.isInIplt); + bool hasBti = btiHeader && + (sym.hasFlag(NEEDS_COPY) || sym.isInIplt || sym.thunkAccessed); if (hasBti) { memcpy(buf, btiData, sizeof(btiData)); buf += sizeof(btiData); Index: lld/ELF/Symbols.h =================================================================== --- lld/ELF/Symbols.h +++ lld/ELF/Symbols.h @@ -292,6 +292,9 @@ // True if defined in a DSO as protected visibility. uint8_t dsoProtected : 1; + // True if targeted by a range extension thunk. + uint8_t thunkAccessed : 1; + // Temporary flags used to communicate which symbol entries need PLT and GOT // entries during postScanRelocations(); std::atomic flags; Index: lld/ELF/Thunks.cpp =================================================================== --- lld/ELF/Thunks.cpp +++ lld/ELF/Thunks.cpp @@ -1134,7 +1134,9 @@ return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14; } -Thunk::Thunk(Symbol &d, int64_t a) : destination(d), addend(a), offset(0) {} +Thunk::Thunk(Symbol &d, int64_t a) : destination(d), addend(a), offset(0) { + destination.thunkAccessed = true; +} Thunk::~Thunk() = default; Index: lld/test/ELF/aarch64-feature-bti-plt.s =================================================================== --- /dev/null +++ lld/test/ELF/aarch64-feature-bti-plt.s @@ -0,0 +1,57 @@ +# REQUIRES: aarch64 + +# RUN: rm -rf %t && split-file %s %t + +# RUN: llvm-mc --triple=aarch64 --filetype=obj -o %t.o %t/a.s +# RUN: ld.lld --shared -T %t/largegap.lds -z force-bti %t.o -o %t.elf +# RUN: llvm-objdump -d %t.elf | FileCheck %s + +## Range extension thunk is inserted to reach the PLT of foo. +## The PLT must start with a bti c instruction due to the indirect +## call from the range extension thunk. Previously the call to the +## PLT was direct so no bti was required. + +#--- largegap.lds +SECTIONS { + .plt : { *(.plt) } + .text.near 0x1000 : AT(0x1000) { *(.text.near) } + .text.far 0xf0000000 : AT(0xf0000000) { *(.text.far) } +} + +#--- a.s +# CHECK: <.plt>: +# CHECK-NEXT: bti c + +# CHECK: : +# CHECK-NEXT: bti c + +# biz is directly called, so no need for bti c +# CHECK: : +# CHECK-NEXT: adrp x16, {{.*}} + +# CHECK: : +# CHECK-NEXT: bl {{.*}} +# CHECK-NEXT: bl {{.*}} + +# CHECK: : +# CHECK-NEXT: bl {{.*}} <__AArch64ADRPThunk_foo> + +# CHECK: <__AArch64ADRPThunk_foo>: +# CHECK-NEXT: adrp x16, 0x0 +# CHECK-NEXT: add x16, x16, {{.*}} +# CHECK-NEXT: br x16 + + .global foo + .global biz + .section .text.near, "ax", %progbits +bar: + .type bar, %function + bl foo + bl biz + ret + + .section .text.far, "ax", %progbits +func: + .type func, %function + bl foo + ret