[PATCH] D45239: AArch64: Implement support for the shadowcallstack attribute.
This revision was automatically updated to reflect the committed changes. Closed by commit rL329236: AArch64: Implement support for the shadowcallstack attribute. (authored by pcc, committed by ). Changed prior to commit: https://reviews.llvm.org/D45239?vs=141063&id=141068#toc Repository: rL LLVM https://reviews.llvm.org/D45239 Files: cfe/trunk/docs/ShadowCallStack.rst cfe/trunk/lib/Driver/SanitizerArgs.cpp cfe/trunk/lib/Driver/ToolChain.cpp cfe/trunk/test/Driver/sanitizer-ld.c llvm/trunk/include/llvm/Support/TargetParser.h llvm/trunk/lib/Support/TargetParser.cpp llvm/trunk/lib/Target/AArch64/AArch64CallingConvention.td llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp llvm/trunk/lib/Target/AArch64/AArch64Subtarget.cpp llvm/trunk/test/CodeGen/AArch64/shadow-call-stack.ll Index: llvm/trunk/lib/Target/AArch64/AArch64CallingConvention.td === --- llvm/trunk/lib/Target/AArch64/AArch64CallingConvention.td +++ llvm/trunk/lib/Target/AArch64/AArch64CallingConvention.td @@ -349,3 +349,18 @@ : CalleeSavedRegs<(add (sequence "X%u", 0, 15), (sequence "X%u", 18, 28), FP, SP, (sequence "Q%u", 0, 31))>; + +// Variants of the standard calling conventions for shadow call stack. +// These all preserve x18 in addition to any other registers. +def CSR_AArch64_NoRegs_SCS +: CalleeSavedRegs<(add CSR_AArch64_NoRegs, X18)>; +def CSR_AArch64_AllRegs_SCS +: CalleeSavedRegs<(add CSR_AArch64_AllRegs, X18)>; +def CSR_AArch64_CXX_TLS_Darwin_SCS +: CalleeSavedRegs<(add CSR_AArch64_CXX_TLS_Darwin, X18)>; +def CSR_AArch64_AAPCS_SwiftError_SCS +: CalleeSavedRegs<(add CSR_AArch64_AAPCS_SwiftError, X18)>; +def CSR_AArch64_RT_MostRegs_SCS +: CalleeSavedRegs<(add CSR_AArch64_RT_MostRegs, X18)>; +def CSR_AArch64_AAPCS_SCS +: CalleeSavedRegs<(add CSR_AArch64_AAPCS, X18)>; Index: llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp === --- llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp +++ llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -75,21 +75,25 @@ const uint32_t * AArch64RegisterInfo::getCallPreservedMask(const MachineFunction &MF, CallingConv::ID CC) const { + bool SCS = MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack); if (CC == CallingConv::GHC) // This is academic because all GHC calls are (supposed to be) tail calls -return CSR_AArch64_NoRegs_RegMask; +return SCS ? CSR_AArch64_NoRegs_SCS_RegMask : CSR_AArch64_NoRegs_RegMask; if (CC == CallingConv::AnyReg) -return CSR_AArch64_AllRegs_RegMask; +return SCS ? CSR_AArch64_AllRegs_SCS_RegMask : CSR_AArch64_AllRegs_RegMask; if (CC == CallingConv::CXX_FAST_TLS) -return CSR_AArch64_CXX_TLS_Darwin_RegMask; +return SCS ? CSR_AArch64_CXX_TLS_Darwin_SCS_RegMask + : CSR_AArch64_CXX_TLS_Darwin_RegMask; if (MF.getSubtarget().getTargetLowering() ->supportSwiftError() && MF.getFunction().getAttributes().hasAttrSomewhere(Attribute::SwiftError)) -return CSR_AArch64_AAPCS_SwiftError_RegMask; +return SCS ? CSR_AArch64_AAPCS_SwiftError_SCS_RegMask + : CSR_AArch64_AAPCS_SwiftError_RegMask; if (CC == CallingConv::PreserveMost) -return CSR_AArch64_RT_MostRegs_RegMask; +return SCS ? CSR_AArch64_RT_MostRegs_SCS_RegMask + : CSR_AArch64_RT_MostRegs_RegMask; else -return CSR_AArch64_AAPCS_RegMask; +return SCS ? CSR_AArch64_AAPCS_SCS_RegMask : CSR_AArch64_AAPCS_RegMask; } const uint32_t *AArch64RegisterInfo::getTLSCallPreservedMask() const { Index: llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp === --- llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp +++ llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -414,6 +414,14 @@ static MachineBasicBlock::iterator convertCalleeSaveRestoreToSPPrePostIncDec( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, const TargetInstrInfo *TII, int CSStackSizeInc) { + // Ignore instructions that do not operate on SP, i.e. shadow call stack + // instructions. + while (MBBI->getOpcode() == AArch64::STRXpost || + MBBI->getOpcode() == AArch64::LDRXpre) { +assert(MBBI->getOperand(0).getReg() != AArch64::SP); +++MBBI; + } + unsigned NewOpc; bool NewIsUnscaled = false; switch (MBBI->getOpcode()) { @@ -481,6 +489,14 @@ static void fixupCalleeSaveRestoreStackOffset(MachineInstr &MI, unsigned LocalStackSize) { unsigned Opc = MI.getOpcode(); + + // Ignore instructions that do not operate on SP, i.e. shadow call stack + // instructions. + if (Opc == AArch64::STRXpost || Opc == AArch64::LDRXpre
[PATCH] D45239: AArch64: Implement support for the shadowcallstack attribute.
pcc updated this revision to Diff 141063. pcc marked 3 inline comments as done. pcc added a comment. - Addres review comments https://reviews.llvm.org/D45239 Files: clang/docs/ShadowCallStack.rst clang/lib/Driver/SanitizerArgs.cpp clang/lib/Driver/ToolChain.cpp clang/test/Driver/sanitizer-ld.c llvm/include/llvm/Support/TargetParser.h llvm/lib/Support/TargetParser.cpp llvm/lib/Target/AArch64/AArch64CallingConvention.td llvm/lib/Target/AArch64/AArch64FrameLowering.cpp llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp llvm/lib/Target/AArch64/AArch64Subtarget.cpp llvm/test/CodeGen/AArch64/shadow-call-stack.ll Index: llvm/test/CodeGen/AArch64/shadow-call-stack.ll === --- /dev/null +++ llvm/test/CodeGen/AArch64/shadow-call-stack.ll @@ -0,0 +1,47 @@ +; RUN: llc -verify-machineinstrs -o - %s -mtriple=aarch64-linux-gnu -mattr=+reserve-x18 | FileCheck %s + +define void @f1() shadowcallstack { + ; CHECK: f1: + ; CHECK-NOT: x18 + ; CHECK: ret + ret void +} + +declare void @foo() + +define void @f2() shadowcallstack { + ; CHECK: f2: + ; CHECK-NOT: x18 + ; CHECK: b foo + tail call void @foo() + ret void +} + +declare i32 @bar() + +define i32 @f3() shadowcallstack { + ; CHECK: f3: + ; CHECK: str x30, [x18], #8 + ; CHECK: str x30, [sp, #-16]! + %res = call i32 @bar() + %res1 = add i32 %res, 1 + ; CHECK: ldr x30, [sp], #16 + ; CHECK: ldr x30, [x18, #-8]! + ; CHECK: ret + ret i32 %res +} + +define i32 @f4() shadowcallstack { + ; CHECK: f4: + %res1 = call i32 @bar() + %res2 = call i32 @bar() + %res3 = call i32 @bar() + %res4 = call i32 @bar() + %res12 = add i32 %res1, %res2 + %res34 = add i32 %res3, %res4 + %res1234 = add i32 %res12, %res34 + ; CHECK: ldp {{.*}}x30, [sp + ; CHECK: ldr x30, [x18, #-8]! + ; CHECK: ret + ret i32 %res1234 +} Index: llvm/lib/Target/AArch64/AArch64Subtarget.cpp === --- llvm/lib/Target/AArch64/AArch64Subtarget.cpp +++ llvm/lib/Target/AArch64/AArch64Subtarget.cpp @@ -24,6 +24,7 @@ #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" #include "llvm/CodeGen/MachineScheduler.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/Support/TargetParser.h" using namespace llvm; @@ -151,8 +152,8 @@ const std::string &FS, const TargetMachine &TM, bool LittleEndian) : AArch64GenSubtargetInfo(TT, CPU, FS), - ReserveX18(TT.isOSDarwin() || TT.isOSFuchsia() || TT.isOSWindows()), - IsLittle(LittleEndian), TargetTriple(TT), FrameLowering(), + ReserveX18(AArch64::isX18ReservedByDefault(TT)), IsLittle(LittleEndian), + TargetTriple(TT), FrameLowering(), InstrInfo(initializeSubtargetDependencies(FS, CPU)), TSInfo(), TLInfo(TM, *this) { CallLoweringInfo.reset(new AArch64CallLowering(*getTargetLowering())); Index: llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp === --- llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp +++ llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -75,21 +75,25 @@ const uint32_t * AArch64RegisterInfo::getCallPreservedMask(const MachineFunction &MF, CallingConv::ID CC) const { + bool SCS = MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack); if (CC == CallingConv::GHC) // This is academic because all GHC calls are (supposed to be) tail calls -return CSR_AArch64_NoRegs_RegMask; +return SCS ? CSR_AArch64_NoRegs_SCS_RegMask : CSR_AArch64_NoRegs_RegMask; if (CC == CallingConv::AnyReg) -return CSR_AArch64_AllRegs_RegMask; +return SCS ? CSR_AArch64_AllRegs_SCS_RegMask : CSR_AArch64_AllRegs_RegMask; if (CC == CallingConv::CXX_FAST_TLS) -return CSR_AArch64_CXX_TLS_Darwin_RegMask; +return SCS ? CSR_AArch64_CXX_TLS_Darwin_SCS_RegMask + : CSR_AArch64_CXX_TLS_Darwin_RegMask; if (MF.getSubtarget().getTargetLowering() ->supportSwiftError() && MF.getFunction().getAttributes().hasAttrSomewhere(Attribute::SwiftError)) -return CSR_AArch64_AAPCS_SwiftError_RegMask; +return SCS ? CSR_AArch64_AAPCS_SwiftError_SCS_RegMask + : CSR_AArch64_AAPCS_SwiftError_RegMask; if (CC == CallingConv::PreserveMost) -return CSR_AArch64_RT_MostRegs_RegMask; +return SCS ? CSR_AArch64_RT_MostRegs_SCS_RegMask + : CSR_AArch64_RT_MostRegs_RegMask; else -return CSR_AArch64_AAPCS_RegMask; +return SCS ? CSR_AArch64_AAPCS_SCS_RegMask : CSR_AArch64_AAPCS_RegMask; } const uint32_t *AArch64RegisterInfo::getTLSCallPreservedMask() const { Index: llvm/lib/Target/AArch64/AArch64FrameLowering.cpp === --- llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -414,6 +414,14 @@ static MachineBasicB
[PATCH] D45239: AArch64: Implement support for the shadowcallstack attribute.
eugenis added inline comments. Comment at: clang/docs/ShadowCallStack.rst:12 ShadowCallStack is an **experimental** instrumentation pass, currently only implemented for x86_64, that protects programs against return address overwrites (e.g. stack buffer overflows.) It works by saving a function's return vlad.tsyrklevich wrote: > Should also mention aarch64 here. needs update Comment at: llvm/lib/Target/AArch64/AArch64FrameLowering.cpp:1153 +report_fatal_error("Must reserve x18 to use shadow call stack"); + NeedSCSProlog = true; +} That's way too cryptic, please call it NeedShadowCallStackProlog or something similar. https://reviews.llvm.org/D45239 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D45239: AArch64: Implement support for the shadowcallstack attribute.
vlad.tsyrklevich accepted this revision. vlad.tsyrklevich added inline comments. This revision is now accepted and ready to land. Comment at: clang/docs/ShadowCallStack.rst:12 ShadowCallStack is an **experimental** instrumentation pass, currently only implemented for x86_64, that protects programs against return address overwrites (e.g. stack buffer overflows.) It works by saving a function's return Should also mention aarch64 here. Comment at: llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp:78 CallingConv::ID CC) const { + bool SCS = MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack); if (CC == CallingConv::GHC) It's sort of a stretch to construct a scenario where this is likely to happen, but is it possible that a runtime function marked with `__attribute__((no_sanitize("shadowcallstack")))` would spill x18 across a function call because of this mask if it's referenced before and after? If that was a concern, we could make this test `hasAttr(SCS) || hasFlag(fFixedx18)` https://reviews.llvm.org/D45239 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D45239: AArch64: Implement support for the shadowcallstack attribute.
pcc created this revision. pcc added reviewers: vlad.tsyrklevich, eugenis, kcc, t.p.northover, olista01. Herald added subscribers: hiraditya, kristof.beyls, javed.absar, rengolin. The implementation of shadow call stack on aarch64 is quite different to the implementation on x86_64. Instead of reserving a segment register for the shadow call stack, we reserve the platform register, x18. Any function that spills lr to sp also spills it to the shadow call stack, a pointer to which is stored in x18. https://reviews.llvm.org/D45239 Files: clang/docs/ShadowCallStack.rst clang/lib/Driver/SanitizerArgs.cpp clang/lib/Driver/ToolChain.cpp clang/test/Driver/sanitizer-ld.c llvm/include/llvm/Support/TargetParser.h llvm/lib/Support/TargetParser.cpp llvm/lib/Target/AArch64/AArch64CallingConvention.td llvm/lib/Target/AArch64/AArch64FrameLowering.cpp llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp llvm/lib/Target/AArch64/AArch64Subtarget.cpp llvm/test/CodeGen/AArch64/shadow-call-stack.ll Index: llvm/test/CodeGen/AArch64/shadow-call-stack.ll === --- /dev/null +++ llvm/test/CodeGen/AArch64/shadow-call-stack.ll @@ -0,0 +1,47 @@ +; RUN: llc -verify-machineinstrs -o - %s -mtriple=aarch64-linux-gnu -mattr=+reserve-x18 | FileCheck %s + +define void @f1() shadowcallstack { + ; CHECK: f1: + ; CHECK-NOT: x18 + ; CHECK: ret + ret void +} + +declare void @foo() + +define void @f2() shadowcallstack { + ; CHECK: f2: + ; CHECK-NOT: x18 + ; CHECK: b foo + tail call void @foo() + ret void +} + +declare i32 @bar() + +define i32 @f3() shadowcallstack { + ; CHECK: f3: + ; CHECK: str x30, [x18], #8 + ; CHECK: str x30, [sp, #-16]! + %res = call i32 @bar() + %res1 = add i32 %res, 1 + ; CHECK: ldr x30, [sp], #16 + ; CHECK: ldr x30, [x18, #-8]! + ; CHECK: ret + ret i32 %res +} + +define i32 @f4() shadowcallstack { + ; CHECK: f4: + %res1 = call i32 @bar() + %res2 = call i32 @bar() + %res3 = call i32 @bar() + %res4 = call i32 @bar() + %res12 = add i32 %res1, %res2 + %res34 = add i32 %res3, %res4 + %res1234 = add i32 %res12, %res34 + ; CHECK: ldp {{.*}}x30, [sp + ; CHECK: ldr x30, [x18, #-8]! + ; CHECK: ret + ret i32 %res1234 +} Index: llvm/lib/Target/AArch64/AArch64Subtarget.cpp === --- llvm/lib/Target/AArch64/AArch64Subtarget.cpp +++ llvm/lib/Target/AArch64/AArch64Subtarget.cpp @@ -24,6 +24,7 @@ #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" #include "llvm/CodeGen/MachineScheduler.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/Support/TargetParser.h" using namespace llvm; @@ -151,8 +152,8 @@ const std::string &FS, const TargetMachine &TM, bool LittleEndian) : AArch64GenSubtargetInfo(TT, CPU, FS), - ReserveX18(TT.isOSDarwin() || TT.isOSFuchsia() || TT.isOSWindows()), - IsLittle(LittleEndian), TargetTriple(TT), FrameLowering(), + ReserveX18(AArch64::isX18ReservedByDefault(TT)), IsLittle(LittleEndian), + TargetTriple(TT), FrameLowering(), InstrInfo(initializeSubtargetDependencies(FS, CPU)), TSInfo(), TLInfo(TM, *this) { CallLoweringInfo.reset(new AArch64CallLowering(*getTargetLowering())); Index: llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp === --- llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp +++ llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -75,21 +75,25 @@ const uint32_t * AArch64RegisterInfo::getCallPreservedMask(const MachineFunction &MF, CallingConv::ID CC) const { + bool SCS = MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack); if (CC == CallingConv::GHC) // This is academic because all GHC calls are (supposed to be) tail calls -return CSR_AArch64_NoRegs_RegMask; +return SCS ? CSR_AArch64_NoRegs_SCS_RegMask : CSR_AArch64_NoRegs_RegMask; if (CC == CallingConv::AnyReg) -return CSR_AArch64_AllRegs_RegMask; +return SCS ? CSR_AArch64_AllRegs_SCS_RegMask : CSR_AArch64_AllRegs_RegMask; if (CC == CallingConv::CXX_FAST_TLS) -return CSR_AArch64_CXX_TLS_Darwin_RegMask; +return SCS ? CSR_AArch64_CXX_TLS_Darwin_SCS_RegMask + : CSR_AArch64_CXX_TLS_Darwin_RegMask; if (MF.getSubtarget().getTargetLowering() ->supportSwiftError() && MF.getFunction().getAttributes().hasAttrSomewhere(Attribute::SwiftError)) -return CSR_AArch64_AAPCS_SwiftError_RegMask; +return SCS ? CSR_AArch64_AAPCS_SwiftError_SCS_RegMask + : CSR_AArch64_AAPCS_SwiftError_RegMask; if (CC == CallingConv::PreserveMost) -return CSR_AArch64_RT_MostRegs_RegMask; +return SCS ? CSR_AArch64_RT_MostRegs_SCS_RegMask + : CSR_AArch64_RT_MostRegs_RegMask; else -return CSR_AArch64_AAPCS_RegMask; +return SCS ? CSR_AArch64_AAPCS_SCS_RegMask : C