}
namespace {
-class AArch64 final : public TargetInfo {
+class AArch64 : public TargetInfo {
public:
AArch64();
RelExpr getRelExpr(RelType Type, const Symbol &S,
llvm_unreachable("invalid relocation for TLS IE to LE relaxation");
}
-TargetInfo *elf::getAArch64TargetInfo() {
- static AArch64 Target;
- return &Target;
+// AArch64 may use security features in variant PLT sequences. These are:
+// Pointer Authentication (PAC), introduced in armv8.3-a and Branch Target
+// Indicator (BTI) introduced in armv8.5-a. The additional instructions used
+// in the variant Plt sequences are encoded in the Hint space so they can be
+// deployed on older architectures, which treat the instructions as a nop.
+// PAC and BTI can be combined leading to the following combinations:
+// writePltHeader
+// writePltHeaderBti (no PAC Header needed)
+// writePlt
+// writePltBti (BTI only)
+// writePltPac (PAC only)
+// writePltBtiPac (BTI and PAC)
+//
+// When PAC is enabled the dynamic loader encrypts the address that it places
+// in the .got.plt using the pacia1716 instruction which encrypts the value in
+// x17 using the modifier in x16. The static linker places autia1716 before the
+// indirect branch to x17 to authenticate the address in x17 with the modifier
+// in x16. This makes it more difficult for an attacker to modify the value in
+// the .got.plt.
+//
+// When BTI is enabled all indirect branches must land on a bti instruction.
+// The static linker must place a bti instruction at the start of any PLT entry
+// that may be the target of an indirect branch. As the PLT entries call the
+// lazy resolver indirectly this must have a bti instruction at start. In
+// general a bti instruction is not needed for a PLT entry as indirect calls
+// are resolved to the function address and not the PLT entry for the function.
+// There are a small number of cases where the PLT address can escape, such as
+// taking the address of a function or ifunc via a non got-generating
+// relocation, and a shared library refers to that symbol.
+//
+// We use the bti c variant of the instruction which permits indirect branches
+// (br) via x16/x17 and indirect function calls (blr) via any register. The ABI
+// guarantees that all indirect branches from code requiring BTI protection
+// will go via x16/x17
+
+namespace {
+class AArch64BtiPac final : public AArch64 {
+public:
+ AArch64BtiPac();
+ void writePltHeader(uint8_t *Buf) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+ int32_t Index, unsigned RelOff) const override;
+
+private:
+ bool BtiHeader; // bti instruction needed in PLT Header
+ bool BtiEntry; // bti instruction needed in PLT Entry
+ bool PacEntry; // autia1716 instruction needed in PLT Entry
+};
+} // namespace
+
+AArch64BtiPac::AArch64BtiPac() {
+ BtiHeader = (Config->AndFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI);
+ // A BTI (Branch Target Indicator) Plt Entry is only required if the
+ // address of the PLT entry can be taken by the program, which permits an
+ // indirect jump to the PLT entry. This can happen when the address
+ // of the PLT entry for a function is canonicalised due to the address of
+ // the function in an executable being taken by a shared library.
+ // FIXME: There is a potential optimization to omit the BTI if we detect
+ // that the address of the PLT entry isn't taken.
+ BtiEntry = BtiHeader && !Config->Shared;
+ PacEntry = (Config->AndFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_PAC);
+
+ if (BtiEntry || PacEntry)
+ PltEntrySize = 24;
}
+
+void AArch64BtiPac::writePltHeader(uint8_t *Buf) const {
+ const uint8_t BtiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c
+ const uint8_t PltData[] = {
+ 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]!
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2]))
+ 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))]
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2]))
+ 0x20, 0x02, 0x1f, 0xd6, // br x17
+ 0x1f, 0x20, 0x03, 0xd5, // nop
+ 0x1f, 0x20, 0x03, 0xd5 // nop
+ };
+ const uint8_t NopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop
+
+ uint64_t Got = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
+
+ if (BtiHeader) {
+ // PltHeader is called indirectly by Plt[N]. Prefix PltData with a BTI C
+ // instruction.
+ memcpy(Buf, BtiData, sizeof(BtiData));
+ Buf += sizeof(BtiData);
+ Plt += sizeof(BtiData);
+ }
+ memcpy(Buf, PltData, sizeof(PltData));
+
+ relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
+ getAArch64Page(Got + 16) - getAArch64Page(Plt + 8));
+ relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
+ relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16);
+ if (!BtiHeader)
+ // We didn't add the BTI c instruction so round out size with NOP.
+ memcpy(Buf + sizeof(PltData), NopData, sizeof(NopData));
+}
+
+void AArch64BtiPac::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ // The PLT entry is of the form:
+ // [BtiData] AddrInst (PacBr | StdBr) [NopData]
+ const uint8_t BtiData[] = { 0x5f, 0x24, 0x03, 0xd5 }; // bti c
+ const uint8_t AddrInst[] = {
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n]))
+ 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))]
+ 0x10, 0x02, 0x00, 0x91 // add x16, x16, Offset(&(.plt.got[n]))
+ };
+ const uint8_t PacBr[] = {
+ 0x9f, 0x21, 0x03, 0xd5, // autia1716
+ 0x20, 0x02, 0x1f, 0xd6 // br x17
+ };
+ const uint8_t StdBr[] = {
+ 0x20, 0x02, 0x1f, 0xd6, // br x17
+ 0x1f, 0x20, 0x03, 0xd5 // nop
+ };
+ const uint8_t NopData[] = { 0x1f, 0x20, 0x03, 0xd5 }; // nop
+
+ if (BtiEntry) {
+ memcpy(Buf, BtiData, sizeof(BtiData));
+ Buf += sizeof(BtiData);
+ PltEntryAddr += sizeof(BtiData);
+ }
+
+ memcpy(Buf, AddrInst, sizeof(AddrInst));
+ relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
+ getAArch64Page(GotPltEntryAddr) -
+ getAArch64Page(PltEntryAddr));
+ relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr);
+ relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr);
+
+ if (PacEntry)
+ memcpy(Buf + sizeof(AddrInst), PacBr, sizeof(PacBr));
+ else
+ memcpy(Buf + sizeof(AddrInst), StdBr, sizeof(StdBr));
+ if (!BtiEntry)
+ // We didn't add the BTI c instruction so round out size with NOP.
+ memcpy(Buf + sizeof(AddrInst) + sizeof(StdBr), NopData, sizeof(NopData));
+}
+
+static TargetInfo *getTargetInfo() {
+ if (Config->AndFeatures & (GNU_PROPERTY_AARCH64_FEATURE_1_BTI |
+ GNU_PROPERTY_AARCH64_FEATURE_1_PAC)) {
+ static AArch64BtiPac T;
+ return &T;
+ }
+ static AArch64 T;
+ return &T;
+}
+
+TargetInfo *elf::getAArch64TargetInfo() { return getTargetInfo(); }
bool ExecuteOnly;
bool ExportDynamic;
bool FixCortexA53Errata843419;
+ bool ForceBTI;
bool FormatBinary = false;
bool RequireCET;
bool GcSections;
bool OFormatBinary;
bool Omagic;
bool OptRemarksWithHotness;
+ bool PacPlt;
bool PicThunk;
bool Pie;
bool PrintGcSections;
if (Config->ZRetpolineplt && Config->RequireCET)
error("--require-cet may not be used with -z retpolineplt");
+
+ if (Config->EMachine != EM_AARCH64) {
+ if (Config->PacPlt)
+ error("--pac-plt only supported on AArch64");
+ if (Config->ForceBTI)
+ error("--force-bti only supported on AArch64");
+ }
}
static const char *getReproduceOption(opt::InputArgList &Args) {
Config->FilterList = args::getStrings(Args, OPT_filter);
Config->Fini = Args.getLastArgValue(OPT_fini, "_fini");
Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419);
+ Config->ForceBTI = Args.hasArg(OPT_force_bti);
Config->RequireCET = Args.hasArg(OPT_require_cet);
Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false);
Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true);
Config->Optimize = args::getInteger(Args, OPT_O, 1);
Config->OrphanHandling = getOrphanHandling(Args);
Config->OutputFile = Args.getLastArgValue(OPT_o);
+ Config->PacPlt = Args.hasArg(OPT_pac_plt);
Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false);
Config->PrintIcfSections =
Args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
// with CET.
//
// This function returns the merged feature flags. If 0, we cannot enable CET.
+// This is also the case with AARCH64's BTI and PAC which use the similar
+// GNU_PROPERTY_AARCH64_FEATURE_1_AND mechanism.
//
// Note that the CET-aware PLT is not implemented yet. We do error
// check only.
template <class ELFT> static uint32_t getAndFeatures() {
- if (Config->EMachine != EM_386 && Config->EMachine != EM_X86_64)
+ if (Config->EMachine != EM_386 && Config->EMachine != EM_X86_64 &&
+ Config->EMachine != EM_AARCH64)
return 0;
uint32_t Ret = -1;
for (InputFile *F : ObjectFiles) {
uint32_t Features = cast<ObjFile<ELFT>>(F)->AndFeatures;
- if (!Features && Config->RequireCET)
+ if (Config->ForceBTI && !(Features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) {
+ warn(toString(F) + ": --force-bti: file does not have BTI property");
+ Features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
+ } else if (!Features && Config->RequireCET)
error(toString(F) + ": --require-cet: file is not compatible with CET");
Ret &= Features;
}
+
+ // Force enable pointer authentication Plt, we don't warn in this case as
+ // this does not require support in the object for correctness.
+ if (Config->PacPlt)
+ Ret |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC;
+
return Ret;
}
// contain a hint to tweak linker's and loader's behaviors.
Config->AndFeatures = getAndFeatures<ELFT>();
+ // The Target instance handles target-specific stuff, such as applying
+ // relocations or writing a PLT section. It also contains target-dependent
+ // values such as a default image base address.
+ Target = getTarget();
+
Config->EFlags = Target->calcEFlags();
// MaxPageSize (sometimes called abi page size) is the maximum page size that
// the output can be run on. For example if the OS can use 4k or 64k page
continue;
}
+ uint32_t FeatureAndType = Config->EMachine == EM_AARCH64
+ ? GNU_PROPERTY_AARCH64_FEATURE_1_AND
+ : GNU_PROPERTY_X86_FEATURE_1_AND;
+
// Read a body of a NOTE record, which consists of type-length-value fields.
ArrayRef<uint8_t> Desc = Note.getDesc();
while (!Desc.empty()) {
uint32_t Type = read32le(Desc.data());
uint32_t Size = read32le(Desc.data() + 4);
- if (Type == GNU_PROPERTY_X86_FEATURE_1_AND) {
+ if (Type == FeatureAndType) {
// We found a FEATURE_1_AND field. There may be more than one of these
// in a .note.gnu.propery section, for a relocatable object we
// accumulate the bits set.
if (Name == ".note.GNU-stack")
return &InputSection::Discarded;
- // If an object file is compatible with Intel Control-Flow Enforcement
- // Technology (CET), it has a .note.gnu.property section containing the
+ // Object files that use processor features such as Intel Control-Flow
+ // Enforcement (CET) or AArch64 Branch Target Identification BTI, use a
+ // .note.gnu.property section containing a bitfield of feature bits like the
// GNU_PROPERTY_X86_FEATURE_1_IBT flag. Read a bitmap containing the flag.
//
// Since we merge bitmaps from multiple object files to create a new
// is not complete.
def require_cet: F<"require-cet">;
+def force_bti: F<"force-bti">,
+ HelpText<"Force enable AArch64 BTI in PLT, warn if Input ELF file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property">;
+
defm format: Eq<"format", "Change the input format of the inputs following this option">,
MetaVarName<"[default,elf,binary]">;
Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">,
MetaVarName<"[none,android,relr,android+relr]">;
+def pac_plt: F<"pac-plt">,
+ HelpText<"AArch64 only, use pointer authentication in PLT">;
+
defm use_android_relr_tags: B<"use-android-relr-tags",
"Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*",
"Use SHT_RELR / DT_RELR* tags (default)">;
// This class represents a linker-synthesized .note.gnu.property section.
//
-// In x86, object files may contain feature flags indicating the features that
-// they are using. The flags are stored in a .note.gnu.property section.
+// In x86 and AArch64, object files may contain feature flags indicating the
+// features that they have used. The flags are stored in a .note.gnu.property
+// section.
//
// lld reads the sections from input files and merges them by computing AND of
// the flags. The result is written as a new .note.gnu.property section.
".note.gnu.property") {}
void GnuPropertySection::writeTo(uint8_t *Buf) {
+ uint32_t FeatureAndType = Config->EMachine == EM_AARCH64
+ ? GNU_PROPERTY_AARCH64_FEATURE_1_AND
+ : GNU_PROPERTY_X86_FEATURE_1_AND;
+
write32(Buf, 4); // Name size
write32(Buf + 4, Config->Is64 ? 16 : 12); // Content size
write32(Buf + 8, NT_GNU_PROPERTY_TYPE_0); // Type
memcpy(Buf + 12, "GNU", 4); // Name string
- write32(Buf + 16, GNU_PROPERTY_X86_FEATURE_1_AND); // Feature type
+ write32(Buf + 16, FeatureAndType); // Feature type
write32(Buf + 20, 4); // Feature size
write32(Buf + 24, Config->AndFeatures); // Feature flags
if (Config->Is64)
addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL);
}
+ if (Config->EMachine == EM_AARCH64) {
+ if (Config->AndFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
+ addInt(DT_AARCH64_BTI_PLT, 0);
+ if (Config->AndFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_PAC)
+ addInt(DT_AARCH64_PAC_PLT, 0);
+ }
+
addInSec(DT_SYMTAB, In.DynSymTab);
addInt(DT_SYMENT, sizeof(Elf_Sym));
addInSec(DT_STRTAB, In.DynStrTab);
field to the specified value.
.It Fl -fini Ns = Ns Ar symbol
Specify a finalizer function.
+.It Fl -force-bti
+Force enable AArch64 BTI instruction in PLT, warn if Input ELF file does not have GNU_PROPERTY_AARCH64_FEATURE_1_BTI property.
.It Fl -format Ns = Ns Ar input-format , Fl b Ar input-format
Specify the format of the inputs following this option.
.Ar input-format
.Fl -use-android-relr-tags
is specified, use SHT_ANDROID_RELR instead of SHT_RELR.
.Pp
+.It Fl -pac-plt
+AArch64 only, use pointer authentication in PLT.
.It Fl -pic-veneer
Always generate position independent thunks.
.It Fl -pie , Fl -pic-executable
--- /dev/null
+ .text
+ .globl myfunc
+ .globl func1
+ .type func1, %function
+func1:
+ adrp x8, :got: myfunc
+ ldr x8, [x8, :got_lo12: myfunc]
+ ret
--- /dev/null
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+.long 0
+
+.text
+.globl func2
+.type func2,@function
+func2:
+ .globl func3
+ .type func3, @function
+ bl func3
+ ret
--- /dev/null
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 3 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC and BTI
+.long 0
+
+.text
+.globl func2
+.type func2,@function
+func2:
+ .globl func3
+ .type func3, @function
+ bl func3
+ ret
--- /dev/null
+.text
+.globl func2
+.type func2,@function
+func2:
+ .globl func3
+ .type func3, @function
+ bl func3
+ ret
--- /dev/null
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+.long 0
+
+.text
+.globl func3
+.type func3,@function
+func3:
+ ret
--- /dev/null
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 3 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+.long 0
+
+.text
+.globl func3
+.type func3,@function
+func3:
+ ret
--- /dev/null
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+.long 0
+
+.text
+.globl func3
+.type func3,@function
+func3:
+ ret
--- /dev/null
+.text
+.globl func3
+.type func3,@function
+func3:
+ ret
--- /dev/null
+.text
+.globl func2
+.type func2,@function
+func2:
+ .globl func3
+ .type func3, @function
+ bl func3
+ ret
--- /dev/null
+.text
+.globl func2
+.type func2,@function
+func2:
+ .globl func3
+ .type func3, @function
+ bl func3
+ ret
--- /dev/null
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+.long 0
+
+.text
+.globl func2
+.type func2,@function
+func2:
+ .globl func3
+ .type func3, @function
+ bl func3
+ ret
--- /dev/null
+# REQUIRES: x86
+# RUN: llvm-mc --triple=x86_64-pc-linux --filetype=obj -o %t.o %s
+# RUN: not ld.lld --pac-plt --force-bti %t.o -o %t 2>&1 | FileCheck %s
+#
+## Check that we error if --pac-plt and --force-bti are used when target is not
+## aarch64
+
+# CHECK: error: --pac-plt only supported on AArch64
+# CHECK-NEXT: error: --force-bti only supported on AArch64
+
+ .globl start
+start: ret
--- /dev/null
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-bti1.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3-bti.s -o %t3.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func2.s -o %tno.o
+
+## We do not add BTI support when the inputs don't have the .note.gnu.property
+## field.
+
+# RUN: ld.lld %tno.o %t3.o --shared -o %tno.so
+# RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %tno.so | FileCheck --check-prefix=NOBTI %s
+# RUN: llvm-readelf -x .got.plt %tno.so | FileCheck --check-prefix SOGOTPLT %s
+# RUN: llvm-readelf --dynamic-table %tno.so | FileCheck --check-prefix NOBTIDYN %s
+
+# NOBTIDYN-NOT: 0x0000000070000001 (AARCH64_BTI_PLT)
+# NOBTIDYN-NOT: 0x0000000070000003 (AARCH64_PAC_PLT)
+
+# NOBTI: 0000000000010000 func2:
+# NOBTI-NEXT: 10000: bl #48 <func3@plt>
+# NOBTI-NEXT: 10004: ret
+# NOBTI: Disassembly of section .plt:
+# NOBTI: 0000000000010010 .plt:
+# NOBTI-NEXT: 10010: stp x16, x30, [sp, #-16]!
+# NOBTI-NEXT: 10014: adrp x16, #131072
+# NOBTI-NEXT: 10018: ldr x17, [x16, #16]
+# NOBTI-NEXT: 1001c: add x16, x16, #16
+# NOBTI-NEXT: 10020: br x17
+# NOBTI-NEXT: 10024: nop
+# NOBTI-NEXT: 10028: nop
+# NOBTI-NEXT: 1002c: nop
+# NOBTI: 0000000000010030 func3@plt:
+# NOBTI-NEXT: 10030: adrp x16, #131072
+# NOBTI-NEXT: 10034: ldr x17, [x16, #24]
+# NOBTI-NEXT: 10038: add x16, x16, #24
+# NOBTI-NEXT: 1003c: br x17
+
+## Expect a bti c at the start of plt[0], the plt entries do not need bti c as
+## their address doesn't escape the shared object, so they can't be indirectly
+## called. Expect no other difference.
+
+# RUN: ld.lld %t1.o %t3.o --shared -o %t.so
+# RUN: llvm-readelf -n %t.so | FileCheck --check-prefix BTIPROP %s
+# RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %t.so | FileCheck --check-prefix BTISO %s
+# RUN: llvm-readelf -x .got.plt %t.so | FileCheck --check-prefix SOGOTPLT %s
+# RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix BTIDYN %s
+
+# BTIPROP: Properties: aarch64 feature: BTI
+
+# BTIDYN: 0x0000000070000001 (AARCH64_BTI_PLT)
+# BTIDYN-NOT: 0x0000000070000003 (AARCH64_PAC_PLT)
+
+# BTISO: 0000000000010000 func2:
+# BTISO-NEXT: 10000: bl #48 <func3@plt>
+# BTISO-NEXT: 10004: ret
+# BTISO: Disassembly of section .plt:
+# BTISO: 0000000000010010 .plt:
+# BTISO-NEXT: 10010: bti c
+# BTISO-NEXT: 10014: stp x16, x30, [sp, #-16]!
+# BTISO-NEXT: 10018: adrp x16, #131072
+# BTISO-NEXT: 1001c: ldr x17, [x16, #16]
+# BTISO-NEXT: 10020: add x16, x16, #16
+# BTISO-NEXT: 10024: br x17
+# BTISO-NEXT: 10028: nop
+# BTISO-NEXT: 1002c: nop
+# BTISO: 0000000000010030 func3@plt:
+# BTISO-NEXT: 10030: adrp x16, #131072
+# BTISO-NEXT: 10034: ldr x17, [x16, #24]
+# BTISO-NEXT: 10038: add x16, x16, #24
+# BTISO-NEXT: 1003c: br x17
+
+## The .got.plt should be identical between the BTI and no BTI DSO PLT.
+# SOGOTPLT: Hex dump of section '.got.plt'
+# SOGOTPLT-NEXT: 0x00030000 00000000 00000000 00000000 00000000
+# SOGOTPLT-NEXT: 0x00030010 00000000 00000000 10000100 00000000
+
+## Build an executable with all relocatable inputs having the BTI
+## .note.gnu.property. We expect a bti c in front of all PLT entries as the
+## address of a PLT entry can escape an executable.
+
+# RUN: ld.lld %t2.o --shared -o %t2.so
+
+# RUN: ld.lld %t.o %t.so %t2.so -o %t.exe
+# RUN: llvm-readelf --dynamic-table -n %t.exe | FileCheck --check-prefix=BTIPROP %s
+# RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %t.exe | FileCheck --check-prefix=EXECBTI %s
+
+# EXECBTI: Disassembly of section .text:
+# EXECBTI: 0000000000210000 func1:
+# EXECBTI-NEXT: 210000: bl #48 <func2@plt>
+# EXECBTI-NEXT: 210004: ret
+# EXECBTI: Disassembly of section .plt:
+# EXECBTI: 0000000000210010 .plt:
+# EXECBTI-NEXT: 210010: bti c
+# EXECBTI-NEXT: 210014: stp x16, x30, [sp, #-16]!
+# EXECBTI-NEXT: 210018: adrp x16, #131072
+# EXECBTI-NEXT: 21001c: ldr x17, [x16, #16]
+# EXECBTI-NEXT: 210020: add x16, x16, #16
+# EXECBTI-NEXT: 210024: br x17
+# EXECBTI-NEXT: 210028: nop
+# EXECBTI-NEXT: 21002c: nop
+# EXECBTI: 0000000000210030 func2@plt:
+# EXECBTI-NEXT: 210030: bti c
+# EXECBTI-NEXT: 210034: adrp x16, #131072
+# EXECBTI-NEXT: 210038: ldr x17, [x16, #24]
+# EXECBTI-NEXT: 21003c: add x16, x16, #24
+# EXECBTI-NEXT: 210040: br x17
+# EXECBTI-NEXT: 210044: nop
+
+## We expect the same for PIE, as the address of an ifunc can escape
+# RUN: ld.lld --pie %t.o %t.so %t2.so -o %tpie.exe
+# RUN: llvm-readelf -n %tpie.exe | FileCheck --check-prefix=BTIPROP %s
+# RUN: llvm-readelf --dynamic-table -n %tpie.exe | FileCheck --check-prefix=BTIPROP %s
+# RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %tpie.exe | FileCheck --check-prefix=PIE %s
+
+# PIE: Disassembly of section .text:
+# PIE: 0000000000010000 func1:
+# PIE-NEXT: 10000: bl #48 <func2@plt>
+# PIE-NEXT: 10004: ret
+# PIE: Disassembly of section .plt:
+# PIE: 0000000000010010 .plt:
+# PIE-NEXT: 10010: bti c
+# PIE-NEXT: 10014: stp x16, x30, [sp, #-16]!
+# PIE-NEXT: 10018: adrp x16, #131072
+# PIE-NEXT: 1001c: ldr x17, [x16, #16]
+# PIE-NEXT: 10020: add x16, x16, #16
+# PIE-NEXT: 10024: br x17
+# PIE-NEXT: 10028: nop
+# PIE-NEXT: 1002c: nop
+# PIE: 0000000000010030 func2@plt:
+# PIE-NEXT: 10030: bti c
+# PIE-NEXT: 10034: adrp x16, #131072
+# PIE-NEXT: 10038: ldr x17, [x16, #24]
+# PIE-NEXT: 1003c: add x16, x16, #24
+# PIE-NEXT: 10040: br x17
+# PIE-NEXT: 10044: nop
+
+## Build and executable with not all relocatable inputs having the BTI
+## .note.property, expect no bti c and no .note.gnu.property entry
+
+# RUN: ld.lld %t.o %t2.o %t.so -o %tnobti.exe
+# RUN: llvm-readelf --dynamic-table %tnobti.exe | FileCheck --check-prefix NOBTIDYN %s
+# RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %tnobti.exe | FileCheck --check-prefix=NOEX %s
+
+# NOEX: Disassembly of section .text:
+# NOEX: 0000000000210000 func1:
+# NOEX-NEXT: 210000: bl #48 <func2@plt>
+# NOEX-NEXT: 210004: ret
+# NOEX: 0000000000210008 func3:
+# NOEX-NEXT: 210008: ret
+# NOEX: Disassembly of section .plt:
+# NOEX: 0000000000210010 .plt:
+# NOEX-NEXT: 210010: stp x16, x30, [sp, #-16]!
+# NOEX-NEXT: 210014: adrp x16, #131072
+# NOEX-NEXT: 210018: ldr x17, [x16, #16]
+# NOEX-NEXT: 21001c: add x16, x16, #16
+# NOEX-NEXT: 210020: br x17
+# NOEX-NEXT: 210024: nop
+# NOEX-NEXT: 210028: nop
+# NOEX-NEXT: 21002c: nop
+# NOEX: 0000000000210030 func2@plt:
+# NOEX-NEXT: 210030: adrp x16, #131072
+# NOEX-NEXT: 210034: ldr x17, [x16, #24]
+# NOEX-NEXT: 210038: add x16, x16, #24
+# NOEX-NEXT: 21003c: br x17
+
+## Force BTI entries with the --force-bti command line option. Expect a warning
+## from the file without the .note.gnu.property.
+
+# RUN: ld.lld %t.o %t2.o --force-bti %t.so -o %tforcebti.exe 2>&1 | FileCheck --check-prefix=FORCE-WARN %s
+
+# FORCE-WARN: aarch64-feature-bti.s.tmp2.o: --force-bti: file does not have BTI property
+
+
+# RUN: llvm-readelf -n %tforcebti.exe | FileCheck --check-prefix=BTIPROP %s
+# RUN: llvm-readelf --dynamic-table %tforcebti.exe | FileCheck --check-prefix BTIDYN %s
+# RUN: llvm-objdump -d -mattr=+bti --no-show-raw-insn %tforcebti.exe | FileCheck --check-prefix=FORCE %s
+
+# FORCE: Disassembly of section .text:
+# FORCE: 0000000000210000 func1:
+# FORCE-NEXT: 210000: bl #48 <func2@plt>
+# FORCE-NEXT: 210004: ret
+# FORCE: 0000000000210008 func3:
+# FORCE-NEXT: 210008: ret
+# FORCE: Disassembly of section .plt:
+# FORCE: 0000000000210010 .plt:
+# FORCE-NEXT: 210010: bti c
+# FORCE-NEXT: 210014: stp x16, x30, [sp, #-16]!
+# FORCE-NEXT: 210018: adrp x16, #131072
+# FORCE-NEXT: 21001c: ldr x17, [x16, #16]
+# FORCE-NEXT: 210020: add x16, x16, #16
+# FORCE-NEXT: 210024: br x17
+# FORCE-NEXT: 210028: nop
+# FORCE-NEXT: 21002c: nop
+# FORCE: 0000000000210030 func2@plt:
+# FORCE-NEXT: 210030: bti c
+# FORCE-NEXT: 210034: adrp x16, #131072
+# FORCE-NEXT: 210038: ldr x17, [x16, #24]
+# FORCE-NEXT: 21003c: add x16, x16, #24
+# FORCE-NEXT: 210040: br x17
+# FORCE-NEXT: 210044: nop
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+.long 0
+
+.text
+.globl _start
+.type func1,%function
+func1:
+ bl func2
+ ret
--- /dev/null
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-btipac1.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3.s -o %t3.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3-btipac.s -o %t3btipac.o
+
+## Build shared library with all inputs having BTI and PAC, expect PLT
+## entries supporting both PAC and BTI. For a shared library this means:
+## PLT[0] has bti c at start
+## PLT[n] has autia1716 before br x17
+
+# RUN: ld.lld %t1.o %t3btipac.o --shared -o %t.so
+# RUN: llvm-readelf -n %t.so | FileCheck --check-prefix BTIPACPROP %s
+# RUN: llvm-objdump -d -mattr=+v8.5a --no-show-raw-insn %t.so | FileCheck --check-prefix BTIPACSO %s
+# RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix BTIPACDYN %s
+
+# BTIPACSO: Disassembly of section .text:
+# BTIPACSO: 0000000000010000 func2:
+# BTIPACSO-NEXT: 10000: bl #48 <func3@plt>
+# BTIPACSO-NEXT: 10004: ret
+# BTIPACSO: 0000000000010008 func3:
+# BTIPACSO-NEXT: 10008: ret
+# BTIPACSO: Disassembly of section .plt:
+# BTIPACSO: 0000000000010010 .plt:
+# BTIPACSO-NEXT: 10010: bti c
+# BTIPACSO-NEXT: 10014: stp x16, x30, [sp, #-16]!
+# BTIPACSO-NEXT: 10018: adrp x16, #131072
+# BTIPACSO-NEXT: 1001c: ldr x17, [x16, #16]
+# BTIPACSO-NEXT: 10020: add x16, x16, #16
+# BTIPACSO-NEXT: 10024: br x17
+# BTIPACSO-NEXT: 10028: nop
+# BTIPACSO-NEXT: 1002c: nop
+# BTIPACSO: 0000000000010030 func3@plt:
+# BTIPACSO-NEXT: 10030: adrp x16, #131072
+# BTIPACSO-NEXT: 10034: ldr x17, [x16, #24]
+# BTIPACSO-NEXT: 10038: add x16, x16, #24
+# BTIPACSO-NEXT: 1003c: autia1716
+# BTIPACSO-NEXT: 10040: br x17
+# BTIPACSO-NEXT: 10044: nop
+
+# BTIPACPROP: Properties: aarch64 feature: BTI, PAC
+
+# BTIPACDYN: 0x0000000070000001 (AARCH64_BTI_PLT)
+# BTIPACDYN: 0x0000000070000003 (AARCH64_PAC_PLT)
+
+## Make an executable with both BTI and PAC properties. Expect:
+## PLT[0] bti c as first instruction
+## PLT[n] bti n as first instruction, autia1716 before br x17
+
+# RUN: ld.lld %t.o %t3btipac.o %t.so -o %t.exe
+# RUN: llvm-readelf -n %t.exe | FileCheck --check-prefix=BTIPACPROP %s
+# RUN: llvm-objdump -d -mattr=+v8.5a --no-show-raw-insn %t.exe | FileCheck --check-prefix BTIPACEX %s
+# RUN: llvm-readelf --dynamic-table %t.exe | FileCheck --check-prefix BTIPACDYN %s
+
+# BTIPACEX: Disassembly of section .text:
+# BTIPACEX: 0000000000210000 func1:
+# BTIPACEX-NEXT: 210000: bl #48 <func2@plt>
+# BTIPACEX-NEXT: 210004: ret
+# BTIPACEX-NEXT: 210008: ret
+# BTIPACEX: 000000000021000c func3:
+# BTIPACEX-NEXT: 21000c: ret
+# BTIPACEX: Disassembly of section .plt:
+# BTIPACEX: 0000000000210010 .plt:
+# BTIPACEX-NEXT: 210010: bti c
+# BTIPACEX-NEXT: 210014: stp x16, x30, [sp, #-16]!
+# BTIPACEX-NEXT: 210018: adrp x16, #131072
+# BTIPACEX-NEXT: 21001c: ldr x17, [x16, #16]
+# BTIPACEX-NEXT: 210020: add x16, x16, #16
+# BTIPACEX-NEXT: 210024: br x17
+# BTIPACEX-NEXT: 210028: nop
+# BTIPACEX-NEXT: 21002c: nop
+# BTIPACEX: 0000000000210030 func2@plt:
+# BTIPACEX-NEXT: 210030: bti c
+# BTIPACEX-NEXT: 210034: adrp x16, #131072
+# BTIPACEX-NEXT: 210038: ldr x17, [x16, #24]
+# BTIPACEX-NEXT: 21003c: add x16, x16, #24
+# BTIPACEX-NEXT: 210040: autia1716
+# BTIPACEX-NEXT: 210044: br x17
+
+## Check that combinations of BTI+PAC with 0 properties results in standard PLT
+
+# RUN: ld.lld %t.o %t3.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -mattr=+v8.5a --no-show-raw-insn %t.exe | FileCheck --check-prefix EX %s
+# RUN: llvm-readelf --dynamic-table %t.exe | FileCheck --check-prefix=NODYN %s
+
+# EX: Disassembly of section .text:
+# EX: 0000000000210000 func1:
+# EX-NEXT: 210000: bl #48 <func2@plt>
+# EX-NEXT: 210004: ret
+# EX-NEXT: 210008: ret
+# EX: 000000000021000c func3:
+# EX-NEXT: 21000c: ret
+# EX: Disassembly of section .plt:
+# EX: 0000000000210010 .plt:
+# EX-NEXT: 210010: stp x16, x30, [sp, #-16]!
+# EX-NEXT: 210014: adrp x16, #131072
+# EX-NEXT: 210018: ldr x17, [x16, #16]
+# EX-NEXT: 21001c: add x16, x16, #16
+# EX-NEXT: 210020: br x17
+# EX-NEXT: 210024: nop
+# EX-NEXT: 210028: nop
+# EX-NEXT: 21002c: nop
+# EX: 0000000000210030 func2@plt:
+# EX: 210030: adrp x16, #131072
+# EX-NEXT: 210034: ldr x17, [x16, #24]
+# EX-NEXT: 210038: add x16, x16, #24
+# EX-NEXT: 21003c: br x17
+
+# NODYN-NOT: 0x0000000070000001 (AARCH64_BTI_PLT)
+# NODYN-NOT: 0x0000000070000003 (AARCH64_PAC_PLT)
+
+## Check that combination of --pac-plt and --force-bti warns for the file that
+## doesn't contain the BTI property, but generates PAC and BTI PLT sequences.
+## The --pac-plt doesn't warn as it is not required for correctness.
+
+# RUN: ld.lld %t.o %t3.o %t.so --pac-plt --force-bti -o %t.exe 2>&1 | FileCheck --check-prefix=FORCE-WARN %s
+
+# FORCE-WARN: aarch64-feature-btipac.s.tmp3.o: --force-bti: file does not have BTI property
+
+# RUN: llvm-readelf -n %t.exe | FileCheck --check-prefix=BTIPACPROP %s
+# RUN: llvm-objdump -d -mattr=+v8.5a --no-show-raw-insn %t.exe | FileCheck --check-prefix BTIPACEX %s
+# RUN: llvm-readelf --dynamic-table %t.exe | FileCheck --check-prefix BTIPACDYN %s
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 3 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI and PAC
+.long 0
+
+.text
+.globl _start
+.type func1,%function
+func1:
+ bl func2
+ ret
+.globl func3
+.type func3,%function
+ ret
--- /dev/null
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-pac1.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func3-pac.s -o %t3.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/aarch64-func2.s -o %tno.o
+
+## We do not add PAC support when the inputs don't have the .note.gnu.property
+## field.
+
+# RUN: ld.lld %tno.o %t3.o --shared -o %tno.so
+# RUN: llvm-objdump -d -mattr=+v8.3a --no-show-raw-insn %tno.so | FileCheck --check-prefix=NOPAC %s
+# RUN: llvm-readelf -x .got.plt %tno.so | FileCheck --check-prefix SOGOTPLT %s
+# RUN: llvm-readelf --dynamic-table %tno.so | FileCheck --check-prefix NOPACDYN %s
+
+# NOPAC: 0000000000010000 func2:
+# NOPAC-NEXT: 10000: bl #48 <func3@plt>
+# NOPAC-NEXT: 10004: ret
+# NOPAC: Disassembly of section .plt:
+# NOPAC: 0000000000010010 .plt:
+# NOPAC-NEXT: 10010: stp x16, x30, [sp, #-16]!
+# NOPAC-NEXT: 10014: adrp x16, #131072
+# NOPAC-NEXT: 10018: ldr x17, [x16, #16]
+# NOPAC-NEXT: 1001c: add x16, x16, #16
+# NOPAC-NEXT: 10020: br x17
+# NOPAC-NEXT: 10024: nop
+# NOPAC-NEXT: 10028: nop
+# NOPAC-NEXT: 1002c: nop
+# NOPAC: 0000000000010030 func3@plt:
+# NOPAC-NEXT: 10030: adrp x16, #131072
+# NOPAC-NEXT: 10034: ldr x17, [x16, #24]
+# NOPAC-NEXT: 10038: add x16, x16, #24
+# NOPAC-NEXT: 1003c: br x17
+
+# NOPACDYN-NOT: 0x0000000070000001 (AARCH64_BTI_PLT)
+# NOPACDYN-NOT: 0x0000000070000003 (AARCH64_PAC_PLT)
+
+# RUN: ld.lld %t1.o %t3.o --shared -o %t.so
+# RUN: llvm-readelf -n %t.so | FileCheck --check-prefix PACPROP %s
+# RUN: llvm-objdump -d -mattr=+v8.3a --no-show-raw-insn %t.so | FileCheck --check-prefix PACSO %s
+# RUN: llvm-readelf -x .got.plt %t.so | FileCheck --check-prefix SOGOTPLT %s
+# RUN: llvm-readelf --dynamic-table %t.so | FileCheck --check-prefix PACDYN %s
+
+## PAC has no effect on PLT[0], for PLT[N] autia1716 is used to authenticate
+## the address in x17 (context in x16) before branching to it. The dynamic
+## loader is responsible for calling pacia1716 on the entry.
+# PACSO: 0000000000010000 func2:
+# PACSO-NEXT: 10000: bl #48 <func3@plt>
+# PACSO-NEXT: 10004: ret
+# PACSO: Disassembly of section .plt:
+# PACSO: 0000000000010010 .plt:
+# PACSO-NEXT: 10010: stp x16, x30, [sp, #-16]!
+# PACSO-NEXT: 10014: adrp x16, #131072
+# PACSO-NEXT: 10018: ldr x17, [x16, #16]
+# PACSO-NEXT: 1001c: add x16, x16, #16
+# PACSO-NEXT: 10020: br x17
+# PACSO-NEXT: 10024: nop
+# PACSO-NEXT: 10028: nop
+# PACSO-NEXT: 1002c: nop
+# PACSO: 0000000000010030 func3@plt:
+# PACSO-NEXT: 10030: adrp x16, #131072
+# PACSO-NEXT: 10034: ldr x17, [x16, #24]
+# PACSO-NEXT: 10038: add x16, x16, #24
+# PACSO-NEXT: 1003c: autia1716
+# PACSO-NEXT: 10040: br x17
+# PACSO-NEXT: 10044: nop
+
+# The .got.plt should be identical between the PAC and no PAC DSO PLT.
+# SOGOTPLT: Hex dump of section '.got.plt':
+# SOGOTPLT-NEXT: 0x00030000 00000000 00000000 00000000 00000000
+# SOGOTPLT-NEXT: 0x00030010 00000000 00000000 10000100 00000000
+
+# PACPROP: Properties: aarch64 feature: PAC
+
+# PACDYN-NOT: 0x0000000070000001 (AARCH64_BTI_PLT)
+# PACDYN: 0x0000000070000003 (AARCH64_PAC_PLT)
+
+## Turn on PAC entries with the --pac-plt command line option. There are no
+## warnings in this case as the choice to use PAC in PLT entries is orthogonal
+## to the choice of using PAC in relocatable objects. The presence of the PAC
+## .note.gnu.property is an indication of preference by the relocatable object.
+
+# RUN: ld.lld %t.o %t2.o --pac-plt %t.so -o %tpacplt.exe
+# RUN: llvm-readelf -n %tpacplt.exe | FileCheck --check-prefix=PACPROP %s
+# RUN: llvm-readelf --dynamic-table %tpacplt.exe | FileCheck --check-prefix PACDYN %s
+# RUN: llvm-objdump -d -mattr=+v8.3a --no-show-raw-insn %tpacplt.exe | FileCheck --check-prefix PACPLT %s
+
+# PACPLT: Disassembly of section .text:
+# PACPLT: 0000000000210000 func1:
+# PACPLT-NEXT: 210000: bl #48 <func2@plt>
+# PACPLT-NEXT: 210004: ret
+# PACPLT: 0000000000210008 func3:
+# PACPLT-NEXT: 210008: ret
+# PACPLT: Disassembly of section .plt:
+# PACPLT: 0000000000210010 .plt:
+# PACPLT-NEXT: 210010: stp x16, x30, [sp, #-16]!
+# PACPLT-NEXT: 210014: adrp x16, #131072
+# PACPLT-NEXT: 210018: ldr x17, [x16, #16]
+# PACPLT-NEXT: 21001c: add x16, x16, #16
+# PACPLT-NEXT: 210020: br x17
+# PACPLT-NEXT: 210024: nop
+# PACPLT-NEXT: 210028: nop
+# PACPLT-NEXT: 21002c: nop
+# PACPLT: 0000000000210030 func2@plt:
+# PACPLT-NEXT: 210030: adrp x16, #131072
+# PACPLT-NEXT: 210034: ldr x17, [x16, #24]
+# PACPLT-NEXT: 210038: add x16, x16, #24
+# PACPLT-NEXT: 21003c: autia1716
+# PACPLT-NEXT: 210040: br x17
+# PACPLT-NEXT: 210044: nop
+
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+.long 0
+
+.text
+.globl _start
+.type func1,%function
+func1:
+ bl func2
+ ret
--- /dev/null
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %p/Inputs/aarch64-addrifunc.s -o %lib.o
+
+# RUN: ld.lld --shared %lib.o -o %lib.so
+# RUN: ld.lld --pie %lib.so %t.o -o %t
+# RUN: llvm-objdump -d -mattr=+bti -triple=aarch64-linux-gnu %t | FileCheck %s
+
+# When the address of an ifunc is taken using a non-got reference which clang
+# can do, LLD exports a canonical PLT entry that may have its address taken so
+# we must use bti c.
+
+# CHECK: Disassembly of section .plt:
+# CHECK: 0000000000010020 .plt:
+# CHECK-NEXT: 10020: 5f 24 03 d5 bti c
+# CHECK-NEXT: 10024: f0 7b bf a9 stp x16, x30, [sp, #-16]!
+# CHECK-NEXT: 10028: 10 01 00 90 adrp x16, #131072
+# CHECK-NEXT: 1002c: 11 0a 40 f9 ldr x17, [x16, #16]
+# CHECK-NEXT: 10030: 10 42 00 91 add x16, x16, #16
+# CHECK-NEXT: 10034: 20 02 1f d6 br x17
+# CHECK-NEXT: 10038: 1f 20 03 d5 nop
+# CHECK-NEXT: 1003c: 1f 20 03 d5 nop
+# CHECK: 0000000000010040 func1@plt:
+# CHECK-NEXT: 10040: 5f 24 03 d5 bti c
+# CHECK-NEXT: 10044: 10 01 00 90 adrp x16, #131072
+# CHECK-NEXT: 10048: 11 0e 40 f9 ldr x17, [x16, #24]
+# CHECK-NEXT: 1004c: 10 62 00 91 add x16, x16, #24
+# CHECK-NEXT: 10050: 20 02 1f d6 br x17
+# CHECK-NEXT: 10054: 1f 20 03 d5 nop
+# CHECK-NEXT: ...
+# CHECK: 0000000000010060 myfunc:
+# CHECK-NEXT: 10060: 5f 24 03 d5 bti c
+# CHECK-NEXT: 10064: 10 01 00 90 adrp x16, #131072
+# CHECK-NEXT: 10068: 11 12 40 f9 ldr x17, [x16, #32]
+# CHECK-NEXT: 1006c: 10 82 00 91 add x16, x16, #32
+# CHECK-NEXT: 10070: 20 02 1f d6 br x17
+# CHECK-NEXT: 10074: 1f 20 03 d5 nop
+
+.section ".note.gnu.property", "a"
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+.long 0
+
+.text
+.globl myfunc
+.type myfunc,@gnu_indirect_function
+myfunc:
+ ret
+
+.globl func1
+
+.text
+.globl _start
+.type _start, %function
+_start:
+ bl func1
+ adrp x8, myfunc
+ add x8, x8, :lo12:myfunc
+ ret
--- /dev/null
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o
+# RUN: ld.lld -r %t.o -o %t2.o
+# RUN: llvm-readelf -n %t2.o | FileCheck -match-full-lines %s
+
+## Test that .note.gnu.property is passed through -r, and that we can handle
+## more than one FEATURE_AND in the same object file. This is logically the
+## same as if the features were combined in a single FEATURE_AND as the rule
+## states that the bit in the output pr_data field if it is set in all
+.text
+ret
+
+.section ".note.gnu.property", "a"
+.p2align 3
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 1 // GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+.long 0
+
+.long 4
+.long 0x10
+.long 0x5
+.asciz "GNU"
+.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
+.long 4
+.long 2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+.long 0
+
+# CHECK: Owner Data size Description
+# CHECK-NEXT: GNU 0x00000010 NT_GNU_PROPERTY_TYPE_0 (property note)
+# CHECK-NEXT: Properties: aarch64 feature: BTI, PAC