diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -506,6 +506,7 @@ size_t getRelativeRelocCount() const { return numRelativeRelocs; } void finalizeContents() override; int32_t dynamicTag, sizeDynamicTag; + bool aarch64VariantPcs; std::vector relocs; protected: diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1436,6 +1436,10 @@ case EM_SPARCV9: addInSec(DT_PLTGOT, in.plt); break; + case EM_AARCH64: + if (in.relaPlt->aarch64VariantPcs) + addInt(DT_AARCH64_VARIANT_PCS, 0); + LLVM_FALLTHROUGH; default: addInSec(DT_PLTGOT, in.gotPlt); break; @@ -1574,7 +1578,8 @@ int32_t dynamicTag, int32_t sizeDynamicTag) : SyntheticSection(SHF_ALLOC, type, config->wordsize, name), - dynamicTag(dynamicTag), sizeDynamicTag(sizeDynamicTag) {} + dynamicTag(dynamicTag), sizeDynamicTag(sizeDynamicTag), + aarch64VariantPcs(false) {} void RelocationBaseSection::addReloc(RelType dynType, InputSectionBase *isec, uint64_t offsetInSec, Symbol *sym) { @@ -1596,6 +1601,9 @@ void RelocationBaseSection::addReloc(const DynamicReloc &reloc) { if (reloc.type == target->relativeRel) ++numRelativeRelocs; + if (config->emachine == EM_AARCH64 && reloc.type == target->pltRel + && reloc.sym->stOther & STO_AARCH64_VARIANT_PCS) + aarch64VariantPcs = true; relocs.push_back(reloc); } @@ -2181,6 +2189,8 @@ // See getPPC64GlobalEntryToLocalEntryOffset() for more details. if (config->emachine == EM_PPC64) eSym->st_other |= sym->stOther & 0xe0; + else if (config->emachine == EM_AARCH64) + eSym->st_other |= sym->stOther & STO_AARCH64_VARIANT_PCS; eSym->st_name = ent.strTabOffset; if (isDefinedHere) diff --git a/lld/test/ELF/aarch64-variant_pcs-not-required.s b/lld/test/ELF/aarch64-variant_pcs-not-required.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/aarch64-variant_pcs-not-required.s @@ -0,0 +1,58 @@ +# 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 are exported and st_other it set correctly. +# PCSSYM: Symbol table '.dynsym' +# PCSSYM: {{0+}} 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] UND pcs_func_global_undef +# PCSSYM: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] 5 pcs_func_global_def +# PCSSYM: 0 IFUNC GLOBAL DEFAULT [VARIANT_PCS] 5 pcs_ifunc_global_def +# PCSSYM: Symbol table '.symtab' +# PCSSYM: 0 NOTYPE LOCAL DEFAULT [VARIANT_PCS] 5 pcs_func_local +# PCSSYM: 0 IFUNC LOCAL DEFAULT [VARIANT_PCS] 5 pcs_ifunc_local +# PCSSYM: 0 NOTYPE LOCAL HIDDEN [VARIANT_PCS] 5 pcs_func_global_hidden +# PCSSYM: 0 IFUNC LOCAL HIDDEN [VARIANT_PCS] 5 pcs_ifunc_global_hidden +# PCSSYM: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] 5 pcs_func_global_def +# PCSSYM: {{0+}} 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] UND pcs_func_global_undef +# PCSSYM: 0 IFUNC GLOBAL DEFAULT [VARIANT_PCS] 5 pcs_ifunc_global_def + +.text + +.global pcs_func_global_def +.global pcs_func_global_undef +.global pcs_func_global_hidden +.global pcs_ifunc_global_def +.global pcs_ifunc_global_hidden +.local pcs_func_local + +.hidden pcs_func_global_hidden +.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 create 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 diff --git a/lld/test/ELF/aarch64-variant_pcs.s b/lld/test/ELF/aarch64-variant_pcs.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/aarch64-variant_pcs.s @@ -0,0 +1,91 @@ +# 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 are exported and st_other it set correctly. +# PCSSYM: Symbol table '.dynsym' +# PCSSYM: {{0+}} 0 NOTYPE GLOBAL DEFAULT UND func_global_undef +# PCSSYM: {{0+}} 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] UND pcs_func_global_undef +# PCSSYM: 0 NOTYPE GLOBAL DEFAULT 7 func_global_def +# PCSSYM: 0 IFUNC GLOBAL DEFAULT 7 ifunc_global_def +# PCSSYM: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] 7 pcs_func_global_def +# PCSSYM: 0 IFUNC GLOBAL DEFAULT [VARIANT_PCS] 7 pcs_ifunc_global_def +# PCSSYM: Symbol table '.symtab' +# PCSSYM: 0 NOTYPE LOCAL DEFAULT [VARIANT_PCS] 7 pcs_func_local +# PCSSYM: 0 IFUNC LOCAL DEFAULT [VARIANT_PCS] 7 pcs_ifunc_local +# PCSSYM: 0 NOTYPE LOCAL HIDDEN 7 func_global_hidden +# PCSSYM: 0 IFUNC LOCAL HIDDEN 7 ifunc_global_hidden +# PCSSYM: 0 NOTYPE LOCAL HIDDEN [VARIANT_PCS] 7 pcs_func_global_hidden +# PCSSYM: 0 IFUNC LOCAL HIDDEN [VARIANT_PCS] 7 pcs_ifunc_global_hidden +# PCSSYM: 0 NOTYPE GLOBAL DEFAULT 7 func_global_def +# PCSSYM: {{0+}} 0 NOTYPE GLOBAL DEFAULT UND func_global_undef +# PCSSYM: 0 IFUNC GLOBAL DEFAULT 7 ifunc_global_def +# PCSSYM: 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] 7 pcs_func_global_def +# PCSSYM: {{0+}} 0 NOTYPE GLOBAL DEFAULT [VARIANT_PCS] UND pcs_func_global_undef +# PCSSYM: 0 IFUNC GLOBAL DEFAULT [VARIANT_PCS] 7 pcs_ifunc_global_def + +.text + +.global pcs_func_global_def +.global pcs_func_global_undef +.global pcs_func_global_hidden +.global pcs_ifunc_global_def +.global pcs_ifunc_global_hidden +.local pcs_func_local + +.hidden pcs_func_global_hidden +.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 +.global func_global_undef +.global func_global_hidden +.global ifunc_global_def +.global ifunc_global_hidden + +.hidden func_global_hidden +.hidden ifunc_global_hidden + +.type ifunc_global_def, %gnu_indirect_function +.type ifunc_global_hidden, %gnu_indirect_function + +# To avoid create 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