X86AsmInstrumentation.cpp revision 280031
1274955Ssvnmir//===-- X86AsmInstrumentation.cpp - Instrument X86 inline assembly C++ -*-===//
2274955Ssvnmir//
3274955Ssvnmir//                     The LLVM Compiler Infrastructure
4274955Ssvnmir//
5274955Ssvnmir// This file is distributed under the University of Illinois Open Source
6274955Ssvnmir// License. See LICENSE.TXT for details.
7274955Ssvnmir//
8274955Ssvnmir//===----------------------------------------------------------------------===//
9274955Ssvnmir
10274955Ssvnmir#include "MCTargetDesc/X86BaseInfo.h"
11274955Ssvnmir#include "X86AsmInstrumentation.h"
12274955Ssvnmir#include "X86Operand.h"
13280031Sdim#include "X86RegisterInfo.h"
14274955Ssvnmir#include "llvm/ADT/StringExtras.h"
15274955Ssvnmir#include "llvm/ADT/Triple.h"
16280031Sdim#include "llvm/CodeGen/MachineValueType.h"
17274955Ssvnmir#include "llvm/IR/Function.h"
18280031Sdim#include "llvm/MC/MCAsmInfo.h"
19274955Ssvnmir#include "llvm/MC/MCContext.h"
20274955Ssvnmir#include "llvm/MC/MCInst.h"
21274955Ssvnmir#include "llvm/MC/MCInstBuilder.h"
22274955Ssvnmir#include "llvm/MC/MCInstrInfo.h"
23274955Ssvnmir#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
24274955Ssvnmir#include "llvm/MC/MCStreamer.h"
25274955Ssvnmir#include "llvm/MC/MCSubtargetInfo.h"
26274955Ssvnmir#include "llvm/MC/MCTargetAsmParser.h"
27274955Ssvnmir#include "llvm/MC/MCTargetOptions.h"
28274955Ssvnmir#include "llvm/Support/CommandLine.h"
29280031Sdim#include <algorithm>
30280031Sdim#include <cassert>
31280031Sdim#include <vector>
32274955Ssvnmir
33280031Sdim// Following comment describes how assembly instrumentation works.
34280031Sdim// Currently we have only AddressSanitizer instrumentation, but we're
35280031Sdim// planning to implement MemorySanitizer for inline assembly too. If
36280031Sdim// you're not familiar with AddressSanitizer algorithm, please, read
37280031Sdim// https://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm.
38280031Sdim//
39280031Sdim// When inline assembly is parsed by an instance of X86AsmParser, all
40280031Sdim// instructions are emitted via EmitInstruction method. That's the
41280031Sdim// place where X86AsmInstrumentation analyzes an instruction and
42280031Sdim// decides, whether the instruction should be emitted as is or
43280031Sdim// instrumentation is required. The latter case happens when an
44280031Sdim// instruction reads from or writes to memory. Now instruction opcode
45280031Sdim// is explicitly checked, and if an instruction has a memory operand
46280031Sdim// (for instance, movq (%rsi, %rcx, 8), %rax) - it should be
47280031Sdim// instrumented.  There're also exist instructions that modify
48280031Sdim// memory but don't have an explicit memory operands, for instance,
49280031Sdim// movs.
50280031Sdim//
51280031Sdim// Let's consider at first 8-byte memory accesses when an instruction
52280031Sdim// has an explicit memory operand. In this case we need two registers -
53280031Sdim// AddressReg to compute address of a memory cells which are accessed
54280031Sdim// and ShadowReg to compute corresponding shadow address. So, we need
55280031Sdim// to spill both registers before instrumentation code and restore them
56280031Sdim// after instrumentation. Thus, in general, instrumentation code will
57280031Sdim// look like this:
58280031Sdim// PUSHF  # Store flags, otherwise they will be overwritten
59280031Sdim// PUSH AddressReg  # spill AddressReg
60280031Sdim// PUSH ShadowReg   # spill ShadowReg
61280031Sdim// LEA MemOp, AddressReg  # compute address of the memory operand
62280031Sdim// MOV AddressReg, ShadowReg
63280031Sdim// SHR ShadowReg, 3
64280031Sdim// # ShadowOffset(AddressReg >> 3) contains address of a shadow
65280031Sdim// # corresponding to MemOp.
66280031Sdim// CMP ShadowOffset(ShadowReg), 0  # test shadow value
67280031Sdim// JZ .Done  # when shadow equals to zero, everything is fine
68280031Sdim// MOV AddressReg, RDI
69280031Sdim// # Call __asan_report function with AddressReg as an argument
70280031Sdim// CALL __asan_report
71280031Sdim// .Done:
72280031Sdim// POP ShadowReg  # Restore ShadowReg
73280031Sdim// POP AddressReg  # Restore AddressReg
74280031Sdim// POPF  # Restore flags
75280031Sdim//
76280031Sdim// Memory accesses with different size (1-, 2-, 4- and 16-byte) are
77280031Sdim// handled in a similar manner, but small memory accesses (less than 8
78280031Sdim// byte) require an additional ScratchReg, which is used for shadow value.
79280031Sdim//
80280031Sdim// If, suppose, we're instrumenting an instruction like movs, only
81280031Sdim// contents of RDI, RDI + AccessSize * RCX, RSI, RSI + AccessSize *
82280031Sdim// RCX are checked.  In this case there're no need to spill and restore
83280031Sdim// AddressReg , ShadowReg or flags four times, they're saved on stack
84280031Sdim// just once, before instrumentation of these four addresses, and restored
85280031Sdim// at the end of the instrumentation.
86280031Sdim//
87280031Sdim// There exist several things which complicate this simple algorithm.
88280031Sdim// * Instrumented memory operand can have RSP as a base or an index
89280031Sdim//   register.  So we need to add a constant offset before computation
90280031Sdim//   of memory address, since flags, AddressReg, ShadowReg, etc. were
91280031Sdim//   already stored on stack and RSP was modified.
92280031Sdim// * Debug info (usually, DWARF) should be adjusted, because sometimes
93280031Sdim//   RSP is used as a frame register. So, we need to select some
94280031Sdim//   register as a frame register and temprorary override current CFA
95280031Sdim//   register.
96280031Sdim
97274955Ssvnmirnamespace llvm {
98274955Ssvnmirnamespace {
99274955Ssvnmir
100274955Ssvnmirstatic cl::opt<bool> ClAsanInstrumentAssembly(
101274955Ssvnmir    "asan-instrument-assembly",
102274955Ssvnmir    cl::desc("instrument assembly with AddressSanitizer checks"), cl::Hidden,
103274955Ssvnmir    cl::init(false));
104274955Ssvnmir
105280031Sdimconst int64_t MinAllowedDisplacement = std::numeric_limits<int32_t>::min();
106280031Sdimconst int64_t MaxAllowedDisplacement = std::numeric_limits<int32_t>::max();
107280031Sdim
108280031Sdimint64_t ApplyDisplacementBounds(int64_t Displacement) {
109280031Sdim  return std::max(std::min(MaxAllowedDisplacement, Displacement),
110280031Sdim                  MinAllowedDisplacement);
111274955Ssvnmir}
112274955Ssvnmir
113280031Sdimvoid CheckDisplacementBounds(int64_t Displacement) {
114280031Sdim  assert(Displacement >= MinAllowedDisplacement &&
115280031Sdim         Displacement <= MaxAllowedDisplacement);
116280031Sdim}
117280031Sdim
118280031Sdimbool IsStackReg(unsigned Reg) { return Reg == X86::RSP || Reg == X86::ESP; }
119280031Sdim
120280031Sdimbool IsSmallMemAccess(unsigned AccessSize) { return AccessSize < 8; }
121280031Sdim
122274955Ssvnmirstd::string FuncName(unsigned AccessSize, bool IsWrite) {
123274955Ssvnmir  return std::string("__asan_report_") + (IsWrite ? "store" : "load") +
124274955Ssvnmir         utostr(AccessSize);
125274955Ssvnmir}
126274955Ssvnmir
127274955Ssvnmirclass X86AddressSanitizer : public X86AsmInstrumentation {
128274955Ssvnmirpublic:
129280031Sdim  struct RegisterContext {
130280031Sdim  private:
131280031Sdim    enum RegOffset {
132280031Sdim      REG_OFFSET_ADDRESS = 0,
133280031Sdim      REG_OFFSET_SHADOW,
134280031Sdim      REG_OFFSET_SCRATCH
135280031Sdim    };
136280031Sdim
137280031Sdim  public:
138280031Sdim    RegisterContext(unsigned AddressReg, unsigned ShadowReg,
139280031Sdim                    unsigned ScratchReg) {
140280031Sdim      BusyRegs.push_back(convReg(AddressReg, MVT::i64));
141280031Sdim      BusyRegs.push_back(convReg(ShadowReg, MVT::i64));
142280031Sdim      BusyRegs.push_back(convReg(ScratchReg, MVT::i64));
143280031Sdim    }
144280031Sdim
145280031Sdim    unsigned AddressReg(MVT::SimpleValueType VT) const {
146280031Sdim      return convReg(BusyRegs[REG_OFFSET_ADDRESS], VT);
147280031Sdim    }
148280031Sdim
149280031Sdim    unsigned ShadowReg(MVT::SimpleValueType VT) const {
150280031Sdim      return convReg(BusyRegs[REG_OFFSET_SHADOW], VT);
151280031Sdim    }
152280031Sdim
153280031Sdim    unsigned ScratchReg(MVT::SimpleValueType VT) const {
154280031Sdim      return convReg(BusyRegs[REG_OFFSET_SCRATCH], VT);
155280031Sdim    }
156280031Sdim
157280031Sdim    void AddBusyReg(unsigned Reg) {
158280031Sdim      if (Reg != X86::NoRegister)
159280031Sdim        BusyRegs.push_back(convReg(Reg, MVT::i64));
160280031Sdim    }
161280031Sdim
162280031Sdim    void AddBusyRegs(const X86Operand &Op) {
163280031Sdim      AddBusyReg(Op.getMemBaseReg());
164280031Sdim      AddBusyReg(Op.getMemIndexReg());
165280031Sdim    }
166280031Sdim
167280031Sdim    unsigned ChooseFrameReg(MVT::SimpleValueType VT) const {
168280031Sdim      static const MCPhysReg Candidates[] = { X86::RBP, X86::RAX, X86::RBX,
169280031Sdim                                              X86::RCX, X86::RDX, X86::RDI,
170280031Sdim                                              X86::RSI };
171280031Sdim      for (unsigned Reg : Candidates) {
172280031Sdim        if (!std::count(BusyRegs.begin(), BusyRegs.end(), Reg))
173280031Sdim          return convReg(Reg, VT);
174280031Sdim      }
175280031Sdim      return X86::NoRegister;
176280031Sdim    }
177280031Sdim
178280031Sdim  private:
179280031Sdim    unsigned convReg(unsigned Reg, MVT::SimpleValueType VT) const {
180280031Sdim      return Reg == X86::NoRegister ? Reg : getX86SubSuperRegister(Reg, VT);
181280031Sdim    }
182280031Sdim
183280031Sdim    std::vector<unsigned> BusyRegs;
184280031Sdim  };
185280031Sdim
186280031Sdim  X86AddressSanitizer(const MCSubtargetInfo &STI)
187280031Sdim      : X86AsmInstrumentation(STI), RepPrefix(false), OrigSPOffset(0) {}
188280031Sdim
189274955Ssvnmir  virtual ~X86AddressSanitizer() {}
190274955Ssvnmir
191274955Ssvnmir  // X86AsmInstrumentation implementation:
192280031Sdim  virtual void InstrumentAndEmitInstruction(const MCInst &Inst,
193280031Sdim                                            OperandVector &Operands,
194280031Sdim                                            MCContext &Ctx,
195280031Sdim                                            const MCInstrInfo &MII,
196280031Sdim                                            MCStreamer &Out) override {
197280031Sdim    InstrumentMOVS(Inst, Operands, Ctx, MII, Out);
198280031Sdim    if (RepPrefix)
199280031Sdim      EmitInstruction(Out, MCInstBuilder(X86::REP_PREFIX));
200280031Sdim
201274955Ssvnmir    InstrumentMOV(Inst, Operands, Ctx, MII, Out);
202280031Sdim
203280031Sdim    RepPrefix = (Inst.getOpcode() == X86::REP_PREFIX);
204280031Sdim    if (!RepPrefix)
205280031Sdim      EmitInstruction(Out, Inst);
206274955Ssvnmir  }
207274955Ssvnmir
208280031Sdim  // Adjusts up stack and saves all registers used in instrumentation.
209280031Sdim  virtual void InstrumentMemOperandPrologue(const RegisterContext &RegCtx,
210280031Sdim                                            MCContext &Ctx,
211280031Sdim                                            MCStreamer &Out) = 0;
212274955Ssvnmir
213280031Sdim  // Restores all registers used in instrumentation and adjusts stack.
214280031Sdim  virtual void InstrumentMemOperandEpilogue(const RegisterContext &RegCtx,
215280031Sdim                                            MCContext &Ctx,
216280031Sdim                                            MCStreamer &Out) = 0;
217280031Sdim
218280031Sdim  virtual void InstrumentMemOperandSmall(X86Operand &Op, unsigned AccessSize,
219280031Sdim                                         bool IsWrite,
220280031Sdim                                         const RegisterContext &RegCtx,
221280031Sdim                                         MCContext &Ctx, MCStreamer &Out) = 0;
222280031Sdim  virtual void InstrumentMemOperandLarge(X86Operand &Op, unsigned AccessSize,
223280031Sdim                                         bool IsWrite,
224280031Sdim                                         const RegisterContext &RegCtx,
225280031Sdim                                         MCContext &Ctx, MCStreamer &Out) = 0;
226280031Sdim
227280031Sdim  virtual void InstrumentMOVSImpl(unsigned AccessSize, MCContext &Ctx,
228280031Sdim                                  MCStreamer &Out) = 0;
229280031Sdim
230280031Sdim  void InstrumentMemOperand(X86Operand &Op, unsigned AccessSize, bool IsWrite,
231280031Sdim                            const RegisterContext &RegCtx, MCContext &Ctx,
232280031Sdim                            MCStreamer &Out);
233280031Sdim  void InstrumentMOVSBase(unsigned DstReg, unsigned SrcReg, unsigned CntReg,
234280031Sdim                          unsigned AccessSize, MCContext &Ctx, MCStreamer &Out);
235280031Sdim
236280031Sdim  void InstrumentMOVS(const MCInst &Inst, OperandVector &Operands,
237280031Sdim                      MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
238274955Ssvnmir  void InstrumentMOV(const MCInst &Inst, OperandVector &Operands,
239274955Ssvnmir                     MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
240274955Ssvnmir
241280031Sdimprotected:
242274955Ssvnmir  void EmitLabel(MCStreamer &Out, MCSymbol *Label) { Out.EmitLabel(Label); }
243274955Ssvnmir
244280031Sdim  void EmitLEA(X86Operand &Op, MVT::SimpleValueType VT, unsigned Reg,
245280031Sdim               MCStreamer &Out) {
246280031Sdim    assert(VT == MVT::i32 || VT == MVT::i64);
247280031Sdim    MCInst Inst;
248280031Sdim    Inst.setOpcode(VT == MVT::i32 ? X86::LEA32r : X86::LEA64r);
249280031Sdim    Inst.addOperand(MCOperand::CreateReg(getX86SubSuperRegister(Reg, VT)));
250280031Sdim    Op.addMemOperands(Inst, 5);
251280031Sdim    EmitInstruction(Out, Inst);
252280031Sdim  }
253280031Sdim
254280031Sdim  void ComputeMemOperandAddress(X86Operand &Op, MVT::SimpleValueType VT,
255280031Sdim                                unsigned Reg, MCContext &Ctx, MCStreamer &Out);
256280031Sdim
257280031Sdim  // Creates new memory operand with Displacement added to an original
258280031Sdim  // displacement. Residue will contain a residue which could happen when the
259280031Sdim  // total displacement exceeds 32-bit limitation.
260280031Sdim  std::unique_ptr<X86Operand> AddDisplacement(X86Operand &Op,
261280031Sdim                                              int64_t Displacement,
262280031Sdim                                              MCContext &Ctx, int64_t *Residue);
263280031Sdim
264280031Sdim  bool is64BitMode() const {
265280031Sdim    return (STI.getFeatureBits() & X86::Mode64Bit) != 0;
266280031Sdim  }
267280031Sdim  bool is32BitMode() const {
268280031Sdim    return (STI.getFeatureBits() & X86::Mode32Bit) != 0;
269280031Sdim  }
270280031Sdim  bool is16BitMode() const {
271280031Sdim    return (STI.getFeatureBits() & X86::Mode16Bit) != 0;
272280031Sdim  }
273280031Sdim
274280031Sdim  unsigned getPointerWidth() {
275280031Sdim    if (is16BitMode()) return 16;
276280031Sdim    if (is32BitMode()) return 32;
277280031Sdim    if (is64BitMode()) return 64;
278280031Sdim    llvm_unreachable("invalid mode");
279280031Sdim  }
280280031Sdim
281280031Sdim  // True when previous instruction was actually REP prefix.
282280031Sdim  bool RepPrefix;
283280031Sdim
284280031Sdim  // Offset from the original SP register.
285280031Sdim  int64_t OrigSPOffset;
286274955Ssvnmir};
287274955Ssvnmir
288274955Ssvnmirvoid X86AddressSanitizer::InstrumentMemOperand(
289280031Sdim    X86Operand &Op, unsigned AccessSize, bool IsWrite,
290280031Sdim    const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
291274955Ssvnmir  assert(Op.isMem() && "Op should be a memory operand.");
292274955Ssvnmir  assert((AccessSize & (AccessSize - 1)) == 0 && AccessSize <= 16 &&
293274955Ssvnmir         "AccessSize should be a power of two, less or equal than 16.");
294280031Sdim  // FIXME: take into account load/store alignment.
295280031Sdim  if (IsSmallMemAccess(AccessSize))
296280031Sdim    InstrumentMemOperandSmall(Op, AccessSize, IsWrite, RegCtx, Ctx, Out);
297280031Sdim  else
298280031Sdim    InstrumentMemOperandLarge(Op, AccessSize, IsWrite, RegCtx, Ctx, Out);
299280031Sdim}
300274955Ssvnmir
301280031Sdimvoid X86AddressSanitizer::InstrumentMOVSBase(unsigned DstReg, unsigned SrcReg,
302280031Sdim                                             unsigned CntReg,
303280031Sdim                                             unsigned AccessSize,
304280031Sdim                                             MCContext &Ctx, MCStreamer &Out) {
305280031Sdim  // FIXME: check whole ranges [DstReg .. DstReg + AccessSize * (CntReg - 1)]
306280031Sdim  // and [SrcReg .. SrcReg + AccessSize * (CntReg - 1)].
307280031Sdim  RegisterContext RegCtx(X86::RDX /* AddressReg */, X86::RAX /* ShadowReg */,
308280031Sdim                         IsSmallMemAccess(AccessSize)
309280031Sdim                             ? X86::RBX
310280031Sdim                             : X86::NoRegister /* ScratchReg */);
311280031Sdim  RegCtx.AddBusyReg(DstReg);
312280031Sdim  RegCtx.AddBusyReg(SrcReg);
313280031Sdim  RegCtx.AddBusyReg(CntReg);
314280031Sdim
315280031Sdim  InstrumentMemOperandPrologue(RegCtx, Ctx, Out);
316280031Sdim
317280031Sdim  // Test (%SrcReg)
318280031Sdim  {
319280031Sdim    const MCExpr *Disp = MCConstantExpr::Create(0, Ctx);
320280031Sdim    std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
321280031Sdim        getPointerWidth(), 0, Disp, SrcReg, 0, AccessSize, SMLoc(), SMLoc()));
322280031Sdim    InstrumentMemOperand(*Op, AccessSize, false /* IsWrite */, RegCtx, Ctx,
323280031Sdim                         Out);
324280031Sdim  }
325280031Sdim
326280031Sdim  // Test -1(%SrcReg, %CntReg, AccessSize)
327280031Sdim  {
328280031Sdim    const MCExpr *Disp = MCConstantExpr::Create(-1, Ctx);
329280031Sdim    std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
330280031Sdim        getPointerWidth(), 0, Disp, SrcReg, CntReg, AccessSize, SMLoc(),
331280031Sdim        SMLoc()));
332280031Sdim    InstrumentMemOperand(*Op, AccessSize, false /* IsWrite */, RegCtx, Ctx,
333280031Sdim                         Out);
334280031Sdim  }
335280031Sdim
336280031Sdim  // Test (%DstReg)
337280031Sdim  {
338280031Sdim    const MCExpr *Disp = MCConstantExpr::Create(0, Ctx);
339280031Sdim    std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
340280031Sdim        getPointerWidth(), 0, Disp, DstReg, 0, AccessSize, SMLoc(), SMLoc()));
341280031Sdim    InstrumentMemOperand(*Op, AccessSize, true /* IsWrite */, RegCtx, Ctx, Out);
342280031Sdim  }
343280031Sdim
344280031Sdim  // Test -1(%DstReg, %CntReg, AccessSize)
345280031Sdim  {
346280031Sdim    const MCExpr *Disp = MCConstantExpr::Create(-1, Ctx);
347280031Sdim    std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
348280031Sdim        getPointerWidth(), 0, Disp, DstReg, CntReg, AccessSize, SMLoc(),
349280031Sdim        SMLoc()));
350280031Sdim    InstrumentMemOperand(*Op, AccessSize, true /* IsWrite */, RegCtx, Ctx, Out);
351280031Sdim  }
352280031Sdim
353280031Sdim  InstrumentMemOperandEpilogue(RegCtx, Ctx, Out);
354280031Sdim}
355280031Sdim
356280031Sdimvoid X86AddressSanitizer::InstrumentMOVS(const MCInst &Inst,
357280031Sdim                                         OperandVector &Operands,
358280031Sdim                                         MCContext &Ctx, const MCInstrInfo &MII,
359280031Sdim                                         MCStreamer &Out) {
360280031Sdim  // Access size in bytes.
361280031Sdim  unsigned AccessSize = 0;
362280031Sdim
363280031Sdim  switch (Inst.getOpcode()) {
364280031Sdim  case X86::MOVSB:
365280031Sdim    AccessSize = 1;
366280031Sdim    break;
367280031Sdim  case X86::MOVSW:
368280031Sdim    AccessSize = 2;
369280031Sdim    break;
370280031Sdim  case X86::MOVSL:
371280031Sdim    AccessSize = 4;
372280031Sdim    break;
373280031Sdim  case X86::MOVSQ:
374280031Sdim    AccessSize = 8;
375280031Sdim    break;
376280031Sdim  default:
377274955Ssvnmir    return;
378280031Sdim  }
379274955Ssvnmir
380280031Sdim  InstrumentMOVSImpl(AccessSize, Ctx, Out);
381274955Ssvnmir}
382274955Ssvnmir
383280031Sdimvoid X86AddressSanitizer::InstrumentMOV(const MCInst &Inst,
384280031Sdim                                        OperandVector &Operands, MCContext &Ctx,
385280031Sdim                                        const MCInstrInfo &MII,
386280031Sdim                                        MCStreamer &Out) {
387274955Ssvnmir  // Access size in bytes.
388274955Ssvnmir  unsigned AccessSize = 0;
389274955Ssvnmir
390274955Ssvnmir  switch (Inst.getOpcode()) {
391274955Ssvnmir  case X86::MOV8mi:
392274955Ssvnmir  case X86::MOV8mr:
393274955Ssvnmir  case X86::MOV8rm:
394274955Ssvnmir    AccessSize = 1;
395274955Ssvnmir    break;
396274955Ssvnmir  case X86::MOV16mi:
397274955Ssvnmir  case X86::MOV16mr:
398274955Ssvnmir  case X86::MOV16rm:
399274955Ssvnmir    AccessSize = 2;
400274955Ssvnmir    break;
401274955Ssvnmir  case X86::MOV32mi:
402274955Ssvnmir  case X86::MOV32mr:
403274955Ssvnmir  case X86::MOV32rm:
404274955Ssvnmir    AccessSize = 4;
405274955Ssvnmir    break;
406274955Ssvnmir  case X86::MOV64mi32:
407274955Ssvnmir  case X86::MOV64mr:
408274955Ssvnmir  case X86::MOV64rm:
409274955Ssvnmir    AccessSize = 8;
410274955Ssvnmir    break;
411274955Ssvnmir  case X86::MOVAPDmr:
412274955Ssvnmir  case X86::MOVAPSmr:
413274955Ssvnmir  case X86::MOVAPDrm:
414274955Ssvnmir  case X86::MOVAPSrm:
415274955Ssvnmir    AccessSize = 16;
416274955Ssvnmir    break;
417274955Ssvnmir  default:
418274955Ssvnmir    return;
419274955Ssvnmir  }
420274955Ssvnmir
421274955Ssvnmir  const bool IsWrite = MII.get(Inst.getOpcode()).mayStore();
422280031Sdim
423274955Ssvnmir  for (unsigned Ix = 0; Ix < Operands.size(); ++Ix) {
424274955Ssvnmir    assert(Operands[Ix]);
425274955Ssvnmir    MCParsedAsmOperand &Op = *Operands[Ix];
426280031Sdim    if (Op.isMem()) {
427280031Sdim      X86Operand &MemOp = static_cast<X86Operand &>(Op);
428280031Sdim      RegisterContext RegCtx(
429280031Sdim          X86::RDI /* AddressReg */, X86::RAX /* ShadowReg */,
430280031Sdim          IsSmallMemAccess(AccessSize) ? X86::RCX
431280031Sdim                                       : X86::NoRegister /* ScratchReg */);
432280031Sdim      RegCtx.AddBusyRegs(MemOp);
433280031Sdim      InstrumentMemOperandPrologue(RegCtx, Ctx, Out);
434280031Sdim      InstrumentMemOperand(MemOp, AccessSize, IsWrite, RegCtx, Ctx, Out);
435280031Sdim      InstrumentMemOperandEpilogue(RegCtx, Ctx, Out);
436280031Sdim    }
437274955Ssvnmir  }
438274955Ssvnmir}
439274955Ssvnmir
440280031Sdimvoid X86AddressSanitizer::ComputeMemOperandAddress(X86Operand &Op,
441280031Sdim                                                   MVT::SimpleValueType VT,
442280031Sdim                                                   unsigned Reg, MCContext &Ctx,
443280031Sdim                                                   MCStreamer &Out) {
444280031Sdim  int64_t Displacement = 0;
445280031Sdim  if (IsStackReg(Op.getMemBaseReg()))
446280031Sdim    Displacement -= OrigSPOffset;
447280031Sdim  if (IsStackReg(Op.getMemIndexReg()))
448280031Sdim    Displacement -= OrigSPOffset * Op.getMemScale();
449280031Sdim
450280031Sdim  assert(Displacement >= 0);
451280031Sdim
452280031Sdim  // Emit Op as is.
453280031Sdim  if (Displacement == 0) {
454280031Sdim    EmitLEA(Op, VT, Reg, Out);
455280031Sdim    return;
456280031Sdim  }
457280031Sdim
458280031Sdim  int64_t Residue;
459280031Sdim  std::unique_ptr<X86Operand> NewOp =
460280031Sdim      AddDisplacement(Op, Displacement, Ctx, &Residue);
461280031Sdim  EmitLEA(*NewOp, VT, Reg, Out);
462280031Sdim
463280031Sdim  while (Residue != 0) {
464280031Sdim    const MCConstantExpr *Disp =
465280031Sdim        MCConstantExpr::Create(ApplyDisplacementBounds(Residue), Ctx);
466280031Sdim    std::unique_ptr<X86Operand> DispOp =
467280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, Reg, 0, 1, SMLoc(),
468280031Sdim                              SMLoc());
469280031Sdim    EmitLEA(*DispOp, VT, Reg, Out);
470280031Sdim    Residue -= Disp->getValue();
471280031Sdim  }
472280031Sdim}
473280031Sdim
474280031Sdimstd::unique_ptr<X86Operand>
475280031SdimX86AddressSanitizer::AddDisplacement(X86Operand &Op, int64_t Displacement,
476280031Sdim                                     MCContext &Ctx, int64_t *Residue) {
477280031Sdim  assert(Displacement >= 0);
478280031Sdim
479280031Sdim  if (Displacement == 0 ||
480280031Sdim      (Op.getMemDisp() && Op.getMemDisp()->getKind() != MCExpr::Constant)) {
481280031Sdim    *Residue = Displacement;
482280031Sdim    return X86Operand::CreateMem(Op.getMemModeSize(), Op.getMemSegReg(),
483280031Sdim                                 Op.getMemDisp(), Op.getMemBaseReg(),
484280031Sdim                                 Op.getMemIndexReg(), Op.getMemScale(),
485280031Sdim                                 SMLoc(), SMLoc());
486280031Sdim  }
487280031Sdim
488280031Sdim  int64_t OrigDisplacement =
489280031Sdim      static_cast<const MCConstantExpr *>(Op.getMemDisp())->getValue();
490280031Sdim  CheckDisplacementBounds(OrigDisplacement);
491280031Sdim  Displacement += OrigDisplacement;
492280031Sdim
493280031Sdim  int64_t NewDisplacement = ApplyDisplacementBounds(Displacement);
494280031Sdim  CheckDisplacementBounds(NewDisplacement);
495280031Sdim
496280031Sdim  *Residue = Displacement - NewDisplacement;
497280031Sdim  const MCExpr *Disp = MCConstantExpr::Create(NewDisplacement, Ctx);
498280031Sdim  return X86Operand::CreateMem(Op.getMemModeSize(), Op.getMemSegReg(), Disp,
499280031Sdim                               Op.getMemBaseReg(), Op.getMemIndexReg(),
500280031Sdim                               Op.getMemScale(), SMLoc(), SMLoc());
501280031Sdim}
502280031Sdim
503274955Ssvnmirclass X86AddressSanitizer32 : public X86AddressSanitizer {
504274955Ssvnmirpublic:
505274955Ssvnmir  static const long kShadowOffset = 0x20000000;
506274955Ssvnmir
507274955Ssvnmir  X86AddressSanitizer32(const MCSubtargetInfo &STI)
508274955Ssvnmir      : X86AddressSanitizer(STI) {}
509280031Sdim
510274955Ssvnmir  virtual ~X86AddressSanitizer32() {}
511274955Ssvnmir
512280031Sdim  unsigned GetFrameReg(const MCContext &Ctx, MCStreamer &Out) {
513280031Sdim    unsigned FrameReg = GetFrameRegGeneric(Ctx, Out);
514280031Sdim    if (FrameReg == X86::NoRegister)
515280031Sdim      return FrameReg;
516280031Sdim    return getX86SubSuperRegister(FrameReg, MVT::i32);
517280031Sdim  }
518274955Ssvnmir
519280031Sdim  void SpillReg(MCStreamer &Out, unsigned Reg) {
520280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(Reg));
521280031Sdim    OrigSPOffset -= 4;
522280031Sdim  }
523280031Sdim
524280031Sdim  void RestoreReg(MCStreamer &Out, unsigned Reg) {
525280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(Reg));
526280031Sdim    OrigSPOffset += 4;
527280031Sdim  }
528280031Sdim
529280031Sdim  void StoreFlags(MCStreamer &Out) {
530280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::PUSHF32));
531280031Sdim    OrigSPOffset -= 4;
532280031Sdim  }
533280031Sdim
534280031Sdim  void RestoreFlags(MCStreamer &Out) {
535280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::POPF32));
536280031Sdim    OrigSPOffset += 4;
537280031Sdim  }
538280031Sdim
539280031Sdim  virtual void InstrumentMemOperandPrologue(const RegisterContext &RegCtx,
540280031Sdim                                            MCContext &Ctx,
541280031Sdim                                            MCStreamer &Out) override {
542280031Sdim    unsigned LocalFrameReg = RegCtx.ChooseFrameReg(MVT::i32);
543280031Sdim    assert(LocalFrameReg != X86::NoRegister);
544280031Sdim
545280031Sdim    const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
546280031Sdim    unsigned FrameReg = GetFrameReg(Ctx, Out);
547280031Sdim    if (MRI && FrameReg != X86::NoRegister) {
548280031Sdim      SpillReg(Out, LocalFrameReg);
549280031Sdim      if (FrameReg == X86::ESP) {
550280031Sdim        Out.EmitCFIAdjustCfaOffset(4 /* byte size of the LocalFrameReg */);
551280031Sdim        Out.EmitCFIRelOffset(
552280031Sdim            MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */), 0);
553280031Sdim      }
554280031Sdim      EmitInstruction(
555280031Sdim          Out,
556280031Sdim          MCInstBuilder(X86::MOV32rr).addReg(LocalFrameReg).addReg(FrameReg));
557280031Sdim      Out.EmitCFIRememberState();
558280031Sdim      Out.EmitCFIDefCfaRegister(
559280031Sdim          MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */));
560280031Sdim    }
561280031Sdim
562280031Sdim    SpillReg(Out, RegCtx.AddressReg(MVT::i32));
563280031Sdim    SpillReg(Out, RegCtx.ShadowReg(MVT::i32));
564280031Sdim    if (RegCtx.ScratchReg(MVT::i32) != X86::NoRegister)
565280031Sdim      SpillReg(Out, RegCtx.ScratchReg(MVT::i32));
566280031Sdim    StoreFlags(Out);
567280031Sdim  }
568280031Sdim
569280031Sdim  virtual void InstrumentMemOperandEpilogue(const RegisterContext &RegCtx,
570280031Sdim                                            MCContext &Ctx,
571280031Sdim                                            MCStreamer &Out) override {
572280031Sdim    unsigned LocalFrameReg = RegCtx.ChooseFrameReg(MVT::i32);
573280031Sdim    assert(LocalFrameReg != X86::NoRegister);
574280031Sdim
575280031Sdim    RestoreFlags(Out);
576280031Sdim    if (RegCtx.ScratchReg(MVT::i32) != X86::NoRegister)
577280031Sdim      RestoreReg(Out, RegCtx.ScratchReg(MVT::i32));
578280031Sdim    RestoreReg(Out, RegCtx.ShadowReg(MVT::i32));
579280031Sdim    RestoreReg(Out, RegCtx.AddressReg(MVT::i32));
580280031Sdim
581280031Sdim    unsigned FrameReg = GetFrameReg(Ctx, Out);
582280031Sdim    if (Ctx.getRegisterInfo() && FrameReg != X86::NoRegister) {
583280031Sdim      RestoreReg(Out, LocalFrameReg);
584280031Sdim      Out.EmitCFIRestoreState();
585280031Sdim      if (FrameReg == X86::ESP)
586280031Sdim        Out.EmitCFIAdjustCfaOffset(-4 /* byte size of the LocalFrameReg */);
587280031Sdim    }
588280031Sdim  }
589280031Sdim
590280031Sdim  virtual void InstrumentMemOperandSmall(X86Operand &Op, unsigned AccessSize,
591280031Sdim                                         bool IsWrite,
592280031Sdim                                         const RegisterContext &RegCtx,
593280031Sdim                                         MCContext &Ctx,
594280031Sdim                                         MCStreamer &Out) override;
595280031Sdim  virtual void InstrumentMemOperandLarge(X86Operand &Op, unsigned AccessSize,
596280031Sdim                                         bool IsWrite,
597280031Sdim                                         const RegisterContext &RegCtx,
598280031Sdim                                         MCContext &Ctx,
599280031Sdim                                         MCStreamer &Out) override;
600280031Sdim  virtual void InstrumentMOVSImpl(unsigned AccessSize, MCContext &Ctx,
601280031Sdim                                  MCStreamer &Out) override;
602280031Sdim
603280031Sdimprivate:
604280031Sdim  void EmitCallAsanReport(unsigned AccessSize, bool IsWrite, MCContext &Ctx,
605280031Sdim                          MCStreamer &Out, const RegisterContext &RegCtx) {
606274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::CLD));
607274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::MMX_EMMS));
608274955Ssvnmir
609280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::AND64ri8)
610280031Sdim                             .addReg(X86::ESP)
611280031Sdim                             .addReg(X86::ESP)
612280031Sdim                             .addImm(-16));
613280031Sdim    EmitInstruction(
614280031Sdim        Out, MCInstBuilder(X86::PUSH32r).addReg(RegCtx.AddressReg(MVT::i32)));
615274955Ssvnmir
616280031Sdim    const std::string &Fn = FuncName(AccessSize, IsWrite);
617274955Ssvnmir    MCSymbol *FnSym = Ctx.GetOrCreateSymbol(StringRef(Fn));
618274955Ssvnmir    const MCSymbolRefExpr *FnExpr =
619274955Ssvnmir        MCSymbolRefExpr::Create(FnSym, MCSymbolRefExpr::VK_PLT, Ctx);
620274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::CALLpcrel32).addExpr(FnExpr));
621274955Ssvnmir  }
622274955Ssvnmir};
623274955Ssvnmir
624280031Sdimvoid X86AddressSanitizer32::InstrumentMemOperandSmall(
625280031Sdim    X86Operand &Op, unsigned AccessSize, bool IsWrite,
626280031Sdim    const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
627280031Sdim  unsigned AddressRegI32 = RegCtx.AddressReg(MVT::i32);
628280031Sdim  unsigned ShadowRegI32 = RegCtx.ShadowReg(MVT::i32);
629280031Sdim  unsigned ShadowRegI8 = RegCtx.ShadowReg(MVT::i8);
630274955Ssvnmir
631280031Sdim  assert(RegCtx.ScratchReg(MVT::i32) != X86::NoRegister);
632280031Sdim  unsigned ScratchRegI32 = RegCtx.ScratchReg(MVT::i32);
633274955Ssvnmir
634280031Sdim  ComputeMemOperandAddress(Op, MVT::i32, AddressRegI32, Ctx, Out);
635274955Ssvnmir
636280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ShadowRegI32).addReg(
637280031Sdim                           AddressRegI32));
638280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::SHR32ri)
639280031Sdim                           .addReg(ShadowRegI32)
640280031Sdim                           .addReg(ShadowRegI32)
641280031Sdim                           .addImm(3));
642280031Sdim
643274955Ssvnmir  {
644274955Ssvnmir    MCInst Inst;
645274955Ssvnmir    Inst.setOpcode(X86::MOV8rm);
646280031Sdim    Inst.addOperand(MCOperand::CreateReg(ShadowRegI8));
647274955Ssvnmir    const MCExpr *Disp = MCConstantExpr::Create(kShadowOffset, Ctx);
648274955Ssvnmir    std::unique_ptr<X86Operand> Op(
649280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI32, 0, 1,
650280031Sdim                              SMLoc(), SMLoc()));
651274955Ssvnmir    Op->addMemOperands(Inst, 5);
652274955Ssvnmir    EmitInstruction(Out, Inst);
653274955Ssvnmir  }
654274955Ssvnmir
655280031Sdim  EmitInstruction(
656280031Sdim      Out, MCInstBuilder(X86::TEST8rr).addReg(ShadowRegI8).addReg(ShadowRegI8));
657274955Ssvnmir  MCSymbol *DoneSym = Ctx.CreateTempSymbol();
658274955Ssvnmir  const MCExpr *DoneExpr = MCSymbolRefExpr::Create(DoneSym, Ctx);
659280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
660274955Ssvnmir
661280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ScratchRegI32).addReg(
662280031Sdim                           AddressRegI32));
663280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::AND32ri)
664280031Sdim                           .addReg(ScratchRegI32)
665280031Sdim                           .addReg(ScratchRegI32)
666280031Sdim                           .addImm(7));
667274955Ssvnmir
668274955Ssvnmir  switch (AccessSize) {
669280031Sdim  default: llvm_unreachable("Incorrect access size");
670274955Ssvnmir  case 1:
671274955Ssvnmir    break;
672274955Ssvnmir  case 2: {
673274955Ssvnmir    const MCExpr *Disp = MCConstantExpr::Create(1, Ctx);
674274955Ssvnmir    std::unique_ptr<X86Operand> Op(
675280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ScratchRegI32, 0, 1,
676280031Sdim                              SMLoc(), SMLoc()));
677280031Sdim    EmitLEA(*Op, MVT::i32, ScratchRegI32, Out);
678274955Ssvnmir    break;
679274955Ssvnmir  }
680274955Ssvnmir  case 4:
681280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::ADD32ri8)
682280031Sdim                             .addReg(ScratchRegI32)
683280031Sdim                             .addReg(ScratchRegI32)
684280031Sdim                             .addImm(3));
685274955Ssvnmir    break;
686274955Ssvnmir  }
687274955Ssvnmir
688274955Ssvnmir  EmitInstruction(
689280031Sdim      Out,
690280031Sdim      MCInstBuilder(X86::MOVSX32rr8).addReg(ShadowRegI32).addReg(ShadowRegI8));
691280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::CMP32rr).addReg(ScratchRegI32).addReg(
692280031Sdim                           ShadowRegI32));
693280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JL_1).addExpr(DoneExpr));
694274955Ssvnmir
695280031Sdim  EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
696274955Ssvnmir  EmitLabel(Out, DoneSym);
697274955Ssvnmir}
698274955Ssvnmir
699280031Sdimvoid X86AddressSanitizer32::InstrumentMemOperandLarge(
700280031Sdim    X86Operand &Op, unsigned AccessSize, bool IsWrite,
701280031Sdim    const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
702280031Sdim  unsigned AddressRegI32 = RegCtx.AddressReg(MVT::i32);
703280031Sdim  unsigned ShadowRegI32 = RegCtx.ShadowReg(MVT::i32);
704274955Ssvnmir
705280031Sdim  ComputeMemOperandAddress(Op, MVT::i32, AddressRegI32, Ctx, Out);
706280031Sdim
707280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ShadowRegI32).addReg(
708280031Sdim                           AddressRegI32));
709280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::SHR32ri)
710280031Sdim                           .addReg(ShadowRegI32)
711280031Sdim                           .addReg(ShadowRegI32)
712280031Sdim                           .addImm(3));
713274955Ssvnmir  {
714274955Ssvnmir    MCInst Inst;
715274955Ssvnmir    switch (AccessSize) {
716280031Sdim    default: llvm_unreachable("Incorrect access size");
717280031Sdim    case 8:
718280031Sdim      Inst.setOpcode(X86::CMP8mi);
719280031Sdim      break;
720280031Sdim    case 16:
721280031Sdim      Inst.setOpcode(X86::CMP16mi);
722280031Sdim      break;
723274955Ssvnmir    }
724274955Ssvnmir    const MCExpr *Disp = MCConstantExpr::Create(kShadowOffset, Ctx);
725274955Ssvnmir    std::unique_ptr<X86Operand> Op(
726280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI32, 0, 1,
727280031Sdim                              SMLoc(), SMLoc()));
728274955Ssvnmir    Op->addMemOperands(Inst, 5);
729274955Ssvnmir    Inst.addOperand(MCOperand::CreateImm(0));
730274955Ssvnmir    EmitInstruction(Out, Inst);
731274955Ssvnmir  }
732274955Ssvnmir  MCSymbol *DoneSym = Ctx.CreateTempSymbol();
733274955Ssvnmir  const MCExpr *DoneExpr = MCSymbolRefExpr::Create(DoneSym, Ctx);
734280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
735274955Ssvnmir
736280031Sdim  EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
737274955Ssvnmir  EmitLabel(Out, DoneSym);
738280031Sdim}
739274955Ssvnmir
740280031Sdimvoid X86AddressSanitizer32::InstrumentMOVSImpl(unsigned AccessSize,
741280031Sdim                                               MCContext &Ctx,
742280031Sdim                                               MCStreamer &Out) {
743280031Sdim  StoreFlags(Out);
744280031Sdim
745280031Sdim  // No need to test when ECX is equals to zero.
746280031Sdim  MCSymbol *DoneSym = Ctx.CreateTempSymbol();
747280031Sdim  const MCExpr *DoneExpr = MCSymbolRefExpr::Create(DoneSym, Ctx);
748280031Sdim  EmitInstruction(
749280031Sdim      Out, MCInstBuilder(X86::TEST32rr).addReg(X86::ECX).addReg(X86::ECX));
750280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
751280031Sdim
752280031Sdim  // Instrument first and last elements in src and dst range.
753280031Sdim  InstrumentMOVSBase(X86::EDI /* DstReg */, X86::ESI /* SrcReg */,
754280031Sdim                     X86::ECX /* CntReg */, AccessSize, Ctx, Out);
755280031Sdim
756280031Sdim  EmitLabel(Out, DoneSym);
757280031Sdim  RestoreFlags(Out);
758274955Ssvnmir}
759274955Ssvnmir
760274955Ssvnmirclass X86AddressSanitizer64 : public X86AddressSanitizer {
761274955Ssvnmirpublic:
762274955Ssvnmir  static const long kShadowOffset = 0x7fff8000;
763274955Ssvnmir
764274955Ssvnmir  X86AddressSanitizer64(const MCSubtargetInfo &STI)
765274955Ssvnmir      : X86AddressSanitizer(STI) {}
766280031Sdim
767274955Ssvnmir  virtual ~X86AddressSanitizer64() {}
768274955Ssvnmir
769280031Sdim  unsigned GetFrameReg(const MCContext &Ctx, MCStreamer &Out) {
770280031Sdim    unsigned FrameReg = GetFrameRegGeneric(Ctx, Out);
771280031Sdim    if (FrameReg == X86::NoRegister)
772280031Sdim      return FrameReg;
773280031Sdim    return getX86SubSuperRegister(FrameReg, MVT::i64);
774280031Sdim  }
775274955Ssvnmir
776280031Sdim  void SpillReg(MCStreamer &Out, unsigned Reg) {
777280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(Reg));
778280031Sdim    OrigSPOffset -= 8;
779280031Sdim  }
780280031Sdim
781280031Sdim  void RestoreReg(MCStreamer &Out, unsigned Reg) {
782280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(Reg));
783280031Sdim    OrigSPOffset += 8;
784280031Sdim  }
785280031Sdim
786280031Sdim  void StoreFlags(MCStreamer &Out) {
787280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::PUSHF64));
788280031Sdim    OrigSPOffset -= 8;
789280031Sdim  }
790280031Sdim
791280031Sdim  void RestoreFlags(MCStreamer &Out) {
792280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::POPF64));
793280031Sdim    OrigSPOffset += 8;
794280031Sdim  }
795280031Sdim
796280031Sdim  virtual void InstrumentMemOperandPrologue(const RegisterContext &RegCtx,
797280031Sdim                                            MCContext &Ctx,
798280031Sdim                                            MCStreamer &Out) override {
799280031Sdim    unsigned LocalFrameReg = RegCtx.ChooseFrameReg(MVT::i64);
800280031Sdim    assert(LocalFrameReg != X86::NoRegister);
801280031Sdim
802280031Sdim    const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
803280031Sdim    unsigned FrameReg = GetFrameReg(Ctx, Out);
804280031Sdim    if (MRI && FrameReg != X86::NoRegister) {
805280031Sdim      SpillReg(Out, X86::RBP);
806280031Sdim      if (FrameReg == X86::RSP) {
807280031Sdim        Out.EmitCFIAdjustCfaOffset(8 /* byte size of the LocalFrameReg */);
808280031Sdim        Out.EmitCFIRelOffset(
809280031Sdim            MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */), 0);
810280031Sdim      }
811280031Sdim      EmitInstruction(
812280031Sdim          Out,
813280031Sdim          MCInstBuilder(X86::MOV64rr).addReg(LocalFrameReg).addReg(FrameReg));
814280031Sdim      Out.EmitCFIRememberState();
815280031Sdim      Out.EmitCFIDefCfaRegister(
816280031Sdim          MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */));
817280031Sdim    }
818280031Sdim
819280031Sdim    EmitAdjustRSP(Ctx, Out, -128);
820280031Sdim    SpillReg(Out, RegCtx.ShadowReg(MVT::i64));
821280031Sdim    SpillReg(Out, RegCtx.AddressReg(MVT::i64));
822280031Sdim    if (RegCtx.ScratchReg(MVT::i64) != X86::NoRegister)
823280031Sdim      SpillReg(Out, RegCtx.ScratchReg(MVT::i64));
824280031Sdim    StoreFlags(Out);
825280031Sdim  }
826280031Sdim
827280031Sdim  virtual void InstrumentMemOperandEpilogue(const RegisterContext &RegCtx,
828280031Sdim                                            MCContext &Ctx,
829280031Sdim                                            MCStreamer &Out) override {
830280031Sdim    unsigned LocalFrameReg = RegCtx.ChooseFrameReg(MVT::i64);
831280031Sdim    assert(LocalFrameReg != X86::NoRegister);
832280031Sdim
833280031Sdim    RestoreFlags(Out);
834280031Sdim    if (RegCtx.ScratchReg(MVT::i64) != X86::NoRegister)
835280031Sdim      RestoreReg(Out, RegCtx.ScratchReg(MVT::i64));
836280031Sdim    RestoreReg(Out, RegCtx.AddressReg(MVT::i64));
837280031Sdim    RestoreReg(Out, RegCtx.ShadowReg(MVT::i64));
838280031Sdim    EmitAdjustRSP(Ctx, Out, 128);
839280031Sdim
840280031Sdim    unsigned FrameReg = GetFrameReg(Ctx, Out);
841280031Sdim    if (Ctx.getRegisterInfo() && FrameReg != X86::NoRegister) {
842280031Sdim      RestoreReg(Out, LocalFrameReg);
843280031Sdim      Out.EmitCFIRestoreState();
844280031Sdim      if (FrameReg == X86::RSP)
845280031Sdim        Out.EmitCFIAdjustCfaOffset(-8 /* byte size of the LocalFrameReg */);
846280031Sdim    }
847280031Sdim  }
848280031Sdim
849280031Sdim  virtual void InstrumentMemOperandSmall(X86Operand &Op, unsigned AccessSize,
850280031Sdim                                         bool IsWrite,
851280031Sdim                                         const RegisterContext &RegCtx,
852280031Sdim                                         MCContext &Ctx,
853280031Sdim                                         MCStreamer &Out) override;
854280031Sdim  virtual void InstrumentMemOperandLarge(X86Operand &Op, unsigned AccessSize,
855280031Sdim                                         bool IsWrite,
856280031Sdim                                         const RegisterContext &RegCtx,
857280031Sdim                                         MCContext &Ctx,
858280031Sdim                                         MCStreamer &Out) override;
859280031Sdim  virtual void InstrumentMOVSImpl(unsigned AccessSize, MCContext &Ctx,
860280031Sdim                                  MCStreamer &Out) override;
861280031Sdim
862274955Ssvnmirprivate:
863274955Ssvnmir  void EmitAdjustRSP(MCContext &Ctx, MCStreamer &Out, long Offset) {
864274955Ssvnmir    const MCExpr *Disp = MCConstantExpr::Create(Offset, Ctx);
865274955Ssvnmir    std::unique_ptr<X86Operand> Op(
866280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, X86::RSP, 0, 1,
867280031Sdim                              SMLoc(), SMLoc()));
868280031Sdim    EmitLEA(*Op, MVT::i64, X86::RSP, Out);
869280031Sdim    OrigSPOffset += Offset;
870274955Ssvnmir  }
871274955Ssvnmir
872280031Sdim  void EmitCallAsanReport(unsigned AccessSize, bool IsWrite, MCContext &Ctx,
873280031Sdim                          MCStreamer &Out, const RegisterContext &RegCtx) {
874274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::CLD));
875274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::MMX_EMMS));
876274955Ssvnmir
877280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::AND64ri8)
878280031Sdim                             .addReg(X86::RSP)
879280031Sdim                             .addReg(X86::RSP)
880280031Sdim                             .addImm(-16));
881274955Ssvnmir
882280031Sdim    if (RegCtx.AddressReg(MVT::i64) != X86::RDI) {
883280031Sdim      EmitInstruction(Out, MCInstBuilder(X86::MOV64rr).addReg(X86::RDI).addReg(
884280031Sdim                               RegCtx.AddressReg(MVT::i64)));
885280031Sdim    }
886280031Sdim    const std::string &Fn = FuncName(AccessSize, IsWrite);
887274955Ssvnmir    MCSymbol *FnSym = Ctx.GetOrCreateSymbol(StringRef(Fn));
888274955Ssvnmir    const MCSymbolRefExpr *FnExpr =
889274955Ssvnmir        MCSymbolRefExpr::Create(FnSym, MCSymbolRefExpr::VK_PLT, Ctx);
890274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::CALL64pcrel32).addExpr(FnExpr));
891274955Ssvnmir  }
892274955Ssvnmir};
893274955Ssvnmir
894280031Sdimvoid X86AddressSanitizer64::InstrumentMemOperandSmall(
895280031Sdim    X86Operand &Op, unsigned AccessSize, bool IsWrite,
896280031Sdim    const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
897280031Sdim  unsigned AddressRegI64 = RegCtx.AddressReg(MVT::i64);
898280031Sdim  unsigned AddressRegI32 = RegCtx.AddressReg(MVT::i32);
899280031Sdim  unsigned ShadowRegI64 = RegCtx.ShadowReg(MVT::i64);
900280031Sdim  unsigned ShadowRegI32 = RegCtx.ShadowReg(MVT::i32);
901280031Sdim  unsigned ShadowRegI8 = RegCtx.ShadowReg(MVT::i8);
902280031Sdim
903280031Sdim  assert(RegCtx.ScratchReg(MVT::i32) != X86::NoRegister);
904280031Sdim  unsigned ScratchRegI32 = RegCtx.ScratchReg(MVT::i32);
905280031Sdim
906280031Sdim  ComputeMemOperandAddress(Op, MVT::i64, AddressRegI64, Ctx, Out);
907280031Sdim
908280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV64rr).addReg(ShadowRegI64).addReg(
909280031Sdim                           AddressRegI64));
910280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::SHR64ri)
911280031Sdim                           .addReg(ShadowRegI64)
912280031Sdim                           .addReg(ShadowRegI64)
913280031Sdim                           .addImm(3));
914274955Ssvnmir  {
915274955Ssvnmir    MCInst Inst;
916274955Ssvnmir    Inst.setOpcode(X86::MOV8rm);
917280031Sdim    Inst.addOperand(MCOperand::CreateReg(ShadowRegI8));
918274955Ssvnmir    const MCExpr *Disp = MCConstantExpr::Create(kShadowOffset, Ctx);
919274955Ssvnmir    std::unique_ptr<X86Operand> Op(
920280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI64, 0, 1,
921280031Sdim                              SMLoc(), SMLoc()));
922274955Ssvnmir    Op->addMemOperands(Inst, 5);
923274955Ssvnmir    EmitInstruction(Out, Inst);
924274955Ssvnmir  }
925274955Ssvnmir
926280031Sdim  EmitInstruction(
927280031Sdim      Out, MCInstBuilder(X86::TEST8rr).addReg(ShadowRegI8).addReg(ShadowRegI8));
928274955Ssvnmir  MCSymbol *DoneSym = Ctx.CreateTempSymbol();
929274955Ssvnmir  const MCExpr *DoneExpr = MCSymbolRefExpr::Create(DoneSym, Ctx);
930280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
931274955Ssvnmir
932280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ScratchRegI32).addReg(
933280031Sdim                           AddressRegI32));
934280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::AND32ri)
935280031Sdim                           .addReg(ScratchRegI32)
936280031Sdim                           .addReg(ScratchRegI32)
937280031Sdim                           .addImm(7));
938274955Ssvnmir
939274955Ssvnmir  switch (AccessSize) {
940280031Sdim  default: llvm_unreachable("Incorrect access size");
941274955Ssvnmir  case 1:
942274955Ssvnmir    break;
943274955Ssvnmir  case 2: {
944274955Ssvnmir    const MCExpr *Disp = MCConstantExpr::Create(1, Ctx);
945274955Ssvnmir    std::unique_ptr<X86Operand> Op(
946280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ScratchRegI32, 0, 1,
947280031Sdim                              SMLoc(), SMLoc()));
948280031Sdim    EmitLEA(*Op, MVT::i32, ScratchRegI32, Out);
949274955Ssvnmir    break;
950274955Ssvnmir  }
951274955Ssvnmir  case 4:
952280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::ADD32ri8)
953280031Sdim                             .addReg(ScratchRegI32)
954280031Sdim                             .addReg(ScratchRegI32)
955280031Sdim                             .addImm(3));
956274955Ssvnmir    break;
957274955Ssvnmir  }
958274955Ssvnmir
959274955Ssvnmir  EmitInstruction(
960280031Sdim      Out,
961280031Sdim      MCInstBuilder(X86::MOVSX32rr8).addReg(ShadowRegI32).addReg(ShadowRegI8));
962280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::CMP32rr).addReg(ScratchRegI32).addReg(
963280031Sdim                           ShadowRegI32));
964280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JL_1).addExpr(DoneExpr));
965274955Ssvnmir
966280031Sdim  EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
967274955Ssvnmir  EmitLabel(Out, DoneSym);
968274955Ssvnmir}
969274955Ssvnmir
970280031Sdimvoid X86AddressSanitizer64::InstrumentMemOperandLarge(
971280031Sdim    X86Operand &Op, unsigned AccessSize, bool IsWrite,
972280031Sdim    const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
973280031Sdim  unsigned AddressRegI64 = RegCtx.AddressReg(MVT::i64);
974280031Sdim  unsigned ShadowRegI64 = RegCtx.ShadowReg(MVT::i64);
975274955Ssvnmir
976280031Sdim  ComputeMemOperandAddress(Op, MVT::i64, AddressRegI64, Ctx, Out);
977280031Sdim
978280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV64rr).addReg(ShadowRegI64).addReg(
979280031Sdim                           AddressRegI64));
980280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::SHR64ri)
981280031Sdim                           .addReg(ShadowRegI64)
982280031Sdim                           .addReg(ShadowRegI64)
983280031Sdim                           .addImm(3));
984274955Ssvnmir  {
985274955Ssvnmir    MCInst Inst;
986274955Ssvnmir    switch (AccessSize) {
987280031Sdim    default: llvm_unreachable("Incorrect access size");
988274955Ssvnmir    case 8:
989274955Ssvnmir      Inst.setOpcode(X86::CMP8mi);
990274955Ssvnmir      break;
991274955Ssvnmir    case 16:
992274955Ssvnmir      Inst.setOpcode(X86::CMP16mi);
993274955Ssvnmir      break;
994274955Ssvnmir    }
995274955Ssvnmir    const MCExpr *Disp = MCConstantExpr::Create(kShadowOffset, Ctx);
996274955Ssvnmir    std::unique_ptr<X86Operand> Op(
997280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI64, 0, 1,
998280031Sdim                              SMLoc(), SMLoc()));
999274955Ssvnmir    Op->addMemOperands(Inst, 5);
1000274955Ssvnmir    Inst.addOperand(MCOperand::CreateImm(0));
1001274955Ssvnmir    EmitInstruction(Out, Inst);
1002274955Ssvnmir  }
1003274955Ssvnmir
1004274955Ssvnmir  MCSymbol *DoneSym = Ctx.CreateTempSymbol();
1005274955Ssvnmir  const MCExpr *DoneExpr = MCSymbolRefExpr::Create(DoneSym, Ctx);
1006280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
1007274955Ssvnmir
1008280031Sdim  EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
1009274955Ssvnmir  EmitLabel(Out, DoneSym);
1010280031Sdim}
1011274955Ssvnmir
1012280031Sdimvoid X86AddressSanitizer64::InstrumentMOVSImpl(unsigned AccessSize,
1013280031Sdim                                               MCContext &Ctx,
1014280031Sdim                                               MCStreamer &Out) {
1015280031Sdim  StoreFlags(Out);
1016280031Sdim
1017280031Sdim  // No need to test when RCX is equals to zero.
1018280031Sdim  MCSymbol *DoneSym = Ctx.CreateTempSymbol();
1019280031Sdim  const MCExpr *DoneExpr = MCSymbolRefExpr::Create(DoneSym, Ctx);
1020280031Sdim  EmitInstruction(
1021280031Sdim      Out, MCInstBuilder(X86::TEST64rr).addReg(X86::RCX).addReg(X86::RCX));
1022280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
1023280031Sdim
1024280031Sdim  // Instrument first and last elements in src and dst range.
1025280031Sdim  InstrumentMOVSBase(X86::RDI /* DstReg */, X86::RSI /* SrcReg */,
1026280031Sdim                     X86::RCX /* CntReg */, AccessSize, Ctx, Out);
1027280031Sdim
1028280031Sdim  EmitLabel(Out, DoneSym);
1029280031Sdim  RestoreFlags(Out);
1030274955Ssvnmir}
1031274955Ssvnmir
1032274955Ssvnmir} // End anonymous namespace
1033274955Ssvnmir
1034280031SdimX86AsmInstrumentation::X86AsmInstrumentation(const MCSubtargetInfo &STI)
1035280031Sdim    : STI(STI), InitialFrameReg(0) {}
1036280031Sdim
1037274955SsvnmirX86AsmInstrumentation::~X86AsmInstrumentation() {}
1038274955Ssvnmir
1039280031Sdimvoid X86AsmInstrumentation::InstrumentAndEmitInstruction(
1040274955Ssvnmir    const MCInst &Inst, OperandVector &Operands, MCContext &Ctx,
1041280031Sdim    const MCInstrInfo &MII, MCStreamer &Out) {
1042280031Sdim  EmitInstruction(Out, Inst);
1043280031Sdim}
1044274955Ssvnmir
1045280031Sdimvoid X86AsmInstrumentation::EmitInstruction(MCStreamer &Out,
1046280031Sdim                                            const MCInst &Inst) {
1047280031Sdim  Out.EmitInstruction(Inst, STI);
1048280031Sdim}
1049280031Sdim
1050280031Sdimunsigned X86AsmInstrumentation::GetFrameRegGeneric(const MCContext &Ctx,
1051280031Sdim                                                   MCStreamer &Out) {
1052280031Sdim  if (!Out.getNumFrameInfos()) // No active dwarf frame
1053280031Sdim    return X86::NoRegister;
1054280031Sdim  const MCDwarfFrameInfo &Frame = Out.getDwarfFrameInfos().back();
1055280031Sdim  if (Frame.End) // Active dwarf frame is closed
1056280031Sdim    return X86::NoRegister;
1057280031Sdim  const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
1058280031Sdim  if (!MRI) // No register info
1059280031Sdim    return X86::NoRegister;
1060280031Sdim
1061280031Sdim  if (InitialFrameReg) {
1062280031Sdim    // FrameReg is set explicitly, we're instrumenting a MachineFunction.
1063280031Sdim    return InitialFrameReg;
1064280031Sdim  }
1065280031Sdim
1066280031Sdim  return MRI->getLLVMRegNum(Frame.CurrentCfaRegister, true /* IsEH */);
1067280031Sdim}
1068280031Sdim
1069274955SsvnmirX86AsmInstrumentation *
1070274955SsvnmirCreateX86AsmInstrumentation(const MCTargetOptions &MCOptions,
1071274955Ssvnmir                            const MCContext &Ctx, const MCSubtargetInfo &STI) {
1072274955Ssvnmir  Triple T(STI.getTargetTriple());
1073274955Ssvnmir  const bool hasCompilerRTSupport = T.isOSLinux();
1074274955Ssvnmir  if (ClAsanInstrumentAssembly && hasCompilerRTSupport &&
1075274955Ssvnmir      MCOptions.SanitizeAddress) {
1076274955Ssvnmir    if ((STI.getFeatureBits() & X86::Mode32Bit) != 0)
1077274955Ssvnmir      return new X86AddressSanitizer32(STI);
1078274955Ssvnmir    if ((STI.getFeatureBits() & X86::Mode64Bit) != 0)
1079274955Ssvnmir      return new X86AddressSanitizer64(STI);
1080274955Ssvnmir  }
1081280031Sdim  return new X86AsmInstrumentation(STI);
1082274955Ssvnmir}
1083274955Ssvnmir
1084274955Ssvnmir} // End llvm namespace
1085