OLD | NEW |
(Empty) | |
| 1 //=== ARMMCNaCl.cpp - Expansion of NaCl pseudo-instructions --*- C++ -*-=// |
| 2 // |
| 3 // The LLVM Compiler Infrastructure |
| 4 // |
| 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. |
| 7 // |
| 8 //===----------------------------------------------------------------------===// |
| 9 // |
| 10 //===----------------------------------------------------------------------===// |
| 11 #define DEBUG_TYPE "arm-mc-nacl" |
| 12 |
| 13 #include "MCTargetDesc/ARMBaseInfo.h" |
| 14 #include "MCTargetDesc/ARMMCExpr.h" |
| 15 #include "MCTargetDesc/ARMMCNaCl.h" |
| 16 #include "MCTargetDesc/ARMMCTargetDesc.h" |
| 17 #include "llvm/MC/MCInst.h" |
| 18 #include "llvm/MC/MCStreamer.h" |
| 19 #include "llvm/Support/CommandLine.h" |
| 20 #include "llvm/Support/Debug.h" |
| 21 |
| 22 using namespace llvm; |
| 23 |
| 24 /// Two helper functions for emitting the actual guard instructions |
| 25 |
| 26 static void EmitBICMask(const MCSubtargetInfo &STI, MCStreamer &Out, |
| 27 unsigned Addr, int64_t Pred, unsigned Mask) { |
| 28 // bic\Pred \Addr, \Addr, #Mask |
| 29 MCInst BICInst; |
| 30 BICInst.setOpcode(ARM::BICri); |
| 31 BICInst.addOperand(MCOperand::CreateReg(Addr)); // rD |
| 32 BICInst.addOperand(MCOperand::CreateReg(Addr)); // rS |
| 33 BICInst.addOperand(MCOperand::CreateImm(Mask)); // imm |
| 34 BICInst.addOperand(MCOperand::CreateImm(Pred)); // predicate |
| 35 BICInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); // CPSR |
| 36 BICInst.addOperand(MCOperand::CreateReg(0)); // flag out |
| 37 Out.EmitInstruction(BICInst, STI); |
| 38 } |
| 39 |
| 40 static void EmitTST(const MCSubtargetInfo &STI, MCStreamer &Out, unsigned Reg) { |
| 41 // tst \reg, #\MASK typically 0xc0000000 |
| 42 const unsigned Mask = 0xC0000000; |
| 43 MCInst TSTInst; |
| 44 TSTInst.setOpcode(ARM::TSTri); |
| 45 TSTInst.addOperand(MCOperand::CreateReg(Reg)); // rS |
| 46 TSTInst.addOperand(MCOperand::CreateImm(Mask)); // imm |
| 47 TSTInst.addOperand(MCOperand::CreateImm((int64_t)ARMCC::AL)); // Always |
| 48 TSTInst.addOperand(MCOperand::CreateImm(0)); // flag out |
| 49 Out.EmitInstruction(TSTInst, STI); |
| 50 } |
| 51 |
| 52 |
| 53 // This is ONLY used for sandboxing stack changes. |
| 54 // The reason why SFI_NOP_IF_AT_BUNDLE_END gets handled here is that |
| 55 // it must ensure that the two instructions are in the same bundle. |
| 56 // It just so happens that the SFI_NOP_IF_AT_BUNDLE_END is always |
| 57 // emitted in conjunction with a SFI_DATA_MASK |
| 58 // |
| 59 static void EmitDataMask(const MCSubtargetInfo &STI, int I, MCInst Saved[], |
| 60 MCStreamer &Out) { |
| 61 assert(I == 3 && (ARM::SFI_NOP_IF_AT_BUNDLE_END == Saved[0].getOpcode()) && |
| 62 (ARM::SFI_DATA_MASK == Saved[2].getOpcode()) && |
| 63 "Unexpected SFI Pseudo while lowering"); |
| 64 |
| 65 unsigned Addr = Saved[2].getOperand(0).getReg(); |
| 66 int64_t Pred = Saved[2].getOperand(2).getImm(); |
| 67 assert((ARM::SP == Addr) && "Unexpected register at stack guard"); |
| 68 |
| 69 Out.EmitBundleLock(false); |
| 70 Out.EmitInstruction(Saved[1], STI); |
| 71 EmitBICMask(STI, Out, Addr, Pred, 0xC0000000); |
| 72 Out.EmitBundleUnlock(); |
| 73 } |
| 74 |
| 75 static void EmitDirectGuardCall(const MCSubtargetInfo &STI, int I, |
| 76 MCInst Saved[], MCStreamer &Out) { |
| 77 // sfi_call_preamble cond= |
| 78 // sfi_nops_to_force_slot3 |
| 79 assert(I == 2 && (ARM::SFI_GUARD_CALL == Saved[0].getOpcode()) && |
| 80 "Unexpected SFI Pseudo while lowering SFI_GUARD_CALL"); |
| 81 Out.EmitBundleLock(true); |
| 82 Out.EmitInstruction(Saved[1], STI); |
| 83 Out.EmitBundleUnlock(); |
| 84 } |
| 85 |
| 86 static void EmitIndirectGuardCall(const MCSubtargetInfo &STI, int I, |
| 87 MCInst Saved[], MCStreamer &Out) { |
| 88 // sfi_indirect_call_preamble link cond= |
| 89 // sfi_nops_to_force_slot2 |
| 90 // sfi_code_mask \link \cond |
| 91 assert(I == 2 && (ARM::SFI_GUARD_INDIRECT_CALL == Saved[0].getOpcode()) && |
| 92 "Unexpected SFI Pseudo while lowering SFI_GUARD_CALL"); |
| 93 unsigned Reg = Saved[0].getOperand(0).getReg(); |
| 94 int64_t Pred = Saved[0].getOperand(2).getImm(); |
| 95 Out.EmitBundleLock(true); |
| 96 EmitBICMask(STI, Out, Reg, Pred, 0xC000000F); |
| 97 Out.EmitInstruction(Saved[1], STI); |
| 98 Out.EmitBundleUnlock(); |
| 99 } |
| 100 |
| 101 static void EmitIndirectGuardJmp(const MCSubtargetInfo &STI, int I, |
| 102 MCInst Saved[], MCStreamer &Out) { |
| 103 // sfi_indirect_jump_preamble link cond= |
| 104 // sfi_nop_if_at_bundle_end |
| 105 // sfi_code_mask \link \cond |
| 106 assert(I == 2 && (ARM::SFI_GUARD_INDIRECT_JMP == Saved[0].getOpcode()) && |
| 107 "Unexpected SFI Pseudo while lowering SFI_GUARD_CALL"); |
| 108 unsigned Reg = Saved[0].getOperand(0).getReg(); |
| 109 int64_t Pred = Saved[0].getOperand(2).getImm(); |
| 110 |
| 111 Out.EmitBundleLock(false); |
| 112 EmitBICMask(STI, Out, Reg, Pred, 0xC000000F); |
| 113 Out.EmitInstruction(Saved[1], STI); |
| 114 Out.EmitBundleUnlock(); |
| 115 } |
| 116 |
| 117 static void EmitGuardReturn(const MCSubtargetInfo &STI, int I, MCInst Saved[], |
| 118 MCStreamer &Out) { |
| 119 // sfi_return_preamble reg cond= |
| 120 // sfi_nop_if_at_bundle_end |
| 121 // sfi_code_mask \reg \cond |
| 122 assert(I == 2 && (ARM::SFI_GUARD_RETURN == Saved[0].getOpcode()) && |
| 123 "Unexpected SFI Pseudo while lowering SFI_GUARD_RETURN"); |
| 124 int64_t Pred = Saved[0].getOperand(0).getImm(); |
| 125 |
| 126 Out.EmitBundleLock(false); |
| 127 EmitBICMask(STI, Out, ARM::LR, Pred, 0xC000000F); |
| 128 Out.EmitInstruction(Saved[1], STI); |
| 129 Out.EmitBundleUnlock(); |
| 130 } |
| 131 |
| 132 static void EmitGuardLoadOrStore(const MCSubtargetInfo &STI, int I, |
| 133 MCInst Saved[], MCStreamer &Out) { |
| 134 // sfi_store_preamble reg cond ----> |
| 135 // sfi_nop_if_at_bundle_end |
| 136 // sfi_data_mask \reg, \cond |
| 137 assert(I == 2 && (ARM::SFI_GUARD_LOADSTORE == Saved[0].getOpcode()) && |
| 138 "Unexpected SFI Pseudo while lowering SFI_GUARD_RETURN"); |
| 139 unsigned Reg = Saved[0].getOperand(0).getReg(); |
| 140 int64_t Pred = Saved[0].getOperand(2).getImm(); |
| 141 |
| 142 Out.EmitBundleLock(false); |
| 143 EmitBICMask(STI, Out, Reg, Pred, 0xC0000000); |
| 144 Out.EmitInstruction(Saved[1], STI); |
| 145 Out.EmitBundleUnlock(); |
| 146 } |
| 147 |
| 148 static void EmitGuardLoadOrStoreTst(const MCSubtargetInfo &STI, int I, |
| 149 MCInst Saved[], MCStreamer &Out) { |
| 150 // sfi_cstore_preamble reg --> |
| 151 // sfi_nop_if_at_bundle_end |
| 152 // sfi_data_tst \reg |
| 153 assert(I == 2 && (ARM::SFI_GUARD_LOADSTORE_TST == Saved[0].getOpcode()) && |
| 154 "Unexpected SFI Pseudo while lowering"); |
| 155 unsigned Reg = Saved[0].getOperand(0).getReg(); |
| 156 |
| 157 Out.EmitBundleLock(false); |
| 158 EmitTST(STI, Out, Reg); |
| 159 Out.EmitInstruction(Saved[1], STI); |
| 160 Out.EmitBundleUnlock(); |
| 161 } |
| 162 |
| 163 // This is ONLY used for loads into the stack pointer. |
| 164 static void EmitGuardSpLoad(const MCSubtargetInfo &STI, int I, MCInst Saved[], |
| 165 MCStreamer &Out) { |
| 166 assert(I == 4 && |
| 167 (ARM::SFI_GUARD_SP_LOAD == Saved[0].getOpcode()) && |
| 168 (ARM::SFI_NOP_IF_AT_BUNDLE_END == Saved[1].getOpcode()) && |
| 169 (ARM::SFI_DATA_MASK == Saved[3].getOpcode()) && |
| 170 "Unexpected SFI Pseudo while lowering"); |
| 171 |
| 172 unsigned AddrReg = Saved[0].getOperand(0).getReg(); |
| 173 unsigned SpReg = Saved[3].getOperand(0).getReg(); |
| 174 int64_t Pred = Saved[3].getOperand(2).getImm(); |
| 175 assert((ARM::SP == SpReg) && "Unexpected register at stack guard"); |
| 176 |
| 177 Out.EmitBundleLock(false); |
| 178 EmitBICMask(STI, Out, AddrReg, Pred, 0xC0000000); |
| 179 Out.EmitInstruction(Saved[2], STI); |
| 180 EmitBICMask(STI, Out, SpReg, Pred, 0xC0000000); |
| 181 Out.EmitBundleUnlock(); |
| 182 } |
| 183 |
| 184 namespace llvm { |
| 185 |
| 186 const int ARMMCNaClSFIState::MaxSaved; |
| 187 |
| 188 // CustomExpandInstNaClARM - |
| 189 // If Inst is a NaCl pseudo instruction, emits the substitute |
| 190 // expansion to the MCStreamer and returns true. |
| 191 // Otherwise, returns false. |
| 192 // |
| 193 // NOTE: Each time this function calls Out.EmitInstruction(), it will be |
| 194 // called again recursively to rewrite the new instruction being emitted. |
| 195 // Care must be taken to ensure that this does not result in an infinite |
| 196 // loop. Also, global state must be managed carefully so that it is |
| 197 // consistent during recursive calls. |
| 198 bool CustomExpandInstNaClARM(const MCSubtargetInfo &STI, const MCInst &Inst, |
| 199 MCStreamer &Out, ARMMCNaClSFIState &State) { |
| 200 // Logic: |
| 201 // This is somewhat convoluted, but in the current model, the SFI |
| 202 // guard pseudo instructions occur PRIOR to the actual instruction. |
| 203 // So, the bundling/alignment operation has to refer to the FOLLOWING |
| 204 // instructions. |
| 205 // |
| 206 // When a SFI pseudo is detected, it is saved. Then, the saved SFI |
| 207 // pseudo and the very next instructions (their amount depending on the kind |
| 208 // of the SFI pseudo) are used as arguments to the Emit*() functions in |
| 209 // this file. |
| 210 // |
| 211 // Some state data is used to preserve state accross calls: |
| 212 // |
| 213 // Saved: the saved instructions (starting with the SFI_ pseudo). |
| 214 // SavedCount: the amount of saved instructions required for the SFI pseudo |
| 215 // that's being expanded. |
| 216 // I: the index of the currently saved instruction - used to track |
| 217 // where in Saved to insert the instruction and how many more |
| 218 // remain. |
| 219 // |
| 220 |
| 221 // If we are emitting to .s, just emit all pseudo-instructions directly. |
| 222 if (Out.hasRawTextSupport()) { |
| 223 return false; |
| 224 } |
| 225 |
| 226 // Protect against recursive execution. If State.RecurseiveCall == true, it |
| 227 // means we're already in the process of expanding a custom instruction, and |
| 228 // we don't need to run recursively on anything generated by such an |
| 229 // expansion. |
| 230 if (State.RecursiveCall) |
| 231 return false; |
| 232 |
| 233 DEBUG(dbgs() << "CustomExpandInstNaClARM("; Inst.dump(); dbgs() << ")\n"); |
| 234 |
| 235 if ((State.I == 0) && (State.SaveCount == 0)) { |
| 236 // Base state: no SFI guard identified yet and no saving started. |
| 237 switch (Inst.getOpcode()) { |
| 238 default: |
| 239 // We don't handle non-SFI guards here |
| 240 return false; |
| 241 case ARM::SFI_NOP_IF_AT_BUNDLE_END: |
| 242 // Note: SFI_NOP_IF_AT_BUNDLE_END is only emitted directly as part of |
| 243 // a stack guard in conjunction with a SFI_DATA_MASK. |
| 244 State.SaveCount = 3; |
| 245 break; |
| 246 case ARM::SFI_DATA_MASK: |
| 247 llvm_unreachable( |
| 248 "SFI_DATA_MASK found without preceding SFI_NOP_IF_AT_BUNDLE_END"); |
| 249 return false; |
| 250 case ARM::SFI_GUARD_CALL: |
| 251 case ARM::SFI_GUARD_INDIRECT_CALL: |
| 252 case ARM::SFI_GUARD_INDIRECT_JMP: |
| 253 case ARM::SFI_GUARD_RETURN: |
| 254 case ARM::SFI_GUARD_LOADSTORE: |
| 255 case ARM::SFI_GUARD_LOADSTORE_TST: |
| 256 State.SaveCount = 2; |
| 257 break; |
| 258 case ARM::SFI_GUARD_SP_LOAD: |
| 259 State.SaveCount = 4; |
| 260 break; |
| 261 } |
| 262 } |
| 263 |
| 264 // We're in "saving instructions" state |
| 265 if (State.I < State.SaveCount) { |
| 266 // This instruction has to be saved |
| 267 assert(State.I < State.MaxSaved && "Trying to save too many instructions"); |
| 268 State.Saved[State.I++] = Inst; |
| 269 if (State.I < State.SaveCount) |
| 270 return true; |
| 271 } |
| 272 |
| 273 // We're in "saved enough instructions, time to emit" state |
| 274 assert(State.I == State.SaveCount && State.SaveCount > 0 && "Bookeeping Error"
); |
| 275 |
| 276 // When calling Emit* functions, do that with RecurseGuard set (the comment |
| 277 // at the beginning of this function explains why) |
| 278 State.RecursiveCall = true; |
| 279 switch (State.Saved[0].getOpcode()) { |
| 280 default: |
| 281 break; |
| 282 case ARM::SFI_NOP_IF_AT_BUNDLE_END: |
| 283 EmitDataMask(STI, State.I, State.Saved, Out); |
| 284 break; |
| 285 case ARM::SFI_DATA_MASK: |
| 286 llvm_unreachable("SFI_DATA_MASK can't start a SFI sequence"); |
| 287 break; |
| 288 case ARM::SFI_GUARD_CALL: |
| 289 EmitDirectGuardCall(STI, State.I, State.Saved, Out); |
| 290 break; |
| 291 case ARM::SFI_GUARD_INDIRECT_CALL: |
| 292 EmitIndirectGuardCall(STI, State.I, State.Saved, Out); |
| 293 break; |
| 294 case ARM::SFI_GUARD_INDIRECT_JMP: |
| 295 EmitIndirectGuardJmp(STI, State.I, State.Saved, Out); |
| 296 break; |
| 297 case ARM::SFI_GUARD_RETURN: |
| 298 EmitGuardReturn(STI, State.I, State.Saved, Out); |
| 299 break; |
| 300 case ARM::SFI_GUARD_LOADSTORE: |
| 301 EmitGuardLoadOrStore(STI, State.I, State.Saved, Out); |
| 302 break; |
| 303 case ARM::SFI_GUARD_LOADSTORE_TST: |
| 304 EmitGuardLoadOrStoreTst(STI, State.I, State.Saved, Out); |
| 305 break; |
| 306 case ARM::SFI_GUARD_SP_LOAD: |
| 307 EmitGuardSpLoad(STI, State.I, State.Saved, Out); |
| 308 break; |
| 309 } |
| 310 assert(State.RecursiveCall && "Illegal Depth"); |
| 311 State.RecursiveCall = false; |
| 312 |
| 313 // We're done expanding a SFI guard. Reset state vars. |
| 314 State.SaveCount = 0; |
| 315 State.I = 0; |
| 316 return true; |
| 317 } |
| 318 |
| 319 } // namespace llvm |
OLD | NEW |