From cf9ee5b111370eab06b628fd3b3de1f4269c890c Mon Sep 17 00:00:00 2001 From: mortimer Date: Fri, 25 Oct 2019 00:40:57 +0000 Subject: Add retguard for octeon/mips64. For this architecture we use separate retguard prologue and epilogue code for static or PIC code. In the PIC case we use some additional code before the retguard epilogue to recover the function start address and the GOT pointer in order to get the per-function random cookie. Much thanks to visa@ for suggestions and advice making it all work. ok deraadt@ visa@ --- gnu/llvm/lib/Target/Mips/CMakeLists.txt | 34 ++- gnu/llvm/lib/Target/Mips/MipsAsmPrinter.cpp | 77 ++++++ gnu/llvm/lib/Target/Mips/MipsFrameLowering.cpp | 62 ++--- gnu/llvm/lib/Target/Mips/MipsFrameLowering.h | 16 +- gnu/llvm/lib/Target/Mips/MipsInstrInfo.td | 25 ++ .../Target/Mips/MipsReturnProtectorLowering.cpp | 272 +++++++++++++++++++++ .../lib/Target/Mips/MipsReturnProtectorLowering.h | 46 ++++ .../tools/clang/lib/Driver/ToolChains/Clang.cpp | 2 + 8 files changed, 488 insertions(+), 46 deletions(-) create mode 100644 gnu/llvm/lib/Target/Mips/MipsReturnProtectorLowering.cpp create mode 100644 gnu/llvm/lib/Target/Mips/MipsReturnProtectorLowering.h (limited to 'gnu/llvm') diff --git a/gnu/llvm/lib/Target/Mips/CMakeLists.txt b/gnu/llvm/lib/Target/Mips/CMakeLists.txt index bde843afd3d..dbf01f85eee 100644 --- a/gnu/llvm/lib/Target/Mips/CMakeLists.txt +++ b/gnu/llvm/lib/Target/Mips/CMakeLists.txt @@ -1,16 +1,19 @@ set(LLVM_TARGET_DEFINITIONS Mips.td) -tablegen(LLVM MipsGenRegisterInfo.inc -gen-register-info) -tablegen(LLVM MipsGenInstrInfo.inc -gen-instr-info) -tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler) -tablegen(LLVM MipsGenMCCodeEmitter.inc -gen-emitter) +tablegen(LLVM MipsGenAsmMatcher.inc -gen-asm-matcher) tablegen(LLVM MipsGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM MipsGenCallingConv.inc -gen-callingconv) tablegen(LLVM MipsGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM MipsGenDisassemblerTables.inc -gen-disassembler) tablegen(LLVM MipsGenFastISel.inc -gen-fast-isel) -tablegen(LLVM MipsGenCallingConv.inc -gen-callingconv) -tablegen(LLVM MipsGenSubtargetInfo.inc -gen-subtarget) -tablegen(LLVM MipsGenAsmMatcher.inc -gen-asm-matcher) +tablegen(LLVM MipsGenGlobalISel.inc -gen-global-isel) +tablegen(LLVM MipsGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM MipsGenMCCodeEmitter.inc -gen-emitter) tablegen(LLVM MipsGenMCPseudoLowering.inc -gen-pseudo-lowering) +tablegen(LLVM MipsGenRegisterBank.inc -gen-register-bank) +tablegen(LLVM MipsGenRegisterInfo.inc -gen-register-info) +tablegen(LLVM MipsGenSubtargetInfo.inc -gen-subtarget) + add_public_tablegen_target(MipsCommonTableGen) add_llvm_target(MipsCodeGen @@ -23,21 +26,28 @@ add_llvm_target(MipsCodeGen Mips16RegisterInfo.cpp MipsAnalyzeImmediate.cpp MipsAsmPrinter.cpp + MipsCallLowering.cpp MipsCCState.cpp MipsConstantIslandPass.cpp MipsDelaySlotFiller.cpp + MipsExpandPseudo.cpp MipsFastISel.cpp MipsInstrInfo.cpp + MipsInstructionSelector.cpp MipsISelDAGToDAG.cpp MipsISelLowering.cpp MipsFrameLowering.cpp - MipsLongBranch.cpp + MipsLegalizerInfo.cpp + MipsBranchExpansion.cpp MipsMCInstLower.cpp MipsMachineFunction.cpp MipsModuleISelDAGToDAG.cpp MipsOptimizePICCall.cpp MipsOs16.cpp + MipsPreLegalizerCombiner.cpp + MipsRegisterBankInfo.cpp MipsRegisterInfo.cpp + MipsReturnProtectorLowering.cpp MipsSEFrameLowering.cpp MipsSEInstrInfo.cpp MipsSEISelDAGToDAG.cpp @@ -46,11 +56,11 @@ add_llvm_target(MipsCodeGen MipsSubtarget.cpp MipsTargetMachine.cpp MipsTargetObjectFile.cpp + MicroMipsSizeReduction.cpp ) -add_subdirectory(InstPrinter) +add_subdirectory(AsmParser) add_subdirectory(Disassembler) -add_subdirectory(TargetInfo) +add_subdirectory(InstPrinter) add_subdirectory(MCTargetDesc) -add_subdirectory(AsmParser) - +add_subdirectory(TargetInfo) diff --git a/gnu/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/gnu/llvm/lib/Target/Mips/MipsAsmPrinter.cpp index 4a2c4a7239f..ade0ef82783 100644 --- a/gnu/llvm/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/gnu/llvm/lib/Target/Mips/MipsAsmPrinter.cpp @@ -241,6 +241,83 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { case Mips::PATCHABLE_TAIL_CALL: LowerPATCHABLE_TAIL_CALL(*MI); return; + case Mips::RETGUARD_GET_FUNCTION_ADDR: + { + MCSymbol *PCSym = OutContext.createTempSymbol(); + MCSymbol *FuncSym = OutContext.lookupSymbol(MI->getMF()->getName()); + if (FuncSym == nullptr) + llvm_unreachable("Function name has no symbol"); + + // Branch and link forward, calculate the distance + // from here to the start of the function, and fill the + // address in the given dest register + unsigned OUT = MI->getOperand(0).getReg(); + unsigned IN1 = MI->getOperand(1).getReg(); + unsigned IN2 = MI->getOperand(2).getReg(); + MCSymbol *ReturnSym = MI->getOperand(3).getMCSymbol(); + + // Save the value of RA in IN1 + EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::OR64) + .addReg(IN1) + .addReg(Mips::RA_64) + .addReg(Mips::ZERO_64)); + // BAL to get the PC into RA + EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::BAL) + .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext))); + // NOP + EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::SLL) + .addReg(Mips::ZERO_64) + .addReg(Mips::ZERO_64) + .addImm(0)); + + // Emit a symbol for "here/PC" because BAL will put + // the address of the instruction following the NOP into RA + // and we need this symbol to do the math + OutStreamer->EmitLabel(PCSym); + + // Store PC in IN2 + EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::OR64) + .addReg(IN2) + .addReg(Mips::RA_64) + .addReg(Mips::ZERO_64)); + // Restore original RA + EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::OR64) + .addReg(Mips::RA_64) + .addReg(IN1) + .addReg(Mips::ZERO_64)); + // Load the offset from PCSym to the start of the function + EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::LUi64) + .addReg(IN1) + .addExpr(MipsMCExpr::create(MipsMCExpr::MipsExprKind::MEK_HI, + MCBinaryExpr::createSub( + MCSymbolRefExpr::create(PCSym, OutContext), + MCSymbolRefExpr::create(FuncSym, OutContext), + OutContext), + OutContext))); + EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::DADDiu) + .addReg(IN1) + .addReg(IN1) + .addExpr(MipsMCExpr::create(MipsMCExpr::MipsExprKind::MEK_LO, + MCBinaryExpr::createSub( + MCSymbolRefExpr::create(PCSym, OutContext), + MCSymbolRefExpr::create(FuncSym, OutContext), + OutContext), + OutContext))); + + // Sub distance from here to start of function + // to get address of the start of function + EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::DSUBu) + .addReg(OUT) + .addReg(IN2) + .addReg(IN1)); + return; + } + case Mips::RETGUARD_EMIT_SYMBOL: + { + MCSymbol *ReturnSym = MI->getOperand(0).getMCSymbol(); + OutStreamer->EmitLabel(ReturnSym); + return; + } } if (EmitJalrReloc && diff --git a/gnu/llvm/lib/Target/Mips/MipsFrameLowering.cpp b/gnu/llvm/lib/Target/Mips/MipsFrameLowering.cpp index a74c8abd2e2..54cac00577f 100644 --- a/gnu/llvm/lib/Target/Mips/MipsFrameLowering.cpp +++ b/gnu/llvm/lib/Target/Mips/MipsFrameLowering.cpp @@ -13,9 +13,9 @@ #include "MipsFrameLowering.h" #include "MCTargetDesc/MipsBaseInfo.h" -#include "MipsAnalyzeImmediate.h" #include "MipsInstrInfo.h" #include "MipsMachineFunction.h" +#include "MipsReturnProtectorLowering.h" #include "MipsTargetMachine.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -24,7 +24,6 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetOptions.h" using namespace llvm; @@ -94,57 +93,54 @@ const MipsFrameLowering *MipsFrameLowering::create(const MipsSubtarget &ST) { // if it needs dynamic stack realignment, if frame pointer elimination is // disabled, or if the frame address is taken. bool MipsFrameLowering::hasFP(const MachineFunction &MF) const { - const MachineFrameInfo *MFI = MF.getFrameInfo(); + const MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetRegisterInfo *TRI = STI.getRegisterInfo(); return MF.getTarget().Options.DisableFramePointerElim(MF) || - MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken() || + MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken() || TRI->needsStackRealignment(MF); } bool MipsFrameLowering::hasBP(const MachineFunction &MF) const { - const MachineFrameInfo *MFI = MF.getFrameInfo(); + const MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetRegisterInfo *TRI = STI.getRegisterInfo(); - return MFI->hasVarSizedObjects() && TRI->needsStackRealignment(MF); + return MFI.hasVarSizedObjects() && TRI->needsStackRealignment(MF); } +// Estimate the size of the stack, including the incoming arguments. We need to +// account for register spills, local objects, reserved call frame and incoming +// arguments. This is required to determine the largest possible positive offset +// from $sp so that it can be determined if an emergency spill slot for stack +// addresses is required. uint64_t MipsFrameLowering::estimateStackSize(const MachineFunction &MF) const { - const MachineFrameInfo *MFI = MF.getFrameInfo(); + const MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); - int64_t Offset = 0; + int64_t Size = 0; - // Iterate over fixed sized objects. - for (int I = MFI->getObjectIndexBegin(); I != 0; ++I) - Offset = std::max(Offset, -MFI->getObjectOffset(I)); + // Iterate over fixed sized objects which are incoming arguments. + for (int I = MFI.getObjectIndexBegin(); I != 0; ++I) + if (MFI.getObjectOffset(I) > 0) + Size += MFI.getObjectSize(I); + + // Account for saving return protector register + if (MFI.getReturnProtectorNeeded()) + Size += TRI.getSpillSize(*TRI.getMinimalPhysRegClass(Mips::T9_64)); // Conservatively assume all callee-saved registers will be saved. for (const MCPhysReg *R = TRI.getCalleeSavedRegs(&MF); *R; ++R) { - unsigned Size = TRI.getMinimalPhysRegClass(*R)->getSize(); - Offset = RoundUpToAlignment(Offset + Size, Size); + unsigned RegSize = TRI.getSpillSize(*TRI.getMinimalPhysRegClass(*R)); + Size = alignTo(Size + RegSize, RegSize); } - unsigned MaxAlign = MFI->getMaxAlignment(); - - // Check that MaxAlign is not zero if there is a stack object that is not a - // callee-saved spill. - assert(!MFI->getObjectIndexEnd() || MaxAlign); - - // Iterate over other objects. - for (unsigned I = 0, E = MFI->getObjectIndexEnd(); I != E; ++I) - Offset = RoundUpToAlignment(Offset + MFI->getObjectSize(I), MaxAlign); - - // Call frame. - if (MFI->adjustsStack() && hasReservedCallFrame(MF)) - Offset = RoundUpToAlignment(Offset + MFI->getMaxCallFrameSize(), - std::max(MaxAlign, getStackAlignment())); - - return RoundUpToAlignment(Offset, getStackAlignment()); + // Get the size of the rest of the frame objects and any possible reserved + // call frame, accounting for alignment. + return Size + MFI.estimateStackSize(MF); } // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions -void MipsFrameLowering:: +MachineBasicBlock::iterator MipsFrameLowering:: eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { unsigned SP = STI.getABI().IsN64() ? Mips::SP_64 : Mips::SP; @@ -157,5 +153,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, STI.getInstrInfo()->adjustStackPtr(SP, Amount, MBB, I); } - MBB.erase(I); + return MBB.erase(I); +} + +const ReturnProtectorLowering *MipsFrameLowering::getReturnProtector() const { + return &RPL; } diff --git a/gnu/llvm/lib/Target/Mips/MipsFrameLowering.h b/gnu/llvm/lib/Target/Mips/MipsFrameLowering.h index 5eabd58e868..b86f31bd452 100644 --- a/gnu/llvm/lib/Target/Mips/MipsFrameLowering.h +++ b/gnu/llvm/lib/Target/Mips/MipsFrameLowering.h @@ -15,7 +15,8 @@ #define LLVM_LIB_TARGET_MIPS_MIPSFRAMELOWERING_H #include "Mips.h" -#include "llvm/Target/TargetFrameLowering.h" +#include "MipsReturnProtectorLowering.h" +#include "llvm/CodeGen/TargetFrameLowering.h" namespace llvm { class MipsSubtarget; @@ -25,8 +26,11 @@ protected: const MipsSubtarget &STI; public: + + const MipsReturnProtectorLowering RPL; + explicit MipsFrameLowering(const MipsSubtarget &sti, unsigned Alignment) - : TargetFrameLowering(StackGrowsDown, Alignment, 0, Alignment), STI(sti) {} + : TargetFrameLowering(StackGrowsDown, Alignment, 0, Alignment), STI(sti), RPL() {} static const MipsFrameLowering *create(const MipsSubtarget &ST); @@ -36,7 +40,13 @@ public: bool isFPCloseToIncomingSP() const override { return false; } - void + bool enableShrinkWrapping(const MachineFunction &MF) const override { + return true; + } + + const ReturnProtectorLowering *getReturnProtector() const override; + + MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override; diff --git a/gnu/llvm/lib/Target/Mips/MipsInstrInfo.td b/gnu/llvm/lib/Target/Mips/MipsInstrInfo.td index 447f7c395c3..e71478503d1 100644 --- a/gnu/llvm/lib/Target/Mips/MipsInstrInfo.td +++ b/gnu/llvm/lib/Target/Mips/MipsInstrInfo.td @@ -2022,6 +2022,31 @@ def LONG_BRANCH_ADDiu : PseudoSE<(outs GPR32Opnd:$dst), def LONG_BRANCH_ADDiu2Op : PseudoSE<(outs GPR32Opnd:$dst), (ins GPR32Opnd:$src, brtarget:$tgt), []>; +// Pseudo instructions used by retguard. In order to calculste the PC +// for PIC code, we use a pair of pseudos to get the function address +// into T9, which is normally used to hold this value but is trashed +// by function epilogue. +let isCodeGenOnly = 1, hasNoSchedulingInfo = 1 in { + + // Use BAL to get the PC into RA, then calculate the address of the + // current function and save this value in $rd. $rs and $rt are used + // as scratch registers and are trashed by this pseudo. $tgt is the + // symbol to branch to when calling BAL. + let Size = 32 in { + def RETGUARD_GET_FUNCTION_ADDR: PseudoSE<(outs GPR64:$rd), + (ins GPR64:$rs, GPR64:$rt, brtarget:$tgt), []>; + } + + // Emit the symbol used for $tgt in RETGUARD_GET_FUNCTION_ADDR. We + // emit this symbol immediately before the usual function return, with + // the effect that the BAL branches to an immediate return and resumes + // execution through the rest of the RETGUARD epilogue. We pair BAL + // with RET to satisfy return branch predictors. + let Size = 0 in { + def RETGUARD_EMIT_SYMBOL: PseudoSE<(outs), (ins brtarget:$tgt), []>; + } +} + //===----------------------------------------------------------------------===// // Instruction definition //===----------------------------------------------------------------------===// diff --git a/gnu/llvm/lib/Target/Mips/MipsReturnProtectorLowering.cpp b/gnu/llvm/lib/Target/Mips/MipsReturnProtectorLowering.cpp new file mode 100644 index 00000000000..e9d72d3a90a --- /dev/null +++ b/gnu/llvm/lib/Target/Mips/MipsReturnProtectorLowering.cpp @@ -0,0 +1,272 @@ +//===-- MipsReturnProtectorLowering.cpp --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of ReturnProtectorLowering +// class. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsInstrInfo.h" +#include "MipsMachineFunction.h" +#include "MipsReturnProtectorLowering.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Debug.h" +#include "llvm/Target/TargetOptions.h" +#include + +using namespace llvm; + +void MipsReturnProtectorLowering::insertReturnProtectorPrologue( + MachineFunction &MF, MachineBasicBlock &MBB, GlobalVariable *cookie) const { + + MachineBasicBlock::instr_iterator MI = MBB.instr_begin(); + DebugLoc MBBDL = MBB.findDebugLoc(MI); + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + const TargetMachine &TM = MF.getTarget(); + unsigned REG = MF.getFrameInfo().getReturnProtectorRegister(); + + const GlobalValue *FName = &MF.getFunction(); + + // Select some scratch registers + unsigned TempReg1 = Mips::AT_64; + unsigned TempReg2 = Mips::V0_64; + if (!MBB.isLiveIn(TempReg1)) + MBB.addLiveIn(TempReg1); + if (!MBB.isLiveIn(TempReg2)) + MBB.addLiveIn(TempReg2); + + if (TM.isPositionIndependent()) { + + if (!MBB.isLiveIn(Mips::T9_64)) + MBB.addLiveIn(Mips::T9_64); + + // TempReg1 loads the GOT pointer + // TempReg2 load the offset from GOT to random cookie pointer + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2) + .addGlobalAddress(cookie, 0, MipsII::MO_GOT_HI16); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1) + .addReg(TempReg1) + .addReg(Mips::T9_64); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg2) + .addReg(TempReg2) + .addGlobalAddress(cookie, 0, MipsII::MO_GOT_LO16); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1) + .addReg(TempReg1) + .addReg(TempReg2); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), REG) + .addReg(TempReg1) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), REG) + .addReg(REG) + .addImm(0); + } else { + // TempReg1 loads the high 32 bits + // TempReg2 loads the low 32 bits + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1) + .addGlobalAddress(cookie, 0, MipsII::MO_HIGHEST); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2) + .addGlobalAddress(cookie, 0, MipsII::MO_ABS_HI); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg1) + .addReg(TempReg1) + .addGlobalAddress(cookie, 0, MipsII::MO_HIGHER); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DSLL), TempReg1) + .addReg(TempReg1) + .addImm(32); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1) + .addReg(TempReg1) + .addReg(TempReg2); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), REG) + .addReg(TempReg1) + .addGlobalAddress(cookie, 0, MipsII::MO_ABS_LO); + } + + BuildMI(MBB, MI, MBBDL, TII->get(Mips::XOR64), REG) + .addReg(REG) + .addReg(Mips::RA_64); +} + +void MipsReturnProtectorLowering::insertReturnProtectorEpilogue( + MachineFunction &MF, MachineInstr &MI, GlobalVariable *cookie) const { + + + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc MBBDL = MI.getDebugLoc(); + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + const TargetMachine &TM = MF.getTarget(); + unsigned REG = MF.getFrameInfo().getReturnProtectorRegister(); + + const GlobalValue *FName = &MF.getFunction(); + + // Select some scratch registers + unsigned TempReg1 = Mips::T7_64; + unsigned TempReg2 = Mips::T8_64; + if (REG == Mips::T7_64 || REG == Mips::T8_64) { + TempReg1 = Mips::T5_64; + TempReg2 = Mips::T6_64; + } + if (!MBB.isLiveIn(TempReg1)) + MBB.addLiveIn(TempReg1); + if (!MBB.isLiveIn(TempReg2)) + MBB.addLiveIn(TempReg2); + + // Undo the XOR to retrieve the random cookie + BuildMI(MBB, MI, MBBDL, TII->get(Mips::XOR64), REG) + .addReg(REG) + .addReg(Mips::RA_64); + + // Load the random cookie + if (TM.isPositionIndependent()) { + + if (!MBB.isLiveIn(Mips::T9_64)) + MBB.addLiveIn(Mips::T9_64); + + // T9 is trashed by this point, and we cannot trust saving + // the value from function entry on the stack, so calculate + // the address of the function entry using a pseudo + MCSymbol *BALTarget = MF.getContext().createTempSymbol(); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::RETGUARD_GET_FUNCTION_ADDR), Mips::T9_64) + .addReg(TempReg1) + .addReg(TempReg2) + .addSym(BALTarget); + + // TempReg1 loads the GOT pointer + // TempReg2 load the offset from GOT to random cookie pointer + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2) + .addGlobalAddress(cookie, 0, MipsII::MO_GOT_HI16); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1) + .addReg(TempReg1) + .addReg(Mips::T9_64); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg2) + .addReg(TempReg2) + .addGlobalAddress(cookie, 0, MipsII::MO_GOT_LO16); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1) + .addReg(TempReg1) + .addReg(TempReg2); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), TempReg1) + .addReg(TempReg1) + .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), TempReg1) + .addReg(TempReg1) + .addImm(0); + // Verify the random cookie + BuildMI(MBB, MI, MBBDL, TII->get(Mips::TNE)) + .addReg(TempReg1) + .addReg(REG) + .addImm(0); + // Emit the BAL target symbol from above + BuildMI(MBB, MI, MBBDL, TII->get(Mips::RETGUARD_EMIT_SYMBOL)) + .addSym(BALTarget); + } else { + // TempReg1 loads the high 32 bits + // TempReg2 loads the low 32 bits + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1) + .addGlobalAddress(cookie, 0, MipsII::MO_HIGHEST); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2) + .addGlobalAddress(cookie, 0, MipsII::MO_ABS_HI); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg1) + .addReg(TempReg1) + .addGlobalAddress(cookie, 0, MipsII::MO_HIGHER); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DSLL), TempReg1) + .addReg(TempReg1) + .addImm(32); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1) + .addReg(TempReg1) + .addReg(TempReg2); + BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), TempReg1) + .addReg(TempReg1) + .addGlobalAddress(cookie, 0, MipsII::MO_ABS_LO); + // Verify the random cookie + BuildMI(MBB, MI, MBBDL, TII->get(Mips::TNE)) + .addReg(TempReg1) + .addReg(REG) + .addImm(0); + } +} + +bool MipsReturnProtectorLowering::opcodeIsReturn(unsigned opcode) const { + switch (opcode) { + case Mips::RetRA: + return true; + default: + return false; + } +} + +void MipsReturnProtectorLowering::fillTempRegisters( + MachineFunction &MF, std::vector &TempRegs) const { + + const Function &F = MF.getFunction(); + + // long double arguments (f128) occupy two arg registers, so shift + // subsequent arguments down by one register + size_t shift_reg = 0; + for (const auto &arg : F.args()) { + if (arg.getType()->isFP128Ty()) + shift_reg += 1; + } + + if (!F.isVarArg()) { + // We can use any of the caller saved unused arg registers + switch (F.arg_size() + shift_reg) { + case 0: + // A0 is used to return f128 values in soft float + case 1: + TempRegs.push_back(Mips::A1_64); + LLVM_FALLTHROUGH; + case 2: + TempRegs.push_back(Mips::A2_64); + LLVM_FALLTHROUGH; + case 3: + TempRegs.push_back(Mips::A3_64); + LLVM_FALLTHROUGH; + case 4: + TempRegs.push_back(Mips::T0_64); + LLVM_FALLTHROUGH; + case 5: + TempRegs.push_back(Mips::T1_64); + LLVM_FALLTHROUGH; + case 6: + TempRegs.push_back(Mips::T2_64); + LLVM_FALLTHROUGH; + case 7: + TempRegs.push_back(Mips::T3_64); + LLVM_FALLTHROUGH; + case 8: + TempRegs.push_back(Mips::T4_64); + LLVM_FALLTHROUGH; + case 9: + TempRegs.push_back(Mips::T5_64); + LLVM_FALLTHROUGH; + case 10: + TempRegs.push_back(Mips::T6_64); + LLVM_FALLTHROUGH; + case 11: + TempRegs.push_back(Mips::T7_64); + LLVM_FALLTHROUGH; + case 12: + TempRegs.push_back(Mips::T8_64); + LLVM_FALLTHROUGH; + default: + break; + } + } + // For FastCC this is the only scratch reg that isn't V0 or T9 + TempRegs.push_back(Mips::AT_64); +} diff --git a/gnu/llvm/lib/Target/Mips/MipsReturnProtectorLowering.h b/gnu/llvm/lib/Target/Mips/MipsReturnProtectorLowering.h new file mode 100644 index 00000000000..677101cf950 --- /dev/null +++ b/gnu/llvm/lib/Target/Mips/MipsReturnProtectorLowering.h @@ -0,0 +1,46 @@ +//===-- MipsReturnProtectorLowering.h - --------------------- -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the Mips implementation of ReturnProtectorLowering +// class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_MIPS_MIPSRETURNPROTECTORLOWERING_H +#define LLVM_LIB_TARGET_MIPS_MIPSRETURNPROTECTORLOWERING_H + +#include "llvm/CodeGen/ReturnProtectorLowering.h" + +namespace llvm { + +class MipsReturnProtectorLowering : public ReturnProtectorLowering { +public: + /// insertReturnProtectorPrologue/Epilogue - insert return protector + /// instrumentation in prologue or epilogue. + virtual void + insertReturnProtectorPrologue(MachineFunction &MF, MachineBasicBlock &MBB, + GlobalVariable *cookie) const override; + virtual void + insertReturnProtectorEpilogue(MachineFunction &MF, MachineInstr &MI, + GlobalVariable *cookie) const override; + + /// opcodeIsReturn - Reuturn true is the given opcode is a return + /// instruction needing return protection, false otherwise. + virtual bool opcodeIsReturn(unsigned opcode) const override; + + /// fillTempRegisters - Fill the list of available temp registers we can + /// use as a return protector register. + virtual void + fillTempRegisters(MachineFunction &MF, + std::vector &TempRegs) const override; +}; + +} // namespace llvm + +#endif diff --git a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp index 78bf9acf5c9..760820d2ce0 100644 --- a/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp +++ b/gnu/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp @@ -4561,6 +4561,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } if (RetProtector && ((getToolChain().getArch() == llvm::Triple::x86_64) || + (getToolChain().getArch() == llvm::Triple::mips64) || + (getToolChain().getArch() == llvm::Triple::mips64el) || (getToolChain().getArch() == llvm::Triple::aarch64)) && !Args.hasArg(options::OPT_fno_stack_protector) && !Args.hasArg(options::OPT_pg)) { -- cgit v1.2.3