Index: lld/ELF/SyntheticSections.cpp =================================================================== --- lld/ELF/SyntheticSections.cpp +++ lld/ELF/SyntheticSections.cpp @@ -1436,6 +1436,13 @@ case EM_SPARCV9: addInSec(DT_PLTGOT, in.plt); break; + case EM_AARCH64: + if (llvm::find_if(in.relaPlt->relocs, [](const DynamicReloc &r) { + return r.type == target->pltRel && + r.sym->stOther & STO_AARCH64_VARIANT_PCS; + }) != in.relaPlt->relocs.end()) + addInt(DT_AARCH64_VARIANT_PCS, 0); + LLVM_FALLTHROUGH; default: addInSec(DT_PLTGOT, in.gotPlt); break; @@ -2181,6 +2188,10 @@ // See getPPC64GlobalEntryToLocalEntryOffset() for more details. if (config->emachine == EM_PPC64) eSym->st_other |= sym->stOther & 0xe0; + // The most significant bit of st_other is used by AArch64 ABI for the + // variant PCS. + else if (config->emachine == EM_AARCH64) + eSym->st_other |= sym->stOther & STO_AARCH64_VARIANT_PCS; eSym->st_name = ent.strTabOffset; if (isDefinedHere) Index: lld/test/ELF/aarch64-variant_pcs-not-required.s =================================================================== --- /dev/null +++ lld/test/ELF/aarch64-variant_pcs-not-required.s @@ -0,0 +1,54 @@ +# REQUIRES: aarch64 +# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o + +# RUN: ld.lld %t.o --shared --soname=t.so -o %t.so +# RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix PCSDYN %s +# RUN: llvm-readelf --symbols %t.so | FileCheck --check-prefix PCSSYM %s + +## Since there is no R_AARCH64_JMP_SLOT to ANY VARIANT_PCS there is no need +## to add a DT_AARCH64_VARIANT_PCS. +# PCSDYN-NOT: 0x0000000070000005 (AARCH64_VARIANT_PCS) 0 + +## Check if variant_pcs is exported and st_other is set correctly. +# PCSSYM: Symbol table '.dynsym' +# PCSSYM: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] UND pcs_func_global_undef +# PCSSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] [[#]] pcs_func_global_def +# PCSSYM-NEXT: 0 IFUNC GLOBAL DEFAULT [VARIANT_PCS] [[#]] pcs_ifunc_global_def +# PCSSYM: Symbol table '.symtab' +# PCSSYM: 0 NOTYPE LOCAL DEFAULT [VARIANT_PCS] [[#]] pcs_func_local +# PCSSYM-NEXT: 0 IFUNC LOCAL DEFAULT [VARIANT_PCS] [[#]] pcs_ifunc_local +# PCSSYM-NEXT: 0 NOTYPE LOCAL HIDDEN [VARIANT_PCS] [[#]] pcs_func_global_hidden +# PCSSYM-NEXT: 0 IFUNC LOCAL HIDDEN [VARIANT_PCS] [[#]] pcs_ifunc_global_hidden +# PCSSYM: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] [[#]] pcs_func_global_def +# PCSSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] UND pcs_func_global_undef +# PCSSYM-NEXT: 0 IFUNC GLOBAL DEFAULT [VARIANT_PCS] [[#]] pcs_ifunc_global_def + +.text + +.global pcs_func_global_def, pcs_func_global_undef, pcs_func_global_hidden +.global pcs_ifunc_global_def, pcs_ifunc_global_hidden +.local pcs_func_local + +.hidden pcs_func_global_hidden, pcs_ifunc_global_hidden + +.type pcs_ifunc_global_def, %gnu_indirect_function +.type pcs_ifunc_global_hidden, %gnu_indirect_function +.type pcs_ifunc_local, %gnu_indirect_function + +.variant_pcs pcs_func_global_def +.variant_pcs pcs_func_global_undef +.variant_pcs pcs_func_global_hidden +.variant_pcs pcs_func_local +.variant_pcs pcs_ifunc_global_def +.variant_pcs pcs_ifunc_global_hidden +.variant_pcs pcs_ifunc_local + +# To avoid creating multiple permutations, make all defined symbols branch +# to all symbols +pcs_func_global_def: +pcs_func_global_hidden: +pcs_func_local: +pcs_ifunc_global_def: +pcs_ifunc_global_hidden: +pcs_ifunc_local: + ret Index: lld/test/ELF/aarch64-variant_pcs.s =================================================================== --- /dev/null +++ lld/test/ELF/aarch64-variant_pcs.s @@ -0,0 +1,83 @@ +# REQUIRES: aarch64 +# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o + +# RUN: ld.lld %t.o --shared --soname=t.so -o %t.so +# RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix PCSDYN %s +# RUN: llvm-readelf --symbols %t.so | FileCheck --check-prefix PCSSYM %s + +# PCSDYN: 0x0000000070000005 (AARCH64_VARIANT_PCS) 0 + +## Check if variant_pcs is exported and st_other is set correctly. +# PCSSYM: Symbol table '.dynsym' +# PCSSYM: 0 NOTYPE GLOBAL DEFAULT UND func_global_undef +# PCSSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] UND pcs_func_global_undef +# PCSSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT [[#]] func_global_def +# PCSSYM-NEXT: 0 IFUNC GLOBAL DEFAULT [[#]] ifunc_global_def +# PCSSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] [[#]] pcs_func_global_def +# PCSSYM-NEXT: 0 IFUNC GLOBAL DEFAULT [VARIANT_PCS] [[#]] pcs_ifunc_global_def +# PCSSYM: Symbol table '.symtab' +# PCSSYM: 0 NOTYPE LOCAL DEFAULT [VARIANT_PCS] [[#]] pcs_func_local +# PCSSYM-NEXT: 0 IFUNC LOCAL DEFAULT [VARIANT_PCS] [[#]] pcs_ifunc_local +# PCSSYM-NEXT: 0 NOTYPE LOCAL HIDDEN [[#]] func_global_hidden +# PCSSYM-NEXT: 0 IFUNC LOCAL HIDDEN [[#]] ifunc_global_hidden +# PCSSYM-NEXT: 0 NOTYPE LOCAL HIDDEN [VARIANT_PCS] [[#]] pcs_func_global_hidden +# PCSSYM-NEXT: 0 IFUNC LOCAL HIDDEN [VARIANT_PCS] [[#]] pcs_ifunc_global_hidden +# PCSSYM: 0 NOTYPE GLOBAL DEFAULT [[#]] func_global_def +# PCSSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT UND func_global_undef +# PCSSYM-NEXT: 0 IFUNC GLOBAL DEFAULT [[#]] ifunc_global_def +# PCSSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] [[#]] pcs_func_global_def +# PCSSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] UND pcs_func_global_undef +# PCSSYM-NEXT: 0 IFUNC GLOBAL DEFAULT [VARIANT_PCS] [[#]] pcs_ifunc_global_def + +.text + +.global pcs_func_global_def, pcs_func_global_undef, pcs_func_global_hidden +.global pcs_ifunc_global_def, pcs_ifunc_global_hidden +.local pcs_func_local + +.hidden pcs_func_global_hidden, pcs_ifunc_global_hidden + +.type pcs_ifunc_global_def, %gnu_indirect_function +.type pcs_ifunc_global_hidden, %gnu_indirect_function +.type pcs_ifunc_local, %gnu_indirect_function + +.variant_pcs pcs_func_global_def +.variant_pcs pcs_func_global_undef +.variant_pcs pcs_func_global_hidden +.variant_pcs pcs_func_local +.variant_pcs pcs_ifunc_global_def +.variant_pcs pcs_ifunc_global_hidden +.variant_pcs pcs_ifunc_local + +.global func_global_def, func_global_undef, func_global_hidden, ifunc_global_def +.global ifunc_global_hidden + +.hidden func_global_hidden, ifunc_global_hidden + +.type ifunc_global_def, %gnu_indirect_function +.type ifunc_global_hidden, %gnu_indirect_function + +# To avoid creating multiple permutations, make all defined symbols branch +# to all symbols +pcs_func_global_def: +pcs_func_global_hidden: +pcs_func_local: +pcs_ifunc_global_def: +pcs_ifunc_global_hidden: +pcs_ifunc_local: +func_global_def: +func_global_hidden: +ifunc_global_def: +ifunc_global_hidden: + bl pcs_func_global_def + bl pcs_func_global_undef + bl pcs_func_global_hidden + bl pcs_func_local + bl pcs_ifunc_global_def + bl pcs_ifunc_global_hidden + bl pcs_ifunc_local + bl func_global_def + bl func_global_undef + bl func_global_hidden + bl ifunc_global_def + bl ifunc_global_hidden