diff --git a/lib/Target/Sparc/SparcISelLowering.cpp b/lib/Target/Sparc/SparcISelLowering.cpp index 527d052258d..7a1e7538ba0 100644 --- a/lib/Target/Sparc/SparcISelLowering.cpp +++ b/lib/Target/Sparc/SparcISelLowering.cpp @@ -3302,3 +3302,16 @@ void SparcTargetLowering::ReplaceNodeResults(SDNode *N, } } } + +// Override to enable LOAD_STACK_GUARD lowering on Linux. +bool SparcTargetLowering::useLoadStackGuardNode() const { + if (!Subtarget->isTargetLinux()) + return TargetLowering::useLoadStackGuardNode(); + return true; +} + +// Override to disable global variable loading on Linux. +void SparcTargetLowering::insertSSPDeclarations(Module &M) const { + if (!Subtarget->isTargetLinux()) + return TargetLowering::insertSSPDeclarations(M); +} diff --git a/lib/Target/Sparc/SparcISelLowering.h b/lib/Target/Sparc/SparcISelLowering.h index 5eee611bf61..42a71d81518 100644 --- a/lib/Target/Sparc/SparcISelLowering.h +++ b/lib/Target/Sparc/SparcISelLowering.h @@ -103,6 +103,10 @@ namespace llvm { return SP::I1; } + /// Override to support customized stack guard loading. + bool useLoadStackGuardNode() const override; + void insertSSPDeclarations(Module &M) const override; + /// getSetCCResultType - Return the ISD::SETCC ValueType EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override; diff --git a/lib/Target/Sparc/SparcInstrInfo.cpp b/lib/Target/Sparc/SparcInstrInfo.cpp index 28b81b608b3..175d4b73d59 100644 --- a/lib/Target/Sparc/SparcInstrInfo.cpp +++ b/lib/Target/Sparc/SparcInstrInfo.cpp @@ -491,3 +491,19 @@ unsigned SparcInstrInfo::getGlobalBaseReg(MachineFunction *MF) const SparcFI->setGlobalBaseReg(GlobalBaseReg); return GlobalBaseReg; } + +bool SparcInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const { + switch (MI->getOpcode()) { + case TargetOpcode::LOAD_STACK_GUARD: { + assert(Subtarget->isTargetLinux() && + "Only Linux target is expected to contain LOAD_STACK_GUARD"); + // offsetof(tcbhead_t, stack_guard) from sysdeps/sparc/nptl/tls.h in glibc. + const int64_t Offset = Subtarget.is64Bit() ? 0x28 : 0x14; + MI->setDesc(get(Subtarget.is64Bit() ? SP::LDXri : SP::LDri)); + MachineInstrBuilder(*MI->getParent()->getParent(), MI) + .addReg(SP::G7).addImm(Offset); + return true; + } + } + return false; +} diff --git a/lib/Target/Sparc/SparcInstrInfo.h b/lib/Target/Sparc/SparcInstrInfo.h index 9de624cc958..52ce4e84749 100644 --- a/lib/Target/Sparc/SparcInstrInfo.h +++ b/lib/Target/Sparc/SparcInstrInfo.h @@ -97,6 +97,9 @@ public: const TargetRegisterInfo *TRI) const override; unsigned getGlobalBaseReg(MachineFunction *MF) const; + + // Lower pseudo instructions after register allocation. + bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const override; }; } diff --git a/lib/Target/Sparc/SparcSubtarget.cpp b/lib/Target/Sparc/SparcSubtarget.cpp index 69cf294aeed..3bc22b530f6 100644 --- a/lib/Target/Sparc/SparcSubtarget.cpp +++ b/lib/Target/Sparc/SparcSubtarget.cpp @@ -52,7 +52,7 @@ SparcSubtarget &SparcSubtarget::initializeSubtargetDependencies(StringRef CPU, SparcSubtarget::SparcSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS, TargetMachine &TM, bool is64Bit) - : SparcGenSubtargetInfo(TT, CPU, FS), Is64Bit(is64Bit), + : SparcGenSubtargetInfo(TT, CPU, FS), TargetTriple(TT), Is64Bit(is64Bit), InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), FrameLowering(*this) {} diff --git a/lib/Target/Sparc/SparcSubtarget.h b/lib/Target/Sparc/SparcSubtarget.h index 7db962806a5..31f688e74c6 100644 --- a/lib/Target/Sparc/SparcSubtarget.h +++ b/lib/Target/Sparc/SparcSubtarget.h @@ -30,6 +30,7 @@ namespace llvm { class StringRef; class SparcSubtarget : public SparcGenSubtargetInfo { + Triple TargetTriple; virtual void anchor(); bool IsV9; bool IsLeon; @@ -89,6 +90,8 @@ public: /// returns adjusted framesize which includes space for register window /// spills and arguments. int getAdjustedFrameSize(int stackSize) const; + + bool isTargetLinux() const { return TargetTriple.isOSLinux(); } }; } // end namespace llvm diff --git a/test/CodeGen/SPARC/stack-protector.ll b/test/CodeGen/SPARC/stack-protector.ll new file mode 100644 index 00000000000..70a73664aa1 --- /dev/null +++ b/test/CodeGen/SPARC/stack-protector.ll @@ -0,0 +1,33 @@ +; RUN: llc -mtriple=sparc-unknown-linux < %s | FileCheck %s --check-prefix=LINUX-32 +; RUN: llc -mtriple=sparc64-unknown-linux < %s | FileCheck %s --check-prefix=LINUX-64 +; RUN: llc -mtriple=sparc-unknown-solaris < %s | FileCheck %s --check-prefix=GENERIC +; RUN: llc -mtriple=sparc64-unknown-solaris < %s | FileCheck %s --check-prefix=GENERIC + +; LINUX-32: ld [%g7+20], [[REG1:%[ilo][0-9]*]] +; LINUX-64: ldx [%g7+40], [[REG1:%[ilo][0-9]*]] +; LINUX-32-NOT: __stack_chk_guard +; LINUX-64-NOT: __stack_chk_guard +; GENERIC: __stack_chk_guard + +@"\01LC" = internal constant [11 x i8] c"buf == %s\0A\00" ; <[11 x i8]*> [#uses=1] + +define void @test(i8* %a) nounwind ssp { +entry: + %a_addr = alloca i8* ; [#uses=2] + %buf = alloca [8 x i8] ; <[8 x i8]*> [#uses=2] + %"alloca point" = bitcast i32 0 to i32 ; [#uses=0] + store i8* %a, i8** %a_addr + %buf1 = bitcast [8 x i8]* %buf to i8* ; [#uses=1] + %0 = load i8*, i8** %a_addr, align 4 ; [#uses=1] + %1 = call i8* @strcpy(i8* %buf1, i8* %0) nounwind ; [#uses=0] + %buf2 = bitcast [8 x i8]* %buf to i8* ; [#uses=1] + %2 = call i32 (i8*, ...) @printf(i8* getelementptr ([11 x i8], [11 x i8]* @"\01LC", i32 0, i32 0), i8* %buf2) nounwind ; [#uses=0] + br label %return + +return: ; preds = %entry + ret void +} + +declare i8* @strcpy(i8*, i8*) nounwind + +declare i32 @printf(i8*, ...) nounwind