Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 162 additions & 15 deletions llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@
#include "llvm/IR/Module.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
Expand Down Expand Up @@ -95,6 +97,7 @@ class AArch64AsmPrinter : public AsmPrinter {
bool EnableImportCallOptimization = false;
DenseMap<MCSection *, std::vector<std::pair<MCSymbol *, MCSymbol *>>>
SectionToImportedFunctionCalls;
unsigned PAuthIFuncNextUniqueID = 1;

public:
static char ID;
Expand Down Expand Up @@ -212,6 +215,10 @@ class AArch64AsmPrinter : public AsmPrinter {
// authenticating)
void LowerLOADgotAUTH(const MachineInstr &MI);

const MCExpr *emitPAuthRelocationAsIRelative(
const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
bool HasAddressDiversity, bool IsDSOLocal);

/// tblgen'erated driver function for lowering simple MI->MC
/// pseudo instructions.
bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst);
Expand Down Expand Up @@ -2303,6 +2310,143 @@ void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, BRInst);
}

static void emitAddress(MCStreamer &Streamer, MCRegister Reg,
const MCExpr *Expr, bool DSOLocal,
const MCSubtargetInfo &STI) {
MCValue Val;
if (!Expr->evaluateAsRelocatable(Val, nullptr))
report_fatal_error("emitAddress could not evaluate");
if (DSOLocal) {
Streamer.emitInstruction(
MCInstBuilder(AArch64::ADRP)
.addReg(Reg)
.addExpr(MCSpecifierExpr::create(Expr, AArch64::S_ABS_PAGE,
Streamer.getContext())),
STI);
Streamer.emitInstruction(
MCInstBuilder(AArch64::ADDXri)
.addReg(Reg)
.addReg(Reg)
.addExpr(MCSpecifierExpr::create(Expr, AArch64::S_LO12,
Streamer.getContext()))
.addImm(0),
STI);
} else {
auto *SymRef = MCSymbolRefExpr::create(Val.getAddSym(), Streamer.getContext());
Streamer.emitInstruction(
MCInstBuilder(AArch64::ADRP)
.addReg(Reg)
.addExpr(MCSpecifierExpr::create(SymRef, AArch64::S_GOT_PAGE,
Streamer.getContext())),
STI);
Streamer.emitInstruction(
MCInstBuilder(AArch64::LDRXui)
.addReg(Reg)
.addReg(Reg)
.addExpr(MCSpecifierExpr::create(SymRef, AArch64::S_GOT_LO12,
Streamer.getContext())),
STI);
if (Val.getConstant())
Streamer.emitInstruction(MCInstBuilder(AArch64::ADDXri)
.addReg(Reg)
.addReg(Reg)
.addImm(Val.getConstant())
.addImm(0),
STI);
}
}

static bool targetSupportsPAuthRelocation(const Triple &TT,
const MCExpr *Target) {
// No released version of glibc supports PAuth relocations.
if (TT.isOSGlibc())
return false;

// We emit PAuth constants as IRELATIVE relocations in cases where the
// constant cannot be represented as a PAuth relocation:
// 1) The signed value is not a symbol.
return !isa<MCConstantExpr>(Target);
}

static bool targetSupportsIRelativeRelocation(const Triple &TT) {
// IFUNCs are ELF-only.
if (!TT.isOSBinFormatELF())
return false;

// musl doesn't support IFUNCs.
if (TT.isMusl())
return false;

return true;
}

const MCExpr *AArch64AsmPrinter::emitPAuthRelocationAsIRelative(
const MCExpr *Target, uint16_t Disc, AArch64PACKey::ID KeyID,
bool HasAddressDiversity, bool IsDSOLocal) {
const Triple &TT = TM.getTargetTriple();

// We only emit an IRELATIVE relocation if the target supports IRELATIVE and
// does not support the kind of PAuth relocation that we are trying to emit.
if (targetSupportsPAuthRelocation(TT, Target) ||
!targetSupportsIRelativeRelocation(TT))
return nullptr;

// For now, only the DA key is supported.
if (KeyID != AArch64PACKey::DA)
return nullptr;

std::unique_ptr<MCSubtargetInfo> STI(
TM.getTarget().createMCSubtargetInfo(TT, "", ""));
assert(STI && "Unable to create subtarget info");

MCSymbol *Place = OutStreamer->getContext().createTempSymbol();
OutStreamer->emitLabel(Place);
OutStreamer->pushSection();

OutStreamer->switchSection(OutStreamer->getContext().getELFSection(
".text.startup", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_EXECINSTR,
0, "", true, PAuthIFuncNextUniqueID++, nullptr));

MCSymbol *IRelativeSym =
OutStreamer->getContext().createLinkerPrivateSymbol("pauth_ifunc");
OutStreamer->emitLabel(IRelativeSym);
if (isa<MCConstantExpr>(Target)) {
OutStreamer->emitInstruction(MCInstBuilder(AArch64::MOVZXi)
.addReg(AArch64::X0)
.addExpr(Target)
.addImm(0),
*STI);
} else {
emitAddress(*OutStreamer, AArch64::X0, Target, IsDSOLocal, *STI);
}
if (HasAddressDiversity) {
auto *PlacePlusDisc = MCBinaryExpr::createAdd(
MCSymbolRefExpr::create(Place, OutStreamer->getContext()),
MCConstantExpr::create(static_cast<int16_t>(Disc),
OutStreamer->getContext()),
OutStreamer->getContext());
emitAddress(*OutStreamer, AArch64::X1, PlacePlusDisc, /*IsDSOLocal=*/true,
*STI);
} else {
emitMOVZ(AArch64::X1, Disc, 0);
}

// We don't know the subtarget because this is being emitted for a global
// initializer. Because the performance of IFUNC resolvers is unimportant, we
// always call the EmuPAC runtime, which will end up using the PAC instruction
// if the target supports PAC.
MCSymbol *EmuPAC =
OutStreamer->getContext().getOrCreateSymbol("__emupac_pacda");
const MCSymbolRefExpr *EmuPACRef =
MCSymbolRefExpr::create(EmuPAC, OutStreamer->getContext());
OutStreamer->emitInstruction(MCInstBuilder(AArch64::B).addExpr(EmuPACRef),
*STI);
OutStreamer->popSection();

return MCSymbolRefExpr::create(IRelativeSym, AArch64::S_FUNCINIT,
OutStreamer->getContext());
}

const MCExpr *
AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
MCContext &Ctx = OutContext;
Expand All @@ -2314,23 +2458,20 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {

auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV);

// If we can't understand the referenced ConstantExpr, there's nothing
// else we can do: emit an error.
if (!BaseGVB) {
BaseGV->getContext().emitError(
"cannot resolve target base/addend of ptrauth constant");
return nullptr;
const MCExpr *Sym;
if (BaseGVB) {
// If there is an addend, turn that into the appropriate MCExpr.
Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
if (Offset.sgt(0))
Sym = MCBinaryExpr::createAdd(
Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
else if (Offset.slt(0))
Sym = MCBinaryExpr::createSub(
Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);
} else {
Sym = MCConstantExpr::create(Offset.getSExtValue(), Ctx);
}

// If there is an addend, turn that into the appropriate MCExpr.
const MCExpr *Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx);
if (Offset.sgt(0))
Sym = MCBinaryExpr::createAdd(
Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx);
else if (Offset.slt(0))
Sym = MCBinaryExpr::createSub(
Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx);

uint64_t KeyID = CPA.getKey()->getZExtValue();
// We later rely on valid KeyID value in AArch64PACKeyIDToString call from
// AArch64AuthMCExpr::printImpl, so fail fast.
Expand All @@ -2348,6 +2489,12 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
Disc = 0;
}

// Check if we need to represent this with an IRELATIVE and emit it if so.
if (auto *IFuncSym = emitPAuthRelocationAsIRelative(
Sym, Disc, AArch64PACKey::ID(KeyID), CPA.hasAddressDiscriminator(),
BaseGVB && BaseGVB->isDSOLocal()))
return IFuncSym;

// Finally build the complete @AUTH expr.
return AArch64AuthMCExpr::create(Sym, Disc, AArch64PACKey::ID(KeyID),
CPA.hasAddressDiscriminator(), Ctx);
Expand Down
78 changes: 78 additions & 0 deletions llvm/test/CodeGen/AArch64/ptrauth-irelative.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
; RUN: llc -mtriple aarch64-linux-gnu -mattr=+pauth -filetype=asm -o - %s | FileCheck %s

; CHECK: nullref:
; CHECK-NEXT: [[PLACE:.*]]:
; CHECK-NEXT: .section .text.startup
; CHECK-NEXT: [[FUNC:.*]]:
; CHECK-NEXT: movz x0, #0
; CHECK-NEXT: mov x1, #1
; CHECK-NEXT: b __emupac_pacda
; CHECK-NEXT: .section .rodata
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
@nullref = constant ptr ptrauth (ptr null, i32 2, i64 1, ptr null), align 8

@dsolocal = external dso_local global i8

; CHECK: dsolocalref:
; CHECK-NEXT: [[PLACE:.*]]:
; CHECK-NEXT: .section .text.startup
; CHECK-NEXT: [[FUNC:.*]]:
; CHECK-NEXT: adrp x0, dsolocal
; CHECK-NEXT: add x0, x0, :lo12:dsolocal
; CHECK-NEXT: mov x1, #2
; CHECK-NEXT: b __emupac_pacda
; CHECK-NEXT: .section .rodata
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
@dsolocalref = constant ptr ptrauth (ptr @dsolocal, i32 2, i64 2, ptr null), align 8

; CHECK: dsolocalref8:
; CHECK-NEXT: [[PLACE:.*]]:
; CHECK-NEXT: .section .text.startup
; CHECK-NEXT: [[FUNC:.*]]:
; CHECK-NEXT: adrp x0, dsolocal+8
; CHECK-NEXT: add x0, x0, :lo12:dsolocal+8
; CHECK-NEXT: mov x1, #3
; CHECK-NEXT: b __emupac_pacda
; CHECK-NEXT: .section .rodata
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
@dsolocalref8 = constant ptr ptrauth (ptr getelementptr (i8, ptr @dsolocal, i64 8), i32 2, i64 3, ptr null), align 8

; CHECK: disc:
; CHECK-NEXT: [[PLACE:.*]]:
; CHECK-NEXT: .section .text.startup
; CHECK-NEXT: [[FUNC:.*]]:
; CHECK-NEXT: adrp x0, dsolocal
; CHECK-NEXT: add x0, x0, :lo12:dsolocal
; CHECK-NEXT: adrp x1, [[PLACE]]
; CHECK-NEXT: add x1, x1, :lo12:[[PLACE]]
; CHECK-NEXT: b __emupac_pacda
; CHECK-NEXT: .section .rodata
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
@disc = constant ptr ptrauth (ptr @dsolocal, i32 2, i64 0, ptr @disc), align 8

@global = external global i8

; CHECK: globalref:
; CHECK-NEXT: [[PLACE:.*]]:
; CHECK-NEXT: .section .text.startup
; CHECK-NEXT: [[FUNC:.*]]:
; CHECK-NEXT: adrp x0, :got:global
; CHECK-NEXT: ldr x0, [x0, :got_lo12:global]
; CHECK-NEXT: mov x1, #4
; CHECK-NEXT: b __emupac_pacda
; CHECK-NEXT: .section .rodata
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
@globalref = constant ptr ptrauth (ptr @global, i32 2, i64 4, ptr null), align 8

; CHECK: globalref8:
; CHECK-NEXT: [[PLACE:.*]]:
; CHECK-NEXT: .section .text.startup
; CHECK-NEXT: [[FUNC:.*]]:
; CHECK-NEXT: adrp x0, :got:global
; CHECK-NEXT: ldr x0, [x0, :got_lo12:global]
; CHECK-NEXT: add x0, x0, #8
; CHECK-NEXT: mov x1, #5
; CHECK-NEXT: b __emupac_pacda
; CHECK-NEXT: .section .rodata
; CHECK-NEXT: .xword [[FUNC]]@FUNCINIT
@globalref8 = constant ptr ptrauth (ptr getelementptr (i8, ptr @global, i64 8), i32 2, i64 5, ptr null), align 8
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/AArch64/ptrauth-type-info-vptr-discr.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: llc -mtriple aarch64-linux-gnu -mattr=+pauth -filetype=asm -o - %s | FileCheck --check-prefix=ELF %s
; RUN: llc -mtriple aarch64-linux-musl -mattr=+pauth -filetype=asm -o - %s | FileCheck --check-prefix=ELF %s
; RUN: llc -mtriple aarch64-apple-darwin -mattr=+pauth -filetype=asm -o - %s | FileCheck --check-prefix=MACHO %s

; ELF-LABEL: _ZTI10Disc:
Expand Down
Loading