| Index: lib/Target/ARM/ARMNaClRewritePass.cpp
|
| diff --git a/lib/Target/ARM/ARMNaClRewritePass.cpp b/lib/Target/ARM/ARMNaClRewritePass.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dbf29e606cc516b1d65c2321ccc0b7c6a2811933
|
| --- /dev/null
|
| +++ b/lib/Target/ARM/ARMNaClRewritePass.cpp
|
| @@ -0,0 +1,1085 @@
|
| +//===-- ARMNaClRewritePass.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 "arm-sfi"
|
| +#include "ARM.h"
|
| +#include "ARMBaseInstrInfo.h"
|
| +#include "ARMNaClRewritePass.h"
|
| +#include "llvm/CodeGen/MachineFunctionPass.h"
|
| +#include "llvm/CodeGen/MachineInstrBuilder.h"
|
| +#include "llvm/IR/Function.h"
|
| +#include "llvm/Support/Debug.h"
|
| +#include "llvm/Support/raw_ostream.h"
|
| +#include "llvm/Target/TargetSubtargetInfo.h"
|
| +#include <set>
|
| +#include <stdio.h>
|
| +
|
| +using namespace llvm;
|
| +
|
| +namespace {
|
| + class ARMNaClRewritePass : public MachineFunctionPass {
|
| + public:
|
| + static char ID;
|
| + ARMNaClRewritePass() : MachineFunctionPass(ID) {}
|
| +
|
| + const ARMBaseInstrInfo *TII;
|
| + const TargetRegisterInfo *TRI;
|
| + virtual void getAnalysisUsage(AnalysisUsage &AU) const;
|
| + virtual bool runOnMachineFunction(MachineFunction &Fn);
|
| +
|
| + virtual const char *getPassName() const {
|
| + return "ARM Native Client Rewrite Pass";
|
| + }
|
| +
|
| + private:
|
| +
|
| + bool SandboxMemoryReferencesInBlock(MachineBasicBlock &MBB);
|
| + void SandboxMemory(MachineBasicBlock &MBB,
|
| + MachineBasicBlock::iterator MBBI,
|
| + MachineInstr &MI,
|
| + int AddrIdx,
|
| + bool IsLoad);
|
| +
|
| + bool SandboxBranchesInBlock(MachineBasicBlock &MBB);
|
| + bool SandboxStackChangesInBlock(MachineBasicBlock &MBB);
|
| +
|
| + void SandboxStackChange(MachineBasicBlock &MBB,
|
| + MachineBasicBlock::iterator MBBI);
|
| + void LightweightVerify(MachineFunction &MF);
|
| + };
|
| + char ARMNaClRewritePass::ID = 0;
|
| +}
|
| +
|
| +static bool IsReturn(const MachineInstr &MI) {
|
| + return (MI.getOpcode() == ARM::BX_RET);
|
| +}
|
| +
|
| +static bool IsIndirectJump(const MachineInstr &MI) {
|
| + switch (MI.getOpcode()) {
|
| + default: return false;
|
| + case ARM::BX:
|
| + case ARM::TAILJMPr:
|
| + return true;
|
| + }
|
| +}
|
| +
|
| +static bool IsIndirectCall(const MachineInstr &MI) {
|
| + return MI.getOpcode() == ARM::BLX;
|
| +}
|
| +
|
| +static bool IsDirectCall(const MachineInstr &MI) {
|
| + switch (MI.getOpcode()) {
|
| + default: return false;
|
| + case ARM::BL:
|
| + case ARM::BL_pred:
|
| + case ARM::TPsoft:
|
| + return true;
|
| + }
|
| +}
|
| +
|
| +static void DumpInstructionVerbose(const MachineInstr &MI) {
|
| + DEBUG({
|
| + dbgs() << MI;
|
| + dbgs() << MI.getNumOperands() << " operands:" << "\n";
|
| + for (unsigned i = 0; i < MI.getNumOperands(); ++i) {
|
| + const MachineOperand& op = MI.getOperand(i);
|
| + dbgs() << " " << i << "(" << (unsigned)op.getType() << "):" << op
|
| + << "\n";
|
| + }
|
| + dbgs() << "\n";
|
| + });
|
| +}
|
| +
|
| +static void DumpBasicBlockVerbose(const MachineBasicBlock &MBB) {
|
| + DEBUG({
|
| + dbgs() << "\n<<<<< DUMP BASIC BLOCK START\n";
|
| + for (MachineBasicBlock::const_iterator
|
| + MBBI = MBB.begin(), MBBE = MBB.end();
|
| + MBBI != MBBE;
|
| + ++MBBI) {
|
| + DumpInstructionVerbose(*MBBI);
|
| + }
|
| + dbgs() << "<<<<< DUMP BASIC BLOCK END\n\n";
|
| + });
|
| +}
|
| +
|
| +/**********************************************************************/
|
| +/* Exported functions */
|
| +
|
| +namespace ARM_SFI {
|
| +
|
| +bool IsStackChange(const MachineInstr &MI, const TargetRegisterInfo *TRI) {
|
| + return MI.modifiesRegister(ARM::SP, TRI);
|
| +}
|
| +
|
| +bool NextInstrMasksSP(const MachineInstr &MI) {
|
| + MachineBasicBlock::const_iterator It = &MI;
|
| + const MachineBasicBlock *MBB = MI.getParent();
|
| +
|
| + MachineBasicBlock::const_iterator next = ++It;
|
| + if (next == MBB->end()) {
|
| + return false;
|
| + }
|
| +
|
| + const MachineInstr &next_instr = *next;
|
| + unsigned opcode = next_instr.getOpcode();
|
| + return (opcode == ARM::SFI_DATA_MASK) &&
|
| + (next_instr.getOperand(0).getReg() == ARM::SP);
|
| +}
|
| +
|
| +bool IsSandboxedStackChange(const MachineInstr &MI) {
|
| + // Calls do not change the stack on ARM but they have implicit-defs, so
|
| + // make sure they do not get sandboxed.
|
| + if (MI.getDesc().isCall())
|
| + return true;
|
| +
|
| + unsigned opcode = MI.getOpcode();
|
| + switch (opcode) {
|
| + default: break;
|
| +
|
| + // Our mask instructions correctly update the stack pointer.
|
| + case ARM::SFI_DATA_MASK:
|
| + return true;
|
| +
|
| + // These just bump SP by a little (and access the stack),
|
| + // so that is okay due to guard pages.
|
| + case ARM::STMIA_UPD:
|
| + case ARM::STMDA_UPD:
|
| + case ARM::STMDB_UPD:
|
| + case ARM::STMIB_UPD:
|
| +
|
| + case ARM::VSTMDIA_UPD:
|
| + case ARM::VSTMDDB_UPD:
|
| + case ARM::VSTMSIA_UPD:
|
| + case ARM::VSTMSDB_UPD:
|
| + return true;
|
| +
|
| + // Similar, unless it is a load into SP...
|
| + case ARM::LDMIA_UPD:
|
| + case ARM::LDMDA_UPD:
|
| + case ARM::LDMDB_UPD:
|
| + case ARM::LDMIB_UPD:
|
| +
|
| + case ARM::VLDMDIA_UPD:
|
| + case ARM::VLDMDDB_UPD:
|
| + case ARM::VLDMSIA_UPD:
|
| + case ARM::VLDMSDB_UPD: {
|
| + bool dest_SP = false;
|
| + // Dest regs start at operand index 4.
|
| + for (unsigned i = 4; i < MI.getNumOperands(); ++i) {
|
| + const MachineOperand &DestReg = MI.getOperand(i);
|
| + dest_SP = dest_SP || (DestReg.getReg() == ARM::SP);
|
| + }
|
| + if (dest_SP) {
|
| + break;
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + // Some localmods *should* prevent selecting a reg offset
|
| + // (see SelectAddrMode2 in ARMISelDAGToDAG.cpp).
|
| + // Otherwise, the store is already a potential violation.
|
| + case ARM::STR_PRE_REG:
|
| + case ARM::STR_PRE_IMM:
|
| +
|
| + case ARM::STRH_PRE:
|
| +
|
| + case ARM::STRB_PRE_REG:
|
| + case ARM::STRB_PRE_IMM:
|
| + return true;
|
| +
|
| + // Similar, unless it is a load into SP...
|
| + case ARM::LDRi12:
|
| + case ARM::LDR_PRE_REG:
|
| + case ARM::LDR_PRE_IMM:
|
| + case ARM::LDRH_PRE:
|
| + case ARM::LDRB_PRE_REG:
|
| + case ARM::LDRB_PRE_IMM:
|
| + case ARM::LDRSH_PRE:
|
| + case ARM::LDRSB_PRE: {
|
| + const MachineOperand &DestReg = MI.getOperand(0);
|
| + if (DestReg.getReg() == ARM::SP) {
|
| + break;
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + // Here, if SP is the base / write-back reg, we need to check if
|
| + // a reg is used as offset (otherwise it is not a small nudge).
|
| + case ARM::STR_POST_REG:
|
| + case ARM::STR_POST_IMM:
|
| + case ARM::STRH_POST:
|
| + case ARM::STRB_POST_REG:
|
| + case ARM::STRB_POST_IMM: {
|
| + const MachineOperand &WBReg = MI.getOperand(0);
|
| + const MachineOperand &OffReg = MI.getOperand(3);
|
| + if (WBReg.getReg() == ARM::SP && OffReg.getReg() != 0) {
|
| + break;
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + // Similar, but also check that DestReg is not SP.
|
| + case ARM::LDR_POST_REG:
|
| + case ARM::LDR_POST_IMM:
|
| + case ARM::LDRB_POST_REG:
|
| + case ARM::LDRB_POST_IMM:
|
| + case ARM::LDRH_POST:
|
| + case ARM::LDRSH_POST:
|
| + case ARM::LDRSB_POST: {
|
| + const MachineOperand &DestReg = MI.getOperand(0);
|
| + if (DestReg.getReg() == ARM::SP) {
|
| + break;
|
| + }
|
| + const MachineOperand &WBReg = MI.getOperand(1);
|
| + const MachineOperand &OffReg = MI.getOperand(3);
|
| + if (WBReg.getReg() == ARM::SP && OffReg.getReg() != 0) {
|
| + break;
|
| + }
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + return (NextInstrMasksSP(MI));
|
| +}
|
| +
|
| +bool NeedSandboxStackChange(const MachineInstr &MI,
|
| + const TargetRegisterInfo *TRI) {
|
| + return (IsStackChange(MI, TRI) && !IsSandboxedStackChange(MI));
|
| +}
|
| +
|
| +} // namespace ARM_SFI
|
| +
|
| +/**********************************************************************/
|
| +
|
| +void ARMNaClRewritePass::getAnalysisUsage(AnalysisUsage &AU) const {
|
| + // Slight (possibly unnecessary) efficiency tweak:
|
| + // Promise not to modify the CFG.
|
| + AU.setPreservesCFG();
|
| + MachineFunctionPass::getAnalysisUsage(AU);
|
| +}
|
| +
|
| +/*
|
| + * A primitive validator to catch problems at compile time.
|
| + * E.g., it could be used along with bugpoint to reduce a bitcode file.
|
| + */
|
| +void ARMNaClRewritePass::LightweightVerify(MachineFunction &MF) {
|
| + DEBUG({
|
| + for (MachineFunction::iterator MFI = MF.begin(), MFE = MF.end();
|
| + MFI != MFE;
|
| + ++MFI) {
|
| + MachineBasicBlock &MBB = *MFI;
|
| + for (MachineBasicBlock::iterator MBBI = MBB.begin(), MBBE = MBB.end();
|
| + MBBI != MBBE;
|
| + ++MBBI) {
|
| + MachineInstr &MI = *MBBI;
|
| + if (ARM_SFI::NeedSandboxStackChange(MI, TRI)) {
|
| + dbgs() << "LightWeightVerify for function: "
|
| + << MF.getFunction()->getName() << " (BAD STACK CHANGE)\n";
|
| + DumpInstructionVerbose(MI);
|
| + DumpBasicBlockVerbose(MBB);
|
| + }
|
| + }
|
| + }
|
| + });
|
| +}
|
| +
|
| +void ARMNaClRewritePass::SandboxStackChange(MachineBasicBlock &MBB,
|
| + MachineBasicBlock::iterator MBBI) {
|
| + // (1) Ensure there is room in the bundle for a data mask instruction
|
| + // (nop'ing to the next bundle if needed).
|
| + // (2) Do a data mask on SP after the instruction that updated SP.
|
| + MachineInstr &MI = *MBBI;
|
| +
|
| + // Use same predicate as current instruction.
|
| + unsigned PredReg = 0;
|
| + ARMCC::CondCodes Pred = llvm::getInstrPredicate(&MI, PredReg);
|
| +
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(ARM::SFI_NOP_IF_AT_BUNDLE_END));
|
| +
|
| + // Get to next instr.
|
| + MachineBasicBlock::iterator MBBINext = (++MBBI);
|
| +
|
| + BuildMI(MBB, MBBINext, MI.getDebugLoc(),
|
| + TII->get(ARM::SFI_DATA_MASK))
|
| + .addReg(ARM::SP, RegState::Define) // modify SP (as dst)
|
| + .addReg(ARM::SP, RegState::Kill) // start with SP (as src)
|
| + .addImm((int64_t) Pred) // predicate condition
|
| + .addReg(PredReg); // predicate source register (CPSR)
|
| +}
|
| +
|
| +bool ARMNaClRewritePass::SandboxStackChangesInBlock(MachineBasicBlock &MBB) {
|
| + bool Modified = false;
|
| + for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
|
| + MBBI != E;
|
| + ++MBBI) {
|
| + MachineInstr &MI = *MBBI;
|
| + if (ARM_SFI::NeedSandboxStackChange(MI, TRI)) {
|
| + SandboxStackChange(MBB, MBBI);
|
| + Modified |= true;
|
| + }
|
| + }
|
| + return Modified;
|
| +}
|
| +
|
| +bool ARMNaClRewritePass::SandboxBranchesInBlock(MachineBasicBlock &MBB) {
|
| + bool Modified = false;
|
| +
|
| + for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
|
| + MBBI != E;
|
| + ++MBBI) {
|
| + MachineInstr &MI = *MBBI;
|
| + // Use same predicate as current instruction.
|
| + unsigned PredReg = 0;
|
| + ARMCC::CondCodes Pred = llvm::getInstrPredicate(&MI, PredReg);
|
| +
|
| + if (IsReturn(MI)) {
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(ARM::SFI_GUARD_RETURN))
|
| + .addImm((int64_t) Pred) // predicate condition
|
| + .addReg(PredReg); // predicate source register (CPSR)
|
| + Modified = true;
|
| + }
|
| +
|
| + if (IsIndirectJump(MI)) {
|
| + unsigned Addr = MI.getOperand(0).getReg();
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(ARM::SFI_GUARD_INDIRECT_JMP))
|
| + .addReg(Addr, RegState::Define) // Destination definition (as dst)
|
| + .addReg(Addr, RegState::Kill) // Destination read (as src)
|
| + .addImm((int64_t) Pred) // predicate condition
|
| + .addReg(PredReg); // predicate source register (CPSR)
|
| + Modified = true;
|
| + }
|
| +
|
| + if (IsDirectCall(MI)) {
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(ARM::SFI_GUARD_CALL))
|
| + .addImm((int64_t) Pred) // predicate condition
|
| + .addReg(PredReg); // predicate source register (CPSR)
|
| + Modified = true;
|
| + }
|
| +
|
| + if (IsIndirectCall(MI)) {
|
| + unsigned Addr = MI.getOperand(0).getReg();
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + TII->get(ARM::SFI_GUARD_INDIRECT_CALL))
|
| + .addReg(Addr, RegState::Define) // Destination definition (as dst)
|
| + .addReg(Addr, RegState::Kill) // Destination read (as src)
|
| + .addImm((int64_t) Pred) // predicate condition
|
| + .addReg(PredReg); // predicate source register (CPSR)
|
| + Modified = true;
|
| + }
|
| + }
|
| +
|
| + return Modified;
|
| +}
|
| +
|
| +static bool IsDangerousLoad(const MachineInstr &MI, int *AddrIdx) {
|
| + unsigned Opcode = MI.getOpcode();
|
| + switch (Opcode) {
|
| + default: return false;
|
| +
|
| + // Instructions with base address register in position 0...
|
| + case ARM::LDMIA:
|
| + case ARM::LDMDA:
|
| + case ARM::LDMDB:
|
| + case ARM::LDMIB:
|
| +
|
| + case ARM::VLDMDIA:
|
| + case ARM::VLDMSIA:
|
| +
|
| + case ARM::PLDi12:
|
| + case ARM::PLDWi12:
|
| + case ARM::PLIi12:
|
| + *AddrIdx = 0;
|
| + break;
|
| + // Instructions with base address register in position 1...
|
| + case ARM::LDMIA_UPD: // same reg at position 0 and position 1
|
| + case ARM::LDMDA_UPD:
|
| + case ARM::LDMDB_UPD:
|
| + case ARM::LDMIB_UPD:
|
| +
|
| + case ARM::LDRSB:
|
| + case ARM::LDRH:
|
| + case ARM::LDRSH:
|
| +
|
| + case ARM::LDRi12:
|
| + case ARM::LDRrs:
|
| + case ARM::LDRBi12:
|
| + case ARM::LDRBrs:
|
| + case ARM::VLDMDIA_UPD:
|
| + case ARM::VLDMDDB_UPD:
|
| + case ARM::VLDMSIA_UPD:
|
| + case ARM::VLDMSDB_UPD:
|
| + case ARM::VLDRS:
|
| + case ARM::VLDRD:
|
| +
|
| + case ARM::LDREX:
|
| + case ARM::LDREXB:
|
| + case ARM::LDREXH:
|
| + case ARM::LDREXD:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + // Instructions with base address register in position 2...
|
| + case ARM::LDR_PRE_REG:
|
| + case ARM::LDR_PRE_IMM:
|
| + case ARM::LDR_POST_REG:
|
| + case ARM::LDR_POST_IMM:
|
| +
|
| + case ARM::LDRB_PRE_REG:
|
| + case ARM::LDRB_PRE_IMM:
|
| + case ARM::LDRB_POST_REG:
|
| + case ARM::LDRB_POST_IMM:
|
| + case ARM::LDRSB_PRE:
|
| + case ARM::LDRSB_POST:
|
| +
|
| + case ARM::LDRH_PRE:
|
| + case ARM::LDRH_POST:
|
| + case ARM::LDRSH_PRE:
|
| + case ARM::LDRSH_POST:
|
| +
|
| + case ARM::LDRD:
|
| + *AddrIdx = 2;
|
| + break;
|
| +
|
| + //
|
| + // NEON loads
|
| + //
|
| +
|
| + // VLD1
|
| + case ARM::VLD1d8:
|
| + case ARM::VLD1d16:
|
| + case ARM::VLD1d32:
|
| + case ARM::VLD1d64:
|
| + case ARM::VLD1q8:
|
| + case ARM::VLD1q16:
|
| + case ARM::VLD1q32:
|
| + case ARM::VLD1q64:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + case ARM::VLD1d8wb_fixed:
|
| + case ARM::VLD1d16wb_fixed:
|
| + case ARM::VLD1d32wb_fixed:
|
| + case ARM::VLD1d64wb_fixed:
|
| + case ARM::VLD1q8wb_fixed:
|
| + case ARM::VLD1q16wb_fixed:
|
| + case ARM::VLD1q32wb_fixed:
|
| + case ARM::VLD1q64wb_fixed:
|
| + case ARM::VLD1d8wb_register:
|
| + case ARM::VLD1d16wb_register:
|
| + case ARM::VLD1d32wb_register:
|
| + case ARM::VLD1d64wb_register:
|
| + case ARM::VLD1q8wb_register:
|
| + case ARM::VLD1q16wb_register:
|
| + case ARM::VLD1q32wb_register:
|
| + case ARM::VLD1q64wb_register:
|
| + *AddrIdx = 2;
|
| + break;
|
| +
|
| + // VLD1T
|
| + case ARM::VLD1d8T:
|
| + case ARM::VLD1d16T:
|
| + case ARM::VLD1d32T:
|
| + case ARM::VLD1d64T:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + case ARM::VLD1d8Twb_fixed:
|
| + case ARM::VLD1d16Twb_fixed:
|
| + case ARM::VLD1d32Twb_fixed:
|
| + case ARM::VLD1d64Twb_fixed:
|
| + case ARM::VLD1d8Twb_register:
|
| + case ARM::VLD1d16Twb_register:
|
| + case ARM::VLD1d32Twb_register:
|
| + case ARM::VLD1d64Twb_register:
|
| + *AddrIdx = 2;
|
| + break;
|
| +
|
| + // VLD1Q
|
| + case ARM::VLD1d8Q:
|
| + case ARM::VLD1d16Q:
|
| + case ARM::VLD1d32Q:
|
| + case ARM::VLD1d64Q:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + case ARM::VLD1d8Qwb_fixed:
|
| + case ARM::VLD1d16Qwb_fixed:
|
| + case ARM::VLD1d32Qwb_fixed:
|
| + case ARM::VLD1d64Qwb_fixed:
|
| + case ARM::VLD1d8Qwb_register:
|
| + case ARM::VLD1d16Qwb_register:
|
| + case ARM::VLD1d32Qwb_register:
|
| + case ARM::VLD1d64Qwb_register:
|
| + *AddrIdx = 2;
|
| + break;
|
| +
|
| + // VLD1LN
|
| + case ARM::VLD1LNd8:
|
| + case ARM::VLD1LNd16:
|
| + case ARM::VLD1LNd32:
|
| + case ARM::VLD1LNd8_UPD:
|
| + case ARM::VLD1LNd16_UPD:
|
| + case ARM::VLD1LNd32_UPD:
|
| +
|
| + // VLD1DUP
|
| + case ARM::VLD1DUPd8:
|
| + case ARM::VLD1DUPd16:
|
| + case ARM::VLD1DUPd32:
|
| + case ARM::VLD1DUPq8:
|
| + case ARM::VLD1DUPq16:
|
| + case ARM::VLD1DUPq32:
|
| + case ARM::VLD1DUPd8wb_fixed:
|
| + case ARM::VLD1DUPd16wb_fixed:
|
| + case ARM::VLD1DUPd32wb_fixed:
|
| + case ARM::VLD1DUPq8wb_fixed:
|
| + case ARM::VLD1DUPq16wb_fixed:
|
| + case ARM::VLD1DUPq32wb_fixed:
|
| + case ARM::VLD1DUPd8wb_register:
|
| + case ARM::VLD1DUPd16wb_register:
|
| + case ARM::VLD1DUPd32wb_register:
|
| + case ARM::VLD1DUPq8wb_register:
|
| + case ARM::VLD1DUPq16wb_register:
|
| + case ARM::VLD1DUPq32wb_register:
|
| +
|
| + // VLD2
|
| + case ARM::VLD2d8:
|
| + case ARM::VLD2d16:
|
| + case ARM::VLD2d32:
|
| + case ARM::VLD2b8:
|
| + case ARM::VLD2b16:
|
| + case ARM::VLD2b32:
|
| + case ARM::VLD2q8:
|
| + case ARM::VLD2q16:
|
| + case ARM::VLD2q32:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + case ARM::VLD2d8wb_fixed:
|
| + case ARM::VLD2d16wb_fixed:
|
| + case ARM::VLD2d32wb_fixed:
|
| + case ARM::VLD2b8wb_fixed:
|
| + case ARM::VLD2b16wb_fixed:
|
| + case ARM::VLD2b32wb_fixed:
|
| + case ARM::VLD2q8wb_fixed:
|
| + case ARM::VLD2q16wb_fixed:
|
| + case ARM::VLD2q32wb_fixed:
|
| + case ARM::VLD2d8wb_register:
|
| + case ARM::VLD2d16wb_register:
|
| + case ARM::VLD2d32wb_register:
|
| + case ARM::VLD2b8wb_register:
|
| + case ARM::VLD2b16wb_register:
|
| + case ARM::VLD2b32wb_register:
|
| + case ARM::VLD2q8wb_register:
|
| + case ARM::VLD2q16wb_register:
|
| + case ARM::VLD2q32wb_register:
|
| + *AddrIdx = 2;
|
| + break;
|
| +
|
| + // VLD2LN
|
| + case ARM::VLD2LNd8:
|
| + case ARM::VLD2LNd16:
|
| + case ARM::VLD2LNd32:
|
| + case ARM::VLD2LNq16:
|
| + case ARM::VLD2LNq32:
|
| + *AddrIdx = 2;
|
| + break;
|
| +
|
| + case ARM::VLD2LNd8_UPD:
|
| + case ARM::VLD2LNd16_UPD:
|
| + case ARM::VLD2LNd32_UPD:
|
| + case ARM::VLD2LNq16_UPD:
|
| + case ARM::VLD2LNq32_UPD:
|
| + *AddrIdx = 3;
|
| + break;
|
| +
|
| + // VLD2DUP
|
| + case ARM::VLD2DUPd8:
|
| + case ARM::VLD2DUPd16:
|
| + case ARM::VLD2DUPd32:
|
| + case ARM::VLD2DUPd8x2:
|
| + case ARM::VLD2DUPd16x2:
|
| + case ARM::VLD2DUPd32x2:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + case ARM::VLD2DUPd8wb_fixed:
|
| + case ARM::VLD2DUPd16wb_fixed:
|
| + case ARM::VLD2DUPd32wb_fixed:
|
| + case ARM::VLD2DUPd8wb_register:
|
| + case ARM::VLD2DUPd16wb_register:
|
| + case ARM::VLD2DUPd32wb_register:
|
| + case ARM::VLD2DUPd8x2wb_fixed:
|
| + case ARM::VLD2DUPd16x2wb_fixed:
|
| + case ARM::VLD2DUPd32x2wb_fixed:
|
| + case ARM::VLD2DUPd8x2wb_register:
|
| + case ARM::VLD2DUPd16x2wb_register:
|
| + case ARM::VLD2DUPd32x2wb_register:
|
| + *AddrIdx = 2;
|
| + break;
|
| +
|
| + // VLD3
|
| + case ARM::VLD3d8:
|
| + case ARM::VLD3d16:
|
| + case ARM::VLD3d32:
|
| + case ARM::VLD3q8:
|
| + case ARM::VLD3q16:
|
| + case ARM::VLD3q32:
|
| + case ARM::VLD3d8_UPD:
|
| + case ARM::VLD3d16_UPD:
|
| + case ARM::VLD3d32_UPD:
|
| + case ARM::VLD3q8_UPD:
|
| + case ARM::VLD3q16_UPD:
|
| + case ARM::VLD3q32_UPD:
|
| +
|
| + // VLD3LN
|
| + case ARM::VLD3LNd8:
|
| + case ARM::VLD3LNd16:
|
| + case ARM::VLD3LNd32:
|
| + case ARM::VLD3LNq16:
|
| + case ARM::VLD3LNq32:
|
| + *AddrIdx = 3;
|
| + break;
|
| +
|
| + case ARM::VLD3LNd8_UPD:
|
| + case ARM::VLD3LNd16_UPD:
|
| + case ARM::VLD3LNd32_UPD:
|
| + case ARM::VLD3LNq16_UPD:
|
| + case ARM::VLD3LNq32_UPD:
|
| + *AddrIdx = 4;
|
| + break;
|
| +
|
| + // VLD3DUP
|
| + case ARM::VLD3DUPd8:
|
| + case ARM::VLD3DUPd16:
|
| + case ARM::VLD3DUPd32:
|
| + case ARM::VLD3DUPq8:
|
| + case ARM::VLD3DUPq16:
|
| + case ARM::VLD3DUPq32:
|
| + *AddrIdx = 3;
|
| + break;
|
| +
|
| + case ARM::VLD3DUPd8_UPD:
|
| + case ARM::VLD3DUPd16_UPD:
|
| + case ARM::VLD3DUPd32_UPD:
|
| + case ARM::VLD3DUPq8_UPD:
|
| + case ARM::VLD3DUPq16_UPD:
|
| + case ARM::VLD3DUPq32_UPD:
|
| + *AddrIdx = 4;
|
| + break;
|
| +
|
| + // VLD4
|
| + case ARM::VLD4d8:
|
| + case ARM::VLD4d16:
|
| + case ARM::VLD4d32:
|
| + case ARM::VLD4q8:
|
| + case ARM::VLD4q16:
|
| + case ARM::VLD4q32:
|
| + *AddrIdx = 4;
|
| + break;
|
| +
|
| + case ARM::VLD4d8_UPD:
|
| + case ARM::VLD4d16_UPD:
|
| + case ARM::VLD4d32_UPD:
|
| + case ARM::VLD4q8_UPD:
|
| + case ARM::VLD4q16_UPD:
|
| + case ARM::VLD4q32_UPD:
|
| + *AddrIdx = 5;
|
| + break;
|
| +
|
| + // VLD4LN
|
| + case ARM::VLD4LNd8:
|
| + case ARM::VLD4LNd16:
|
| + case ARM::VLD4LNd32:
|
| + case ARM::VLD4LNq16:
|
| + case ARM::VLD4LNq32:
|
| + *AddrIdx = 4;
|
| + break;
|
| +
|
| + case ARM::VLD4LNd8_UPD:
|
| + case ARM::VLD4LNd16_UPD:
|
| + case ARM::VLD4LNd32_UPD:
|
| + case ARM::VLD4LNq16_UPD:
|
| + case ARM::VLD4LNq32_UPD:
|
| + *AddrIdx = 5;
|
| + break;
|
| +
|
| + case ARM::VLD4DUPd8:
|
| + case ARM::VLD4DUPd16:
|
| + case ARM::VLD4DUPd32:
|
| + case ARM::VLD4DUPq16:
|
| + case ARM::VLD4DUPq32:
|
| + *AddrIdx = 4;
|
| + break;
|
| +
|
| + case ARM::VLD4DUPd8_UPD:
|
| + case ARM::VLD4DUPd16_UPD:
|
| + case ARM::VLD4DUPd32_UPD:
|
| + case ARM::VLD4DUPq16_UPD:
|
| + case ARM::VLD4DUPq32_UPD:
|
| + *AddrIdx = 5;
|
| + break;
|
| + }
|
| +
|
| + if (MI.getOperand(*AddrIdx).getReg() == ARM::SP) {
|
| + // The contents of SP do not require masking.
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +/*
|
| + * Sandboxes a memory reference instruction by inserting an appropriate mask
|
| + * or check operation before it.
|
| + */
|
| +void ARMNaClRewritePass::SandboxMemory(MachineBasicBlock &MBB,
|
| + MachineBasicBlock::iterator MBBI,
|
| + MachineInstr &MI,
|
| + int AddrIdx,
|
| + bool IsLoad) {
|
| + unsigned Addr = MI.getOperand(AddrIdx).getReg();
|
| +
|
| + if (Addr == ARM::R9) {
|
| + // R9-relative loads are no longer sandboxed.
|
| + assert(IsLoad && "There should be no r9-relative stores");
|
| + } else {
|
| + unsigned Opcode;
|
| + if (IsLoad && (MI.getOperand(0).getReg() == ARM::SP)) {
|
| + Opcode = ARM::SFI_GUARD_SP_LOAD;
|
| + } else {
|
| + Opcode = ARM::SFI_GUARD_LOADSTORE;
|
| + }
|
| + // Use same predicate as current instruction.
|
| + unsigned PredReg = 0;
|
| + ARMCC::CondCodes Pred = llvm::getInstrPredicate(&MI, PredReg);
|
| + // Use the older BIC sandbox, which is universal, but incurs a stall.
|
| + BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opcode))
|
| + .addReg(Addr, RegState::Define) // Address definition (as dst).
|
| + .addReg(Addr, RegState::Kill) // Address read (as src).
|
| + .addImm((int64_t) Pred) // predicate condition
|
| + .addReg(PredReg); // predicate source register (CPSR)
|
| +
|
| + /*
|
| + * This pseudo-instruction is intended to generate something resembling the
|
| + * following, but with alignment enforced.
|
| + * TODO(cbiffle): move alignment into this function, use the code below.
|
| + *
|
| + * // bic<cc> Addr, Addr, #0xC0000000
|
| + * BuildMI(MBB, MBBI, MI.getDebugLoc(),
|
| + * TII->get(ARM::BICri))
|
| + * .addReg(Addr) // rD
|
| + * .addReg(Addr) // rN
|
| + * .addImm(0xC0000000) // imm
|
| + * .addImm((int64_t) Pred) // predicate condition
|
| + * .addReg(PredReg) // predicate source register (CPSR)
|
| + * .addReg(0); // flag output register (0 == no flags)
|
| + */
|
| + }
|
| +}
|
| +
|
| +static bool IsDangerousStore(const MachineInstr &MI, int *AddrIdx) {
|
| + unsigned Opcode = MI.getOpcode();
|
| + switch (Opcode) {
|
| + default: return false;
|
| +
|
| + // Instructions with base address register in position 0...
|
| + case ARM::STMIA:
|
| + case ARM::STMDA:
|
| + case ARM::STMDB:
|
| + case ARM::STMIB:
|
| +
|
| + case ARM::VSTMDIA:
|
| + case ARM::VSTMSIA:
|
| + *AddrIdx = 0;
|
| + break;
|
| +
|
| + // Instructions with base address register in position 1...
|
| + case ARM::STMIA_UPD: // same reg at position 0 and position 1
|
| + case ARM::STMDA_UPD:
|
| + case ARM::STMDB_UPD:
|
| + case ARM::STMIB_UPD:
|
| +
|
| + case ARM::STRH:
|
| + case ARM::STRi12:
|
| + case ARM::STRrs:
|
| + case ARM::STRBi12:
|
| + case ARM::STRBrs:
|
| + case ARM::VSTMDIA_UPD:
|
| + case ARM::VSTMDDB_UPD:
|
| + case ARM::VSTMSIA_UPD:
|
| + case ARM::VSTMSDB_UPD:
|
| + case ARM::VSTRS:
|
| + case ARM::VSTRD:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + //
|
| + // NEON stores
|
| + //
|
| +
|
| + // VST1
|
| + case ARM::VST1d8:
|
| + case ARM::VST1d16:
|
| + case ARM::VST1d32:
|
| + case ARM::VST1d64:
|
| + case ARM::VST1q8:
|
| + case ARM::VST1q16:
|
| + case ARM::VST1q32:
|
| + case ARM::VST1q64:
|
| + *AddrIdx = 0;
|
| + break;
|
| +
|
| + case ARM::VST1d8wb_fixed:
|
| + case ARM::VST1d16wb_fixed:
|
| + case ARM::VST1d32wb_fixed:
|
| + case ARM::VST1d64wb_fixed:
|
| + case ARM::VST1q8wb_fixed:
|
| + case ARM::VST1q16wb_fixed:
|
| + case ARM::VST1q32wb_fixed:
|
| + case ARM::VST1q64wb_fixed:
|
| + case ARM::VST1d8wb_register:
|
| + case ARM::VST1d16wb_register:
|
| + case ARM::VST1d32wb_register:
|
| + case ARM::VST1d64wb_register:
|
| + case ARM::VST1q8wb_register:
|
| + case ARM::VST1q16wb_register:
|
| + case ARM::VST1q32wb_register:
|
| + case ARM::VST1q64wb_register:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + // VST1LN
|
| + case ARM::VST1LNd8:
|
| + case ARM::VST1LNd16:
|
| + case ARM::VST1LNd32:
|
| + *AddrIdx = 0;
|
| + break;
|
| +
|
| + case ARM::VST1LNd8_UPD:
|
| + case ARM::VST1LNd16_UPD:
|
| + case ARM::VST1LNd32_UPD:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + // VST2
|
| + case ARM::VST2d8:
|
| + case ARM::VST2d16:
|
| + case ARM::VST2d32:
|
| + case ARM::VST2q8:
|
| + case ARM::VST2q16:
|
| + case ARM::VST2q32:
|
| + *AddrIdx = 0;
|
| + break;
|
| +
|
| + case ARM::VST2d8wb_fixed:
|
| + case ARM::VST2d16wb_fixed:
|
| + case ARM::VST2d32wb_fixed:
|
| + case ARM::VST2q8wb_fixed:
|
| + case ARM::VST2q16wb_fixed:
|
| + case ARM::VST2q32wb_fixed:
|
| + case ARM::VST2d8wb_register:
|
| + case ARM::VST2d16wb_register:
|
| + case ARM::VST2d32wb_register:
|
| + case ARM::VST2q8wb_register:
|
| + case ARM::VST2q16wb_register:
|
| + case ARM::VST2q32wb_register:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + // VST2LN
|
| + case ARM::VST2LNd8:
|
| + case ARM::VST2LNd16:
|
| + case ARM::VST2LNq16:
|
| + case ARM::VST2LNd32:
|
| + case ARM::VST2LNq32:
|
| + *AddrIdx = 0;
|
| + break;
|
| +
|
| + case ARM::VST2LNd8_UPD:
|
| + case ARM::VST2LNd16_UPD:
|
| + case ARM::VST2LNq16_UPD:
|
| + case ARM::VST2LNd32_UPD:
|
| + case ARM::VST2LNq32_UPD:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + // VST3
|
| + case ARM::VST3d8:
|
| + case ARM::VST3d16:
|
| + case ARM::VST3d32:
|
| + case ARM::VST3q8:
|
| + case ARM::VST3q16:
|
| + case ARM::VST3q32:
|
| + *AddrIdx = 0;
|
| + break;
|
| +
|
| + case ARM::VST3d8_UPD:
|
| + case ARM::VST3d16_UPD:
|
| + case ARM::VST3d32_UPD:
|
| + case ARM::VST3q8_UPD:
|
| + case ARM::VST3q16_UPD:
|
| + case ARM::VST3q32_UPD:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + // VST3LN
|
| + case ARM::VST3LNd8:
|
| + case ARM::VST3LNd16:
|
| + case ARM::VST3LNq16:
|
| + case ARM::VST3LNd32:
|
| + case ARM::VST3LNq32:
|
| + *AddrIdx = 0;
|
| + break;
|
| +
|
| + case ARM::VST3LNd8_UPD:
|
| + case ARM::VST3LNd16_UPD:
|
| + case ARM::VST3LNq16_UPD:
|
| + case ARM::VST3LNd32_UPD:
|
| + case ARM::VST3LNq32_UPD:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + // VST4
|
| + case ARM::VST4d8:
|
| + case ARM::VST4d16:
|
| + case ARM::VST4d32:
|
| + case ARM::VST4q8:
|
| + case ARM::VST4q16:
|
| + case ARM::VST4q32:
|
| + *AddrIdx = 0;
|
| + break;
|
| +
|
| + case ARM::VST4d8_UPD:
|
| + case ARM::VST4d16_UPD:
|
| + case ARM::VST4d32_UPD:
|
| + case ARM::VST4q8_UPD:
|
| + case ARM::VST4q16_UPD:
|
| + case ARM::VST4q32_UPD:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + // VST4LN
|
| + case ARM::VST4LNd8:
|
| + case ARM::VST4LNd16:
|
| + case ARM::VST4LNq16:
|
| + case ARM::VST4LNd32:
|
| + case ARM::VST4LNq32:
|
| + *AddrIdx = 0;
|
| + break;
|
| +
|
| + case ARM::VST4LNd8_UPD:
|
| + case ARM::VST4LNd16_UPD:
|
| + case ARM::VST4LNq16_UPD:
|
| + case ARM::VST4LNd32_UPD:
|
| + case ARM::VST4LNq32_UPD:
|
| + *AddrIdx = 1;
|
| + break;
|
| +
|
| + // Instructions with base address register in position 2...
|
| + case ARM::STR_PRE_REG:
|
| + case ARM::STR_PRE_IMM:
|
| + case ARM::STR_POST_REG:
|
| + case ARM::STR_POST_IMM:
|
| +
|
| + case ARM::STRB_PRE_REG:
|
| + case ARM::STRB_PRE_IMM:
|
| + case ARM::STRB_POST_REG:
|
| + case ARM::STRB_POST_IMM:
|
| +
|
| + case ARM::STRH_PRE:
|
| + case ARM::STRH_POST:
|
| +
|
| +
|
| + case ARM::STRD:
|
| + case ARM::STREX:
|
| + case ARM::STREXB:
|
| + case ARM::STREXH:
|
| + case ARM::STREXD:
|
| + *AddrIdx = 2;
|
| + break;
|
| + }
|
| +
|
| + if (MI.getOperand(*AddrIdx).getReg() == ARM::SP) {
|
| + // The contents of SP do not require masking.
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool ARMNaClRewritePass::SandboxMemoryReferencesInBlock(
|
| + 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)) {
|
| + SandboxMemory(MBB, MBBI, MI, AddrIdx, true);
|
| + Modified = true;
|
| + }
|
| + if (IsDangerousStore(MI, &AddrIdx)) {
|
| + SandboxMemory(MBB, MBBI, MI, AddrIdx, false);
|
| + Modified = true;
|
| + }
|
| + }
|
| + return Modified;
|
| +}
|
| +
|
| +/**********************************************************************/
|
| +
|
| +bool ARMNaClRewritePass::runOnMachineFunction(MachineFunction &MF) {
|
| + TII = static_cast<const ARMBaseInstrInfo*>(MF.getSubtarget().getInstrInfo());
|
| + TRI = MF.getSubtarget().getRegisterInfo();
|
| +
|
| + bool Modified = false;
|
| + for (MachineFunction::iterator MFI = MF.begin(), E = MF.end();
|
| + MFI != E;
|
| + ++MFI) {
|
| + MachineBasicBlock &MBB = *MFI;
|
| +
|
| + if (MBB.hasAddressTaken()) {
|
| + //FIXME: use symbolic constant or get this value from some configuration
|
| + MBB.setAlignment(4);
|
| + Modified = true;
|
| + }
|
| +
|
| + Modified |= SandboxMemoryReferencesInBlock(MBB);
|
| + Modified |= SandboxBranchesInBlock(MBB);
|
| + Modified |= SandboxStackChangesInBlock(MBB);
|
| + }
|
| + DEBUG(LightweightVerify(MF));
|
| + return Modified;
|
| +}
|
| +
|
| +/// createARMNaClRewritePass - returns an instance of the NaClRewritePass.
|
| +FunctionPass *llvm::createARMNaClRewritePass() {
|
| + return new ARMNaClRewritePass();
|
| +}
|
|
|