Skip to content

Commit

Permalink
[AArch64] __builtin_return_address for PAuth.
Browse files Browse the repository at this point in the history
This change adds the support for __builtin_return_address
for ARMv8.3A Pointer Authentication.
Location of the authentication code in the pointer depends on
the system configuration, therefore a dedicated instruction is used for
effectively removing the authentication code without
authenticating the pointer.

Reviewed By: chill

Differential Revision: https://reviews.llvm.org/D75044
  • Loading branch information
DanielKristofKiss committed Sep 24, 2020
1 parent 0a925a8 commit 2a96f47
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 10 deletions.
9 changes: 9 additions & 0 deletions llvm/include/llvm/CodeGen/ISDOpcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,16 @@ enum NodeType {
/// the parent's frame or return address, and so on.
FRAMEADDR,
RETURNADDR,

/// ADDROFRETURNADDR - Represents the llvm.addressofreturnaddress intrinsic.
/// This node takes no operand, returns a target-specific pointer to the
/// place in the stack frame where the return address of the current
/// function is stored.
ADDROFRETURNADDR,

/// SPONENTRY - Represents the llvm.sponentry intrinsic. Takes no argument
/// and returns the stack pointer value at the entry of the current
/// function calling this intrinsic.
SPONENTRY,

/// LOCAL_RECOVER - Represents the llvm.localrecover intrinsic.
Expand Down
31 changes: 24 additions & 7 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6628,17 +6628,34 @@ SDValue AArch64TargetLowering::LowerRETURNADDR(SDValue Op,
EVT VT = Op.getValueType();
SDLoc DL(Op);
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
SDValue ReturnAddress;
if (Depth) {
SDValue FrameAddr = LowerFRAMEADDR(Op, DAG);
SDValue Offset = DAG.getConstant(8, DL, getPointerTy(DAG.getDataLayout()));
return DAG.getLoad(VT, DL, DAG.getEntryNode(),
DAG.getNode(ISD::ADD, DL, VT, FrameAddr, Offset),
MachinePointerInfo());
ReturnAddress = DAG.getLoad(
VT, DL, DAG.getEntryNode(),
DAG.getNode(ISD::ADD, DL, VT, FrameAddr, Offset), MachinePointerInfo());
} else {
// Return LR, which contains the return address. Mark it an implicit
// live-in.
unsigned Reg = MF.addLiveIn(AArch64::LR, &AArch64::GPR64RegClass);
ReturnAddress = DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, VT);
}

// The XPACLRI instruction assembles to a hint-space instruction before
// Armv8.3-A therefore this instruction can be safely used for any pre
// Armv8.3-A architectures. On Armv8.3-A and onwards XPACI is available so use
// that instead.
SDNode *St;
if (Subtarget->hasV8_3aOps()) {
St = DAG.getMachineNode(AArch64::XPACI, DL, VT, ReturnAddress);
} else {
// XPACLRI operates on LR therefore we must move the operand accordingly.
SDValue Chain =
DAG.getCopyToReg(DAG.getEntryNode(), DL, AArch64::LR, ReturnAddress);
St = DAG.getMachineNode(AArch64::XPACLRI, DL, VT, Chain);
}

// Return LR, which contains the return address. Mark it an implicit live-in.
unsigned Reg = MF.addLiveIn(AArch64::LR, &AArch64::GPR64RegClass);
return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, VT);
return SDValue(St, 0);
}

/// LowerShiftRightParts - Lower SRA_PARTS, which returns two
Expand Down
49 changes: 49 additions & 0 deletions llvm/test/CodeGen/AArch64/aarch64-signedreturnaddress.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
; RUN: llc < %s -mtriple=arm64-eabi -asm-verbose=false -mattr=v8.2a | FileCheck %s
; RUN: llc < %s -mtriple=arm64-eabi -asm-verbose=false -mattr=v8.3a | FileCheck %s --check-prefix=CHECKV83

; Armv8.3-A Pointer Authetication requires a special intsruction to strip the
; pointer authentication code from the pointer.
; The XPACLRI instruction assembles to a hint-space instruction before Armv8.3-A
; therefore this instruction can be safely used for any pre Armv8.3-A architectures.
; On Armv8.3-A and onwards XPACI is available so use that instead.

define i8* @ra0() nounwind readnone {
entry:
; CHECK-LABEL: ra0:
; CHECK-NEXT: str x30, [sp, #-16]!
; CHECK-NEXT: hint #7
; CHECK-NEXT: mov x0, x30
; CHECK-NEXT: ldr x30, [sp], #16
; CHECK-NEXT: ret
; CHECKV83: str x30, [sp, #-16]!
; CHECKV83-NEXT: xpaci x30
; CHECKV83-NEXT: mov x0, x30
; CHECKV83-NEXT: ldr x30, [sp], #16
; CHECKV83-NEXT: ret
%0 = tail call i8* @llvm.returnaddress(i32 0)
ret i8* %0
}

define i8* @ra1() nounwind readnone #0 {
entry:
; CHECK-LABEL: ra1:
; CHECK: hint #25
; CHECK-NEXT: str x30, [sp, #-16]!
; CHECK-NEXT: hint #7
; CHECK-NEXT: mov x0, x30
; CHECK-NEXT: ldr x30, [sp], #16
; CHECK-NEXT: hint #29
; CHECK-NEXT: ret
; CHECKV83: paciasp
; CHECKV83-NEXT: str x30, [sp, #-16]!
; CHECKV83-NEXT: xpaci x30
; CHECKV83-NEXT: mov x0, x30
; CHECKV83-NEXT: ldr x30, [sp], #16
; CHECKV83-NEXT: retaa
%0 = tail call i8* @llvm.returnaddress(i32 0)
ret i8* %0
}

attributes #0 = { "sign-return-address"="all" }

declare i8* @llvm.returnaddress(i32) nounwind readnone
5 changes: 4 additions & 1 deletion llvm/test/CodeGen/AArch64/arm64-returnaddr.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
define i8* @rt0(i32 %x) nounwind readnone {
entry:
; CHECK-LABEL: rt0:
; CHECK: hint #7
; CHECK: mov x0, x30
; CHECK: ret
%0 = tail call i8* @llvm.returnaddress(i32 0)
Expand All @@ -16,7 +17,9 @@ entry:
; CHECK: mov x29, sp
; CHECK: ldr x[[REG:[0-9]+]], [x29]
; CHECK: ldr x[[REG2:[0-9]+]], [x[[REG]]]
; CHECK: ldr x0, [x[[REG2]], #8]
; CHECK: ldr x30, [x[[REG2]], #8]
; CHECK: hint #7
; CHECK: mov x0, x30
; CHECK: ldp x29, x30, [sp], #16
; CHECK: ret
%0 = tail call i8* @llvm.returnaddress(i32 2)
Expand Down
4 changes: 3 additions & 1 deletion llvm/test/CodeGen/AArch64/arm64_32.ll
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,9 @@ define i8* @test_toplevel_returnaddr() {
define i8* @test_deep_returnaddr() {
; CHECK-LABEL: test_deep_returnaddr:
; CHECK: ldr x[[FRAME_REC:[0-9]+]], [x29]
; CHECK-OPT: ldr x0, [x[[FRAME_REC]], #8]
; CHECK-OPT: ldr x30, [x[[FRAME_REC]], #8]
; CHECK-OPT: hint #7
; CHECK-OPT: mov x0, x30
; CHECK-FAST: ldr [[TMP:x[0-9]+]], [x[[FRAME_REC]], #8]
; CHECK-FAST: and x0, [[TMP]], #0xffffffff
%val = call i8* @llvm.returnaddress(i32 1)
Expand Down
5 changes: 4 additions & 1 deletion llvm/test/CodeGen/AArch64/returnaddr.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
define i8* @rt0(i32 %x) nounwind readnone {
entry:
; CHECK-LABEL: rt0:
; CHECK: hint #7
; CHECK: mov x0, x30
%0 = tail call i8* @llvm.returnaddress(i32 0)
ret i8* %0
Expand All @@ -13,7 +14,9 @@ entry:
; CHECK-LABEL: rt2:
; CHECK: ldr x[[reg:[0-9]+]], [x29]
; CHECK: ldr x[[reg]], [x[[reg]]]
; CHECK: ldr x0, [x[[reg]], #8]
; CHECK: ldr x30, [x[[reg]], #8]
; CHECK: hint #7
; CHECK: mov x0, x30
%0 = tail call i8* @llvm.returnaddress(i32 2)
ret i8* %0
}
Expand Down

0 comments on commit 2a96f47

Please sign in to comment.