Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 754aaee

Browse files
Sasa StankovicSasa Stankovic
authored andcommitted
[mips] Implement NaCl sandboxing of loads, stores and SP changes:
* Add masking instructions before loads and stores (in MC layer). * Add masking instructions after SP changes (in MC layer). * Forbid loads, stores and SP changes in delay slots (in MI layer). Differential Revision: http://llvm-reviews.chandlerc.com/D2904 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@203484 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent c32c110 commit 754aaee

File tree

5 files changed

+385
-5
lines changed

5 files changed

+385
-5
lines changed

lib/Target/Mips/MCTargetDesc/MipsMCNaCl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ namespace llvm {
1717
// Log2 of the NaCl MIPS sandbox's instruction bundle size.
1818
static const unsigned MIPS_NACL_BUNDLE_ALIGN = 4u;
1919

20+
bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx,
21+
bool *IsStore = NULL);
22+
bool baseRegNeedsLoadStoreMask(unsigned Reg);
23+
2024
// This function creates an MCELFStreamer for Mips NaCl.
2125
MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
2226
raw_ostream &OS,

lib/Target/Mips/MCTargetDesc/MipsNaClELFStreamer.cpp

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
//
1010
// This file implements MCELFStreamer for Mips NaCl. It emits .o object files
1111
// as required by NaCl's SFI sandbox. It inserts address-masking instructions
12-
// before dangerous control-flow instructions. It aligns on bundle size all
13-
// functions and all targets of indirect branches.
12+
// before dangerous control-flow and memory access instructions. It inserts
13+
// address-masking instructions after instructions that change the stack
14+
// pointer. It ensures that the mask and the dangerous instruction are always
15+
// emitted in the same bundle.
1416
//
1517
//===----------------------------------------------------------------------===//
1618

@@ -25,6 +27,7 @@ using namespace llvm;
2527
namespace {
2628

2729
const unsigned IndirectBranchMaskReg = Mips::T6;
30+
const unsigned LoadStoreStackMaskReg = Mips::T7;
2831

2932
/// Extend the generic MCELFStreamer class so that it can mask dangerous
3033
/// instructions.
@@ -42,6 +45,11 @@ class MipsNaClELFStreamer : public MCELFStreamer {
4245
return MI.getOpcode() == Mips::JR || MI.getOpcode() == Mips::RET;
4346
}
4447

48+
bool isStackPointerFirstOperand(const MCInst &MI) {
49+
return (MI.getNumOperands() > 0 && MI.getOperand(0).isReg()
50+
&& MI.getOperand(0).getReg() == Mips::SP);
51+
}
52+
4553
void emitMask(unsigned AddrReg, unsigned MaskReg,
4654
const MCSubtargetInfo &STI) {
4755
MCInst MaskInst;
@@ -63,21 +71,114 @@ class MipsNaClELFStreamer : public MCELFStreamer {
6371
EmitBundleUnlock();
6472
}
6573

74+
// Sandbox memory access or SP change. Insert mask operation before and/or
75+
// after the instruction.
76+
void sandboxLoadStoreStackChange(const MCInst &MI, unsigned AddrIdx,
77+
const MCSubtargetInfo &STI, bool MaskBefore,
78+
bool MaskAfter) {
79+
EmitBundleLock(false);
80+
if (MaskBefore) {
81+
// Sandbox memory access.
82+
unsigned BaseReg = MI.getOperand(AddrIdx).getReg();
83+
emitMask(BaseReg, LoadStoreStackMaskReg, STI);
84+
}
85+
MCELFStreamer::EmitInstruction(MI, STI);
86+
if (MaskAfter) {
87+
// Sandbox SP change.
88+
unsigned SPReg = MI.getOperand(0).getReg();
89+
assert((Mips::SP == SPReg) && "Unexpected stack-pointer register.");
90+
emitMask(SPReg, LoadStoreStackMaskReg, STI);
91+
}
92+
EmitBundleUnlock();
93+
}
94+
6695
public:
6796
/// This function is the one used to emit instruction data into the ELF
6897
/// streamer. We override it to mask dangerous instructions.
6998
virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) {
70-
if (isIndirectJump(Inst))
99+
// Sandbox indirect jumps.
100+
if (isIndirectJump(Inst)) {
71101
sandboxIndirectJump(Inst, STI);
72-
else
73-
MCELFStreamer::EmitInstruction(Inst, STI);
102+
return;
103+
}
104+
105+
// Sandbox loads, stores and SP changes.
106+
unsigned AddrIdx;
107+
bool IsStore;
108+
bool IsMemAccess = isBasePlusOffsetMemoryAccess(Inst.getOpcode(), &AddrIdx,
109+
&IsStore);
110+
bool IsSPFirstOperand = isStackPointerFirstOperand(Inst);
111+
if (IsMemAccess || IsSPFirstOperand) {
112+
bool MaskBefore = (IsMemAccess
113+
&& baseRegNeedsLoadStoreMask(Inst.getOperand(AddrIdx)
114+
.getReg()));
115+
bool MaskAfter = IsSPFirstOperand && !IsStore;
116+
if (MaskBefore || MaskAfter)
117+
sandboxLoadStoreStackChange(Inst, AddrIdx, STI, MaskBefore, MaskAfter);
118+
else
119+
MCELFStreamer::EmitInstruction(Inst, STI);
120+
return;
121+
}
122+
123+
// None of the sandboxing applies, just emit the instruction.
124+
MCELFStreamer::EmitInstruction(Inst, STI);
74125
}
75126
};
76127

77128
} // end anonymous namespace
78129

79130
namespace llvm {
80131

132+
bool isBasePlusOffsetMemoryAccess(unsigned Opcode, unsigned *AddrIdx,
133+
bool *IsStore) {
134+
if (IsStore)
135+
*IsStore = false;
136+
137+
switch (Opcode) {
138+
default:
139+
return false;
140+
141+
// Load instructions with base address register in position 1.
142+
case Mips::LB:
143+
case Mips::LBu:
144+
case Mips::LH:
145+
case Mips::LHu:
146+
case Mips::LW:
147+
case Mips::LWC1:
148+
case Mips::LDC1:
149+
case Mips::LL:
150+
case Mips::LWL:
151+
case Mips::LWR:
152+
*AddrIdx = 1;
153+
return true;
154+
155+
// Store instructions with base address register in position 1.
156+
case Mips::SB:
157+
case Mips::SH:
158+
case Mips::SW:
159+
case Mips::SWC1:
160+
case Mips::SDC1:
161+
case Mips::SWL:
162+
case Mips::SWR:
163+
*AddrIdx = 1;
164+
if (IsStore)
165+
*IsStore = true;
166+
return true;
167+
168+
// Store instructions with base address register in position 2.
169+
case Mips::SC:
170+
*AddrIdx = 2;
171+
if (IsStore)
172+
*IsStore = true;
173+
return true;
174+
}
175+
}
176+
177+
bool baseRegNeedsLoadStoreMask(unsigned Reg) {
178+
// The contents of SP and thread pointer register do not require masking.
179+
return Reg != Mips::SP && Reg != Mips::T8;
180+
}
181+
81182
MCELFStreamer *createMipsNaClELFStreamer(MCContext &Context, MCAsmBackend &TAB,
82183
raw_ostream &OS,
83184
MCCodeEmitter *Emitter, bool RelaxAll,

lib/Target/Mips/MipsDelaySlotFiller.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#define DEBUG_TYPE "delay-slot-filler"
1515

16+
#include "MCTargetDesc/MipsMCNaCl.h"
1617
#include "Mips.h"
1718
#include "MipsInstrInfo.h"
1819
#include "MipsTargetMachine.h"
@@ -531,6 +532,18 @@ bool Filler::searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End,
531532
if (delayHasHazard(*I, RegDU, IM))
532533
continue;
533534

535+
if (TM.getSubtarget<MipsSubtarget>().isTargetNaCl()) {
536+
// In NaCl, instructions that must be masked are forbidden in delay slots.
537+
// We only check for loads, stores and SP changes. Calls, returns and
538+
// branches are not checked because non-NaCl targets never put them in
539+
// delay slots.
540+
unsigned AddrIdx;
541+
if ((isBasePlusOffsetMemoryAccess(I->getOpcode(), &AddrIdx)
542+
&& baseRegNeedsLoadStoreMask(I->getOperand(AddrIdx).getReg()))
543+
|| I->modifiesRegister(Mips::SP, TM.getRegisterInfo()))
544+
continue;
545+
}
546+
534547
Filler = I;
535548
return true;
536549
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
; RUN: llc -filetype=asm -mtriple=mipsel-none-linux -relocation-model=static \
2+
; RUN: -O3 < %s | FileCheck %s
3+
4+
; RUN: llc -filetype=asm -mtriple=mipsel-none-nacl -relocation-model=static \
5+
; RUN: -O3 < %s | FileCheck %s -check-prefix=CHECK-NACL
6+
7+
@x = global i32 0, align 4
8+
declare void @f1(i32)
9+
declare void @f2()
10+
11+
12+
define void @test1() {
13+
%1 = load i32* @x, align 4
14+
call void @f1(i32 %1)
15+
ret void
16+
17+
18+
; CHECK-LABEL: test1
19+
20+
; We first make sure that for non-NaCl targets branch-delay slot contains
21+
; dangerous instructions.
22+
23+
; Check that branch-delay slot is used to load argument from x before function
24+
; call.
25+
26+
; CHECK: jal
27+
; CHECK-NEXT: lw $4, %lo(x)(${{[0-9]+}})
28+
29+
; Check that branch-delay slot is used for adjusting sp before return.
30+
31+
; CHECK: jr $ra
32+
; CHECK-NEXT: addiu $sp, $sp, {{[0-9]+}}
33+
34+
35+
; For NaCl, check that branch-delay slot doesn't contain dangerous instructions.
36+
37+
; CHECK-NACL: jal
38+
; CHECK-NACL-NEXT: nop
39+
40+
; CHECK-NACL: jr $ra
41+
; CHECK-NACL-NEXT: nop
42+
}
43+
44+
45+
define void @test2() {
46+
store i32 1, i32* @x, align 4
47+
tail call void @f2()
48+
ret void
49+
50+
51+
; CHECK-LABEL: test2
52+
53+
; Check that branch-delay slot is used for storing to x before function call.
54+
55+
; CHECK: jal
56+
; CHECK-NEXT: sw ${{[0-9]+}}, %lo(x)(${{[0-9]+}})
57+
58+
; Check that branch-delay slot is used for adjusting sp before return.
59+
60+
; CHECK: jr $ra
61+
; CHECK-NEXT: addiu $sp, $sp, {{[0-9]+}}
62+
63+
64+
; For NaCl, check that branch-delay slot doesn't contain dangerous instructions.
65+
66+
; CHECK-NACL: jal
67+
; CHECK-NACL-NEXT: nop
68+
69+
; CHECK-NACL: jr $ra
70+
; CHECK-NACL-NEXT: nop
71+
}

0 commit comments

Comments
 (0)