[ELF][AArch64] Support for BTI and PAC

Branch Target Identification (BTI) and Pointer Authentication (PAC) are
architecture features introduced in v8.5a and 8.3a respectively. The new
instructions have been added in the hint space so that binaries take
advantage of support where it exists yet still run on older hardware. The
impact of each feature is:

BTI: For executable pages that have been guarded, all indirect branches
must have a destination that is a BTI instruction of the appropriate type.
For the static linker, this means that PLT entries must have a "BTI c" as
the first instruction in the sequence. BTI is an all or nothing
property for a link unit, any indirect branch not landing on a valid
destination will cause a Branch Target Exception.

PAC: The dynamic loader encodes with PACIA the address of the destination
that the PLT entry will load from the .plt.got, placing the result in a
subset of the top-bits that are not valid virtual addresses. The PLT entry
may authenticate these top-bits using the AUTIA instruction before
branching to the destination. Use of PAC in PLT sequences is a contract
between the dynamic loader and the static linker, it is independent of
whether the relocatable objects use PAC.

BTI and PAC are independent features that can be combined. So we can have
several combinations of PLT:
- Standard with no BTI or PAC
- BTI PLT with "BTI c" as first instruction.
- PAC PLT with "AUTIA1716" before the indirect branch to X17.
- BTIPAC PLT with "BTI c" as first instruction and "AUTIA1716" before the
  first indirect branch to X17.
    
The use of BTI and PAC in relocatable object files are encoded by feature
bits in the .note.gnu.property section in a similar way to Intel CET. There
is one AArch64 specific program property GNU_PROPERTY_AARCH64_FEATURE_1_AND
and two target feature bits defined:
- GNU_PROPERTY_AARCH64_FEATURE_1_BTI
-- All executable sections are compatible with BTI.
- GNU_PROPERTY_AARCH64_FEATURE_1_PAC
-- All executable sections have return address signing enabled.

Due to the properties of FEATURE_1_AND the static linker can tell when all
input relocatable objects have the BTI and PAC feature bits set. The static
linker uses this to enable the appropriate PLT sequence.
Neither -> standard PLT
GNU_PROPERTY_AARCH64_FEATURE_1_BTI -> BTI PLT
GNU_PROPERTY_AARCH64_FEATURE_1_PAC -> PAC PLT
Both properties -> BTIPAC PLT

In addition to the .note.gnu.properties there are two new command line
options:
--force-bti : Act as if all relocatable inputs had
GNU_PROPERTY_AARCH64_FEATURE_1_BTI and warn for every relocatable object
that does not.
--pac-plt : Act as if all relocatable inputs had
GNU_PROPERTY_AARCH64_FEATURE_1_PAC. As PAC is a contract between the loader
and static linker no warning is given if it is not present in an input.

Two processor specific dynamic tags are used to communicate that a non
standard PLT sequence is being used.
DTI_AARCH64_BTI_PLT and DTI_AARCH64_BTI_PAC.

Differential Revision: https://reviews.llvm.org/D62609

llvm-svn: 362793
This commit is contained in:
Peter Smith 2019-06-07 13:00:17 +00:00
parent f2ddd60836
commit e208208a31
24 changed files with 961 additions and 12 deletions

View File

@ -28,7 +28,7 @@ uint64_t elf::getAArch64Page(uint64_t Expr) {
}
namespace {
class AArch64 final : public TargetInfo {
class AArch64 : public TargetInfo {
public:
AArch64();
RelExpr getRelExpr(RelType Type, const Symbol &S,
@ -431,7 +431,157 @@ void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
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(); }

View File

@ -147,6 +147,7 @@ struct Configuration {
bool ExecuteOnly;
bool ExportDynamic;
bool FixCortexA53Errata843419;
bool ForceBTI;
bool FormatBinary = false;
bool RequireCET;
bool GcSections;
@ -168,6 +169,7 @@ struct Configuration {
bool OFormatBinary;
bool Omagic;
bool OptRemarksWithHotness;
bool PacPlt;
bool PicThunk;
bool Pie;
bool PrintGcSections;

View File

@ -337,6 +337,13 @@ static void checkOptions() {
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) {
@ -816,6 +823,7 @@ static void readConfigs(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);
@ -851,6 +859,7 @@ static void readConfigs(opt::InputArgList &Args) {
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);
@ -1594,20 +1603,32 @@ static void wrapSymbols(ArrayRef<WrappedSymbol> Wrapped) {
// 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;
}
@ -1793,6 +1814,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// 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

View File

@ -787,6 +787,10 @@ static uint32_t readAndFeatures(ObjFile<ELFT> *Obj, ArrayRef<uint8_t> Data) {
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()) {
@ -796,7 +800,7 @@ static uint32_t readAndFeatures(ObjFile<ELFT> *Obj, ArrayRef<uint8_t> Data) {
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.
@ -966,8 +970,9 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
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

View File

@ -175,6 +175,9 @@ def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">,
// 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]">;
@ -269,6 +272,9 @@ defm pack_dyn_relocs:
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)">;

View File

@ -290,8 +290,9 @@ static size_t getHashSize() {
// 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.
@ -304,11 +305,15 @@ GnuPropertySection::GnuPropertySection()
".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)
@ -1340,6 +1345,13 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
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);

View File

@ -182,6 +182,8 @@ Set the
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
@ -382,6 +384,8 @@ is the default. If
.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

View File

@ -0,0 +1,8 @@
.text
.globl myfunc
.globl func1
.type func1, %function
func1:
adrp x8, :got: myfunc
ldr x8, [x8, :got_lo12: myfunc]
ret

View File

@ -0,0 +1,19 @@
.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

View File

@ -0,0 +1,19 @@
.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

View File

@ -0,0 +1,8 @@
.text
.globl func2
.type func2,@function
func2:
.globl func3
.type func3, @function
bl func3
ret

View File

@ -0,0 +1,16 @@
.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

View File

@ -0,0 +1,16 @@
.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

View File

@ -0,0 +1,16 @@
.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

View File

@ -0,0 +1,5 @@
.text
.globl func3
.type func3,@function
func3:
ret

View File

@ -0,0 +1,8 @@
.text
.globl func2
.type func2,@function
func2:
.globl func3
.type func3, @function
bl func3
ret

View File

@ -0,0 +1,8 @@
.text
.globl func2
.type func2,@function
func2:
.globl func3
.type func3, @function
bl func3
ret

View File

@ -0,0 +1,19 @@
.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

View File

@ -0,0 +1,12 @@
# 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

View File

@ -0,0 +1,218 @@
# 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

View File

@ -0,0 +1,142 @@
# 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

View File

@ -0,0 +1,129 @@
# 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

View File

@ -0,0 +1,65 @@
# 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

View File

@ -0,0 +1,36 @@
# 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