mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
[PowerPC] Add ROP Protection to prologue and epilogue
Added hashst to the prologue and hashchk to the epilogue. The hash for the prologue and epilogue must always be stored as the first element in the local variable space on the stack. Reviewed By: nemanjai, #powerpc Differential Revision: https://reviews.llvm.org/D99377
This commit is contained in:
parent
65a6f9a60e
commit
20d928df72
@ -642,6 +642,8 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
|
||||
bool HasFP = hasFP(MF);
|
||||
bool HasBP = RegInfo->hasBasePointer(MF);
|
||||
bool HasRedZone = isPPC64 || !isSVR4ABI;
|
||||
bool HasROPProtect = Subtarget.hasROPProtect();
|
||||
bool HasPrivileged = Subtarget.hasPrivileged();
|
||||
|
||||
Register SPReg = isPPC64 ? PPC::X1 : PPC::R1;
|
||||
Register BPReg = RegInfo->getBaseRegister(MF);
|
||||
@ -672,6 +674,8 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
|
||||
const MCInstrDesc &MoveFromCondRegInst = TII.get(isPPC64 ? PPC::MFCR8
|
||||
: PPC::MFCR);
|
||||
const MCInstrDesc &StoreWordInst = TII.get(isPPC64 ? PPC::STW8 : PPC::STW);
|
||||
const MCInstrDesc &HashST =
|
||||
TII.get(HasPrivileged ? PPC::HASHSTP : PPC::HASHST);
|
||||
|
||||
// Regarding this assert: Even though LR is saved in the caller's frame (i.e.,
|
||||
// LROffset is positive), that slot is callee-owned. Because PPC32 SVR4 has no
|
||||
@ -833,11 +837,34 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF,
|
||||
.addReg(SPReg);
|
||||
}
|
||||
|
||||
if (MustSaveLR)
|
||||
// Generate the instruction to store the LR. In the case where ROP protection
|
||||
// is required the register holding the LR should not be killed as it will be
|
||||
// used by the hash store instruction.
|
||||
if (MustSaveLR) {
|
||||
BuildMI(MBB, StackUpdateLoc, dl, StoreInst)
|
||||
.addReg(ScratchReg, getKillRegState(true))
|
||||
.addImm(LROffset)
|
||||
.addReg(SPReg);
|
||||
.addReg(ScratchReg, getKillRegState(!HasROPProtect))
|
||||
.addImm(LROffset)
|
||||
.addReg(SPReg);
|
||||
|
||||
// Add the ROP protection Hash Store instruction.
|
||||
// NOTE: This is technically a violation of the ABI. The hash can be saved
|
||||
// up to 512 bytes into the Protected Zone. This can be outside of the
|
||||
// initial 288 byte volatile program storage region in the Protected Zone.
|
||||
// However, this restriction will be removed in an upcoming revision of the
|
||||
// ABI.
|
||||
if (HasROPProtect) {
|
||||
const int SaveIndex = FI->getROPProtectionHashSaveIndex();
|
||||
const int ImmOffset = MFI.getObjectOffset(SaveIndex);
|
||||
assert((ImmOffset <= -8 && ImmOffset >= -512) &&
|
||||
"ROP hash save offset out of range.");
|
||||
assert(((ImmOffset & 0x7) == 0) &&
|
||||
"ROP hash save offset must be 8 byte aligned.");
|
||||
BuildMI(MBB, StackUpdateLoc, dl, HashST)
|
||||
.addReg(ScratchReg, getKillRegState(true))
|
||||
.addImm(ImmOffset)
|
||||
.addReg(SPReg);
|
||||
}
|
||||
}
|
||||
|
||||
if (MustSaveCR &&
|
||||
!(SingleScratchReg && MustSaveLR)) {
|
||||
@ -1528,6 +1555,8 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
bool HasFP = hasFP(MF);
|
||||
bool HasBP = RegInfo->hasBasePointer(MF);
|
||||
bool HasRedZone = Subtarget.isPPC64() || !Subtarget.isSVR4ABI();
|
||||
bool HasROPProtect = Subtarget.hasROPProtect();
|
||||
bool HasPrivileged = Subtarget.hasPrivileged();
|
||||
|
||||
Register SPReg = isPPC64 ? PPC::X1 : PPC::R1;
|
||||
Register BPReg = RegInfo->getBaseRegister(MF);
|
||||
@ -1552,6 +1581,8 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
: PPC::LWZ);
|
||||
const MCInstrDesc& MoveToCRInst = TII.get( isPPC64 ? PPC::MTOCRF8
|
||||
: PPC::MTOCRF);
|
||||
const MCInstrDesc &HashChk =
|
||||
TII.get(HasPrivileged ? PPC::HASHCHKP : PPC::HASHCHK);
|
||||
int LROffset = getReturnSaveOffset();
|
||||
|
||||
int FPOffset = 0;
|
||||
@ -1820,8 +1851,23 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
BuildMI(MBB, MBBI, dl, MoveToCRInst, MustSaveCRs[i])
|
||||
.addReg(TempReg, getKillRegState(i == e-1));
|
||||
|
||||
if (MustSaveLR)
|
||||
if (MustSaveLR) {
|
||||
// If ROP protection is required, an extra instruction is added to compute a
|
||||
// hash and then compare it to the hash stored in the prologue.
|
||||
if (HasROPProtect) {
|
||||
const int SaveIndex = FI->getROPProtectionHashSaveIndex();
|
||||
const int ImmOffset = MFI.getObjectOffset(SaveIndex);
|
||||
assert((ImmOffset <= -8 && ImmOffset >= -512) &&
|
||||
"ROP hash check location offset out of range.");
|
||||
assert(((ImmOffset & 0x7) == 0) &&
|
||||
"ROP hash check location offset must be 8 byte aligned.");
|
||||
BuildMI(MBB, StackUpdateLoc, dl, HashChk)
|
||||
.addReg(ScratchReg)
|
||||
.addImm(ImmOffset)
|
||||
.addReg(SPReg);
|
||||
}
|
||||
BuildMI(MBB, StackUpdateLoc, dl, MTLRInst).addReg(ScratchReg);
|
||||
}
|
||||
|
||||
// Callee pop calling convention. Pop parameter/linkage area. Used for tail
|
||||
// call optimization
|
||||
|
@ -152,6 +152,15 @@ namespace {
|
||||
GlobalBaseReg = 0;
|
||||
Subtarget = &MF.getSubtarget<PPCSubtarget>();
|
||||
PPCLowering = Subtarget->getTargetLowering();
|
||||
if (Subtarget->hasROPProtect()) {
|
||||
// Create a place on the stack for the ROP Protection Hash.
|
||||
// The ROP Protection Hash will always be 8 bytes and aligned to 8
|
||||
// bytes.
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
PPCFunctionInfo *FI = MF.getInfo<PPCFunctionInfo>();
|
||||
const int Result = MFI.CreateStackObject(8, Align(8), false);
|
||||
FI->setROPProtectionHashSaveIndex(Result);
|
||||
}
|
||||
SelectionDAGISel::runOnMachineFunction(MF);
|
||||
|
||||
return true;
|
||||
|
@ -49,6 +49,9 @@ private:
|
||||
/// Frame index where the old PIC base pointer is stored.
|
||||
int PICBasePointerSaveIndex = 0;
|
||||
|
||||
/// Frame index where the ROP Protection Hash is stored.
|
||||
int ROPProtectionHashSaveIndex = 0;
|
||||
|
||||
/// MustSaveLR - Indicates whether LR is defined (or clobbered) in the current
|
||||
/// function. This is only valid after the initial scan of the function by
|
||||
/// PEI.
|
||||
@ -161,6 +164,13 @@ public:
|
||||
int getPICBasePointerSaveIndex() const { return PICBasePointerSaveIndex; }
|
||||
void setPICBasePointerSaveIndex(int Idx) { PICBasePointerSaveIndex = Idx; }
|
||||
|
||||
int getROPProtectionHashSaveIndex() const {
|
||||
return ROPProtectionHashSaveIndex;
|
||||
}
|
||||
void setROPProtectionHashSaveIndex(int Idx) {
|
||||
ROPProtectionHashSaveIndex = Idx;
|
||||
}
|
||||
|
||||
unsigned getMinReservedArea() const { return MinReservedArea; }
|
||||
void setMinReservedArea(unsigned size) { MinReservedArea = size; }
|
||||
|
||||
|
@ -433,6 +433,16 @@ bool PPCRegisterInfo::requiresFrameIndexScavenging(const MachineFunction &MF) co
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PPCRegisterInfo::requiresVirtualBaseRegisters(
|
||||
const MachineFunction &MF) const {
|
||||
const PPCSubtarget &Subtarget = MF.getSubtarget<PPCSubtarget>();
|
||||
// Do not use virtual base registers when ROP protection is turned on.
|
||||
// Virtual base registers break the layout of the local variable space and may
|
||||
// push the ROP Hash location past the 512 byte range of the ROP store
|
||||
// instruction.
|
||||
return !Subtarget.hasROPProtect();
|
||||
}
|
||||
|
||||
bool PPCRegisterInfo::isCallerPreservedPhysReg(MCRegister PhysReg,
|
||||
const MachineFunction &MF) const {
|
||||
assert(Register::isPhysicalRegister(PhysReg));
|
||||
|
@ -101,9 +101,7 @@ public:
|
||||
|
||||
bool requiresFrameIndexScavenging(const MachineFunction &MF) const override;
|
||||
|
||||
bool requiresVirtualBaseRegisters(const MachineFunction &MF) const override {
|
||||
return true;
|
||||
}
|
||||
bool requiresVirtualBaseRegisters(const MachineFunction &MF) const override;
|
||||
|
||||
void lowerDynamicAlloc(MachineBasicBlock::iterator II) const;
|
||||
void lowerDynamicAreaOffset(MachineBasicBlock::iterator II) const;
|
||||
|
3559
test/CodeGen/PowerPC/ppc64-rop-protection.ll
Normal file
3559
test/CodeGen/PowerPC/ppc64-rop-protection.ll
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user