[llvm] r202479 - [mips] Implement NaCl sandboxing of indirect jumps:
Sasa Stankovic
Sasa.Stankovic at imgtec.com
Fri Feb 28 02:00:38 PST 2014
Author: sstankovic
Date: Fri Feb 28 04:00:38 2014
New Revision: 202479
URL: http://llvm.org/viewvc/llvm-project?rev=202479&view=rev
Log:
[mips] Implement NaCl sandboxing of indirect jumps:
* Align targets of indirect jumps to instruction bundle boundaries (in MI layer).
* Add masking instructions before indirect jumps (in MC layer).
Differential Revision: http://llvm-reviews.chandlerc.com/D2847
Added:
llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h
llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp
llvm/trunk/test/MC/Mips/nacl-align.ll
llvm/trunk/test/MC/Mips/nacl-mask.s
Modified:
llvm/trunk/include/llvm/MC/MCELFStreamer.h
llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
llvm/trunk/lib/Target/Mips/MipsAsmPrinter.cpp
llvm/trunk/lib/Target/Mips/MipsAsmPrinter.h
Modified: llvm/trunk/include/llvm/MC/MCELFStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCELFStreamer.h?rev=202479&r1=202478&r2=202479&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCELFStreamer.h (original)
+++ llvm/trunk/include/llvm/MC/MCELFStreamer.h Fri Feb 28 04:00:38 2014
@@ -84,14 +84,14 @@ public:
virtual void FinishImpl();
-private:
- virtual void EmitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &);
- virtual void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &);
-
virtual void EmitBundleAlignMode(unsigned AlignPow2);
virtual void EmitBundleLock(bool AlignToEnd);
virtual void EmitBundleUnlock();
+private:
+ virtual void EmitInstToFragment(const MCInst &Inst, const MCSubtargetInfo &);
+ virtual void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &);
+
void fixSymbolsInTLSFixups(const MCExpr *expr);
bool SeenIdent;
Added: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h?rev=202479&view=auto
==============================================================================
--- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h (added)
+++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h Fri Feb 28 04:00:38 2014
@@ -0,0 +1,28 @@
+//===-- MipsMCNaCl.h - NaCl-related declarations --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MIPSMCNACL_H
+#define MIPSMCNACL_H
+
+#include "llvm/MC/MCELFStreamer.h"
+
+namespace llvm {
+
+// Log2 of the NaCl MIPS sandbox's instruction bundle size.
+static const unsigned MIPS_NACL_BUNDLE_ALIGN = 4u;
+
+// This function creates an MCELFStreamer for Mips NaCl.
+MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
+ raw_ostream &OS,
+ MCCodeEmitter *Emitter,
+ bool RelaxAll, bool NoExecStack);
+
+}
+
+#endif
Modified: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp?rev=202479&r1=202478&r2=202479&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp Fri Feb 28 04:00:38 2014
@@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "MipsMCTargetDesc.h"
#include "InstPrinter/MipsInstPrinter.h"
#include "MipsMCAsmInfo.h"
+#include "MipsMCNaCl.h"
+#include "MipsMCTargetDesc.h"
#include "MipsTargetStreamer.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCCodeGenInfo.h"
@@ -109,8 +110,12 @@ static MCStreamer *createMCStreamer(cons
raw_ostream &OS, MCCodeEmitter *Emitter,
const MCSubtargetInfo &STI,
bool RelaxAll, bool NoExecStack) {
- MCStreamer *S =
- createELFStreamer(Context, MAB, OS, Emitter, RelaxAll, NoExecStack);
+ MCStreamer *S;
+ if (!Triple(TT).isOSNaCl())
+ S = createELFStreamer(Context, MAB, OS, Emitter, RelaxAll, NoExecStack);
+ else
+ S = createMipsNaClELFStreamer(Context, MAB, OS, Emitter, RelaxAll,
+ NoExecStack);
new MipsTargetELFStreamer(*S, STI);
return S;
}
Added: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp?rev=202479&view=auto
==============================================================================
--- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp (added)
+++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp Fri Feb 28 04:00:38 2014
@@ -0,0 +1,97 @@
+//===-- 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;
+}
+
+}
Modified: llvm/trunk/lib/Target/Mips/MipsAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsAsmPrinter.cpp?rev=202479&r1=202478&r2=202479&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsAsmPrinter.cpp Fri Feb 28 04:00:38 2014
@@ -15,6 +15,7 @@
#define DEBUG_TYPE "mips-asm-printer"
#include "InstPrinter/MipsInstPrinter.h"
#include "MCTargetDesc/MipsBaseInfo.h"
+#include "MCTargetDesc/MipsMCNaCl.h"
#include "Mips.h"
#include "MipsAsmPrinter.h"
#include "MipsInstrInfo.h"
@@ -27,6 +28,7 @@
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DataLayout.h"
@@ -72,6 +74,11 @@ bool MipsAsmPrinter::runOnMachineFunctio
StubsNeeded[Symbol] = Signature;
}
MCP = MF.getConstantPool();
+
+ // In NaCl, all indirect jump targets must be aligned to bundle size.
+ if (Subtarget->isTargetNaCl())
+ NaClAlignIndirectJumpTargets(MF);
+
AsmPrinter::runOnMachineFunction(MF);
return true;
}
@@ -270,6 +277,12 @@ const char *MipsAsmPrinter::getCurrentAB
void MipsAsmPrinter::EmitFunctionEntryLabel() {
MipsTargetStreamer &TS = getTargetStreamer();
+
+ // NaCl sandboxing requires that indirect call instructions are masked.
+ // This means that function entry points should be bundle-aligned.
+ if (Subtarget->isTargetNaCl())
+ EmitAlignment(std::max(MF->getAlignment(), MIPS_NACL_BUNDLE_ALIGN));
+
if (Subtarget->inMicroMipsMode())
TS.emitDirectiveSetMicroMips();
// leave out until FSF available gas has micromips changes
@@ -906,6 +919,28 @@ void MipsAsmPrinter::PrintDebugValueComm
// TODO: implement
}
+// Align all targets of indirect branches on bundle size. Used only if target
+// is NaCl.
+void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) {
+ // Align all blocks that are jumped to through jump table.
+ if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) {
+ const std::vector<MachineJumpTableEntry> &JT = JtInfo->getJumpTables();
+ for (unsigned I = 0; I < JT.size(); ++I) {
+ const std::vector<MachineBasicBlock*> &MBBs = JT[I].MBBs;
+
+ for (unsigned J = 0; J < MBBs.size(); ++J)
+ MBBs[J]->setAlignment(MIPS_NACL_BUNDLE_ALIGN);
+ }
+ }
+
+ // If basic block address is taken, block can be target of indirect branch.
+ for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
+ MBB != E; ++MBB) {
+ if (MBB->hasAddressTaken())
+ MBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN);
+ }
+}
+
// Force static initialization.
extern "C" void LLVMInitializeMipsAsmPrinter() {
RegisterAsmPrinter<MipsAsmPrinter> X(TheMipsTarget);
Modified: llvm/trunk/lib/Target/Mips/MipsAsmPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsAsmPrinter.h?rev=202479&r1=202478&r2=202479&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsAsmPrinter.h (original)
+++ llvm/trunk/lib/Target/Mips/MipsAsmPrinter.h Fri Feb 28 04:00:38 2014
@@ -73,6 +73,8 @@ private:
void EmitFPCallStub(const char *, const Mips16HardFloatInfo::FuncSignature *);
+ void NaClAlignIndirectJumpTargets(MachineFunction &MF);
+
public:
const MipsSubtarget *Subtarget;
Added: llvm/trunk/test/MC/Mips/nacl-align.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/Mips/nacl-align.ll?rev=202479&view=auto
==============================================================================
--- llvm/trunk/test/MC/Mips/nacl-align.ll (added)
+++ llvm/trunk/test/MC/Mips/nacl-align.ll Fri Feb 28 04:00:38 2014
@@ -0,0 +1,96 @@
+; RUN: llc -filetype=asm -mtriple=mipsel-none-nacl -relocation-model=static \
+; RUN: -O3 < %s
+
+
+; This test tests that NaCl functions are bundle-aligned.
+
+define void @test0() {
+ ret void
+
+; CHECK: .align 4
+; CHECK-NOT: .align
+; CHECK-LABEL: test0:
+
+}
+
+
+; This test tests that blocks that are jumped to through jump table are
+; bundle-aligned.
+
+define i32 @test1(i32 %i) {
+entry:
+ switch i32 %i, label %default [
+ i32 0, label %bb1
+ i32 1, label %bb2
+ i32 2, label %bb3
+ i32 3, label %bb4
+ ]
+
+bb1:
+ ret i32 111
+bb2:
+ ret i32 222
+bb3:
+ ret i32 333
+bb4:
+ ret i32 444
+default:
+ ret i32 555
+
+
+; CHECK-LABEL: test1:
+
+; CHECK: .align 4
+; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}:
+; CHECK-NEXT: jr $ra
+; CHECK-NEXT: addiu $2, $zero, 111
+; CHECK-NEXT: .align 4
+; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}:
+; CHECK-NEXT: jr $ra
+; CHECK-NEXT: addiu $2, $zero, 222
+; CHECK-NEXT: .align 4
+; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}:
+; CHECK-NEXT: jr $ra
+; CHECK-NEXT: addiu $2, $zero, 333
+; CHECK-NEXT: .align 4
+; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}:
+; CHECK-NEXT: jr $ra
+; CHECK-NEXT: addiu $2, $zero, 444
+
+}
+
+
+; This test tests that a block whose address is taken is bundle-aligned in NaCl.
+
+ at bb_array = constant [2 x i8*] [i8* blockaddress(@test2, %bb1),
+ i8* blockaddress(@test2, %bb2)], align 4
+
+define i32 @test2(i32 %i) {
+entry:
+ %elementptr = getelementptr inbounds [2 x i8*]* @bb_array, i32 0, i32 %i
+ %0 = load i8** %elementptr, align 4
+ indirectbr i8* %0, [label %bb1, label %bb2]
+
+bb1:
+ ret i32 111
+bb2:
+ ret i32 222
+
+
+; CHECK-LABEL: test2:
+
+; Note that there are two consecutive labels - one temporary and one for
+; basic block.
+
+; CHECK: .align 4
+; CHECK-NEXT: ${{[a-zA-Z0-9]+}}:
+; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}:
+; CHECK-NEXT: jr $ra
+; CHECK-NEXT: addiu $2, $zero, 111
+; CHECK-NEXT: .align 4
+; CHECK-NEXT: ${{[a-zA-Z0-9]+}}:
+; CHECK-NEXT: ${{BB[0-9]+_[0-9]+}}:
+; CHECK-NEXT: jr $ra
+; CHECK-NEXT: addiu $2, $zero, 222
+
+}
Added: llvm/trunk/test/MC/Mips/nacl-mask.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/Mips/nacl-mask.s?rev=202479&view=auto
==============================================================================
--- llvm/trunk/test/MC/Mips/nacl-mask.s (added)
+++ llvm/trunk/test/MC/Mips/nacl-mask.s Fri Feb 28 04:00:38 2014
@@ -0,0 +1,28 @@
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-nacl %s \
+# RUN: | llvm-objdump -triple mipsel -disassemble -no-show-raw-insn - \
+# RUN: | FileCheck %s
+
+# This test tests that address-masking sandboxing is added when given assembly
+# input.
+
+test1:
+ .set noreorder
+
+ jr $a0
+ nop
+ jr $ra
+ nop
+
+# CHECK-LABEL: test1:
+
+# CHECK: and $4, $4, $14
+# CHECK-NEXT: jr $4
+
+# Check that additional nop is inserted, to align mask and jr to the next
+# bundle.
+
+# CHECK-NEXT: nop
+# CHECK-NEXT: nop
+
+# CHECK: and $ra, $ra, $14
+# CHECK-NEXT: jr $ra
More information about the llvm-commits
mailing list