MS asm: Properly handle quoted symbol names
[oota-llvm.git] / lib / Target / X86 / AsmParser / X86AsmInstrumentation.cpp
1 //===-- X86AsmInstrumentation.cpp - Instrument X86 inline assembly 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 #include "MCTargetDesc/X86BaseInfo.h"
11 #include "X86AsmInstrumentation.h"
12 #include "X86Operand.h"
13 #include "llvm/ADT/StringExtras.h"
14 #include "llvm/ADT/Triple.h"
15 #include "llvm/IR/Function.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCInst.h"
18 #include "llvm/MC/MCInstBuilder.h"
19 #include "llvm/MC/MCInstrInfo.h"
20 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
21 #include "llvm/MC/MCStreamer.h"
22 #include "llvm/MC/MCSubtargetInfo.h"
23 #include "llvm/MC/MCTargetAsmParser.h"
24 #include "llvm/MC/MCTargetOptions.h"
25 #include "llvm/Support/CommandLine.h"
26
27 namespace llvm {
28 namespace {
29
30 static cl::opt<bool> ClAsanInstrumentAssembly(
31     "asan-instrument-assembly",
32     cl::desc("instrument assembly with AddressSanitizer checks"), cl::Hidden,
33     cl::init(false));
34
35 bool IsStackReg(unsigned Reg) {
36   return Reg == X86::RSP || Reg == X86::ESP || Reg == X86::SP;
37 }
38
39 std::string FuncName(unsigned AccessSize, bool IsWrite) {
40   return std::string("__sanitizer_sanitize_") + (IsWrite ? "store" : "load") +
41          (utostr(AccessSize));
42 }
43
44 class X86AddressSanitizer : public X86AsmInstrumentation {
45 public:
46   X86AddressSanitizer(const MCSubtargetInfo &STI) : STI(STI) {}
47   virtual ~X86AddressSanitizer() {}
48
49   // X86AsmInstrumentation implementation:
50   virtual void InstrumentInstruction(const MCInst &Inst,
51                                      OperandVector &Operands, MCContext &Ctx,
52                                      const MCInstrInfo &MII,
53                                      MCStreamer &Out) override {
54     InstrumentMOV(Inst, Operands, Ctx, MII, Out);
55   }
56
57   // Should be implemented differently in x86_32 and x86_64 subclasses.
58   virtual void InstrumentMemOperandImpl(X86Operand &Op, unsigned AccessSize,
59                                         bool IsWrite, MCContext &Ctx,
60                                         MCStreamer &Out) = 0;
61
62   void InstrumentMemOperand(MCParsedAsmOperand &Op, unsigned AccessSize,
63                             bool IsWrite, MCContext &Ctx, MCStreamer &Out);
64   void InstrumentMOV(const MCInst &Inst, OperandVector &Operands,
65                      MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
66   void EmitInstruction(MCStreamer &Out, const MCInst &Inst) {
67     Out.EmitInstruction(Inst, STI);
68   }
69
70 protected:
71   const MCSubtargetInfo &STI;
72 };
73
74 void X86AddressSanitizer::InstrumentMemOperand(MCParsedAsmOperand &Op,
75                                                unsigned AccessSize,
76                                                bool IsWrite, MCContext &Ctx,
77                                                MCStreamer &Out) {
78   assert(Op.isMem() && "Op should be a memory operand.");
79   assert((AccessSize & (AccessSize - 1)) == 0 && AccessSize <= 16 &&
80          "AccessSize should be a power of two, less or equal than 16.");
81
82   X86Operand &MemOp = static_cast<X86Operand &>(Op);
83   // FIXME: get rid of this limitation.
84   if (IsStackReg(MemOp.getMemBaseReg()) || IsStackReg(MemOp.getMemIndexReg()))
85     return;
86
87   InstrumentMemOperandImpl(MemOp, AccessSize, IsWrite, Ctx, Out);
88 }
89
90 void X86AddressSanitizer::InstrumentMOV(const MCInst &Inst,
91                                         OperandVector &Operands, MCContext &Ctx,
92                                         const MCInstrInfo &MII,
93                                         MCStreamer &Out) {
94   // Access size in bytes.
95   unsigned AccessSize = 0;
96
97   switch (Inst.getOpcode()) {
98   case X86::MOV8mi:
99   case X86::MOV8mr:
100   case X86::MOV8rm:
101     AccessSize = 1;
102     break;
103   case X86::MOV16mi:
104   case X86::MOV16mr:
105   case X86::MOV16rm:
106     AccessSize = 2;
107     break;
108   case X86::MOV32mi:
109   case X86::MOV32mr:
110   case X86::MOV32rm:
111     AccessSize = 4;
112     break;
113   case X86::MOV64mi32:
114   case X86::MOV64mr:
115   case X86::MOV64rm:
116     AccessSize = 8;
117     break;
118   case X86::MOVAPDmr:
119   case X86::MOVAPSmr:
120   case X86::MOVAPDrm:
121   case X86::MOVAPSrm:
122     AccessSize = 16;
123     break;
124   default:
125     return;
126   }
127
128   const bool IsWrite = MII.get(Inst.getOpcode()).mayStore();
129   for (unsigned Ix = 0; Ix < Operands.size(); ++Ix) {
130     assert(Operands[Ix]);
131     MCParsedAsmOperand &Op = *Operands[Ix];
132     if (Op.isMem())
133       InstrumentMemOperand(Op, AccessSize, IsWrite, Ctx, Out);
134   }
135 }
136
137 class X86AddressSanitizer32 : public X86AddressSanitizer {
138 public:
139   X86AddressSanitizer32(const MCSubtargetInfo &STI)
140       : X86AddressSanitizer(STI) {}
141   virtual ~X86AddressSanitizer32() {}
142
143   virtual void InstrumentMemOperandImpl(X86Operand &Op, unsigned AccessSize,
144                                         bool IsWrite, MCContext &Ctx,
145                                         MCStreamer &Out) override;
146 };
147
148 void X86AddressSanitizer32::InstrumentMemOperandImpl(X86Operand &Op,
149                                                      unsigned AccessSize,
150                                                      bool IsWrite,
151                                                      MCContext &Ctx,
152                                                      MCStreamer &Out) {
153   // FIXME: emit .cfi directives for correct stack unwinding.
154   EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
155   {
156     MCInst Inst;
157     Inst.setOpcode(X86::LEA32r);
158     Inst.addOperand(MCOperand::CreateReg(X86::EAX));
159     Op.addMemOperands(Inst, 5);
160     EmitInstruction(Out, Inst);
161   }
162   EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
163   {
164     const std::string Func = FuncName(AccessSize, IsWrite);
165     const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
166     const MCSymbolRefExpr *FuncExpr =
167         MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
168     EmitInstruction(Out, MCInstBuilder(X86::CALLpcrel32).addExpr(FuncExpr));
169   }
170   EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EAX));
171   EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EAX));
172 }
173
174 class X86AddressSanitizer64 : public X86AddressSanitizer {
175 public:
176   X86AddressSanitizer64(const MCSubtargetInfo &STI)
177       : X86AddressSanitizer(STI) {}
178   virtual ~X86AddressSanitizer64() {}
179
180   virtual void InstrumentMemOperandImpl(X86Operand &Op, unsigned AccessSize,
181                                         bool IsWrite, MCContext &Ctx,
182                                         MCStreamer &Out) override;
183 };
184
185 void X86AddressSanitizer64::InstrumentMemOperandImpl(X86Operand &Op,
186                                                      unsigned AccessSize,
187                                                      bool IsWrite,
188                                                      MCContext &Ctx,
189                                                      MCStreamer &Out) {
190   // FIXME: emit .cfi directives for correct stack unwinding.
191
192   // Set %rsp below current red zone (128 bytes wide) using LEA instruction to
193   // preserve flags.
194   {
195     MCInst Inst;
196     Inst.setOpcode(X86::LEA64r);
197     Inst.addOperand(MCOperand::CreateReg(X86::RSP));
198
199     const MCExpr *Disp = MCConstantExpr::Create(-128, Ctx);
200     std::unique_ptr<X86Operand> Op(
201         X86Operand::CreateMem(0, Disp, X86::RSP, 0, 1, SMLoc(), SMLoc()));
202     Op->addMemOperands(Inst, 5);
203     EmitInstruction(Out, Inst);
204   }
205   EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(X86::RDI));
206   {
207     MCInst Inst;
208     Inst.setOpcode(X86::LEA64r);
209     Inst.addOperand(MCOperand::CreateReg(X86::RDI));
210     Op.addMemOperands(Inst, 5);
211     EmitInstruction(Out, Inst);
212   }
213   {
214     const std::string Func = FuncName(AccessSize, IsWrite);
215     const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
216     const MCSymbolRefExpr *FuncExpr =
217         MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
218     EmitInstruction(Out, MCInstBuilder(X86::CALL64pcrel32).addExpr(FuncExpr));
219   }
220   EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(X86::RDI));
221
222   // Restore old %rsp value.
223   {
224     MCInst Inst;
225     Inst.setOpcode(X86::LEA64r);
226     Inst.addOperand(MCOperand::CreateReg(X86::RSP));
227
228     const MCExpr *Disp = MCConstantExpr::Create(128, Ctx);
229     std::unique_ptr<X86Operand> Op(
230         X86Operand::CreateMem(0, Disp, X86::RSP, 0, 1, SMLoc(), SMLoc()));
231     Op->addMemOperands(Inst, 5);
232     EmitInstruction(Out, Inst);
233   }
234 }
235
236 } // End anonymous namespace
237
238 X86AsmInstrumentation::X86AsmInstrumentation() {}
239 X86AsmInstrumentation::~X86AsmInstrumentation() {}
240
241 void X86AsmInstrumentation::InstrumentInstruction(const MCInst &Inst,
242                                                   OperandVector &Operands,
243                                                   MCContext &Ctx,
244                                                   const MCInstrInfo &MII,
245                                                   MCStreamer &Out) {}
246
247 X86AsmInstrumentation *
248 CreateX86AsmInstrumentation(const MCTargetOptions &MCOptions,
249                             const MCContext &Ctx, const MCSubtargetInfo &STI) {
250   Triple T(STI.getTargetTriple());
251   const bool hasCompilerRTSupport = T.isOSLinux();
252   if (ClAsanInstrumentAssembly && hasCompilerRTSupport &&
253       MCOptions.SanitizeAddress) {
254     if ((STI.getFeatureBits() & X86::Mode32Bit) != 0)
255       return new X86AddressSanitizer32(STI);
256     if ((STI.getFeatureBits() & X86::Mode64Bit) != 0)
257       return new X86AddressSanitizer64(STI);
258   }
259   return new X86AsmInstrumentation();
260 }
261
262 } // End llvm namespace