Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
[mips] Implement NaCl sandboxing of indirect jumps:
Browse files Browse the repository at this point in the history
  * 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


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202479 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Sasa Stankovic authored and Sasa Stankovic committed Feb 28, 2014
1 parent 72c42d9 commit 068a8c1
Show file tree
Hide file tree
Showing 8 changed files with 298 additions and 7 deletions.
8 changes: 4 additions & 4 deletions include/llvm/MC/MCELFStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,14 @@ class MCELFStreamer : public MCObjectStreamer {

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;
Expand Down
28 changes: 28 additions & 0 deletions lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h
Original file line number Diff line number Diff line change
@@ -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
11 changes: 8 additions & 3 deletions lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -109,8 +110,12 @@ static MCStreamer *createMCStreamer(const Target &T, StringRef TT,
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;
}
Expand Down
97 changes: 97 additions & 0 deletions lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp
Original file line number Diff line number Diff line change
@@ -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;
}

}
35 changes: 35 additions & 0 deletions lib/Target/Mips/MipsAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -72,6 +74,11 @@ bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
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;
}
Expand Down Expand Up @@ -270,6 +277,12 @@ const char *MipsAsmPrinter::getCurrentABIString() const {

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
Expand Down Expand Up @@ -906,6 +919,28 @@ void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
// 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);
Expand Down
2 changes: 2 additions & 0 deletions lib/Target/Mips/MipsAsmPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter {

void EmitFPCallStub(const char *, const Mips16HardFloatInfo::FuncSignature *);

void NaClAlignIndirectJumpTargets(MachineFunction &MF);

public:

const MipsSubtarget *Subtarget;
Expand Down
96 changes: 96 additions & 0 deletions test/MC/Mips/nacl-align.ll
Original file line number Diff line number Diff line change
@@ -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.

@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

}
28 changes: 28 additions & 0 deletions test/MC/Mips/nacl-mask.s
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 068a8c1

Please sign in to comment.