forked from OSchip/llvm-project
98 lines
3.1 KiB
C++
98 lines
3.1 KiB
C++
//===-- MipsNaClELFStreamer.cpp - ELF Object Output for Mips NaCl ---------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements MCELFStreamer for Mips NaCl. It emits .o object files
|
|
// as required by NaCl's SFI sandbox. It inserts address-masking instructions
|
|
// before dangerous control-flow instructions. It aligns on bundle size all
|
|
// functions and all targets of indirect branches.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "mips-mc-nacl"
|
|
|
|
#include "Mips.h"
|
|
#include "MipsMCNaCl.h"
|
|
#include "llvm/MC/MCELFStreamer.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
const unsigned IndirectBranchMaskReg = Mips::T6;
|
|
|
|
/// Extend the generic MCELFStreamer class so that it can mask dangerous
|
|
/// instructions.
|
|
|
|
class MipsNaClELFStreamer : public MCELFStreamer {
|
|
public:
|
|
MipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS,
|
|
MCCodeEmitter *Emitter)
|
|
: MCELFStreamer(Context, TAB, OS, Emitter) {}
|
|
|
|
~MipsNaClELFStreamer() {}
|
|
|
|
private:
|
|
bool isIndirectJump(const MCInst &MI) {
|
|
return MI.getOpcode() == Mips::JR || MI.getOpcode() == Mips::RET;
|
|
}
|
|
|
|
void emitMask(unsigned AddrReg, unsigned MaskReg,
|
|
const MCSubtargetInfo &STI) {
|
|
MCInst MaskInst;
|
|
MaskInst.setOpcode(Mips::AND);
|
|
MaskInst.addOperand(MCOperand::CreateReg(AddrReg));
|
|
MaskInst.addOperand(MCOperand::CreateReg(AddrReg));
|
|
MaskInst.addOperand(MCOperand::CreateReg(MaskReg));
|
|
MCELFStreamer::EmitInstruction(MaskInst, STI);
|
|
}
|
|
|
|
// Sandbox indirect branch or return instruction by inserting mask operation
|
|
// before it.
|
|
void sandboxIndirectJump(const MCInst &MI, const MCSubtargetInfo &STI) {
|
|
unsigned AddrReg = MI.getOperand(0).getReg();
|
|
|
|
EmitBundleLock(false);
|
|
emitMask(AddrReg, IndirectBranchMaskReg, STI);
|
|
MCELFStreamer::EmitInstruction(MI, STI);
|
|
EmitBundleUnlock();
|
|
}
|
|
|
|
public:
|
|
/// This function is the one used to emit instruction data into the ELF
|
|
/// streamer. We override it to mask dangerous instructions.
|
|
virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) {
|
|
if (isIndirectJump(Inst))
|
|
sandboxIndirectJump(Inst, STI);
|
|
else
|
|
MCELFStreamer::EmitInstruction(Inst, STI);
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
namespace llvm {
|
|
|
|
MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
|
|
raw_ostream &OS,
|
|
MCCodeEmitter *Emitter, bool RelaxAll,
|
|
bool NoExecStack) {
|
|
MipsNaClELFStreamer *S = new MipsNaClELFStreamer(Context, TAB, OS, Emitter);
|
|
if (RelaxAll)
|
|
S->getAssembler().setRelaxAll(true);
|
|
if (NoExecStack)
|
|
S->getAssembler().setNoExecStack(true);
|
|
|
|
// Set bundle-alignment as required by the NaCl ABI for the target.
|
|
S->EmitBundleAlignMode(MIPS_NACL_BUNDLE_ALIGN);
|
|
|
|
return S;
|
|
}
|
|
|
|
}
|