[PATCH] -fstack-protector-strong part 3: data layout
Magee, Joshua
Joshua_Magee at playstation.sony.com
Wed May 15 19:29:57 PDT 2013
Ping, with updated patch against top-of-tree.
- Josh
At 1365663271 seconds past the Epoch, Magee, Joshua wrote:
> Attached is a re-work of the SSP data layout patch I submitted back in
> February. (Sorry about the extremely tardy follow-up.)
>
> This version removes the introduction of a field to AllocaInst (which was used
> to communicate the layout preference of an AllocaInst from the StackProtector
> pass to the PEI/LocalStack passes.) Instead the SSPLayoutKind required for each
> AI is communicated with getAnalysis(). Currently, the analysis is implemented
> as part of the StackProtector pass. Another possibility would be to split the
> analysis into a separate pass thereby yielding 1 mutation-free analysis pass
> (which determines which AllocaInsts trigger protectors and the SSPLayoutKind they
> require) and another transformation pass (which actually does the insertion of
> the protectors.) I decided to leave it as one pass for now and then see if
> anyone expressed preference for the other during review.
>
> One thing that I am not happy is that I needed to mark several other passes as
> preserving the stack-protector analysis. It felt like there should be a better
> way to express that the analysis won't be invalidated by subsequent passes, but
> I couldn't find one.
>
> - Josh
>
>
> > -----Original Message-----
> > From: llvm-commits-bounces at cs.uiuc.edu [mailto:llvm-commits-
> > bounces at cs.uiuc.edu] On Behalf Of Magee, Josh
> > Sent: Tuesday, February 12, 2013 4:45 PM
> > To: Bill Wendling
> > Cc: llvm-commits at cs.uiuc.edu
> > Subject: RE: [PATCH] -fstack-protector-strong part 3: data layout
> >
> > Hi Bill,
> >
> > I had wondered if adding a field to AllocaInst might be a problem (especially
> > since the field is for a fairly specialized purpose that is not relevant to the
> > majority of users of the class.) I'll re-work the patch to avoid modifying
> > AllocaInst. (My current idea is to maintain a ValueMap of <AllocaInst*,
> > SSPLayoutKinds> in the StackProtector pass itself and then use getAnalysis
> > to access this from the PEI and LocalStackAllocation passes. It seems like I
> > might need to split the StackProtector pass into separate analysis and
> > transform passes, but I'm not certain yet.)
> >
> > Hopefully I can have an update ready within the next couple of days.
> > Thanks!
> > Josh
> >
> >
> > > -----Original Message-----
> > > From: Bill Wendling [mailto:wendling at apple.com]
> > > Sent: Tuesday, February 12, 2013 12:31 AM
> > > To: Magee, Josh
> > > Cc: llvm-commits at cs.uiuc.edu
> > > Subject: Re: [PATCH] -fstack-protector-strong part 3: data layout
> > >
> > > Hi Josh,
> > >
> > > I'll review this in a few days (sorry, I'm swamped). One comment
> > > though, is there *any* way for you to not add a field to AllocaInst?
> > > I'm going to push back hard on that because it's a basic class and
> > > shouldn't be modified unless absolutely necessary, especially if
> > > you're adding fields to it. :)
> > >
> > > -bw
> > >
> > > On Feb 11, 2013, at 7:01 PM, "Magee, Josh"
> > <Joshua.Magee at am.sony.com>
> > > wrote:
> > >
> > > > Hi,
> > > >
> > > > This is part 3 in the stack-protector-strong series.
> > > > This patch adds support for data layout rules.
> > > >
> > > > The rules for ssp are:
> > > > 1) Large arrays and structures containing large arrays should be closest to
> > > > the stack protector. "Large" is defined as >= ssp-buffer-size.
> > > > 2) The remaining stack objects are arranged normally.
> > > >
> > > > These rules for sspstrong and sspreq are the same:
> > > > 1) Large arrays and structures containing large arrays should be closest to
> > > > the stack protector. "Large" is defined as >= ssp-buffer-size.
> > > > 2) Small arrays and structures containing small arrays should be 2nd
> > > > closet
> > > to
> > > > the protector. "Small" is defined as < ssp-buffer-size.
> > > > 3) Variables that have had their address taken should be 3rd closest to
> > the
> > > > protector.
> > > > 4) The remaining stack objects are arranged normally.
> > > >
> > > > LLVM already allocates SSP-triggering objects near the stack protector,
> > but:
> > > > a) The heuristic used is very basic and doesn't necessarily match what
> > the
> > > > StackProtector pass does.
> > > > b) It doesn't handle the finer grained rules for strong/req listed above.
> > > >
> > > > Rather than determining if a stack object may need to be placed near
> > > > the protector in FunctionLoweringInfo.cpp, I thought it is better to
> > > > make this decision in the StackProtector pass (where we already do
> > > > the needed analysis
> > > > anyway.)
> > > >
> > > > The changes I made are:
> > > > 1) Add an enum type to represent the SSP Layout.
> > > > * SSPLayoutKind
> > > > 2) Add a field to AllocaInst to keep track of the SSPLayoutKind.
> > > > 3) Update the StackProtector pass analysis to set the SSPLayoutKind for
> > an
> > > > AllocaInst. This requires two unfortunate changes:
> > > > * Since all variables vulnerable to stack smashing need to be re-
> > arranged
> > > > (and not just the first one encountered), the analyze can't exit early
> > > > after finding the first one.
> > > > * The analysis needs to be run for SSPReq. Before it wasn't necessary
> > for
> > > > SSPReq because all SSPReq functions get a protector regardless of their
> > > > variables. Now the analysis is needed to mark the vulnerable
> > variables.
> > > > 4) Teach the PrologEpilogInserter and LocalStackAllocation passes
> > > > the new
> > > SSP
> > > > stack re-arrangement rules.
> > > >
> > > > Thanks!
> > > > -Josh
> > > > <part3-sspstrong-datalayout.diff>
> > >
> >
> >
> >
> > _______________________________________________
> > llvm-commits mailing list
> > llvm-commits at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
-------------- next part --------------
diff --git docs/LangRef.rst docs/LangRef.rst
index 4d006f1..141f9a1 100644
--- docs/LangRef.rst
+++ docs/LangRef.rst
@@ -903,6 +903,9 @@ example:
- Calls to alloca() with variable sizes or constant sizes greater than
``ssp-buffer-size``.
+ Variables that are identified as requiring a protector will be arranged
+ on the stack such that they are adjacent to the stack protector variable.
+
If a function that has an ``ssp`` attribute is inlined into a
function that doesn't have an ``ssp`` attribute, then the resulting
function will have an ``ssp`` attribute.
@@ -911,6 +914,16 @@ example:
stack smashing protector. This overrides the ``ssp`` function
attribute.
+ Variables that are identified as requiring a protector will be arranged
+ on the stack such that they are adjacent to the stack protector variable.
+ The specific layout rules are:
+ - Large arrays and structures containing large arrays (>= ssp-buffer-size)
+ are closest to the stack protector.
+ - Small arrays and structures containing small arrays (< ssp-buffer-size)
+ are 2nd closest to the protector.
+ - Variables that have had their address taken are 3rd closest to the
+ protector.
+
If a function that has an ``sspreq`` attribute is inlined into a
function that doesn't have an ``sspreq`` attribute or which has an
``ssp`` or ``sspstrong`` attribute, then the resulting function will have
@@ -926,6 +939,16 @@ example:
- Calls to alloca().
- Local variables that have had their address taken.
+ Variables that are identified as requiring a protector will be arranged
+ on the stack such that they are adjacent to the stack protector variable.
+ The specific layout rules are:
+ - Large arrays and structures containing large arrays (>= ssp-buffer-size)
+ are closest to the stack protector.
+ - Small arrays and structures containing small arrays (< ssp-buffer-size)
+ are 2nd closest to the protector.
+ - Variables that have had their address taken are 3rd closest to the
+ protector.
+
This overrides the ``ssp`` function attribute.
If a function that has an ``sspstrong`` attribute is inlined into a
diff --git include/llvm/CodeGen/MachineFrameInfo.h include/llvm/CodeGen/MachineFrameInfo.h
index cdec7e6..6fab88c 100644
--- include/llvm/CodeGen/MachineFrameInfo.h
+++ include/llvm/CodeGen/MachineFrameInfo.h
@@ -100,11 +100,6 @@ class MachineFrameInfo {
// cannot alias any other memory objects.
bool isSpillSlot;
- // MayNeedSP - If true the stack object triggered the creation of the stack
- // protector. We should allocate this object right after the stack
- // protector.
- bool MayNeedSP;
-
/// Alloca - If this stack object is originated from an Alloca instruction
/// this value saves the original IR allocation. Can be NULL.
const AllocaInst *Alloca;
@@ -114,9 +109,9 @@ class MachineFrameInfo {
bool PreAllocated;
StackObject(uint64_t Sz, unsigned Al, int64_t SP, bool IM,
- bool isSS, bool NSP, const AllocaInst *Val)
+ bool isSS, const AllocaInst *Val)
: SPOffset(SP), Size(Sz), Alignment(Al), isImmutable(IM),
- isSpillSlot(isSS), MayNeedSP(NSP), Alloca(Val), PreAllocated(false) {}
+ isSpillSlot(isSS), Alloca(Val), PreAllocated(false) {}
};
/// Objects - The list of stack objects allocated...
@@ -379,14 +374,6 @@ public:
return Objects[ObjectIdx+NumFixedObjects].Alloca;
}
- /// NeedsStackProtector - Returns true if the object may need stack
- /// protectors.
- bool MayNeedStackProtector(int ObjectIdx) const {
- assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
- "Invalid Object Idx!");
- return Objects[ObjectIdx+NumFixedObjects].MayNeedSP;
- }
-
/// getObjectOffset - Return the assigned stack offset of the specified object
/// from the incoming stack pointer.
///
@@ -500,7 +487,7 @@ public:
/// a nonnegative identifier to represent it.
///
int CreateStackObject(uint64_t Size, unsigned Alignment, bool isSS,
- bool MayNeedSP = false, const AllocaInst *Alloca = 0);
+ const AllocaInst *Alloca = 0);
/// CreateSpillStackObject - Create a new statically sized stack object that
/// represents a spill slot, returning a nonnegative identifier to represent
@@ -520,7 +507,7 @@ public:
/// variable sized object is created, whether or not the index returned is
/// actually used.
///
- int CreateVariableSizedObject(unsigned Alignment);
+ int CreateVariableSizedObject(unsigned Alignment, const AllocaInst *Alloca);
/// getCalleeSavedInfo - Returns a reference to call saved info vector for the
/// current function.
diff --git include/llvm/CodeGen/StackProtector.h include/llvm/CodeGen/StackProtector.h
new file mode 100644
index 0000000..960910c
--- /dev/null
+++ include/llvm/CodeGen/StackProtector.h
@@ -0,0 +1,116 @@
+//===-- StackProtector.h - Stack Protector Insertion --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass inserts stack protectors into functions which need them. A variable
+// with a random value in it is stored onto the stack before the local variables
+// are allocated. Upon exiting the block, the stored value is checked. If it's
+// changed, then there was some sort of violation and the program aborts.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_STACKPROTECTOR_H
+#define LLVM_CODEGEN_STACKPROTECTOR_H
+
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/ValueMap.h"
+#include "llvm/Analysis/Dominators.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Target/TargetLowering.h"
+
+namespace llvm {
+class StackProtector : public FunctionPass {
+public:
+ /// SSPLayoutKind. Stack Smashing Protection (SSP) rules require that
+ /// vulnerable stack allocations are located close the stack protector.
+ enum SSPLayoutKind {
+ SSPLK_None, //< Did not trigger a stack protector. No effect on data
+ //< layout.
+ SSPLK_LargeArray, //< Array or nested array >= SSP-buffer-size. Closest
+ //< to the stack protector.
+ SSPLK_SmallArray, //< Array or nested array < SSP-buffer-size. 2nd closest
+ //< to the stack protector.
+ SSPLK_AddrOf //< The address of this allocation is exposed and
+ //< triggered protection. 3rd closest to the protector.
+ };
+
+ /// A mapping of AllocaInsts to their required SSP layout.
+ typedef ValueMap<const AllocaInst*, SSPLayoutKind> SSPLayoutMap;
+
+private:
+ /// TLI - Keep a pointer of a TargetLowering to consult for determining
+ /// target type sizes.
+ const TargetLoweringBase *TLI;
+
+ Function *F;
+ Module *M;
+
+ DominatorTree *DT;
+
+ /// Layout - Mapping of allocations to the required SSPLayoutKind.
+ /// StackProtector analysis will update this map when determining if an
+ /// AllocaInst triggers a stack protector.
+ SSPLayoutMap Layout;
+
+ /// VisitedPHIs - The set of PHI nodes visited when determining
+ /// if a variable's reference has been taken. This set
+ /// is maintained to ensure we don't visit the same PHI node multiple
+ /// times.
+ SmallPtrSet<const PHINode*, 16> VisitedPHIs;
+
+ /// InsertStackProtectors - Insert code into the prologue and epilogue of
+ /// the function.
+ ///
+ /// - The prologue code loads and stores the stack guard onto the stack.
+ /// - The epilogue checks the value stored in the prologue against the
+ /// original value. It calls __stack_chk_fail if they differ.
+ bool InsertStackProtectors();
+
+ /// CreateFailBB - Create a basic block to jump to when the stack protector
+ /// check fails.
+ BasicBlock *CreateFailBB();
+
+ /// ContainsProtectableArray - Check whether the type either is an array or
+ /// contains an array of sufficient size so that we need stack protectors
+ /// for it.
+ /// \param [out] IsLarge is set to true if a protectable array is found and
+ /// it is "large" ( >= ssp-buffer-size). In the case of a structure with
+ /// multiple arrays, this gets set if any of them is large.
+ bool ContainsProtectableArray(Type *Ty, bool &IsLarge, bool Strong = false,
+ bool InStruct = false) const;
+
+ /// \brief Check whether a stack allocation has its address taken.
+ bool HasAddressTaken(const Instruction *AI);
+
+ /// RequiresStackProtector - Check whether or not this function needs a
+ /// stack protector based upon the stack protector level.
+ bool RequiresStackProtector();
+public:
+ static char ID; // Pass identification, replacement for typeid.
+ StackProtector() : FunctionPass(ID), TLI(0) {
+ initializeStackProtectorPass(*PassRegistry::getPassRegistry());
+ }
+ StackProtector(const TargetLoweringBase *tli)
+ : FunctionPass(ID), TLI(tli) {
+ initializeStackProtectorPass(*PassRegistry::getPassRegistry());
+ }
+
+ virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addPreserved<DominatorTree>();
+ }
+
+ SSPLayoutKind getSSPLayout(const AllocaInst *AI) const;
+
+ virtual bool runOnFunction(Function &Fn);
+};
+} // end namespace llvm
+
+#endif // LLVM_CODEGEN_STACKPROTECTOR_H
diff --git lib/CodeGen/LocalStackSlotAllocation.cpp lib/CodeGen/LocalStackSlotAllocation.cpp
index 26a1176..cb770b4 100644
--- lib/CodeGen/LocalStackSlotAllocation.cpp
+++ lib/CodeGen/LocalStackSlotAllocation.cpp
@@ -17,12 +17,14 @@
#define DEBUG_TYPE "localstackalloc"
#include "llvm/CodeGen/Passes.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/StackProtector.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
@@ -60,18 +62,28 @@ namespace {
class LocalStackSlotPass: public MachineFunctionPass {
SmallVector<int64_t,16> LocalOffsets;
+ /// StackObjSet - A set of stack object indexes
+ typedef SmallSetVector<int, 8> StackObjSet;
void AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx, int64_t &Offset,
bool StackGrowsDown, unsigned &MaxAlign);
+
+ void AssignLargeObjSet(const StackObjSet &UnassignedObjs,
+ SmallSet<int, 24> &ProtectedObjs,
+ MachineFrameInfo *MFI, bool StackGrowsDown,
+ int64_t &Offset, unsigned &MaxAlign);
void calculateFrameObjectOffsets(MachineFunction &Fn);
bool insertFrameReferenceRegisters(MachineFunction &Fn);
public:
static char ID; // Pass identification, replacement for typeid
- explicit LocalStackSlotPass() : MachineFunctionPass(ID) { }
+ explicit LocalStackSlotPass() : MachineFunctionPass(ID) {
+ initializeLocalStackSlotPassPass(*PassRegistry::getPassRegistry());
+ }
bool runOnMachineFunction(MachineFunction &MF);
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
+ AU.addRequired<StackProtector>();
MachineFunctionPass::getAnalysisUsage(AU);
}
@@ -81,7 +93,10 @@ namespace {
char LocalStackSlotPass::ID = 0;
char &llvm::LocalStackSlotAllocationID = LocalStackSlotPass::ID;
-INITIALIZE_PASS(LocalStackSlotPass, "localstackalloc",
+INITIALIZE_PASS_BEGIN(LocalStackSlotPass, "localstackalloc",
+ "Local Stack Slot Allocation", false, false)
+INITIALIZE_PASS_DEPENDENCY(StackProtector)
+INITIALIZE_PASS_END(LocalStackSlotPass, "localstackalloc",
"Local Stack Slot Allocation", false, false)
bool LocalStackSlotPass::runOnMachineFunction(MachineFunction &MF) {
@@ -145,6 +160,22 @@ void LocalStackSlotPass::AdjustStackOffset(MachineFrameInfo *MFI,
++NumAllocations;
}
+/// AssignLargeObjSet - Helper function to assign large stack objects (i.e.,
+/// those required to be close to the Stack Protector) to stack offsets.
+void LocalStackSlotPass::AssignLargeObjSet(const StackObjSet &UnassignedObjs,
+ SmallSet<int, 24> &ProtectedObjs,
+ MachineFrameInfo *MFI,
+ bool StackGrowsDown, int64_t &Offset,
+ unsigned &MaxAlign) {
+
+ for (StackObjSet::const_iterator I = UnassignedObjs.begin(),
+ E = UnassignedObjs.end(); I != E; ++I) {
+ int i = *I;
+ AdjustStackOffset(MFI, i, Offset, StackGrowsDown, MaxAlign);
+ ProtectedObjs.insert(i);
+ }
+}
+
/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects.
///
@@ -156,11 +187,15 @@ void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown;
int64_t Offset = 0;
unsigned MaxAlign = 0;
+ StackProtector *SP = &getAnalysis<StackProtector>();
// Make sure that the stack protector comes before the local variables on the
// stack.
- SmallSet<int, 16> LargeStackObjs;
+ SmallSet<int, 24> ProtectedObjs;
if (MFI->getStackProtectorIndex() >= 0) {
+ StackObjSet LargeArrayObjs,
+ SmallArrayObjs,
+ AddrOfObjs;
AdjustStackOffset(MFI, MFI->getStackProtectorIndex(), Offset,
StackGrowsDown, MaxAlign);
@@ -170,12 +205,29 @@ void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
continue;
if (MFI->getStackProtectorIndex() == (int)i)
continue;
- if (!MFI->MayNeedStackProtector(i))
- continue;
- AdjustStackOffset(MFI, i, Offset, StackGrowsDown, MaxAlign);
- LargeStackObjs.insert(i);
+ switch (SP->getSSPLayout(MFI->getObjectAllocation(i))) {
+ case StackProtector::SSPLK_None:
+ continue;
+ case StackProtector::SSPLK_LargeArray:
+ LargeArrayObjs.insert(i);
+ continue;
+ case StackProtector::SSPLK_SmallArray:
+ SmallArrayObjs.insert(i);
+ continue;
+ case StackProtector::SSPLK_AddrOf:
+ AddrOfObjs.insert(i);
+ continue;
+ }
+ llvm_unreachable("Unexpected SSPLayoutKind.");
}
+
+ AssignLargeObjSet(LargeArrayObjs, ProtectedObjs, MFI, StackGrowsDown,
+ Offset, MaxAlign);
+ AssignLargeObjSet(SmallArrayObjs, ProtectedObjs, MFI, StackGrowsDown,
+ Offset, MaxAlign);
+ AssignLargeObjSet(AddrOfObjs, ProtectedObjs, MFI, StackGrowsDown,
+ Offset, MaxAlign);
}
// Then assign frame offsets to stack objects that are not used to spill
@@ -185,7 +237,7 @@ void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
continue;
if (MFI->getStackProtectorIndex() == (int)i)
continue;
- if (LargeStackObjs.count(i))
+ if (ProtectedObjs.count(i))
continue;
AdjustStackOffset(MFI, i, Offset, StackGrowsDown, MaxAlign);
diff --git lib/CodeGen/MachineFunction.cpp lib/CodeGen/MachineFunction.cpp
index 04321f3..a26f929 100644
--- lib/CodeGen/MachineFunction.cpp
+++ lib/CodeGen/MachineFunction.cpp
@@ -480,12 +480,11 @@ static inline unsigned clampStackAlignment(bool ShouldClamp, unsigned Align,
/// a nonnegative identifier to represent it.
///
int MachineFrameInfo::CreateStackObject(uint64_t Size, unsigned Alignment,
- bool isSS, bool MayNeedSP, const AllocaInst *Alloca) {
+ bool isSS, const AllocaInst *Alloca) {
assert(Size != 0 && "Cannot allocate zero size stack objects!");
Alignment = clampStackAlignment(!TFI.isStackRealignable() || !RealignOption,
Alignment, TFI.getStackAlignment());
- Objects.push_back(StackObject(Size, Alignment, 0, false, isSS, MayNeedSP,
- Alloca));
+ Objects.push_back(StackObject(Size, Alignment, 0, false, isSS, Alloca));
int Index = (int)Objects.size() - NumFixedObjects - 1;
assert(Index >= 0 && "Bad frame index!");
ensureMaxAlignment(Alignment);
@@ -500,7 +499,7 @@ int MachineFrameInfo::CreateSpillStackObject(uint64_t Size,
unsigned Alignment) {
Alignment = clampStackAlignment(!TFI.isStackRealignable() || !RealignOption,
Alignment, TFI.getStackAlignment());
- CreateStackObject(Size, Alignment, true, false);
+ CreateStackObject(Size, Alignment, true);
int Index = (int)Objects.size() - NumFixedObjects - 1;
ensureMaxAlignment(Alignment);
return Index;
@@ -511,11 +510,12 @@ int MachineFrameInfo::CreateSpillStackObject(uint64_t Size,
/// variable sized object is created, whether or not the index returned is
/// actually used.
///
-int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment) {
+int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment,
+ const AllocaInst *Alloca) {
HasVarSizedObjects = true;
Alignment = clampStackAlignment(!TFI.isStackRealignable() || !RealignOption,
Alignment, TFI.getStackAlignment());
- Objects.push_back(StackObject(0, Alignment, 0, false, false, true, 0));
+ Objects.push_back(StackObject(0, Alignment, 0, false, false, Alloca));
ensureMaxAlignment(Alignment);
return (int)Objects.size()-NumFixedObjects-1;
}
@@ -538,7 +538,6 @@ int MachineFrameInfo::CreateFixedObject(uint64_t Size, int64_t SPOffset,
Align, TFI.getStackAlignment());
Objects.insert(Objects.begin(), StackObject(Size, Align, SPOffset, Immutable,
/*isSS*/ false,
- /*NeedSP*/ false,
/*Alloca*/ 0));
return -++NumFixedObjects;
}
diff --git lib/CodeGen/MachineFunctionPass.cpp lib/CodeGen/MachineFunctionPass.cpp
index 674cc80..789f204 100644
--- lib/CodeGen/MachineFunctionPass.cpp
+++ lib/CodeGen/MachineFunctionPass.cpp
@@ -51,6 +51,7 @@ void MachineFunctionPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addPreserved("domfrontier");
AU.addPreserved("loops");
AU.addPreserved("lda");
+ AU.addPreserved("stack-protector");
FunctionPass::getAnalysisUsage(AU);
}
diff --git lib/CodeGen/Passes.cpp lib/CodeGen/Passes.cpp
index bfbc062..9f311f8 100644
--- lib/CodeGen/Passes.cpp
+++ lib/CodeGen/Passes.cpp
@@ -422,10 +422,10 @@ void TargetPassConfig::addCodeGenPrepare() {
/// Add common passes that perform LLVM IR to IR transforms in preparation for
/// instruction selection.
void TargetPassConfig::addISelPrepare() {
- addPass(createStackProtectorPass(getTargetLowering()));
-
addPreISel();
+ addPass(createStackProtectorPass(getTargetLowering()));
+
if (PrintISelInput)
addPass(createPrintFunctionPass("\n\n"
"*** Final LLVM Code input to ISel ***\n",
diff --git lib/CodeGen/PrologEpilogInserter.cpp lib/CodeGen/PrologEpilogInserter.cpp
index 959dd7d..d4ddece 100644
--- lib/CodeGen/PrologEpilogInserter.cpp
+++ lib/CodeGen/PrologEpilogInserter.cpp
@@ -23,6 +23,7 @@
#include "PrologEpilogInserter.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineDominators.h"
@@ -31,6 +32,7 @@
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
+#include "llvm/CodeGen/StackProtector.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
@@ -50,6 +52,7 @@ INITIALIZE_PASS_BEGIN(PEI, "prologepilog",
"Prologue/Epilogue Insertion", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
+INITIALIZE_PASS_DEPENDENCY(StackProtector)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_END(PEI, "prologepilog",
"Prologue/Epilogue Insertion & Frame Finalization",
@@ -59,6 +62,9 @@ STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged");
STATISTIC(NumBytesStackSpace,
"Number of bytes used for stack in all functions");
+/// StackObjSet - A set of stack object indexes
+typedef SmallSetVector<int, 8> StackObjSet;
+
/// runOnMachineFunction - Insert prolog/epilog code and replace abstract
/// frame indexes with appropriate references.
///
@@ -472,11 +478,28 @@ AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx,
}
}
+/// AssignLargeObjSet - Helper function to assign large stack objects (i.e.,
+/// those required to be close to the Stack Protector) to stack offsets.
+static void
+AssignLargeObjSet(const StackObjSet &UnassignedObjs,
+ SmallSet<int, 24> &ProtectedObjs,
+ MachineFrameInfo *MFI, bool StackGrowsDown, int64_t &Offset,
+ unsigned &MaxAlign) {
+
+ for (StackObjSet::const_iterator I = UnassignedObjs.begin(),
+ E = UnassignedObjs.end(); I != E; ++I) {
+ int i = *I;
+ AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign);
+ ProtectedObjs.insert(i);
+ }
+}
+
/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects.
///
void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
const TargetFrameLowering &TFI = *Fn.getTarget().getFrameLowering();
+ StackProtector *SP = &getAnalysis<StackProtector>();
bool StackGrowsDown =
TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown;
@@ -582,8 +605,11 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
// Make sure that the stack protector comes before the local variables on the
// stack.
- SmallSet<int, 16> LargeStackObjs;
+ SmallSet<int, 24> ProtectedObjs;
if (MFI->getStackProtectorIndex() >= 0) {
+ StackObjSet LargeArrayObjs,
+ SmallArrayObjs,
+ AddrOfObjs;
AdjustStackOffset(MFI, MFI->getStackProtectorIndex(), StackGrowsDown,
Offset, MaxAlign);
@@ -600,12 +626,29 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
continue;
if (MFI->getStackProtectorIndex() == (int)i)
continue;
- if (!MFI->MayNeedStackProtector(i))
- continue;
- AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign);
- LargeStackObjs.insert(i);
+ switch (SP->getSSPLayout(MFI->getObjectAllocation(i))) {
+ case StackProtector::SSPLK_None:
+ continue;
+ case StackProtector::SSPLK_LargeArray:
+ LargeArrayObjs.insert(i);
+ continue;
+ case StackProtector::SSPLK_SmallArray:
+ SmallArrayObjs.insert(i);
+ continue;
+ case StackProtector::SSPLK_AddrOf:
+ AddrOfObjs.insert(i);
+ continue;
+ }
+ llvm_unreachable("Unexpected SSPLayoutKind.");
}
+
+ AssignLargeObjSet(LargeArrayObjs, ProtectedObjs, MFI, StackGrowsDown,
+ Offset, MaxAlign);
+ AssignLargeObjSet(SmallArrayObjs, ProtectedObjs, MFI, StackGrowsDown,
+ Offset, MaxAlign);
+ AssignLargeObjSet(AddrOfObjs, ProtectedObjs, MFI, StackGrowsDown,
+ Offset, MaxAlign);
}
// Then assign frame offsets to stack objects that are not used to spill
@@ -622,7 +665,7 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
continue;
if (MFI->getStackProtectorIndex() == (int)i)
continue;
- if (LargeStackObjs.count(i))
+ if (ProtectedObjs.count(i))
continue;
AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign);
diff --git lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
index b46edad..aad62e4 100644
--- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
+++ lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
@@ -87,16 +87,8 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf) {
TySize *= CUI->getZExtValue(); // Get total allocated size.
if (TySize == 0) TySize = 1; // Don't create zero-sized stack objects.
- // The object may need to be placed onto the stack near the stack
- // protector if one exists. Determine here if this object is a suitable
- // candidate. I.e., it would trigger the creation of a stack protector.
- bool MayNeedSP =
- (AI->isArrayAllocation() ||
- (TySize >= 8 && isa<ArrayType>(Ty) &&
- cast<ArrayType>(Ty)->getElementType()->isIntegerTy(8)));
StaticAllocaMap[AI] =
- MF->getFrameInfo()->CreateStackObject(TySize, Align, false,
- MayNeedSP, AI);
+ MF->getFrameInfo()->CreateStackObject(TySize, Align, false, AI);
}
for (; BB != EB; ++BB)
diff --git lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 2ded723..5c42800 100644
--- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3259,7 +3259,7 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) {
// Inform the Frame Information that we have just allocated a variable-sized
// object.
- FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1);
+ FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1, &I);
}
void SelectionDAGBuilder::visitLoad(const LoadInst &I) {
diff --git lib/CodeGen/ShrinkWrapping.cpp lib/CodeGen/ShrinkWrapping.cpp
index 2feea59..9c8ab73 100644
--- lib/CodeGen/ShrinkWrapping.cpp
+++ lib/CodeGen/ShrinkWrapping.cpp
@@ -45,6 +45,7 @@
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/StackProtector.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
@@ -92,6 +93,7 @@ void PEI::getAnalysisUsage(AnalysisUsage &AU) const {
}
AU.addPreserved<MachineLoopInfo>();
AU.addPreserved<MachineDominatorTree>();
+ AU.addRequired<StackProtector>();
AU.addRequired<TargetPassConfig>();
MachineFunctionPass::getAnalysisUsage(AU);
}
diff --git lib/CodeGen/StackProtector.cpp lib/CodeGen/StackProtector.cpp
index fbef347..06cc020 100644
--- lib/CodeGen/StackProtector.cpp
+++ lib/CodeGen/StackProtector.cpp
@@ -15,10 +15,11 @@
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "stack-protector"
-#include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/StackProtector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/ValueMap.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Constants.h"
@@ -37,73 +38,19 @@ STATISTIC(NumFunProtected, "Number of functions protected");
STATISTIC(NumAddrTaken, "Number of local variables that have their address"
" taken.");
-namespace {
- class StackProtector : public FunctionPass {
- /// TLI - Keep a pointer of a TargetLowering to consult for determining
- /// target type sizes.
- const TargetLoweringBase *TLI;
-
- Function *F;
- Module *M;
-
- DominatorTree *DT;
-
- /// VisitedPHIs - The set of PHI nodes visited when determining
- /// if a variable's reference has been taken. This set
- /// is maintained to ensure we don't visit the same PHI node multiple
- /// times.
- SmallPtrSet<const PHINode*, 16> VisitedPHIs;
-
- /// InsertStackProtectors - Insert code into the prologue and epilogue of
- /// the function.
- ///
- /// - The prologue code loads and stores the stack guard onto the stack.
- /// - The epilogue checks the value stored in the prologue against the
- /// original value. It calls __stack_chk_fail if they differ.
- bool InsertStackProtectors();
-
- /// CreateFailBB - Create a basic block to jump to when the stack protector
- /// check fails.
- BasicBlock *CreateFailBB();
-
- /// ContainsProtectableArray - Check whether the type either is an array or
- /// contains an array of sufficient size so that we need stack protectors
- /// for it.
- bool ContainsProtectableArray(Type *Ty, bool Strong = false,
- bool InStruct = false) const;
-
- /// \brief Check whether a stack allocation has its address taken.
- bool HasAddressTaken(const Instruction *AI);
-
- /// RequiresStackProtector - Check whether or not this function needs a
- /// stack protector based upon the stack protector level.
- bool RequiresStackProtector();
- public:
- static char ID; // Pass identification, replacement for typeid.
- StackProtector() : FunctionPass(ID), TLI(0) {
- initializeStackProtectorPass(*PassRegistry::getPassRegistry());
- }
- StackProtector(const TargetLoweringBase *tli)
- : FunctionPass(ID), TLI(tli) {
- initializeStackProtectorPass(*PassRegistry::getPassRegistry());
- }
-
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addPreserved<DominatorTree>();
- }
-
- virtual bool runOnFunction(Function &Fn);
- };
-} // end anonymous namespace
-
char StackProtector::ID = 0;
INITIALIZE_PASS(StackProtector, "stack-protector",
- "Insert stack protectors", false, false)
+ "Insert stack protectors", false, true)
FunctionPass *llvm::createStackProtectorPass(const TargetLoweringBase *tli) {
return new StackProtector(tli);
}
+StackProtector::SSPLayoutKind StackProtector::getSSPLayout(const AllocaInst *AI)
+ const {
+ return AI ? Layout.lookup(AI) : SSPLK_None;
+}
+
bool StackProtector::runOnFunction(Function &Fn) {
F = &Fn;
M = F->getParent();
@@ -118,39 +65,51 @@ bool StackProtector::runOnFunction(Function &Fn) {
/// ContainsProtectableArray - Check whether the type either is an array or
/// contains a char array of sufficient size so that we need stack protectors
/// for it.
-bool StackProtector::ContainsProtectableArray(Type *Ty, bool Strong,
- bool InStruct) const {
+/// \param [out] IsLarge is set to true if a protectable array is found and
+/// it is "large" ( >= ssp-buffer-size). In the case of a structure with
+/// multiple arrays, this gets set if any of them is large.
+bool StackProtector::ContainsProtectableArray(Type *Ty, bool &IsLarge,
+ bool Strong, bool InStruct)
+ const {
if (!Ty) return false;
if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
- // In strong mode any array, regardless of type and size, triggers a
- // protector
- if (Strong)
- return true;
const TargetMachine &TM = TLI->getTargetMachine();
if (!AT->getElementType()->isIntegerTy(8)) {
Triple Trip(TM.getTargetTriple());
// If we're on a non-Darwin platform or we're inside of a structure, don't
// add stack protectors unless the array is a character array.
- if (InStruct || !Trip.isOSDarwin())
- return false;
+ // However, in strong mode any array, regardless of type and size,
+ // triggers a protector.
+ if (!Strong && (InStruct || !Trip.isOSDarwin()))
+ return false;
}
// If an array has more than SSPBufferSize bytes of allocated space, then we
// emit stack protectors.
- if (TM.Options.SSPBufferSize <= TLI->getDataLayout()->getTypeAllocSize(AT))
+ if (TM.Options.SSPBufferSize <= TLI->getDataLayout()->getTypeAllocSize(AT)) {
+ IsLarge = true;
+ return true;
+ } else if (Strong) // Require a protector for all arrays in strong mode
return true;
}
const StructType *ST = dyn_cast<StructType>(Ty);
if (!ST) return false;
+ bool NeedsProtector = false;
for (StructType::element_iterator I = ST->element_begin(),
E = ST->element_end(); I != E; ++I)
- if (ContainsProtectableArray(*I, Strong, true))
- return true;
+ if (ContainsProtectableArray(*I, IsLarge, Strong, true)) {
+ // If the element is a protectable array and is large (>= SSPBufferSize)
+ // then we are done. If the protectable array is not large, then
+ // keep looking in case a subsequent element is a large array.
+ if (IsLarge)
+ return true;
+ NeedsProtector = true;
+ }
- return false;
+ return NeedsProtector;
}
bool StackProtector::HasAddressTaken(const Instruction *AI) {
@@ -202,11 +161,13 @@ bool StackProtector::HasAddressTaken(const Instruction *AI) {
/// address taken.
bool StackProtector::RequiresStackProtector() {
bool Strong = false;
+ bool NeedsProtector = false;
if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
- Attribute::StackProtectReq))
- return true;
- else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
- Attribute::StackProtectStrong))
+ Attribute::StackProtectReq)) {
+ NeedsProtector = true;
+ Strong = true; // Use the same heuristic as strong to determine SSPLayout
+ } else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
+ Attribute::StackProtectStrong))
Strong = true;
else if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::StackProtect))
@@ -219,34 +180,43 @@ bool StackProtector::RequiresStackProtector() {
II = BB->begin(), IE = BB->end(); II != IE; ++II) {
if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
if (AI->isArrayAllocation()) {
- // SSP-Strong: Enable protectors for any call to alloca, regardless
- // of size.
- if (Strong)
- return true;
-
if (const ConstantInt *CI =
dyn_cast<ConstantInt>(AI->getArraySize())) {
unsigned BufferSize = TLI->getTargetMachine().Options.SSPBufferSize;
- if (CI->getLimitedValue(BufferSize) >= BufferSize)
+ if (CI->getLimitedValue(BufferSize) >= BufferSize) {
// A call to alloca with size >= SSPBufferSize requires
// stack protectors.
- return true;
- } else // A call to alloca with a variable size requires protectors.
- return true;
+ Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+ NeedsProtector = true;
+ } else if (Strong) {
+ // Require protectors for all alloca calls in strong mode.
+ Layout.insert(std::make_pair(AI, SSPLK_SmallArray));
+ NeedsProtector = true;
+ }
+ } else { // A call to alloca with a variable size requires protectors.
+ Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+ NeedsProtector = true;
+ }
+ continue;
}
- if (ContainsProtectableArray(AI->getAllocatedType(), Strong))
- return true;
+ bool IsLarge = false;
+ if (ContainsProtectableArray(AI->getAllocatedType(), IsLarge, Strong)) {
+ Layout.insert(std::make_pair(AI, IsLarge ? SSPLK_LargeArray : SSPLK_SmallArray));
+ NeedsProtector = true;
+ continue;
+ }
if (Strong && HasAddressTaken(AI)) {
++NumAddrTaken;
- return true;
+ Layout.insert(std::make_pair(AI, SSPLK_AddrOf));
+ NeedsProtector = true;
}
}
}
}
- return false;
+ return NeedsProtector;
}
/// InsertStackProtectors - Insert code into the prologue and epilogue of the
diff --git lib/Target/Hexagon/HexagonRemoveSZExtArgs.cpp lib/Target/Hexagon/HexagonRemoveSZExtArgs.cpp
index 44234e8..552cac2 100644
--- lib/Target/Hexagon/HexagonRemoveSZExtArgs.cpp
+++ lib/Target/Hexagon/HexagonRemoveSZExtArgs.cpp
@@ -42,6 +42,7 @@ namespace {
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<MachineFunctionAnalysis>();
AU.addPreserved<MachineFunctionAnalysis>();
+ AU.addPreserved("stack-protector");
FunctionPass::getAnalysisUsage(AU);
}
};
diff --git lib/Target/MBlaze/MBlazeFrameLowering.cpp lib/Target/MBlaze/MBlazeFrameLowering.cpp
index 172304b..c09f091 100644
--- lib/Target/MBlaze/MBlazeFrameLowering.cpp
+++ lib/Target/MBlaze/MBlazeFrameLowering.cpp
@@ -249,7 +249,7 @@ static void interruptFrameLayout(MachineFunction &MF) {
for (unsigned r = MBlaze::R3; r <= MBlaze::R12; ++r) {
if (!MRI.isPhysRegUsed(r) && !(isIntr && r == MBlaze::R11)) continue;
- int FI = MFI->CreateStackObject(4,4,false,false);
+ int FI = MFI->CreateStackObject(4,4,false);
VFI.push_back(FI);
BuildMI(MENT, MENTI, ENTDL, TII.get(MBlaze::SWI), r)
@@ -257,8 +257,8 @@ static void interruptFrameLayout(MachineFunction &MF) {
}
// Build the prologue SWI for R17, R18
- int R17FI = MFI->CreateStackObject(4,4,false,false);
- int R18FI = MFI->CreateStackObject(4,4,false,false);
+ int R17FI = MFI->CreateStackObject(4,4,false);
+ int R18FI = MFI->CreateStackObject(4,4,false);
BuildMI(MENT, MENTI, ENTDL, TII.get(MBlaze::SWI), MBlaze::R17)
.addFrameIndex(R17FI).addImm(0);
@@ -268,7 +268,7 @@ static void interruptFrameLayout(MachineFunction &MF) {
// Buid the prologue SWI and the epilogue LWI for RMSR if needed
if (isIntr) {
- int MSRFI = MFI->CreateStackObject(4,4,false,false);
+ int MSRFI = MFI->CreateStackObject(4,4,false);
BuildMI(MENT, MENTI, ENTDL, TII.get(MBlaze::MFS), MBlaze::R11)
.addReg(MBlaze::RMSR);
BuildMI(MENT, MENTI, ENTDL, TII.get(MBlaze::SWI), MBlaze::R11)
diff --git lib/Target/NVPTX/NVPTXAllocaHoisting.h lib/Target/NVPTX/NVPTXAllocaHoisting.h
index 19d73c5..d330570 100644
--- lib/Target/NVPTX/NVPTXAllocaHoisting.h
+++ lib/Target/NVPTX/NVPTXAllocaHoisting.h
@@ -32,6 +32,7 @@ public:
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<DataLayout>();
+ AU.addPreserved("stack-protector");
AU.addPreserved<MachineFunctionAnalysis>();
}
diff --git lib/Target/NVPTX/NVPTXLowerAggrCopies.h lib/Target/NVPTX/NVPTXLowerAggrCopies.h
index 286e753..780ed49 100644
--- lib/Target/NVPTX/NVPTXLowerAggrCopies.h
+++ lib/Target/NVPTX/NVPTXLowerAggrCopies.h
@@ -29,6 +29,7 @@ struct NVPTXLowerAggrCopies : public FunctionPass {
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<DataLayout>();
+ AU.addPreserved("stack-protector");
AU.addPreserved<MachineFunctionAnalysis>();
}
diff --git lib/Target/NVPTX/NVPTXSplitBBatBar.h lib/Target/NVPTX/NVPTXSplitBBatBar.h
index bdafba9..03391fe 100644
--- lib/Target/NVPTX/NVPTXSplitBBatBar.h
+++ lib/Target/NVPTX/NVPTXSplitBBatBar.h
@@ -26,6 +26,7 @@ struct NVPTXSplitBBatBar : public FunctionPass {
NVPTXSplitBBatBar() : FunctionPass(ID) {}
void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addPreserved("stack-protector");
AU.addPreserved<MachineFunctionAnalysis>();
}
virtual bool runOnFunction(Function &F);
diff --git lib/Target/X86/X86FastISel.cpp lib/Target/X86/X86FastISel.cpp
index cf44bd0..acb9327 100644
--- lib/Target/X86/X86FastISel.cpp
+++ lib/Target/X86/X86FastISel.cpp
@@ -1568,6 +1568,8 @@ bool X86FastISel::X86VisitIntrinsicCall(const IntrinsicInst &I) {
const Value *Op1 = I.getArgOperand(0); // The guard's value.
const AllocaInst *Slot = cast<AllocaInst>(I.getArgOperand(1));
+ MFI.setStackProtectorIndex(FuncInfo.StaticAllocaMap[Slot]);
+
// Grab the frame index.
X86AddressMode AM;
if (!X86SelectAddress(Slot, AM)) return false;
diff --git test/CodeGen/ARM/ssp-data-layout.ll test/CodeGen/ARM/ssp-data-layout.ll
new file mode 100644
index 0000000..9ac5efb
--- /dev/null
+++ test/CodeGen/ARM/ssp-data-layout.ll
@@ -0,0 +1,529 @@
+; RUN: llc < %s -disable-fp-elim -march=arm -o - | FileCheck %s
+; This test is fairly fragile. The goal is to ensure that "large" stack
+; objects are allocated closest to the stack protector (i.e., farthest away
+; from the Stack Pointer.) In standard SSP mode this means that large (>=
+; ssp-buffer-size) arrays and structures containing such arrays are
+; closet to the protector. With sspstrong and sspreq this means large
+; arrays/structures-with-arrays are closest, followed by small (< ssp-buffer-size)
+; arrays/structures-with-arrays, and then addr-taken variables.
+;
+; Ideally, we only want verify that the objects appear in the correct groups
+; and that the groups have the correct relative stack offset. The ordering
+; within a group is not relevant to this test. Unfortunately, there is not
+; an elegant way to do this, so just match the offset for each object.
+
+%struct.struct_large_char = type { [8 x i8] }
+%struct.struct_large_char2 = type { [2 x i8], [8 x i8] }
+%struct.struct_small_char = type { [2 x i8] }
+%struct.struct_large_nonchar = type { [8 x i32] }
+%struct.struct_small_nonchar = type { [2 x i16] }
+
+define void @layout_ssp() ssp {
+entry:
+; Expected stack layout for ssp is
+; 196 large_char . Group 1, nested arrays, arrays >= ssp-buffer-size
+; 184 struct_large_char .
+; 180 scalar1 | Everything else
+; 176 scalar2
+; 172 scalar3
+; 168 addr-of
+; 164 small_nonchar (84+80)
+; 128 large_nonchar
+; 126 small_char
+; 120 struct_small_char
+; 88 struct_large_nonchar
+; 80 struct_small_nonchar
+
+; CHECK: layout_ssp:
+; r5 is used as an offset into the stack later
+; CHECK: add r5, sp, #80
+
+; CHECK: bl get_scalar1
+; CHECK: str r0, [sp, #180]
+; CHECK: bl end_scalar1
+
+; CHECK: bl get_scalar2
+; CHECK: str r0, [sp, #176]
+; CHECK: bl end_scalar2
+
+; CHECK: bl get_scalar3
+; CHECK: str r0, [sp, #172]
+; CHECK: bl end_scalar3
+
+; CHECK: bl get_addrof
+; CHECK: str r0, [sp, #168]
+; CHECK: bl end_addrof
+
+; CHECK: get_small_nonchar
+; CHECK: strh r0, [r5, #84]
+; CHECK: bl end_small_nonchar
+
+; CHECK: bl get_large_nonchar
+; CHECK: str r0, [sp, #128]
+; CHECK: bl end_large_nonchar
+
+; CHECK: bl get_small_char
+; CHECK: strb r0, [sp, #126]
+; CHECK: bl end_small_char
+
+; CHECK: bl get_large_char
+; CHECK: strb r0, [sp, #196]
+; CHECK: bl end_large_char
+
+; CHECK: bl get_struct_large_char
+; CHECK: strb r0, [sp, #184]
+; CHECK: bl end_struct_large_char
+
+; CHECK: bl get_struct_small_char
+; CHECK: strb r0, [sp, #120]
+; CHECK: bl end_struct_small_char
+
+; CHECK: bl get_struct_large_nonchar
+; CHECK:str r0, [sp, #88]
+; CHECK: bl end_struct_large_nonchar
+
+; CHECK: bl get_struct_small_nonchar
+; CHECK: strh r0, [r5]
+; CHECK: bl end_struct_small_nonchar
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %z = alloca i32, align 4
+ %ptr = alloca i32, align 4
+ %small2 = alloca [2 x i16], align 2
+ %large2 = alloca [8 x i32], align 16
+ %small = alloca [2 x i8], align 1
+ %large = alloca [8 x i8], align 1
+ %a = alloca %struct.struct_large_char, align 1
+ %b = alloca %struct.struct_small_char, align 1
+ %c = alloca %struct.struct_large_nonchar, align 8
+ %d = alloca %struct.struct_small_nonchar, align 2
+ %call = call i32 @get_scalar1()
+ store i32 %call, i32* %x, align 4
+ call void @end_scalar1()
+ %call1 = call i32 @get_scalar2()
+ store i32 %call1, i32* %y, align 4
+ call void @end_scalar2()
+ %call2 = call i32 @get_scalar3()
+ store i32 %call2, i32* %z, align 4
+ call void @end_scalar3()
+ %call3 = call i32 @get_addrof()
+ store i32 %call3, i32* %ptr, align 4
+ call void @end_addrof()
+ %call4 = call signext i16 @get_small_nonchar()
+ %arrayidx = getelementptr inbounds [2 x i16]* %small2, i32 0, i64 0
+ store i16 %call4, i16* %arrayidx, align 2
+ call void @end_small_nonchar()
+ %call5 = call i32 @get_large_nonchar()
+ %arrayidx6 = getelementptr inbounds [8 x i32]* %large2, i32 0, i64 0
+ store i32 %call5, i32* %arrayidx6, align 4
+ call void @end_large_nonchar()
+ %call7 = call signext i8 @get_small_char()
+ %arrayidx8 = getelementptr inbounds [2 x i8]* %small, i32 0, i64 0
+ store i8 %call7, i8* %arrayidx8, align 1
+ call void @end_small_char()
+ %call9 = call signext i8 @get_large_char()
+ %arrayidx10 = getelementptr inbounds [8 x i8]* %large, i32 0, i64 0
+ store i8 %call9, i8* %arrayidx10, align 1
+ call void @end_large_char()
+ %call11 = call signext i8 @get_struct_large_char()
+ %foo = getelementptr inbounds %struct.struct_large_char* %a, i32 0, i32 0
+ %arrayidx12 = getelementptr inbounds [8 x i8]* %foo, i32 0, i64 0
+ store i8 %call11, i8* %arrayidx12, align 1
+ call void @end_struct_large_char()
+ %call13 = call signext i8 @get_struct_small_char()
+ %foo14 = getelementptr inbounds %struct.struct_small_char* %b, i32 0, i32 0
+ %arrayidx15 = getelementptr inbounds [2 x i8]* %foo14, i32 0, i64 0
+ store i8 %call13, i8* %arrayidx15, align 1
+ call void @end_struct_small_char()
+ %call16 = call i32 @get_struct_large_nonchar()
+ %foo17 = getelementptr inbounds %struct.struct_large_nonchar* %c, i32 0, i32 0
+ %arrayidx18 = getelementptr inbounds [8 x i32]* %foo17, i32 0, i64 0
+ store i32 %call16, i32* %arrayidx18, align 4
+ call void @end_struct_large_nonchar()
+ %call19 = call signext i16 @get_struct_small_nonchar()
+ %foo20 = getelementptr inbounds %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %arrayidx21 = getelementptr inbounds [2 x i16]* %foo20, i32 0, i64 0
+ store i16 %call19, i16* %arrayidx21, align 2
+ call void @end_struct_small_nonchar()
+ %arraydecay = getelementptr inbounds [8 x i8]* %large, i32 0, i32 0
+ %arraydecay22 = getelementptr inbounds [2 x i8]* %small, i32 0, i32 0
+ %arraydecay23 = getelementptr inbounds [8 x i32]* %large2, i32 0, i32 0
+ %arraydecay24 = getelementptr inbounds [2 x i16]* %small2, i32 0, i32 0
+ %0 = load i32* %x, align 4
+ %1 = load i32* %y, align 4
+ %2 = load i32* %z, align 4
+ %coerce.dive = getelementptr %struct.struct_large_char* %a, i32 0, i32 0
+ %3 = bitcast [8 x i8]* %coerce.dive to i64*
+ %4 = load i64* %3, align 1
+ %coerce.dive25 = getelementptr %struct.struct_small_char* %b, i32 0, i32 0
+ %5 = bitcast [2 x i8]* %coerce.dive25 to i16*
+ %6 = load i16* %5, align 1
+ %coerce.dive26 = getelementptr %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %7 = bitcast [2 x i16]* %coerce.dive26 to i32*
+ %8 = load i32* %7, align 1
+ call void @takes_all(i64 %4, i16 %6, %struct.struct_large_nonchar* byval align 8 %c, i32 %8, i8* %arraydecay, i8* %arraydecay22, i32* %arraydecay23, i16* %arraydecay24, i32* %ptr, i32 %0, i32 %1, i32 %2)
+ ret void
+}
+
+define void @layout_sspstrong() sspstrong {
+entry:
+; Expected stack layout for sspstrong is
+; 160 large_nonchar . Group 1, nested arrays,
+; 152 large_char . arrays >= ssp-buffer-size
+; 144 struct_large_char .
+; 112 struct_large_nonchar .
+; 96+12 small_non_char | Group 2, nested arrays,
+; 106 small_char | arrays < ssp-buffer-size
+; 104 struct_small_char |
+; 96 struct_small_nonchar |
+; 92 addrof * Group 3, addr-of local
+; 88 scalar1 + Group 4, everything else
+; 84 scalar2 +
+; 80 scalar3 +
+;
+; CHECK: layout_sspstrong:
+; r5 is used as an offset into the stack later
+; CHECK: add r5, sp, #96
+
+; CHECK: bl get_scalar1
+; CHECK: str r0, [sp, #88]
+; CHECK: bl end_scalar1
+
+; CHECK: bl get_scalar2
+; CHECK: str r0, [sp, #84]
+; CHECK: bl end_scalar2
+
+; CHECK: bl get_scalar3
+; CHECK: str r0, [sp, #80]
+; CHECK: bl end_scalar3
+
+; CHECK: bl get_addrof
+; CHECK: str r0, [sp, #92]
+; CHECK: bl end_addrof
+
+; CHECK: get_small_nonchar
+; CHECK: strh r0, [r5, #12]
+; CHECK: bl end_small_nonchar
+
+; CHECK: bl get_large_nonchar
+; CHECK: str r0, [sp, #160]
+; CHECK: bl end_large_nonchar
+
+; CHECK: bl get_small_char
+; CHECK: strb r0, [sp, #106]
+; CHECK: bl end_small_char
+
+; CHECK: bl get_large_char
+; CHECK: strb r0, [sp, #152]
+; CHECK: bl end_large_char
+
+; CHECK: bl get_struct_large_char
+; CHECK: strb r0, [sp, #144]
+; CHECK: bl end_struct_large_char
+
+; CHECK: bl get_struct_small_char
+; CHECK: strb r0, [sp, #104]
+; CHECK: bl end_struct_small_char
+
+; CHECK: bl get_struct_large_nonchar
+; CHECK: str r0, [sp, #112]
+; CHECK: bl end_struct_large_nonchar
+
+; CHECK: bl get_struct_small_nonchar
+; CHECK: strh r0, [r5]
+; CHECK: bl end_struct_small_nonchar
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %z = alloca i32, align 4
+ %ptr = alloca i32, align 4
+ %small2 = alloca [2 x i16], align 2
+ %large2 = alloca [8 x i32], align 16
+ %small = alloca [2 x i8], align 1
+ %large = alloca [8 x i8], align 1
+ %a = alloca %struct.struct_large_char, align 1
+ %b = alloca %struct.struct_small_char, align 1
+ %c = alloca %struct.struct_large_nonchar, align 8
+ %d = alloca %struct.struct_small_nonchar, align 2
+ %call = call i32 @get_scalar1()
+ store i32 %call, i32* %x, align 4
+ call void @end_scalar1()
+ %call1 = call i32 @get_scalar2()
+ store i32 %call1, i32* %y, align 4
+ call void @end_scalar2()
+ %call2 = call i32 @get_scalar3()
+ store i32 %call2, i32* %z, align 4
+ call void @end_scalar3()
+ %call3 = call i32 @get_addrof()
+ store i32 %call3, i32* %ptr, align 4
+ call void @end_addrof()
+ %call4 = call signext i16 @get_small_nonchar()
+ %arrayidx = getelementptr inbounds [2 x i16]* %small2, i32 0, i64 0
+ store i16 %call4, i16* %arrayidx, align 2
+ call void @end_small_nonchar()
+ %call5 = call i32 @get_large_nonchar()
+ %arrayidx6 = getelementptr inbounds [8 x i32]* %large2, i32 0, i64 0
+ store i32 %call5, i32* %arrayidx6, align 4
+ call void @end_large_nonchar()
+ %call7 = call signext i8 @get_small_char()
+ %arrayidx8 = getelementptr inbounds [2 x i8]* %small, i32 0, i64 0
+ store i8 %call7, i8* %arrayidx8, align 1
+ call void @end_small_char()
+ %call9 = call signext i8 @get_large_char()
+ %arrayidx10 = getelementptr inbounds [8 x i8]* %large, i32 0, i64 0
+ store i8 %call9, i8* %arrayidx10, align 1
+ call void @end_large_char()
+ %call11 = call signext i8 @get_struct_large_char()
+ %foo = getelementptr inbounds %struct.struct_large_char* %a, i32 0, i32 0
+ %arrayidx12 = getelementptr inbounds [8 x i8]* %foo, i32 0, i64 0
+ store i8 %call11, i8* %arrayidx12, align 1
+ call void @end_struct_large_char()
+ %call13 = call signext i8 @get_struct_small_char()
+ %foo14 = getelementptr inbounds %struct.struct_small_char* %b, i32 0, i32 0
+ %arrayidx15 = getelementptr inbounds [2 x i8]* %foo14, i32 0, i64 0
+ store i8 %call13, i8* %arrayidx15, align 1
+ call void @end_struct_small_char()
+ %call16 = call i32 @get_struct_large_nonchar()
+ %foo17 = getelementptr inbounds %struct.struct_large_nonchar* %c, i32 0, i32 0
+ %arrayidx18 = getelementptr inbounds [8 x i32]* %foo17, i32 0, i64 0
+ store i32 %call16, i32* %arrayidx18, align 4
+ call void @end_struct_large_nonchar()
+ %call19 = call signext i16 @get_struct_small_nonchar()
+ %foo20 = getelementptr inbounds %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %arrayidx21 = getelementptr inbounds [2 x i16]* %foo20, i32 0, i64 0
+ store i16 %call19, i16* %arrayidx21, align 2
+ call void @end_struct_small_nonchar()
+ %arraydecay = getelementptr inbounds [8 x i8]* %large, i32 0, i32 0
+ %arraydecay22 = getelementptr inbounds [2 x i8]* %small, i32 0, i32 0
+ %arraydecay23 = getelementptr inbounds [8 x i32]* %large2, i32 0, i32 0
+ %arraydecay24 = getelementptr inbounds [2 x i16]* %small2, i32 0, i32 0
+ %0 = load i32* %x, align 4
+ %1 = load i32* %y, align 4
+ %2 = load i32* %z, align 4
+ %coerce.dive = getelementptr %struct.struct_large_char* %a, i32 0, i32 0
+ %3 = bitcast [8 x i8]* %coerce.dive to i64*
+ %4 = load i64* %3, align 1
+ %coerce.dive25 = getelementptr %struct.struct_small_char* %b, i32 0, i32 0
+ %5 = bitcast [2 x i8]* %coerce.dive25 to i16*
+ %6 = load i16* %5, align 1
+ %coerce.dive26 = getelementptr %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %7 = bitcast [2 x i16]* %coerce.dive26 to i32*
+ %8 = load i32* %7, align 1
+ call void @takes_all(i64 %4, i16 %6, %struct.struct_large_nonchar* byval align 8 %c, i32 %8, i8* %arraydecay, i8* %arraydecay22, i32* %arraydecay23, i16* %arraydecay24, i32* %ptr, i32 %0, i32 %1, i32 %2)
+ ret void
+}
+
+define void @layout_sspreq() sspreq {
+entry:
+; Expected stack layout for sspreq is the same as sspstrong
+;
+; CHECK: layout_sspreq:
+; r5 is used as an offset into the stack later
+; CHECK: add r5, sp, #96
+
+; CHECK: bl get_scalar1
+; CHECK: str r0, [sp, #88]
+; CHECK: bl end_scalar1
+
+; CHECK: bl get_scalar2
+; CHECK: str r0, [sp, #84]
+; CHECK: bl end_scalar2
+
+; CHECK: bl get_scalar3
+; CHECK: str r0, [sp, #80]
+; CHECK: bl end_scalar3
+
+; CHECK: bl get_addrof
+; CHECK: str r0, [sp, #92]
+; CHECK: bl end_addrof
+
+; CHECK: get_small_nonchar
+; CHECK: strh r0, [r5, #12]
+; CHECK: bl end_small_nonchar
+
+; CHECK: bl get_large_nonchar
+; CHECK: str r0, [sp, #160]
+; CHECK: bl end_large_nonchar
+
+; CHECK: bl get_small_char
+; CHECK: strb r0, [sp, #106]
+; CHECK: bl end_small_char
+
+; CHECK: bl get_large_char
+; CHECK: strb r0, [sp, #152]
+; CHECK: bl end_large_char
+
+; CHECK: bl get_struct_large_char
+; CHECK: strb r0, [sp, #144]
+; CHECK: bl end_struct_large_char
+
+; CHECK: bl get_struct_small_char
+; CHECK: strb r0, [sp, #104]
+; CHECK: bl end_struct_small_char
+
+; CHECK: bl get_struct_large_nonchar
+; CHECK: str r0, [sp, #112]
+; CHECK: bl end_struct_large_nonchar
+
+; CHECK: bl get_struct_small_nonchar
+; CHECK: strh r0, [r5]
+; CHECK: bl end_struct_small_nonchar
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %z = alloca i32, align 4
+ %ptr = alloca i32, align 4
+ %small2 = alloca [2 x i16], align 2
+ %large2 = alloca [8 x i32], align 16
+ %small = alloca [2 x i8], align 1
+ %large = alloca [8 x i8], align 1
+ %a = alloca %struct.struct_large_char, align 1
+ %b = alloca %struct.struct_small_char, align 1
+ %c = alloca %struct.struct_large_nonchar, align 8
+ %d = alloca %struct.struct_small_nonchar, align 2
+ %call = call i32 @get_scalar1()
+ store i32 %call, i32* %x, align 4
+ call void @end_scalar1()
+ %call1 = call i32 @get_scalar2()
+ store i32 %call1, i32* %y, align 4
+ call void @end_scalar2()
+ %call2 = call i32 @get_scalar3()
+ store i32 %call2, i32* %z, align 4
+ call void @end_scalar3()
+ %call3 = call i32 @get_addrof()
+ store i32 %call3, i32* %ptr, align 4
+ call void @end_addrof()
+ %call4 = call signext i16 @get_small_nonchar()
+ %arrayidx = getelementptr inbounds [2 x i16]* %small2, i32 0, i64 0
+ store i16 %call4, i16* %arrayidx, align 2
+ call void @end_small_nonchar()
+ %call5 = call i32 @get_large_nonchar()
+ %arrayidx6 = getelementptr inbounds [8 x i32]* %large2, i32 0, i64 0
+ store i32 %call5, i32* %arrayidx6, align 4
+ call void @end_large_nonchar()
+ %call7 = call signext i8 @get_small_char()
+ %arrayidx8 = getelementptr inbounds [2 x i8]* %small, i32 0, i64 0
+ store i8 %call7, i8* %arrayidx8, align 1
+ call void @end_small_char()
+ %call9 = call signext i8 @get_large_char()
+ %arrayidx10 = getelementptr inbounds [8 x i8]* %large, i32 0, i64 0
+ store i8 %call9, i8* %arrayidx10, align 1
+ call void @end_large_char()
+ %call11 = call signext i8 @get_struct_large_char()
+ %foo = getelementptr inbounds %struct.struct_large_char* %a, i32 0, i32 0
+ %arrayidx12 = getelementptr inbounds [8 x i8]* %foo, i32 0, i64 0
+ store i8 %call11, i8* %arrayidx12, align 1
+ call void @end_struct_large_char()
+ %call13 = call signext i8 @get_struct_small_char()
+ %foo14 = getelementptr inbounds %struct.struct_small_char* %b, i32 0, i32 0
+ %arrayidx15 = getelementptr inbounds [2 x i8]* %foo14, i32 0, i64 0
+ store i8 %call13, i8* %arrayidx15, align 1
+ call void @end_struct_small_char()
+ %call16 = call i32 @get_struct_large_nonchar()
+ %foo17 = getelementptr inbounds %struct.struct_large_nonchar* %c, i32 0, i32 0
+ %arrayidx18 = getelementptr inbounds [8 x i32]* %foo17, i32 0, i64 0
+ store i32 %call16, i32* %arrayidx18, align 4
+ call void @end_struct_large_nonchar()
+ %call19 = call signext i16 @get_struct_small_nonchar()
+ %foo20 = getelementptr inbounds %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %arrayidx21 = getelementptr inbounds [2 x i16]* %foo20, i32 0, i64 0
+ store i16 %call19, i16* %arrayidx21, align 2
+ call void @end_struct_small_nonchar()
+ %arraydecay = getelementptr inbounds [8 x i8]* %large, i32 0, i32 0
+ %arraydecay22 = getelementptr inbounds [2 x i8]* %small, i32 0, i32 0
+ %arraydecay23 = getelementptr inbounds [8 x i32]* %large2, i32 0, i32 0
+ %arraydecay24 = getelementptr inbounds [2 x i16]* %small2, i32 0, i32 0
+ %0 = load i32* %x, align 4
+ %1 = load i32* %y, align 4
+ %2 = load i32* %z, align 4
+ %coerce.dive = getelementptr %struct.struct_large_char* %a, i32 0, i32 0
+ %3 = bitcast [8 x i8]* %coerce.dive to i64*
+ %4 = load i64* %3, align 1
+ %coerce.dive25 = getelementptr %struct.struct_small_char* %b, i32 0, i32 0
+ %5 = bitcast [2 x i8]* %coerce.dive25 to i16*
+ %6 = load i16* %5, align 1
+ %coerce.dive26 = getelementptr %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %7 = bitcast [2 x i16]* %coerce.dive26 to i32*
+ %8 = load i32* %7, align 1
+ call void @takes_all(i64 %4, i16 %6, %struct.struct_large_nonchar* byval align 8 %c, i32 %8, i8* %arraydecay, i8* %arraydecay22, i32* %arraydecay23, i16* %arraydecay24, i32* %ptr, i32 %0, i32 %1, i32 %2)
+ ret void
+}
+
+define void @struct_with_protectable_arrays() sspstrong {
+entry:
+; Check to ensure that a structure which contains a small array followed by a
+; large array is assigned to the stack properly as a large object.
+; CHECK: struct_with_protectable_arrays:
+; CHECK: bl get_struct_small_char
+; CHECK: strb r0, [sp, #72]
+; CHECK: bl end_struct_small_char
+; CHECK: bl get_struct_large_char2
+; CHECK: strb r0, [sp, #114]
+; CHECK: bl end_struct_large_char2
+ %a = alloca %struct.struct_small_char, align 1
+ %b = alloca %struct.struct_large_char2, align 1
+ %d1 = alloca %struct.struct_large_nonchar, align 8
+ %d2 = alloca %struct.struct_small_nonchar, align 2
+ %call = call signext i8 @get_struct_small_char()
+ %foo = getelementptr inbounds %struct.struct_small_char* %a, i32 0, i32 0
+ %arrayidx = getelementptr inbounds [2 x i8]* %foo, i32 0, i64 0
+ store i8 %call, i8* %arrayidx, align 1
+ call void @end_struct_small_char()
+ %call1 = call signext i8 @get_struct_large_char2()
+ %foo2 = getelementptr inbounds %struct.struct_large_char2* %b, i32 0, i32 1
+ %arrayidx3 = getelementptr inbounds [8 x i8]* %foo2, i32 0, i64 0
+ store i8 %call1, i8* %arrayidx3, align 1
+ call void @end_struct_large_char2()
+ %0 = bitcast %struct.struct_large_char2* %b to %struct.struct_large_char*
+ %coerce.dive = getelementptr %struct.struct_large_char* %0, i32 0, i32 0
+ %1 = bitcast [8 x i8]* %coerce.dive to i64*
+ %2 = load i64* %1, align 1
+ %coerce.dive4 = getelementptr %struct.struct_small_char* %a, i32 0, i32 0
+ %3 = bitcast [2 x i8]* %coerce.dive4 to i16*
+ %4 = load i16* %3, align 1
+ %coerce.dive5 = getelementptr %struct.struct_small_nonchar* %d2, i32 0, i32 0
+ %5 = bitcast [2 x i16]* %coerce.dive5 to i32*
+ %6 = load i32* %5, align 1
+ call void @takes_all(i64 %2, i16 %4, %struct.struct_large_nonchar* byval align 8 %d1, i32 %6, i8* null, i8* null, i32* null, i16* null, i32* null, i32 0, i32 0, i32 0)
+ ret void
+}
+
+declare i32 @get_scalar1()
+declare void @end_scalar1()
+
+declare i32 @get_scalar2()
+declare void @end_scalar2()
+
+declare i32 @get_scalar3()
+declare void @end_scalar3()
+
+declare i32 @get_addrof()
+declare void @end_addrof()
+
+declare signext i16 @get_small_nonchar()
+declare void @end_small_nonchar()
+
+declare i32 @get_large_nonchar()
+declare void @end_large_nonchar()
+
+declare signext i8 @get_small_char()
+declare void @end_small_char()
+
+declare signext i8 @get_large_char()
+declare void @end_large_char()
+
+declare signext i8 @get_struct_large_char()
+declare void @end_struct_large_char()
+
+declare signext i8 @get_struct_large_char2()
+declare void @end_struct_large_char2()
+
+declare signext i8 @get_struct_small_char()
+declare void @end_struct_small_char()
+
+declare i32 @get_struct_large_nonchar()
+declare void @end_struct_large_nonchar()
+
+declare signext i16 @get_struct_small_nonchar()
+declare void @end_struct_small_nonchar()
+
+declare void @takes_all(i64, i16, %struct.struct_large_nonchar* byval align 8, i32, i8*, i8*, i32*, i16*, i32*, i32, i32, i32)
+declare void @takes_two(i32, i8*)
diff --git test/CodeGen/X86/ssp-data-layout.ll test/CodeGen/X86/ssp-data-layout.ll
new file mode 100644
index 0000000..465abb8
--- /dev/null
+++ test/CodeGen/X86/ssp-data-layout.ll
@@ -0,0 +1,553 @@
+; RUN: llc < %s -disable-fp-elim -mtriple=x86_64-pc-linux-gnu -mcpu=corei7 -o - | FileCheck %s
+; This test is fairly fragile. The goal is to ensure that "large" stack
+; objects are allocated closest to the stack protector (i.e., farthest away
+; from the Stack Pointer.) In standard SSP mode this means that large (>=
+; ssp-buffer-size) arrays and structures containing such arrays are
+; closet to the protector. With sspstrong and sspreq this means large
+; arrays/structures-with-arrays are closest, followed by small (< ssp-buffer-size)
+; arrays/structures-with-arrays, and then addr-taken variables.
+;
+; Ideally, we only want verify that the objects appear in the correct groups
+; and that the groups have the correct relative stack offset. The ordering
+; within a group is not relevant to this test. Unfortunately, there is not
+; an elegant way to do this, so just match the offset for each object.
+; RUN: llc < %s -disable-fp-elim -mtriple=x86_64-unknown-unknown -O0 -mcpu=corei7 -o - \
+; RUN: | FileCheck --check-prefix=FAST-NON-LIN %s
+; FastISel was not setting the StackProtectorIndex when lowering
+; Intrinsic::stackprotector and as a result the stack re-arrangement code was
+; never applied. This problem only shows up on non-Linux platforms because on
+; Linux the stack protector cookie is loaded from a special address space which
+; always triggers standard ISel. Run a basic test to ensure that at -O0
+; on a non-linux target the data layout rules are triggered.
+
+%struct.struct_large_char = type { [8 x i8] }
+%struct.struct_large_char2 = type { [2 x i8], [8 x i8] }
+%struct.struct_small_char = type { [2 x i8] }
+%struct.struct_large_nonchar = type { [8 x i32] }
+%struct.struct_small_nonchar = type { [2 x i16] }
+
+define void @layout_ssp() ssp {
+entry:
+; Expected stack layout for ssp is
+; -24 large_char . Group 1, nested arrays, arrays >= ssp-buffer-size
+; -32 struct_large_char .
+; -36 scalar1 | Everything else
+; -40 scalar2
+; -44 scalar3
+; -48 addr-of
+; -52 small_nonchar
+; -96 large_nonchar
+; -98 small_char
+; -104 struct_small_char
+; -136 struct_large_nonchar
+; -144 struct_small_nonchar
+
+; CHECK: layout_ssp:
+; CHECK: call{{l|q}} get_scalar1
+; CHECK: movl %eax, -36(
+; CHECK: call{{l|q}} end_scalar1
+
+; CHECK: call{{l|q}} get_scalar2
+; CHECK: movl %eax, -40(
+; CHECK: call{{l|q}} end_scalar2
+
+; CHECK: call{{l|q}} get_scalar3
+; CHECK: movl %eax, -44(
+; CHECK: call{{l|q}} end_scalar3
+
+; CHECK: call{{l|q}} get_addrof
+; CHECK: movl %eax, -48(
+; CHECK: call{{l|q}} end_addrof
+
+; CHECK: get_small_nonchar
+; CHECK: movw %ax, -52(
+; CHECK: call{{l|q}} end_small_nonchar
+
+; CHECK: call{{l|q}} get_large_nonchar
+; CHECK: movl %eax, -96(
+; CHECK: call{{l|q}} end_large_nonchar
+
+; CHECK: call{{l|q}} get_small_char
+; CHECK: movb %al, -98(
+; CHECK: call{{l|q}} end_small_char
+
+; CHECK: call{{l|q}} get_large_char
+; CHECK: movb %al, -24(
+; CHECK: call{{l|q}} end_large_char
+
+; CHECK: call{{l|q}} get_struct_large_char
+; CHECK: movb %al, -32(
+; CHECK: call{{l|q}} end_struct_large_char
+
+; CHECK: call{{l|q}} get_struct_small_char
+; CHECK: movb %al, -104(
+; CHECK: call{{l|q}} end_struct_small_char
+
+; CHECK: call{{l|q}} get_struct_large_nonchar
+; CHECK: movl %eax, -136(
+; CHECK: call{{l|q}} end_struct_large_nonchar
+
+; CHECK: call{{l|q}} get_struct_small_nonchar
+; CHECK: movw %ax, -144(
+; CHECK: call{{l|q}} end_struct_small_nonchar
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %z = alloca i32, align 4
+ %ptr = alloca i32, align 4
+ %small2 = alloca [2 x i16], align 2
+ %large2 = alloca [8 x i32], align 16
+ %small = alloca [2 x i8], align 1
+ %large = alloca [8 x i8], align 1
+ %a = alloca %struct.struct_large_char, align 1
+ %b = alloca %struct.struct_small_char, align 1
+ %c = alloca %struct.struct_large_nonchar, align 8
+ %d = alloca %struct.struct_small_nonchar, align 2
+ %call = call i32 @get_scalar1()
+ store i32 %call, i32* %x, align 4
+ call void @end_scalar1()
+ %call1 = call i32 @get_scalar2()
+ store i32 %call1, i32* %y, align 4
+ call void @end_scalar2()
+ %call2 = call i32 @get_scalar3()
+ store i32 %call2, i32* %z, align 4
+ call void @end_scalar3()
+ %call3 = call i32 @get_addrof()
+ store i32 %call3, i32* %ptr, align 4
+ call void @end_addrof()
+ %call4 = call signext i16 @get_small_nonchar()
+ %arrayidx = getelementptr inbounds [2 x i16]* %small2, i32 0, i64 0
+ store i16 %call4, i16* %arrayidx, align 2
+ call void @end_small_nonchar()
+ %call5 = call i32 @get_large_nonchar()
+ %arrayidx6 = getelementptr inbounds [8 x i32]* %large2, i32 0, i64 0
+ store i32 %call5, i32* %arrayidx6, align 4
+ call void @end_large_nonchar()
+ %call7 = call signext i8 @get_small_char()
+ %arrayidx8 = getelementptr inbounds [2 x i8]* %small, i32 0, i64 0
+ store i8 %call7, i8* %arrayidx8, align 1
+ call void @end_small_char()
+ %call9 = call signext i8 @get_large_char()
+ %arrayidx10 = getelementptr inbounds [8 x i8]* %large, i32 0, i64 0
+ store i8 %call9, i8* %arrayidx10, align 1
+ call void @end_large_char()
+ %call11 = call signext i8 @get_struct_large_char()
+ %foo = getelementptr inbounds %struct.struct_large_char* %a, i32 0, i32 0
+ %arrayidx12 = getelementptr inbounds [8 x i8]* %foo, i32 0, i64 0
+ store i8 %call11, i8* %arrayidx12, align 1
+ call void @end_struct_large_char()
+ %call13 = call signext i8 @get_struct_small_char()
+ %foo14 = getelementptr inbounds %struct.struct_small_char* %b, i32 0, i32 0
+ %arrayidx15 = getelementptr inbounds [2 x i8]* %foo14, i32 0, i64 0
+ store i8 %call13, i8* %arrayidx15, align 1
+ call void @end_struct_small_char()
+ %call16 = call i32 @get_struct_large_nonchar()
+ %foo17 = getelementptr inbounds %struct.struct_large_nonchar* %c, i32 0, i32 0
+ %arrayidx18 = getelementptr inbounds [8 x i32]* %foo17, i32 0, i64 0
+ store i32 %call16, i32* %arrayidx18, align 4
+ call void @end_struct_large_nonchar()
+ %call19 = call signext i16 @get_struct_small_nonchar()
+ %foo20 = getelementptr inbounds %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %arrayidx21 = getelementptr inbounds [2 x i16]* %foo20, i32 0, i64 0
+ store i16 %call19, i16* %arrayidx21, align 2
+ call void @end_struct_small_nonchar()
+ %arraydecay = getelementptr inbounds [8 x i8]* %large, i32 0, i32 0
+ %arraydecay22 = getelementptr inbounds [2 x i8]* %small, i32 0, i32 0
+ %arraydecay23 = getelementptr inbounds [8 x i32]* %large2, i32 0, i32 0
+ %arraydecay24 = getelementptr inbounds [2 x i16]* %small2, i32 0, i32 0
+ %0 = load i32* %x, align 4
+ %1 = load i32* %y, align 4
+ %2 = load i32* %z, align 4
+ %coerce.dive = getelementptr %struct.struct_large_char* %a, i32 0, i32 0
+ %3 = bitcast [8 x i8]* %coerce.dive to i64*
+ %4 = load i64* %3, align 1
+ %coerce.dive25 = getelementptr %struct.struct_small_char* %b, i32 0, i32 0
+ %5 = bitcast [2 x i8]* %coerce.dive25 to i16*
+ %6 = load i16* %5, align 1
+ %coerce.dive26 = getelementptr %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %7 = bitcast [2 x i16]* %coerce.dive26 to i32*
+ %8 = load i32* %7, align 1
+ call void @takes_all(i64 %4, i16 %6, %struct.struct_large_nonchar* byval align 8 %c, i32 %8, i8* %arraydecay, i8* %arraydecay22, i32* %arraydecay23, i16* %arraydecay24, i32* %ptr, i32 %0, i32 %1, i32 %2)
+ ret void
+}
+
+define void @layout_sspstrong() sspstrong {
+entry:
+; Expected stack layout for sspstrong is
+; -48 large_nonchar . Group 1, nested arrays,
+; -56 large_char . arrays >= ssp-buffer-size
+; -64 struct_large_char .
+; -96 struct_large_nonchar .
+; -100 small_non_char | Group 2, nested arrays,
+; -102 small_char | arrays < ssp-buffer-size
+; -104 struct_small_char |
+; -112 struct_small_nonchar |
+; -116 addrof * Group 3, addr-of local
+; -120 scalar + Group 4, everything else
+; -124 scalar +
+; -128 scalar +
+;
+; CHECK: layout_sspstrong:
+; CHECK: call{{l|q}} get_scalar1
+; CHECK: movl %eax, -120(
+; CHECK: call{{l|q}} end_scalar1
+
+; CHECK: call{{l|q}} get_scalar2
+; CHECK: movl %eax, -124(
+; CHECK: call{{l|q}} end_scalar2
+
+; CHECK: call{{l|q}} get_scalar3
+; CHECK: movl %eax, -128(
+; CHECK: call{{l|q}} end_scalar3
+
+; CHECK: call{{l|q}} get_addrof
+; CHECK: movl %eax, -116(
+; CHECK: call{{l|q}} end_addrof
+
+; CHECK: get_small_nonchar
+; CHECK: movw %ax, -100(
+; CHECK: call{{l|q}} end_small_nonchar
+
+; CHECK: call{{l|q}} get_large_nonchar
+; CHECK: movl %eax, -48(
+; CHECK: call{{l|q}} end_large_nonchar
+
+; CHECK: call{{l|q}} get_small_char
+; CHECK: movb %al, -102(
+; CHECK: call{{l|q}} end_small_char
+
+; CHECK: call{{l|q}} get_large_char
+; CHECK: movb %al, -56(
+; CHECK: call{{l|q}} end_large_char
+
+; CHECK: call{{l|q}} get_struct_large_char
+; CHECK: movb %al, -64(
+; CHECK: call{{l|q}} end_struct_large_char
+
+; CHECK: call{{l|q}} get_struct_small_char
+; CHECK: movb %al, -104(
+; CHECK: call{{l|q}} end_struct_small_char
+
+; CHECK: call{{l|q}} get_struct_large_nonchar
+; CHECK: movl %eax, -96(
+; CHECK: call{{l|q}} end_struct_large_nonchar
+
+; CHECK: call{{l|q}} get_struct_small_nonchar
+; CHECK: movw %ax, -112(
+; CHECK: call{{l|q}} end_struct_small_nonchar
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %z = alloca i32, align 4
+ %ptr = alloca i32, align 4
+ %small2 = alloca [2 x i16], align 2
+ %large2 = alloca [8 x i32], align 16
+ %small = alloca [2 x i8], align 1
+ %large = alloca [8 x i8], align 1
+ %a = alloca %struct.struct_large_char, align 1
+ %b = alloca %struct.struct_small_char, align 1
+ %c = alloca %struct.struct_large_nonchar, align 8
+ %d = alloca %struct.struct_small_nonchar, align 2
+ %call = call i32 @get_scalar1()
+ store i32 %call, i32* %x, align 4
+ call void @end_scalar1()
+ %call1 = call i32 @get_scalar2()
+ store i32 %call1, i32* %y, align 4
+ call void @end_scalar2()
+ %call2 = call i32 @get_scalar3()
+ store i32 %call2, i32* %z, align 4
+ call void @end_scalar3()
+ %call3 = call i32 @get_addrof()
+ store i32 %call3, i32* %ptr, align 4
+ call void @end_addrof()
+ %call4 = call signext i16 @get_small_nonchar()
+ %arrayidx = getelementptr inbounds [2 x i16]* %small2, i32 0, i64 0
+ store i16 %call4, i16* %arrayidx, align 2
+ call void @end_small_nonchar()
+ %call5 = call i32 @get_large_nonchar()
+ %arrayidx6 = getelementptr inbounds [8 x i32]* %large2, i32 0, i64 0
+ store i32 %call5, i32* %arrayidx6, align 4
+ call void @end_large_nonchar()
+ %call7 = call signext i8 @get_small_char()
+ %arrayidx8 = getelementptr inbounds [2 x i8]* %small, i32 0, i64 0
+ store i8 %call7, i8* %arrayidx8, align 1
+ call void @end_small_char()
+ %call9 = call signext i8 @get_large_char()
+ %arrayidx10 = getelementptr inbounds [8 x i8]* %large, i32 0, i64 0
+ store i8 %call9, i8* %arrayidx10, align 1
+ call void @end_large_char()
+ %call11 = call signext i8 @get_struct_large_char()
+ %foo = getelementptr inbounds %struct.struct_large_char* %a, i32 0, i32 0
+ %arrayidx12 = getelementptr inbounds [8 x i8]* %foo, i32 0, i64 0
+ store i8 %call11, i8* %arrayidx12, align 1
+ call void @end_struct_large_char()
+ %call13 = call signext i8 @get_struct_small_char()
+ %foo14 = getelementptr inbounds %struct.struct_small_char* %b, i32 0, i32 0
+ %arrayidx15 = getelementptr inbounds [2 x i8]* %foo14, i32 0, i64 0
+ store i8 %call13, i8* %arrayidx15, align 1
+ call void @end_struct_small_char()
+ %call16 = call i32 @get_struct_large_nonchar()
+ %foo17 = getelementptr inbounds %struct.struct_large_nonchar* %c, i32 0, i32 0
+ %arrayidx18 = getelementptr inbounds [8 x i32]* %foo17, i32 0, i64 0
+ store i32 %call16, i32* %arrayidx18, align 4
+ call void @end_struct_large_nonchar()
+ %call19 = call signext i16 @get_struct_small_nonchar()
+ %foo20 = getelementptr inbounds %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %arrayidx21 = getelementptr inbounds [2 x i16]* %foo20, i32 0, i64 0
+ store i16 %call19, i16* %arrayidx21, align 2
+ call void @end_struct_small_nonchar()
+ %arraydecay = getelementptr inbounds [8 x i8]* %large, i32 0, i32 0
+ %arraydecay22 = getelementptr inbounds [2 x i8]* %small, i32 0, i32 0
+ %arraydecay23 = getelementptr inbounds [8 x i32]* %large2, i32 0, i32 0
+ %arraydecay24 = getelementptr inbounds [2 x i16]* %small2, i32 0, i32 0
+ %0 = load i32* %x, align 4
+ %1 = load i32* %y, align 4
+ %2 = load i32* %z, align 4
+ %coerce.dive = getelementptr %struct.struct_large_char* %a, i32 0, i32 0
+ %3 = bitcast [8 x i8]* %coerce.dive to i64*
+ %4 = load i64* %3, align 1
+ %coerce.dive25 = getelementptr %struct.struct_small_char* %b, i32 0, i32 0
+ %5 = bitcast [2 x i8]* %coerce.dive25 to i16*
+ %6 = load i16* %5, align 1
+ %coerce.dive26 = getelementptr %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %7 = bitcast [2 x i16]* %coerce.dive26 to i32*
+ %8 = load i32* %7, align 1
+ call void @takes_all(i64 %4, i16 %6, %struct.struct_large_nonchar* byval align 8 %c, i32 %8, i8* %arraydecay, i8* %arraydecay22, i32* %arraydecay23, i16* %arraydecay24, i32* %ptr, i32 %0, i32 %1, i32 %2)
+ ret void
+}
+
+define void @layout_sspreq() sspreq {
+entry:
+; Expected stack layout for sspreq is the same as sspstrong
+;
+; CHECK: layout_sspreq:
+; CHECK: call{{l|q}} get_scalar1
+; CHECK: movl %eax, -120(
+; CHECK: call{{l|q}} end_scalar1
+
+; CHECK: call{{l|q}} get_scalar2
+; CHECK: movl %eax, -124(
+; CHECK: call{{l|q}} end_scalar2
+
+; CHECK: call{{l|q}} get_scalar3
+; CHECK: movl %eax, -128(
+; CHECK: call{{l|q}} end_scalar3
+
+; CHECK: call{{l|q}} get_addrof
+; CHECK: movl %eax, -116(
+; CHECK: call{{l|q}} end_addrof
+
+; CHECK: get_small_nonchar
+; CHECK: movw %ax, -100(
+; CHECK: call{{l|q}} end_small_nonchar
+
+; CHECK: call{{l|q}} get_large_nonchar
+; CHECK: movl %eax, -48(
+; CHECK: call{{l|q}} end_large_nonchar
+
+; CHECK: call{{l|q}} get_small_char
+; CHECK: movb %al, -102(
+; CHECK: call{{l|q}} end_small_char
+
+; CHECK: call{{l|q}} get_large_char
+; CHECK: movb %al, -56(
+; CHECK: call{{l|q}} end_large_char
+
+; CHECK: call{{l|q}} get_struct_large_char
+; CHECK: movb %al, -64(
+; CHECK: call{{l|q}} end_struct_large_char
+
+; CHECK: call{{l|q}} get_struct_small_char
+; CHECK: movb %al, -104(
+; CHECK: call{{l|q}} end_struct_small_char
+
+; CHECK: call{{l|q}} get_struct_large_nonchar
+; CHECK: movl %eax, -96(
+; CHECK: call{{l|q}} end_struct_large_nonchar
+
+; CHECK: call{{l|q}} get_struct_small_nonchar
+; CHECK: movw %ax, -112(
+; CHECK: call{{l|q}} end_struct_small_nonchar
+ %x = alloca i32, align 4
+ %y = alloca i32, align 4
+ %z = alloca i32, align 4
+ %ptr = alloca i32, align 4
+ %small2 = alloca [2 x i16], align 2
+ %large2 = alloca [8 x i32], align 16
+ %small = alloca [2 x i8], align 1
+ %large = alloca [8 x i8], align 1
+ %a = alloca %struct.struct_large_char, align 1
+ %b = alloca %struct.struct_small_char, align 1
+ %c = alloca %struct.struct_large_nonchar, align 8
+ %d = alloca %struct.struct_small_nonchar, align 2
+ %call = call i32 @get_scalar1()
+ store i32 %call, i32* %x, align 4
+ call void @end_scalar1()
+ %call1 = call i32 @get_scalar2()
+ store i32 %call1, i32* %y, align 4
+ call void @end_scalar2()
+ %call2 = call i32 @get_scalar3()
+ store i32 %call2, i32* %z, align 4
+ call void @end_scalar3()
+ %call3 = call i32 @get_addrof()
+ store i32 %call3, i32* %ptr, align 4
+ call void @end_addrof()
+ %call4 = call signext i16 @get_small_nonchar()
+ %arrayidx = getelementptr inbounds [2 x i16]* %small2, i32 0, i64 0
+ store i16 %call4, i16* %arrayidx, align 2
+ call void @end_small_nonchar()
+ %call5 = call i32 @get_large_nonchar()
+ %arrayidx6 = getelementptr inbounds [8 x i32]* %large2, i32 0, i64 0
+ store i32 %call5, i32* %arrayidx6, align 4
+ call void @end_large_nonchar()
+ %call7 = call signext i8 @get_small_char()
+ %arrayidx8 = getelementptr inbounds [2 x i8]* %small, i32 0, i64 0
+ store i8 %call7, i8* %arrayidx8, align 1
+ call void @end_small_char()
+ %call9 = call signext i8 @get_large_char()
+ %arrayidx10 = getelementptr inbounds [8 x i8]* %large, i32 0, i64 0
+ store i8 %call9, i8* %arrayidx10, align 1
+ call void @end_large_char()
+ %call11 = call signext i8 @get_struct_large_char()
+ %foo = getelementptr inbounds %struct.struct_large_char* %a, i32 0, i32 0
+ %arrayidx12 = getelementptr inbounds [8 x i8]* %foo, i32 0, i64 0
+ store i8 %call11, i8* %arrayidx12, align 1
+ call void @end_struct_large_char()
+ %call13 = call signext i8 @get_struct_small_char()
+ %foo14 = getelementptr inbounds %struct.struct_small_char* %b, i32 0, i32 0
+ %arrayidx15 = getelementptr inbounds [2 x i8]* %foo14, i32 0, i64 0
+ store i8 %call13, i8* %arrayidx15, align 1
+ call void @end_struct_small_char()
+ %call16 = call i32 @get_struct_large_nonchar()
+ %foo17 = getelementptr inbounds %struct.struct_large_nonchar* %c, i32 0, i32 0
+ %arrayidx18 = getelementptr inbounds [8 x i32]* %foo17, i32 0, i64 0
+ store i32 %call16, i32* %arrayidx18, align 4
+ call void @end_struct_large_nonchar()
+ %call19 = call signext i16 @get_struct_small_nonchar()
+ %foo20 = getelementptr inbounds %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %arrayidx21 = getelementptr inbounds [2 x i16]* %foo20, i32 0, i64 0
+ store i16 %call19, i16* %arrayidx21, align 2
+ call void @end_struct_small_nonchar()
+ %arraydecay = getelementptr inbounds [8 x i8]* %large, i32 0, i32 0
+ %arraydecay22 = getelementptr inbounds [2 x i8]* %small, i32 0, i32 0
+ %arraydecay23 = getelementptr inbounds [8 x i32]* %large2, i32 0, i32 0
+ %arraydecay24 = getelementptr inbounds [2 x i16]* %small2, i32 0, i32 0
+ %0 = load i32* %x, align 4
+ %1 = load i32* %y, align 4
+ %2 = load i32* %z, align 4
+ %coerce.dive = getelementptr %struct.struct_large_char* %a, i32 0, i32 0
+ %3 = bitcast [8 x i8]* %coerce.dive to i64*
+ %4 = load i64* %3, align 1
+ %coerce.dive25 = getelementptr %struct.struct_small_char* %b, i32 0, i32 0
+ %5 = bitcast [2 x i8]* %coerce.dive25 to i16*
+ %6 = load i16* %5, align 1
+ %coerce.dive26 = getelementptr %struct.struct_small_nonchar* %d, i32 0, i32 0
+ %7 = bitcast [2 x i16]* %coerce.dive26 to i32*
+ %8 = load i32* %7, align 1
+ call void @takes_all(i64 %4, i16 %6, %struct.struct_large_nonchar* byval align 8 %c, i32 %8, i8* %arraydecay, i8* %arraydecay22, i32* %arraydecay23, i16* %arraydecay24, i32* %ptr, i32 %0, i32 %1, i32 %2)
+ ret void
+}
+
+define void @struct_with_protectable_arrays() sspstrong {
+entry:
+; Check to ensure that a structure which contains a small array followed by a
+; large array is assigned to the stack properly as a large object.
+; CHECK: struct_with_protectable_arrays:
+; CHECK: call{{l|q}} get_struct_small_char
+; CHECK: movb %al, -64(
+; CHECK: call{{l|q}} end_struct_small_char
+; CHECK: call{{l|q}} get_struct_large_char2
+; CHECK: movb %al, -22(
+; CHECK: call{{l|q}} end_struct_large_char2
+ %a = alloca %struct.struct_small_char, align 1
+ %b = alloca %struct.struct_large_char2, align 1
+ %d1 = alloca %struct.struct_large_nonchar, align 8
+ %d2 = alloca %struct.struct_small_nonchar, align 2
+ %call = call signext i8 @get_struct_small_char()
+ %foo = getelementptr inbounds %struct.struct_small_char* %a, i32 0, i32 0
+ %arrayidx = getelementptr inbounds [2 x i8]* %foo, i32 0, i64 0
+ store i8 %call, i8* %arrayidx, align 1
+ call void @end_struct_small_char()
+ %call1 = call signext i8 @get_struct_large_char2()
+ %foo2 = getelementptr inbounds %struct.struct_large_char2* %b, i32 0, i32 1
+ %arrayidx3 = getelementptr inbounds [8 x i8]* %foo2, i32 0, i64 0
+ store i8 %call1, i8* %arrayidx3, align 1
+ call void @end_struct_large_char2()
+ %0 = bitcast %struct.struct_large_char2* %b to %struct.struct_large_char*
+ %coerce.dive = getelementptr %struct.struct_large_char* %0, i32 0, i32 0
+ %1 = bitcast [8 x i8]* %coerce.dive to i64*
+ %2 = load i64* %1, align 1
+ %coerce.dive4 = getelementptr %struct.struct_small_char* %a, i32 0, i32 0
+ %3 = bitcast [2 x i8]* %coerce.dive4 to i16*
+ %4 = load i16* %3, align 1
+ %coerce.dive5 = getelementptr %struct.struct_small_nonchar* %d2, i32 0, i32 0
+ %5 = bitcast [2 x i16]* %coerce.dive5 to i32*
+ %6 = load i32* %5, align 1
+ call void @takes_all(i64 %2, i16 %4, %struct.struct_large_nonchar* byval align 8 %d1, i32 %6, i8* null, i8* null, i32* null, i16* null, i32* null, i32 0, i32 0, i32 0)
+ ret void
+}
+
+define void @fast_non_linux() sspstrong {
+entry:
+; FAST-NON-LIN: fast_non_linux:
+; FAST-NON-LIN: call{{l|q}} get_scalar1
+; FAST-NON-LIN: movl %eax, -20(
+; FAST-NON-LIN: call{{l|q}} end_scalar1
+
+; FAST-NON-LIN: call{{l|q}} get_large_char
+; FAST-NON-LIN: movb %al, -16(
+; FAST-NON-LIN: call{{l|q}} end_large_char
+ %x = alloca i32, align 4
+ %large = alloca [8 x i8], align 1
+ %call = call i32 @get_scalar1()
+ store i32 %call, i32* %x, align 4
+ call void @end_scalar1()
+ %call1 = call signext i8 @get_large_char()
+ %arrayidx = getelementptr inbounds [8 x i8]* %large, i32 0, i64 0
+ store i8 %call1, i8* %arrayidx, align 1
+ call void @end_large_char()
+ %0 = load i32* %x, align 4
+ %arraydecay = getelementptr inbounds [8 x i8]* %large, i32 0, i32 0
+ call void @takes_two(i32 %0, i8* %arraydecay)
+ ret void
+}
+
+declare i32 @get_scalar1()
+declare void @end_scalar1()
+
+declare i32 @get_scalar2()
+declare void @end_scalar2()
+
+declare i32 @get_scalar3()
+declare void @end_scalar3()
+
+declare i32 @get_addrof()
+declare void @end_addrof()
+
+declare signext i16 @get_small_nonchar()
+declare void @end_small_nonchar()
+
+declare i32 @get_large_nonchar()
+declare void @end_large_nonchar()
+
+declare signext i8 @get_small_char()
+declare void @end_small_char()
+
+declare signext i8 @get_large_char()
+declare void @end_large_char()
+
+declare signext i8 @get_struct_large_char()
+declare void @end_struct_large_char()
+
+declare signext i8 @get_struct_large_char2()
+declare void @end_struct_large_char2()
+
+declare signext i8 @get_struct_small_char()
+declare void @end_struct_small_char()
+
+declare i32 @get_struct_large_nonchar()
+declare void @end_struct_large_nonchar()
+
+declare signext i16 @get_struct_small_nonchar()
+declare void @end_struct_small_nonchar()
+
+declare void @takes_all(i64, i16, %struct.struct_large_nonchar* byval align 8, i32, i8*, i8*, i32*, i16*, i32*, i32, i32, i32)
+declare void @takes_two(i32, i8*)
More information about the llvm-commits
mailing list