| Index: lib/Target/ARM/MCTargetDesc/ARMMCNaCl.cpp
|
| diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCNaCl.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCNaCl.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6af91dea0416cf5027c9bca40900bd28787002cc
|
| --- /dev/null
|
| +++ b/lib/Target/ARM/MCTargetDesc/ARMMCNaCl.cpp
|
| @@ -0,0 +1,319 @@
|
| +//=== ARMMCNaCl.cpp - Expansion of NaCl pseudo-instructions --*- C++ -*-=//
|
| +//
|
| +// The LLVM Compiler Infrastructure
|
| +//
|
| +// This file is distributed under the University of Illinois Open Source
|
| +// License. See LICENSE.TXT for details.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +#define DEBUG_TYPE "arm-mc-nacl"
|
| +
|
| +#include "MCTargetDesc/ARMBaseInfo.h"
|
| +#include "MCTargetDesc/ARMMCExpr.h"
|
| +#include "MCTargetDesc/ARMMCNaCl.h"
|
| +#include "MCTargetDesc/ARMMCTargetDesc.h"
|
| +#include "llvm/MC/MCInst.h"
|
| +#include "llvm/MC/MCStreamer.h"
|
| +#include "llvm/Support/CommandLine.h"
|
| +#include "llvm/Support/Debug.h"
|
| +
|
| +using namespace llvm;
|
| +
|
| +/// Two helper functions for emitting the actual guard instructions
|
| +
|
| +static void EmitBICMask(const MCSubtargetInfo &STI, MCStreamer &Out,
|
| + unsigned Addr, int64_t Pred, unsigned Mask) {
|
| + // bic\Pred \Addr, \Addr, #Mask
|
| + MCInst BICInst;
|
| + BICInst.setOpcode(ARM::BICri);
|
| + BICInst.addOperand(MCOperand::CreateReg(Addr)); // rD
|
| + BICInst.addOperand(MCOperand::CreateReg(Addr)); // rS
|
| + BICInst.addOperand(MCOperand::CreateImm(Mask)); // imm
|
| + BICInst.addOperand(MCOperand::CreateImm(Pred)); // predicate
|
| + BICInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); // CPSR
|
| + BICInst.addOperand(MCOperand::CreateReg(0)); // flag out
|
| + Out.EmitInstruction(BICInst, STI);
|
| +}
|
| +
|
| +static void EmitTST(const MCSubtargetInfo &STI, MCStreamer &Out, unsigned Reg) {
|
| + // tst \reg, #\MASK typically 0xc0000000
|
| + const unsigned Mask = 0xC0000000;
|
| + MCInst TSTInst;
|
| + TSTInst.setOpcode(ARM::TSTri);
|
| + TSTInst.addOperand(MCOperand::CreateReg(Reg)); // rS
|
| + TSTInst.addOperand(MCOperand::CreateImm(Mask)); // imm
|
| + TSTInst.addOperand(MCOperand::CreateImm((int64_t)ARMCC::AL)); // Always
|
| + TSTInst.addOperand(MCOperand::CreateImm(0)); // flag out
|
| + Out.EmitInstruction(TSTInst, STI);
|
| +}
|
| +
|
| +
|
| +// This is ONLY used for sandboxing stack changes.
|
| +// The reason why SFI_NOP_IF_AT_BUNDLE_END gets handled here is that
|
| +// it must ensure that the two instructions are in the same bundle.
|
| +// It just so happens that the SFI_NOP_IF_AT_BUNDLE_END is always
|
| +// emitted in conjunction with a SFI_DATA_MASK
|
| +//
|
| +static void EmitDataMask(const MCSubtargetInfo &STI, int I, MCInst Saved[],
|
| + MCStreamer &Out) {
|
| + assert(I == 3 && (ARM::SFI_NOP_IF_AT_BUNDLE_END == Saved[0].getOpcode()) &&
|
| + (ARM::SFI_DATA_MASK == Saved[2].getOpcode()) &&
|
| + "Unexpected SFI Pseudo while lowering");
|
| +
|
| + unsigned Addr = Saved[2].getOperand(0).getReg();
|
| + int64_t Pred = Saved[2].getOperand(2).getImm();
|
| + assert((ARM::SP == Addr) && "Unexpected register at stack guard");
|
| +
|
| + Out.EmitBundleLock(false);
|
| + Out.EmitInstruction(Saved[1], STI);
|
| + EmitBICMask(STI, Out, Addr, Pred, 0xC0000000);
|
| + Out.EmitBundleUnlock();
|
| +}
|
| +
|
| +static void EmitDirectGuardCall(const MCSubtargetInfo &STI, int I,
|
| + MCInst Saved[], MCStreamer &Out) {
|
| + // sfi_call_preamble cond=
|
| + // sfi_nops_to_force_slot3
|
| + assert(I == 2 && (ARM::SFI_GUARD_CALL == Saved[0].getOpcode()) &&
|
| + "Unexpected SFI Pseudo while lowering SFI_GUARD_CALL");
|
| + Out.EmitBundleLock(true);
|
| + Out.EmitInstruction(Saved[1], STI);
|
| + Out.EmitBundleUnlock();
|
| +}
|
| +
|
| +static void EmitIndirectGuardCall(const MCSubtargetInfo &STI, int I,
|
| + MCInst Saved[], MCStreamer &Out) {
|
| + // sfi_indirect_call_preamble link cond=
|
| + // sfi_nops_to_force_slot2
|
| + // sfi_code_mask \link \cond
|
| + assert(I == 2 && (ARM::SFI_GUARD_INDIRECT_CALL == Saved[0].getOpcode()) &&
|
| + "Unexpected SFI Pseudo while lowering SFI_GUARD_CALL");
|
| + unsigned Reg = Saved[0].getOperand(0).getReg();
|
| + int64_t Pred = Saved[0].getOperand(2).getImm();
|
| + Out.EmitBundleLock(true);
|
| + EmitBICMask(STI, Out, Reg, Pred, 0xC000000F);
|
| + Out.EmitInstruction(Saved[1], STI);
|
| + Out.EmitBundleUnlock();
|
| +}
|
| +
|
| +static void EmitIndirectGuardJmp(const MCSubtargetInfo &STI, int I,
|
| + MCInst Saved[], MCStreamer &Out) {
|
| + // sfi_indirect_jump_preamble link cond=
|
| + // sfi_nop_if_at_bundle_end
|
| + // sfi_code_mask \link \cond
|
| + assert(I == 2 && (ARM::SFI_GUARD_INDIRECT_JMP == Saved[0].getOpcode()) &&
|
| + "Unexpected SFI Pseudo while lowering SFI_GUARD_CALL");
|
| + unsigned Reg = Saved[0].getOperand(0).getReg();
|
| + int64_t Pred = Saved[0].getOperand(2).getImm();
|
| +
|
| + Out.EmitBundleLock(false);
|
| + EmitBICMask(STI, Out, Reg, Pred, 0xC000000F);
|
| + Out.EmitInstruction(Saved[1], STI);
|
| + Out.EmitBundleUnlock();
|
| +}
|
| +
|
| +static void EmitGuardReturn(const MCSubtargetInfo &STI, int I, MCInst Saved[],
|
| + MCStreamer &Out) {
|
| + // sfi_return_preamble reg cond=
|
| + // sfi_nop_if_at_bundle_end
|
| + // sfi_code_mask \reg \cond
|
| + assert(I == 2 && (ARM::SFI_GUARD_RETURN == Saved[0].getOpcode()) &&
|
| + "Unexpected SFI Pseudo while lowering SFI_GUARD_RETURN");
|
| + int64_t Pred = Saved[0].getOperand(0).getImm();
|
| +
|
| + Out.EmitBundleLock(false);
|
| + EmitBICMask(STI, Out, ARM::LR, Pred, 0xC000000F);
|
| + Out.EmitInstruction(Saved[1], STI);
|
| + Out.EmitBundleUnlock();
|
| +}
|
| +
|
| +static void EmitGuardLoadOrStore(const MCSubtargetInfo &STI, int I,
|
| + MCInst Saved[], MCStreamer &Out) {
|
| + // sfi_store_preamble reg cond ---->
|
| + // sfi_nop_if_at_bundle_end
|
| + // sfi_data_mask \reg, \cond
|
| + assert(I == 2 && (ARM::SFI_GUARD_LOADSTORE == Saved[0].getOpcode()) &&
|
| + "Unexpected SFI Pseudo while lowering SFI_GUARD_RETURN");
|
| + unsigned Reg = Saved[0].getOperand(0).getReg();
|
| + int64_t Pred = Saved[0].getOperand(2).getImm();
|
| +
|
| + Out.EmitBundleLock(false);
|
| + EmitBICMask(STI, Out, Reg, Pred, 0xC0000000);
|
| + Out.EmitInstruction(Saved[1], STI);
|
| + Out.EmitBundleUnlock();
|
| +}
|
| +
|
| +static void EmitGuardLoadOrStoreTst(const MCSubtargetInfo &STI, int I,
|
| + MCInst Saved[], MCStreamer &Out) {
|
| + // sfi_cstore_preamble reg -->
|
| + // sfi_nop_if_at_bundle_end
|
| + // sfi_data_tst \reg
|
| + assert(I == 2 && (ARM::SFI_GUARD_LOADSTORE_TST == Saved[0].getOpcode()) &&
|
| + "Unexpected SFI Pseudo while lowering");
|
| + unsigned Reg = Saved[0].getOperand(0).getReg();
|
| +
|
| + Out.EmitBundleLock(false);
|
| + EmitTST(STI, Out, Reg);
|
| + Out.EmitInstruction(Saved[1], STI);
|
| + Out.EmitBundleUnlock();
|
| +}
|
| +
|
| +// This is ONLY used for loads into the stack pointer.
|
| +static void EmitGuardSpLoad(const MCSubtargetInfo &STI, int I, MCInst Saved[],
|
| + MCStreamer &Out) {
|
| + assert(I == 4 &&
|
| + (ARM::SFI_GUARD_SP_LOAD == Saved[0].getOpcode()) &&
|
| + (ARM::SFI_NOP_IF_AT_BUNDLE_END == Saved[1].getOpcode()) &&
|
| + (ARM::SFI_DATA_MASK == Saved[3].getOpcode()) &&
|
| + "Unexpected SFI Pseudo while lowering");
|
| +
|
| + unsigned AddrReg = Saved[0].getOperand(0).getReg();
|
| + unsigned SpReg = Saved[3].getOperand(0).getReg();
|
| + int64_t Pred = Saved[3].getOperand(2).getImm();
|
| + assert((ARM::SP == SpReg) && "Unexpected register at stack guard");
|
| +
|
| + Out.EmitBundleLock(false);
|
| + EmitBICMask(STI, Out, AddrReg, Pred, 0xC0000000);
|
| + Out.EmitInstruction(Saved[2], STI);
|
| + EmitBICMask(STI, Out, SpReg, Pred, 0xC0000000);
|
| + Out.EmitBundleUnlock();
|
| +}
|
| +
|
| +namespace llvm {
|
| +
|
| +const int ARMMCNaClSFIState::MaxSaved;
|
| +
|
| +// CustomExpandInstNaClARM -
|
| +// If Inst is a NaCl pseudo instruction, emits the substitute
|
| +// expansion to the MCStreamer and returns true.
|
| +// Otherwise, returns false.
|
| +//
|
| +// NOTE: Each time this function calls Out.EmitInstruction(), it will be
|
| +// called again recursively to rewrite the new instruction being emitted.
|
| +// Care must be taken to ensure that this does not result in an infinite
|
| +// loop. Also, global state must be managed carefully so that it is
|
| +// consistent during recursive calls.
|
| +bool CustomExpandInstNaClARM(const MCSubtargetInfo &STI, const MCInst &Inst,
|
| + MCStreamer &Out, ARMMCNaClSFIState &State) {
|
| + // Logic:
|
| + // This is somewhat convoluted, but in the current model, the SFI
|
| + // guard pseudo instructions occur PRIOR to the actual instruction.
|
| + // So, the bundling/alignment operation has to refer to the FOLLOWING
|
| + // instructions.
|
| + //
|
| + // When a SFI pseudo is detected, it is saved. Then, the saved SFI
|
| + // pseudo and the very next instructions (their amount depending on the kind
|
| + // of the SFI pseudo) are used as arguments to the Emit*() functions in
|
| + // this file.
|
| + //
|
| + // Some state data is used to preserve state accross calls:
|
| + //
|
| + // Saved: the saved instructions (starting with the SFI_ pseudo).
|
| + // SavedCount: the amount of saved instructions required for the SFI pseudo
|
| + // that's being expanded.
|
| + // I: the index of the currently saved instruction - used to track
|
| + // where in Saved to insert the instruction and how many more
|
| + // remain.
|
| + //
|
| +
|
| + // If we are emitting to .s, just emit all pseudo-instructions directly.
|
| + if (Out.hasRawTextSupport()) {
|
| + return false;
|
| + }
|
| +
|
| + // Protect against recursive execution. If State.RecurseiveCall == true, it
|
| + // means we're already in the process of expanding a custom instruction, and
|
| + // we don't need to run recursively on anything generated by such an
|
| + // expansion.
|
| + if (State.RecursiveCall)
|
| + return false;
|
| +
|
| + DEBUG(dbgs() << "CustomExpandInstNaClARM("; Inst.dump(); dbgs() << ")\n");
|
| +
|
| + if ((State.I == 0) && (State.SaveCount == 0)) {
|
| + // Base state: no SFI guard identified yet and no saving started.
|
| + switch (Inst.getOpcode()) {
|
| + default:
|
| + // We don't handle non-SFI guards here
|
| + return false;
|
| + case ARM::SFI_NOP_IF_AT_BUNDLE_END:
|
| + // Note: SFI_NOP_IF_AT_BUNDLE_END is only emitted directly as part of
|
| + // a stack guard in conjunction with a SFI_DATA_MASK.
|
| + State.SaveCount = 3;
|
| + break;
|
| + case ARM::SFI_DATA_MASK:
|
| + llvm_unreachable(
|
| + "SFI_DATA_MASK found without preceding SFI_NOP_IF_AT_BUNDLE_END");
|
| + return false;
|
| + case ARM::SFI_GUARD_CALL:
|
| + case ARM::SFI_GUARD_INDIRECT_CALL:
|
| + case ARM::SFI_GUARD_INDIRECT_JMP:
|
| + case ARM::SFI_GUARD_RETURN:
|
| + case ARM::SFI_GUARD_LOADSTORE:
|
| + case ARM::SFI_GUARD_LOADSTORE_TST:
|
| + State.SaveCount = 2;
|
| + break;
|
| + case ARM::SFI_GUARD_SP_LOAD:
|
| + State.SaveCount = 4;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + // We're in "saving instructions" state
|
| + if (State.I < State.SaveCount) {
|
| + // This instruction has to be saved
|
| + assert(State.I < State.MaxSaved && "Trying to save too many instructions");
|
| + State.Saved[State.I++] = Inst;
|
| + if (State.I < State.SaveCount)
|
| + return true;
|
| + }
|
| +
|
| + // We're in "saved enough instructions, time to emit" state
|
| + assert(State.I == State.SaveCount && State.SaveCount > 0 && "Bookeeping Error");
|
| +
|
| + // When calling Emit* functions, do that with RecurseGuard set (the comment
|
| + // at the beginning of this function explains why)
|
| + State.RecursiveCall = true;
|
| + switch (State.Saved[0].getOpcode()) {
|
| + default:
|
| + break;
|
| + case ARM::SFI_NOP_IF_AT_BUNDLE_END:
|
| + EmitDataMask(STI, State.I, State.Saved, Out);
|
| + break;
|
| + case ARM::SFI_DATA_MASK:
|
| + llvm_unreachable("SFI_DATA_MASK can't start a SFI sequence");
|
| + break;
|
| + case ARM::SFI_GUARD_CALL:
|
| + EmitDirectGuardCall(STI, State.I, State.Saved, Out);
|
| + break;
|
| + case ARM::SFI_GUARD_INDIRECT_CALL:
|
| + EmitIndirectGuardCall(STI, State.I, State.Saved, Out);
|
| + break;
|
| + case ARM::SFI_GUARD_INDIRECT_JMP:
|
| + EmitIndirectGuardJmp(STI, State.I, State.Saved, Out);
|
| + break;
|
| + case ARM::SFI_GUARD_RETURN:
|
| + EmitGuardReturn(STI, State.I, State.Saved, Out);
|
| + break;
|
| + case ARM::SFI_GUARD_LOADSTORE:
|
| + EmitGuardLoadOrStore(STI, State.I, State.Saved, Out);
|
| + break;
|
| + case ARM::SFI_GUARD_LOADSTORE_TST:
|
| + EmitGuardLoadOrStoreTst(STI, State.I, State.Saved, Out);
|
| + break;
|
| + case ARM::SFI_GUARD_SP_LOAD:
|
| + EmitGuardSpLoad(STI, State.I, State.Saved, Out);
|
| + break;
|
| + }
|
| + assert(State.RecursiveCall && "Illegal Depth");
|
| + State.RecursiveCall = false;
|
| +
|
| + // We're done expanding a SFI guard. Reset state vars.
|
| + State.SaveCount = 0;
|
| + State.I = 0;
|
| + return true;
|
| +}
|
| +
|
| +} // namespace llvm
|
|
|