| Index: llvm/lib/Target/Mips/MipsNaClRewritePass.cpp
|
| ===================================================================
|
| new file mode 100755
|
| --- /dev/null
|
| +++ b/llvm/lib/Target/Mips/MipsNaClRewritePass.cpp
|
| @@ -0,0 +1,333 @@
|
| +//===-- MipsNaClRewritePass.cpp - Native Client Rewrite Pass ------*- C++ -*-=//
|
| +//
|
| +// The LLVM Compiler Infrastructure
|
| +//
|
| +// This file is distributed under the University of Illinois Open Source
|
| +// License. See LICENSE.TXT for details.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +//
|
| +// Native Client Rewrite Pass
|
| +// This final pass inserts the sandboxing instructions needed to run inside
|
| +// the Native Client sandbox. Native Client requires certain software fault
|
| +// isolation (SFI) constructions to be put in place, to prevent escape from
|
| +// the sandbox. Native Client refuses to execute binaries without the correct
|
| +// SFI sequences.
|
| +//
|
| +// Potentially dangerous operations which are protected include:
|
| +// * Stores
|
| +// * Branches
|
| +// * Changes to SP
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +#define DEBUG_TYPE "mips-sfi"
|
| +#include "Mips.h"
|
| +#include "MipsInstrInfo.h"
|
| +#include "MipsNaClRewritePass.h"
|
| +#include "llvm/CodeGen/MachineFunctionPass.h"
|
| +#include "llvm/CodeGen/MachineInstrBuilder.h"
|
| +#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
| +#include "llvm/Function.h"
|
| +#include "llvm/Support/Debug.h"
|
| +#include "llvm/Support/raw_ostream.h"
|
| +#include "llvm/Support/CommandLine.h"
|
| +
|
| +using namespace llvm;
|
| +
|
| +unsigned Mips::LoadStoreStackMaskReg = Mips::T4;
|
| +unsigned Mips::IndirectBranchMaskReg = Mips::T3;
|
| +
|
| +namespace {
|
| + class MipsNaClRewritePass : public MachineFunctionPass {
|
| + public:
|
| + static char ID;
|
| + MipsNaClRewritePass() : MachineFunctionPass(ID) {}
|
| +
|
| + const MipsInstrInfo *TII;
|
| + const TargetRegisterInfo *TRI;
|
| + virtual bool runOnMachineFunction(MachineFunction &Fn);
|
| +
|
| + virtual const char *getPassName() const {
|
| + return "Mips Native Client Rewrite Pass";
|
| + }
|
| +
|
| + private:
|
| +
|
| + bool SandboxLoadsInBlock(MachineBasicBlock &MBB);
|
| + bool SandboxStoresInBlock(MachineBasicBlock &MBB);
|
| + void SandboxLoadStore(MachineBasicBlock &MBB,
|
| + MachineBasicBlock::iterator MBBI,
|
| + MachineInstr &MI,
|
| + int AddrIdx);
|
| +
|
| + bool SandboxBranchesInBlock(MachineBasicBlock &MBB);
|
| + bool SandboxStackChangesInBlock(MachineBasicBlock &MBB);
|
| +
|
| + void SandboxStackChange(MachineBasicBlock &MBB,
|
| + MachineBasicBlock::iterator MBBI);
|
| + void AlignAllJumpTargets(MachineFunction &MF);
|
| + };
|
| + char MipsNaClRewritePass::ID = 0;
|
| +}
|
| +
|
| +static bool IsReturn(const MachineInstr &MI) {
|
| + return (MI.getOpcode() == Mips::RET);
|
| +}
|
| +
|
| +static bool IsIndirectJump(const MachineInstr &MI) {
|
| + return (MI.getOpcode() == Mips::JR);
|
| +}
|
| +
|
| +static bool IsIndirectCall(const MachineInstr &MI) {
|
| + return (MI.getOpcode() == Mips::JALR);
|
| +}
|
| +
|
| +static bool IsDirectCall(const MachineInstr &MI) {
|
| + return (MI.getOpcode() == Mips::JAL);
|
| +}
|
| +
|
| +static bool IsStackMask(const MachineInstr &MI) {
|
| + return (MI.getOpcode() == Mips::SFI_DATA_MASK);
|
| +}
|
| +
|
| +static bool IsStackChange(const MachineInstr &MI,
|
| + const TargetRegisterInfo *TRI) {
|
| + return MI.modifiesRegister(Mips::SP, TRI);
|
| +}
|
| +
|
| +static bool NeedSandboxStackChange(const MachineInstr &MI,
|
| + const TargetRegisterInfo *TRI) {
|
| + return (IsStackChange(MI, TRI) && !IsStackMask(MI));
|
| +}
|
| +
|
| +void MipsNaClRewritePass::SandboxStackChange(MachineBasicBlock &MBB,
|
| + MachineBasicBlock::iterator MBBI) {
|
| + MachineInstr &MI = *MBBI;
|
| +
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(Mips::SFI_NOP_IF_AT_BUNDLE_END));
|
| +
|
| + // Get to next instr (one + to get the original, and one more + to get past).
|
| + MachineBasicBlock::iterator MBBINext = (MBBI++);
|
| + MachineBasicBlock::iterator MBBINext2 = (MBBI++);
|
| +
|
| + BuildMI(MBB, MBBINext2, MI.getDebugLoc(),
|
| + TII->get(Mips::SFI_DATA_MASK), Mips::SP)
|
| + .addReg(Mips::SP)
|
| + .addReg(Mips::LoadStoreStackMaskReg);
|
| + return;
|
| +}
|
| +
|
| +bool MipsNaClRewritePass::SandboxStackChangesInBlock(MachineBasicBlock &MBB) {
|
| + bool Modified = false;
|
| + for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
|
| + MBBI != E; ++MBBI) {
|
| + MachineInstr &MI = *MBBI;
|
| + if (NeedSandboxStackChange(MI, TRI)) {
|
| + SandboxStackChange(MBB, MBBI);
|
| + Modified |= true;
|
| + }
|
| + }
|
| + return Modified;
|
| +}
|
| +
|
| +bool MipsNaClRewritePass::SandboxBranchesInBlock(MachineBasicBlock &MBB) {
|
| + bool Modified = false;
|
| +
|
| + for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
|
| + MBBI != E; ++MBBI) {
|
| + MachineInstr &MI = *MBBI;
|
| +
|
| + if (IsReturn(MI)) {
|
| + unsigned AddrReg = MI.getOperand(0).getReg();
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(Mips::SFI_GUARD_RETURN), AddrReg)
|
| + .addReg(AddrReg)
|
| + .addReg(Mips::IndirectBranchMaskReg);
|
| + Modified = true;
|
| + }
|
| +
|
| + if (IsIndirectJump(MI)) {
|
| + unsigned AddrReg = MI.getOperand(0).getReg();
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(Mips::SFI_GUARD_INDIRECT_JMP), AddrReg)
|
| + .addReg(AddrReg)
|
| + .addReg(Mips::IndirectBranchMaskReg);
|
| + Modified = true;
|
| + }
|
| +
|
| + if (IsDirectCall(MI)) {
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(Mips::SFI_GUARD_CALL));
|
| + Modified = true;
|
| + }
|
| +
|
| + if (IsIndirectCall(MI)) {
|
| + unsigned AddrReg = MI.getOperand(0).getReg();
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(Mips::SFI_GUARD_INDIRECT_CALL), AddrReg)
|
| + .addReg(AddrReg)
|
| + .addReg(Mips::IndirectBranchMaskReg);
|
| + Modified = true;
|
| + }
|
| + }
|
| +
|
| + return Modified;
|
| +}
|
| +
|
| +/*
|
| + * Sandboxes a load or store instruction by inserting an appropriate mask
|
| + * operation before it.
|
| + */
|
| +void MipsNaClRewritePass::SandboxLoadStore(MachineBasicBlock &MBB,
|
| + MachineBasicBlock::iterator MBBI,
|
| + MachineInstr &MI,
|
| + int AddrIdx) {
|
| + unsigned BaseReg = MI.getOperand(AddrIdx).getReg();
|
| +
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(Mips::SFI_GUARD_LOAD_STORE), BaseReg)
|
| + .addReg(BaseReg)
|
| + .addReg(Mips::LoadStoreStackMaskReg);
|
| + return;
|
| +}
|
| +
|
| +static bool IsDangerousLoad(const MachineInstr &MI, int *AddrIdx) {
|
| + unsigned Opcode = MI.getOpcode();
|
| + switch (Opcode) {
|
| + default: return false;
|
| +
|
| + // Instructions with base address register in position 1
|
| + case Mips::LB:
|
| + case Mips::LBu:
|
| + case Mips::LH:
|
| + case Mips::LHu:
|
| + case Mips::LW:
|
| + case Mips::LWC1:
|
| + case Mips::LDC1:
|
| + case Mips::LL:
|
| + *AddrIdx = 1;
|
| + break;
|
| + }
|
| +
|
| + if (MI.getOperand(*AddrIdx).getReg() == Mips::SP) {
|
| + // The contents of SP do not require masking.
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +static bool IsDangerousStore(const MachineInstr &MI, int *AddrIdx) {
|
| + unsigned Opcode = MI.getOpcode();
|
| + switch (Opcode) {
|
| + default: return false;
|
| +
|
| + // Instructions with base address register in position 1
|
| + case Mips::SB:
|
| + case Mips::SH:
|
| + case Mips::SW:
|
| + case Mips::SWC1:
|
| + case Mips::SDC1:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + case Mips::SC:
|
| + *AddrIdx = 2;
|
| + break;
|
| + }
|
| +
|
| + if (MI.getOperand(*AddrIdx).getReg() == Mips::SP) {
|
| + // The contents of SP do not require masking.
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool MipsNaClRewritePass::SandboxLoadsInBlock(MachineBasicBlock &MBB) {
|
| + bool Modified = false;
|
| + for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
|
| + MBBI != E;
|
| + ++MBBI) {
|
| + MachineInstr &MI = *MBBI;
|
| + int AddrIdx;
|
| +
|
| + if (IsDangerousLoad(MI, &AddrIdx)) {
|
| + SandboxLoadStore(MBB, MBBI, MI, AddrIdx);
|
| + Modified = true;
|
| + }
|
| + }
|
| + return Modified;
|
| +}
|
| +
|
| +bool MipsNaClRewritePass::SandboxStoresInBlock(MachineBasicBlock &MBB) {
|
| + bool Modified = false;
|
| + for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
|
| + MBBI != E;
|
| + ++MBBI) {
|
| + MachineInstr &MI = *MBBI;
|
| + int AddrIdx;
|
| +
|
| + if (IsDangerousStore(MI, &AddrIdx)) {
|
| + SandboxLoadStore(MBB, MBBI, MI, AddrIdx);
|
| + Modified = true;
|
| + }
|
| + }
|
| + return Modified;
|
| +}
|
| +
|
| +// Make sure all jump targets are aligned
|
| +void MipsNaClRewritePass::AlignAllJumpTargets(MachineFunction &MF) {
|
| + // JUMP TABLE TARGETS
|
| + MachineJumpTableInfo *jt_info = MF.getJumpTableInfo();
|
| + if (jt_info) {
|
| + const std::vector<MachineJumpTableEntry> &JT = jt_info->getJumpTables();
|
| + for (unsigned i=0; i < JT.size(); ++i) {
|
| + std::vector<MachineBasicBlock*> MBBs = JT[i].MBBs;
|
| +
|
| + for (unsigned j=0; j < MBBs.size(); ++j) {
|
| + MBBs[j]->setAlignment(16);
|
| + }
|
| + }
|
| + }
|
| +
|
| + for (MachineFunction::iterator I = MF.begin(), E = MF.end();
|
| + I != E; ++I) {
|
| + MachineBasicBlock &MBB = *I;
|
| + if (MBB.hasAddressTaken())
|
| + MBB.setAlignment(16);
|
| + }
|
| +}
|
| +
|
| +bool MipsNaClRewritePass::runOnMachineFunction(MachineFunction &MF) {
|
| + TII = static_cast<const MipsInstrInfo*>(MF.getTarget().getInstrInfo());
|
| + TRI = MF.getTarget().getRegisterInfo();
|
| +
|
| + bool Modified = false;
|
| + for (MachineFunction::iterator MFI = MF.begin(), E = MF.end();
|
| + MFI != E;
|
| + ++MFI) {
|
| + MachineBasicBlock &MBB = *MFI;
|
| +
|
| + if (FlagSfiLoad)
|
| + Modified |= SandboxLoadsInBlock(MBB);
|
| + if (FlagSfiStore)
|
| + Modified |= SandboxStoresInBlock(MBB);
|
| + if (FlagSfiBranch)
|
| + Modified |= SandboxBranchesInBlock(MBB);
|
| + if (FlagSfiStack)
|
| + Modified |= SandboxStackChangesInBlock(MBB);
|
| + }
|
| +
|
| + if (FlagSfiBranch)
|
| + AlignAllJumpTargets(MF);
|
| +
|
| + return Modified;
|
| +}
|
| +
|
| +/// createMipsNaClRewritePass - returns an instance of the NaClRewritePass.
|
| +FunctionPass *llvm::createMipsNaClRewritePass() {
|
| + return new MipsNaClRewritePass();
|
| +}
|
|
|