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"
13274955Ssvnmir#include "llvm/ADT/StringExtras.h"
14274955Ssvnmir#include "llvm/ADT/Triple.h"
15280031Sdim#include "llvm/MC/MCAsmInfo.h"
16274955Ssvnmir#include "llvm/MC/MCContext.h"
17274955Ssvnmir#include "llvm/MC/MCInst.h"
18274955Ssvnmir#include "llvm/MC/MCInstBuilder.h"
19274955Ssvnmir#include "llvm/MC/MCInstrInfo.h"
20274955Ssvnmir#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
21274955Ssvnmir#include "llvm/MC/MCStreamer.h"
22274955Ssvnmir#include "llvm/MC/MCSubtargetInfo.h"
23274955Ssvnmir#include "llvm/MC/MCTargetAsmParser.h"
24274955Ssvnmir#include "llvm/MC/MCTargetOptions.h"
25274955Ssvnmir#include "llvm/Support/CommandLine.h"
26280031Sdim#include <algorithm>
27280031Sdim#include <cassert>
28280031Sdim#include <vector>
29274955Ssvnmir
30280031Sdim// Following comment describes how assembly instrumentation works.
31280031Sdim// Currently we have only AddressSanitizer instrumentation, but we're
32280031Sdim// planning to implement MemorySanitizer for inline assembly too. If
33280031Sdim// you're not familiar with AddressSanitizer algorithm, please, read
34280031Sdim// https://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm.
35280031Sdim//
36280031Sdim// When inline assembly is parsed by an instance of X86AsmParser, all
37280031Sdim// instructions are emitted via EmitInstruction method. That's the
38280031Sdim// place where X86AsmInstrumentation analyzes an instruction and
39280031Sdim// decides, whether the instruction should be emitted as is or
40280031Sdim// instrumentation is required. The latter case happens when an
41280031Sdim// instruction reads from or writes to memory. Now instruction opcode
42280031Sdim// is explicitly checked, and if an instruction has a memory operand
43280031Sdim// (for instance, movq (%rsi, %rcx, 8), %rax) - it should be
44280031Sdim// instrumented.  There're also exist instructions that modify
45280031Sdim// memory but don't have an explicit memory operands, for instance,
46280031Sdim// movs.
47280031Sdim//
48280031Sdim// Let's consider at first 8-byte memory accesses when an instruction
49280031Sdim// has an explicit memory operand. In this case we need two registers -
50280031Sdim// AddressReg to compute address of a memory cells which are accessed
51280031Sdim// and ShadowReg to compute corresponding shadow address. So, we need
52280031Sdim// to spill both registers before instrumentation code and restore them
53280031Sdim// after instrumentation. Thus, in general, instrumentation code will
54280031Sdim// look like this:
55280031Sdim// PUSHF  # Store flags, otherwise they will be overwritten
56280031Sdim// PUSH AddressReg  # spill AddressReg
57280031Sdim// PUSH ShadowReg   # spill ShadowReg
58280031Sdim// LEA MemOp, AddressReg  # compute address of the memory operand
59280031Sdim// MOV AddressReg, ShadowReg
60280031Sdim// SHR ShadowReg, 3
61280031Sdim// # ShadowOffset(AddressReg >> 3) contains address of a shadow
62280031Sdim// # corresponding to MemOp.
63280031Sdim// CMP ShadowOffset(ShadowReg), 0  # test shadow value
64280031Sdim// JZ .Done  # when shadow equals to zero, everything is fine
65280031Sdim// MOV AddressReg, RDI
66280031Sdim// # Call __asan_report function with AddressReg as an argument
67280031Sdim// CALL __asan_report
68280031Sdim// .Done:
69280031Sdim// POP ShadowReg  # Restore ShadowReg
70280031Sdim// POP AddressReg  # Restore AddressReg
71280031Sdim// POPF  # Restore flags
72280031Sdim//
73280031Sdim// Memory accesses with different size (1-, 2-, 4- and 16-byte) are
74280031Sdim// handled in a similar manner, but small memory accesses (less than 8
75280031Sdim// byte) require an additional ScratchReg, which is used for shadow value.
76280031Sdim//
77280031Sdim// If, suppose, we're instrumenting an instruction like movs, only
78280031Sdim// contents of RDI, RDI + AccessSize * RCX, RSI, RSI + AccessSize *
79280031Sdim// RCX are checked.  In this case there're no need to spill and restore
80280031Sdim// AddressReg , ShadowReg or flags four times, they're saved on stack
81280031Sdim// just once, before instrumentation of these four addresses, and restored
82280031Sdim// at the end of the instrumentation.
83280031Sdim//
84280031Sdim// There exist several things which complicate this simple algorithm.
85280031Sdim// * Instrumented memory operand can have RSP as a base or an index
86280031Sdim//   register.  So we need to add a constant offset before computation
87280031Sdim//   of memory address, since flags, AddressReg, ShadowReg, etc. were
88280031Sdim//   already stored on stack and RSP was modified.
89280031Sdim// * Debug info (usually, DWARF) should be adjusted, because sometimes
90280031Sdim//   RSP is used as a frame register. So, we need to select some
91280031Sdim//   register as a frame register and temprorary override current CFA
92280031Sdim//   register.
93280031Sdim
94274955Ssvnmirnamespace llvm {
95274955Ssvnmirnamespace {
96274955Ssvnmir
97274955Ssvnmirstatic cl::opt<bool> ClAsanInstrumentAssembly(
98274955Ssvnmir    "asan-instrument-assembly",
99274955Ssvnmir    cl::desc("instrument assembly with AddressSanitizer checks"), cl::Hidden,
100274955Ssvnmir    cl::init(false));
101274955Ssvnmir
102280031Sdimconst int64_t MinAllowedDisplacement = std::numeric_limits<int32_t>::min();
103280031Sdimconst int64_t MaxAllowedDisplacement = std::numeric_limits<int32_t>::max();
104280031Sdim
105280031Sdimint64_t ApplyDisplacementBounds(int64_t Displacement) {
106280031Sdim  return std::max(std::min(MaxAllowedDisplacement, Displacement),
107280031Sdim                  MinAllowedDisplacement);
108274955Ssvnmir}
109274955Ssvnmir
110280031Sdimvoid CheckDisplacementBounds(int64_t Displacement) {
111280031Sdim  assert(Displacement >= MinAllowedDisplacement &&
112280031Sdim         Displacement <= MaxAllowedDisplacement);
113280031Sdim}
114280031Sdim
115280031Sdimbool IsStackReg(unsigned Reg) { return Reg == X86::RSP || Reg == X86::ESP; }
116280031Sdim
117280031Sdimbool IsSmallMemAccess(unsigned AccessSize) { return AccessSize < 8; }
118280031Sdim
119274955Ssvnmirclass X86AddressSanitizer : public X86AsmInstrumentation {
120274955Ssvnmirpublic:
121280031Sdim  struct RegisterContext {
122280031Sdim  private:
123280031Sdim    enum RegOffset {
124280031Sdim      REG_OFFSET_ADDRESS = 0,
125280031Sdim      REG_OFFSET_SHADOW,
126280031Sdim      REG_OFFSET_SCRATCH
127280031Sdim    };
128280031Sdim
129280031Sdim  public:
130280031Sdim    RegisterContext(unsigned AddressReg, unsigned ShadowReg,
131280031Sdim                    unsigned ScratchReg) {
132296417Sdim      BusyRegs.push_back(convReg(AddressReg, 64));
133296417Sdim      BusyRegs.push_back(convReg(ShadowReg, 64));
134296417Sdim      BusyRegs.push_back(convReg(ScratchReg, 64));
135280031Sdim    }
136280031Sdim
137296417Sdim    unsigned AddressReg(unsigned Size) const {
138296417Sdim      return convReg(BusyRegs[REG_OFFSET_ADDRESS], Size);
139280031Sdim    }
140280031Sdim
141296417Sdim    unsigned ShadowReg(unsigned Size) const {
142296417Sdim      return convReg(BusyRegs[REG_OFFSET_SHADOW], Size);
143280031Sdim    }
144280031Sdim
145296417Sdim    unsigned ScratchReg(unsigned Size) const {
146296417Sdim      return convReg(BusyRegs[REG_OFFSET_SCRATCH], Size);
147280031Sdim    }
148280031Sdim
149280031Sdim    void AddBusyReg(unsigned Reg) {
150280031Sdim      if (Reg != X86::NoRegister)
151296417Sdim        BusyRegs.push_back(convReg(Reg, 64));
152280031Sdim    }
153280031Sdim
154280031Sdim    void AddBusyRegs(const X86Operand &Op) {
155280031Sdim      AddBusyReg(Op.getMemBaseReg());
156280031Sdim      AddBusyReg(Op.getMemIndexReg());
157280031Sdim    }
158280031Sdim
159296417Sdim    unsigned ChooseFrameReg(unsigned Size) const {
160280031Sdim      static const MCPhysReg Candidates[] = { X86::RBP, X86::RAX, X86::RBX,
161280031Sdim                                              X86::RCX, X86::RDX, X86::RDI,
162280031Sdim                                              X86::RSI };
163280031Sdim      for (unsigned Reg : Candidates) {
164280031Sdim        if (!std::count(BusyRegs.begin(), BusyRegs.end(), Reg))
165296417Sdim          return convReg(Reg, Size);
166280031Sdim      }
167280031Sdim      return X86::NoRegister;
168280031Sdim    }
169280031Sdim
170280031Sdim  private:
171296417Sdim    unsigned convReg(unsigned Reg, unsigned Size) const {
172296417Sdim      return Reg == X86::NoRegister ? Reg : getX86SubSuperRegister(Reg, Size);
173280031Sdim    }
174280031Sdim
175280031Sdim    std::vector<unsigned> BusyRegs;
176280031Sdim  };
177280031Sdim
178296417Sdim  X86AddressSanitizer(const MCSubtargetInfo *&STI)
179280031Sdim      : X86AsmInstrumentation(STI), RepPrefix(false), OrigSPOffset(0) {}
180280031Sdim
181296417Sdim  ~X86AddressSanitizer() override {}
182274955Ssvnmir
183274955Ssvnmir  // X86AsmInstrumentation implementation:
184296417Sdim  void InstrumentAndEmitInstruction(const MCInst &Inst,
185296417Sdim                                    OperandVector &Operands,
186296417Sdim                                    MCContext &Ctx,
187296417Sdim                                    const MCInstrInfo &MII,
188296417Sdim                                    MCStreamer &Out) override {
189280031Sdim    InstrumentMOVS(Inst, Operands, Ctx, MII, Out);
190280031Sdim    if (RepPrefix)
191280031Sdim      EmitInstruction(Out, MCInstBuilder(X86::REP_PREFIX));
192280031Sdim
193274955Ssvnmir    InstrumentMOV(Inst, Operands, Ctx, MII, Out);
194280031Sdim
195280031Sdim    RepPrefix = (Inst.getOpcode() == X86::REP_PREFIX);
196280031Sdim    if (!RepPrefix)
197280031Sdim      EmitInstruction(Out, Inst);
198274955Ssvnmir  }
199274955Ssvnmir
200280031Sdim  // Adjusts up stack and saves all registers used in instrumentation.
201280031Sdim  virtual void InstrumentMemOperandPrologue(const RegisterContext &RegCtx,
202280031Sdim                                            MCContext &Ctx,
203280031Sdim                                            MCStreamer &Out) = 0;
204274955Ssvnmir
205280031Sdim  // Restores all registers used in instrumentation and adjusts stack.
206280031Sdim  virtual void InstrumentMemOperandEpilogue(const RegisterContext &RegCtx,
207280031Sdim                                            MCContext &Ctx,
208280031Sdim                                            MCStreamer &Out) = 0;
209280031Sdim
210280031Sdim  virtual void InstrumentMemOperandSmall(X86Operand &Op, unsigned AccessSize,
211280031Sdim                                         bool IsWrite,
212280031Sdim                                         const RegisterContext &RegCtx,
213280031Sdim                                         MCContext &Ctx, MCStreamer &Out) = 0;
214280031Sdim  virtual void InstrumentMemOperandLarge(X86Operand &Op, unsigned AccessSize,
215280031Sdim                                         bool IsWrite,
216280031Sdim                                         const RegisterContext &RegCtx,
217280031Sdim                                         MCContext &Ctx, MCStreamer &Out) = 0;
218280031Sdim
219280031Sdim  virtual void InstrumentMOVSImpl(unsigned AccessSize, MCContext &Ctx,
220280031Sdim                                  MCStreamer &Out) = 0;
221280031Sdim
222280031Sdim  void InstrumentMemOperand(X86Operand &Op, unsigned AccessSize, bool IsWrite,
223280031Sdim                            const RegisterContext &RegCtx, MCContext &Ctx,
224280031Sdim                            MCStreamer &Out);
225280031Sdim  void InstrumentMOVSBase(unsigned DstReg, unsigned SrcReg, unsigned CntReg,
226280031Sdim                          unsigned AccessSize, MCContext &Ctx, MCStreamer &Out);
227280031Sdim
228280031Sdim  void InstrumentMOVS(const MCInst &Inst, OperandVector &Operands,
229280031Sdim                      MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
230274955Ssvnmir  void InstrumentMOV(const MCInst &Inst, OperandVector &Operands,
231274955Ssvnmir                     MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
232274955Ssvnmir
233280031Sdimprotected:
234274955Ssvnmir  void EmitLabel(MCStreamer &Out, MCSymbol *Label) { Out.EmitLabel(Label); }
235274955Ssvnmir
236296417Sdim  void EmitLEA(X86Operand &Op, unsigned Size, unsigned Reg, MCStreamer &Out) {
237296417Sdim    assert(Size == 32 || Size == 64);
238280031Sdim    MCInst Inst;
239296417Sdim    Inst.setOpcode(Size == 32 ? X86::LEA32r : X86::LEA64r);
240296417Sdim    Inst.addOperand(MCOperand::createReg(getX86SubSuperRegister(Reg, Size)));
241280031Sdim    Op.addMemOperands(Inst, 5);
242280031Sdim    EmitInstruction(Out, Inst);
243280031Sdim  }
244280031Sdim
245296417Sdim  void ComputeMemOperandAddress(X86Operand &Op, unsigned Size,
246280031Sdim                                unsigned Reg, MCContext &Ctx, MCStreamer &Out);
247280031Sdim
248280031Sdim  // Creates new memory operand with Displacement added to an original
249280031Sdim  // displacement. Residue will contain a residue which could happen when the
250280031Sdim  // total displacement exceeds 32-bit limitation.
251280031Sdim  std::unique_ptr<X86Operand> AddDisplacement(X86Operand &Op,
252280031Sdim                                              int64_t Displacement,
253280031Sdim                                              MCContext &Ctx, int64_t *Residue);
254280031Sdim
255280031Sdim  bool is64BitMode() const {
256296417Sdim    return STI->getFeatureBits()[X86::Mode64Bit];
257280031Sdim  }
258280031Sdim  bool is32BitMode() const {
259296417Sdim    return STI->getFeatureBits()[X86::Mode32Bit];
260280031Sdim  }
261280031Sdim  bool is16BitMode() const {
262296417Sdim    return STI->getFeatureBits()[X86::Mode16Bit];
263280031Sdim  }
264280031Sdim
265280031Sdim  unsigned getPointerWidth() {
266280031Sdim    if (is16BitMode()) return 16;
267280031Sdim    if (is32BitMode()) return 32;
268280031Sdim    if (is64BitMode()) return 64;
269280031Sdim    llvm_unreachable("invalid mode");
270280031Sdim  }
271280031Sdim
272280031Sdim  // True when previous instruction was actually REP prefix.
273280031Sdim  bool RepPrefix;
274280031Sdim
275280031Sdim  // Offset from the original SP register.
276280031Sdim  int64_t OrigSPOffset;
277274955Ssvnmir};
278274955Ssvnmir
279274955Ssvnmirvoid X86AddressSanitizer::InstrumentMemOperand(
280280031Sdim    X86Operand &Op, unsigned AccessSize, bool IsWrite,
281280031Sdim    const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
282274955Ssvnmir  assert(Op.isMem() && "Op should be a memory operand.");
283274955Ssvnmir  assert((AccessSize & (AccessSize - 1)) == 0 && AccessSize <= 16 &&
284274955Ssvnmir         "AccessSize should be a power of two, less or equal than 16.");
285280031Sdim  // FIXME: take into account load/store alignment.
286280031Sdim  if (IsSmallMemAccess(AccessSize))
287280031Sdim    InstrumentMemOperandSmall(Op, AccessSize, IsWrite, RegCtx, Ctx, Out);
288280031Sdim  else
289280031Sdim    InstrumentMemOperandLarge(Op, AccessSize, IsWrite, RegCtx, Ctx, Out);
290280031Sdim}
291274955Ssvnmir
292280031Sdimvoid X86AddressSanitizer::InstrumentMOVSBase(unsigned DstReg, unsigned SrcReg,
293280031Sdim                                             unsigned CntReg,
294280031Sdim                                             unsigned AccessSize,
295280031Sdim                                             MCContext &Ctx, MCStreamer &Out) {
296280031Sdim  // FIXME: check whole ranges [DstReg .. DstReg + AccessSize * (CntReg - 1)]
297280031Sdim  // and [SrcReg .. SrcReg + AccessSize * (CntReg - 1)].
298280031Sdim  RegisterContext RegCtx(X86::RDX /* AddressReg */, X86::RAX /* ShadowReg */,
299280031Sdim                         IsSmallMemAccess(AccessSize)
300280031Sdim                             ? X86::RBX
301280031Sdim                             : X86::NoRegister /* ScratchReg */);
302280031Sdim  RegCtx.AddBusyReg(DstReg);
303280031Sdim  RegCtx.AddBusyReg(SrcReg);
304280031Sdim  RegCtx.AddBusyReg(CntReg);
305280031Sdim
306280031Sdim  InstrumentMemOperandPrologue(RegCtx, Ctx, Out);
307280031Sdim
308280031Sdim  // Test (%SrcReg)
309280031Sdim  {
310288943Sdim    const MCExpr *Disp = MCConstantExpr::create(0, Ctx);
311280031Sdim    std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
312280031Sdim        getPointerWidth(), 0, Disp, SrcReg, 0, AccessSize, SMLoc(), SMLoc()));
313280031Sdim    InstrumentMemOperand(*Op, AccessSize, false /* IsWrite */, RegCtx, Ctx,
314280031Sdim                         Out);
315280031Sdim  }
316280031Sdim
317280031Sdim  // Test -1(%SrcReg, %CntReg, AccessSize)
318280031Sdim  {
319288943Sdim    const MCExpr *Disp = MCConstantExpr::create(-1, Ctx);
320280031Sdim    std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
321280031Sdim        getPointerWidth(), 0, Disp, SrcReg, CntReg, AccessSize, SMLoc(),
322280031Sdim        SMLoc()));
323280031Sdim    InstrumentMemOperand(*Op, AccessSize, false /* IsWrite */, RegCtx, Ctx,
324280031Sdim                         Out);
325280031Sdim  }
326280031Sdim
327280031Sdim  // Test (%DstReg)
328280031Sdim  {
329288943Sdim    const MCExpr *Disp = MCConstantExpr::create(0, Ctx);
330280031Sdim    std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
331280031Sdim        getPointerWidth(), 0, Disp, DstReg, 0, AccessSize, SMLoc(), SMLoc()));
332280031Sdim    InstrumentMemOperand(*Op, AccessSize, true /* IsWrite */, RegCtx, Ctx, Out);
333280031Sdim  }
334280031Sdim
335280031Sdim  // Test -1(%DstReg, %CntReg, AccessSize)
336280031Sdim  {
337288943Sdim    const MCExpr *Disp = MCConstantExpr::create(-1, Ctx);
338280031Sdim    std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
339280031Sdim        getPointerWidth(), 0, Disp, DstReg, CntReg, AccessSize, SMLoc(),
340280031Sdim        SMLoc()));
341280031Sdim    InstrumentMemOperand(*Op, AccessSize, true /* IsWrite */, RegCtx, Ctx, Out);
342280031Sdim  }
343280031Sdim
344280031Sdim  InstrumentMemOperandEpilogue(RegCtx, Ctx, Out);
345280031Sdim}
346280031Sdim
347280031Sdimvoid X86AddressSanitizer::InstrumentMOVS(const MCInst &Inst,
348280031Sdim                                         OperandVector &Operands,
349280031Sdim                                         MCContext &Ctx, const MCInstrInfo &MII,
350280031Sdim                                         MCStreamer &Out) {
351280031Sdim  // Access size in bytes.
352280031Sdim  unsigned AccessSize = 0;
353280031Sdim
354280031Sdim  switch (Inst.getOpcode()) {
355280031Sdim  case X86::MOVSB:
356280031Sdim    AccessSize = 1;
357280031Sdim    break;
358280031Sdim  case X86::MOVSW:
359280031Sdim    AccessSize = 2;
360280031Sdim    break;
361280031Sdim  case X86::MOVSL:
362280031Sdim    AccessSize = 4;
363280031Sdim    break;
364280031Sdim  case X86::MOVSQ:
365280031Sdim    AccessSize = 8;
366280031Sdim    break;
367280031Sdim  default:
368274955Ssvnmir    return;
369280031Sdim  }
370274955Ssvnmir
371280031Sdim  InstrumentMOVSImpl(AccessSize, Ctx, Out);
372274955Ssvnmir}
373274955Ssvnmir
374280031Sdimvoid X86AddressSanitizer::InstrumentMOV(const MCInst &Inst,
375280031Sdim                                        OperandVector &Operands, MCContext &Ctx,
376280031Sdim                                        const MCInstrInfo &MII,
377280031Sdim                                        MCStreamer &Out) {
378274955Ssvnmir  // Access size in bytes.
379274955Ssvnmir  unsigned AccessSize = 0;
380274955Ssvnmir
381274955Ssvnmir  switch (Inst.getOpcode()) {
382274955Ssvnmir  case X86::MOV8mi:
383274955Ssvnmir  case X86::MOV8mr:
384274955Ssvnmir  case X86::MOV8rm:
385274955Ssvnmir    AccessSize = 1;
386274955Ssvnmir    break;
387274955Ssvnmir  case X86::MOV16mi:
388274955Ssvnmir  case X86::MOV16mr:
389274955Ssvnmir  case X86::MOV16rm:
390274955Ssvnmir    AccessSize = 2;
391274955Ssvnmir    break;
392274955Ssvnmir  case X86::MOV32mi:
393274955Ssvnmir  case X86::MOV32mr:
394274955Ssvnmir  case X86::MOV32rm:
395274955Ssvnmir    AccessSize = 4;
396274955Ssvnmir    break;
397274955Ssvnmir  case X86::MOV64mi32:
398274955Ssvnmir  case X86::MOV64mr:
399274955Ssvnmir  case X86::MOV64rm:
400274955Ssvnmir    AccessSize = 8;
401274955Ssvnmir    break;
402274955Ssvnmir  case X86::MOVAPDmr:
403274955Ssvnmir  case X86::MOVAPSmr:
404274955Ssvnmir  case X86::MOVAPDrm:
405274955Ssvnmir  case X86::MOVAPSrm:
406274955Ssvnmir    AccessSize = 16;
407274955Ssvnmir    break;
408274955Ssvnmir  default:
409274955Ssvnmir    return;
410274955Ssvnmir  }
411274955Ssvnmir
412274955Ssvnmir  const bool IsWrite = MII.get(Inst.getOpcode()).mayStore();
413280031Sdim
414274955Ssvnmir  for (unsigned Ix = 0; Ix < Operands.size(); ++Ix) {
415274955Ssvnmir    assert(Operands[Ix]);
416274955Ssvnmir    MCParsedAsmOperand &Op = *Operands[Ix];
417280031Sdim    if (Op.isMem()) {
418280031Sdim      X86Operand &MemOp = static_cast<X86Operand &>(Op);
419280031Sdim      RegisterContext RegCtx(
420280031Sdim          X86::RDI /* AddressReg */, X86::RAX /* ShadowReg */,
421280031Sdim          IsSmallMemAccess(AccessSize) ? X86::RCX
422280031Sdim                                       : X86::NoRegister /* ScratchReg */);
423280031Sdim      RegCtx.AddBusyRegs(MemOp);
424280031Sdim      InstrumentMemOperandPrologue(RegCtx, Ctx, Out);
425280031Sdim      InstrumentMemOperand(MemOp, AccessSize, IsWrite, RegCtx, Ctx, Out);
426280031Sdim      InstrumentMemOperandEpilogue(RegCtx, Ctx, Out);
427280031Sdim    }
428274955Ssvnmir  }
429274955Ssvnmir}
430274955Ssvnmir
431280031Sdimvoid X86AddressSanitizer::ComputeMemOperandAddress(X86Operand &Op,
432296417Sdim                                                   unsigned Size,
433280031Sdim                                                   unsigned Reg, MCContext &Ctx,
434280031Sdim                                                   MCStreamer &Out) {
435280031Sdim  int64_t Displacement = 0;
436280031Sdim  if (IsStackReg(Op.getMemBaseReg()))
437280031Sdim    Displacement -= OrigSPOffset;
438280031Sdim  if (IsStackReg(Op.getMemIndexReg()))
439280031Sdim    Displacement -= OrigSPOffset * Op.getMemScale();
440280031Sdim
441280031Sdim  assert(Displacement >= 0);
442280031Sdim
443280031Sdim  // Emit Op as is.
444280031Sdim  if (Displacement == 0) {
445296417Sdim    EmitLEA(Op, Size, Reg, Out);
446280031Sdim    return;
447280031Sdim  }
448280031Sdim
449280031Sdim  int64_t Residue;
450280031Sdim  std::unique_ptr<X86Operand> NewOp =
451280031Sdim      AddDisplacement(Op, Displacement, Ctx, &Residue);
452296417Sdim  EmitLEA(*NewOp, Size, Reg, Out);
453280031Sdim
454280031Sdim  while (Residue != 0) {
455280031Sdim    const MCConstantExpr *Disp =
456288943Sdim        MCConstantExpr::create(ApplyDisplacementBounds(Residue), Ctx);
457280031Sdim    std::unique_ptr<X86Operand> DispOp =
458280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, Reg, 0, 1, SMLoc(),
459280031Sdim                              SMLoc());
460296417Sdim    EmitLEA(*DispOp, Size, Reg, Out);
461280031Sdim    Residue -= Disp->getValue();
462280031Sdim  }
463280031Sdim}
464280031Sdim
465280031Sdimstd::unique_ptr<X86Operand>
466280031SdimX86AddressSanitizer::AddDisplacement(X86Operand &Op, int64_t Displacement,
467280031Sdim                                     MCContext &Ctx, int64_t *Residue) {
468280031Sdim  assert(Displacement >= 0);
469280031Sdim
470280031Sdim  if (Displacement == 0 ||
471280031Sdim      (Op.getMemDisp() && Op.getMemDisp()->getKind() != MCExpr::Constant)) {
472280031Sdim    *Residue = Displacement;
473280031Sdim    return X86Operand::CreateMem(Op.getMemModeSize(), Op.getMemSegReg(),
474280031Sdim                                 Op.getMemDisp(), Op.getMemBaseReg(),
475280031Sdim                                 Op.getMemIndexReg(), Op.getMemScale(),
476280031Sdim                                 SMLoc(), SMLoc());
477280031Sdim  }
478280031Sdim
479280031Sdim  int64_t OrigDisplacement =
480280031Sdim      static_cast<const MCConstantExpr *>(Op.getMemDisp())->getValue();
481280031Sdim  CheckDisplacementBounds(OrigDisplacement);
482280031Sdim  Displacement += OrigDisplacement;
483280031Sdim
484280031Sdim  int64_t NewDisplacement = ApplyDisplacementBounds(Displacement);
485280031Sdim  CheckDisplacementBounds(NewDisplacement);
486280031Sdim
487280031Sdim  *Residue = Displacement - NewDisplacement;
488288943Sdim  const MCExpr *Disp = MCConstantExpr::create(NewDisplacement, Ctx);
489280031Sdim  return X86Operand::CreateMem(Op.getMemModeSize(), Op.getMemSegReg(), Disp,
490280031Sdim                               Op.getMemBaseReg(), Op.getMemIndexReg(),
491280031Sdim                               Op.getMemScale(), SMLoc(), SMLoc());
492280031Sdim}
493280031Sdim
494274955Ssvnmirclass X86AddressSanitizer32 : public X86AddressSanitizer {
495274955Ssvnmirpublic:
496274955Ssvnmir  static const long kShadowOffset = 0x20000000;
497274955Ssvnmir
498296417Sdim  X86AddressSanitizer32(const MCSubtargetInfo *&STI)
499274955Ssvnmir      : X86AddressSanitizer(STI) {}
500280031Sdim
501296417Sdim  ~X86AddressSanitizer32() override {}
502274955Ssvnmir
503280031Sdim  unsigned GetFrameReg(const MCContext &Ctx, MCStreamer &Out) {
504280031Sdim    unsigned FrameReg = GetFrameRegGeneric(Ctx, Out);
505280031Sdim    if (FrameReg == X86::NoRegister)
506280031Sdim      return FrameReg;
507296417Sdim    return getX86SubSuperRegister(FrameReg, 32);
508280031Sdim  }
509274955Ssvnmir
510280031Sdim  void SpillReg(MCStreamer &Out, unsigned Reg) {
511280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(Reg));
512280031Sdim    OrigSPOffset -= 4;
513280031Sdim  }
514280031Sdim
515280031Sdim  void RestoreReg(MCStreamer &Out, unsigned Reg) {
516280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(Reg));
517280031Sdim    OrigSPOffset += 4;
518280031Sdim  }
519280031Sdim
520280031Sdim  void StoreFlags(MCStreamer &Out) {
521280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::PUSHF32));
522280031Sdim    OrigSPOffset -= 4;
523280031Sdim  }
524280031Sdim
525280031Sdim  void RestoreFlags(MCStreamer &Out) {
526280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::POPF32));
527280031Sdim    OrigSPOffset += 4;
528280031Sdim  }
529280031Sdim
530296417Sdim  void InstrumentMemOperandPrologue(const RegisterContext &RegCtx,
531296417Sdim                                    MCContext &Ctx,
532296417Sdim                                    MCStreamer &Out) override {
533296417Sdim    unsigned LocalFrameReg = RegCtx.ChooseFrameReg(32);
534280031Sdim    assert(LocalFrameReg != X86::NoRegister);
535280031Sdim
536280031Sdim    const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
537280031Sdim    unsigned FrameReg = GetFrameReg(Ctx, Out);
538280031Sdim    if (MRI && FrameReg != X86::NoRegister) {
539280031Sdim      SpillReg(Out, LocalFrameReg);
540280031Sdim      if (FrameReg == X86::ESP) {
541280031Sdim        Out.EmitCFIAdjustCfaOffset(4 /* byte size of the LocalFrameReg */);
542280031Sdim        Out.EmitCFIRelOffset(
543280031Sdim            MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */), 0);
544280031Sdim      }
545280031Sdim      EmitInstruction(
546280031Sdim          Out,
547280031Sdim          MCInstBuilder(X86::MOV32rr).addReg(LocalFrameReg).addReg(FrameReg));
548280031Sdim      Out.EmitCFIRememberState();
549280031Sdim      Out.EmitCFIDefCfaRegister(
550280031Sdim          MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */));
551280031Sdim    }
552280031Sdim
553296417Sdim    SpillReg(Out, RegCtx.AddressReg(32));
554296417Sdim    SpillReg(Out, RegCtx.ShadowReg(32));
555296417Sdim    if (RegCtx.ScratchReg(32) != X86::NoRegister)
556296417Sdim      SpillReg(Out, RegCtx.ScratchReg(32));
557280031Sdim    StoreFlags(Out);
558280031Sdim  }
559280031Sdim
560296417Sdim  void InstrumentMemOperandEpilogue(const RegisterContext &RegCtx,
561296417Sdim                                    MCContext &Ctx,
562296417Sdim                                    MCStreamer &Out) override {
563296417Sdim    unsigned LocalFrameReg = RegCtx.ChooseFrameReg(32);
564280031Sdim    assert(LocalFrameReg != X86::NoRegister);
565280031Sdim
566280031Sdim    RestoreFlags(Out);
567296417Sdim    if (RegCtx.ScratchReg(32) != X86::NoRegister)
568296417Sdim      RestoreReg(Out, RegCtx.ScratchReg(32));
569296417Sdim    RestoreReg(Out, RegCtx.ShadowReg(32));
570296417Sdim    RestoreReg(Out, RegCtx.AddressReg(32));
571280031Sdim
572280031Sdim    unsigned FrameReg = GetFrameReg(Ctx, Out);
573280031Sdim    if (Ctx.getRegisterInfo() && FrameReg != X86::NoRegister) {
574280031Sdim      RestoreReg(Out, LocalFrameReg);
575280031Sdim      Out.EmitCFIRestoreState();
576280031Sdim      if (FrameReg == X86::ESP)
577280031Sdim        Out.EmitCFIAdjustCfaOffset(-4 /* byte size of the LocalFrameReg */);
578280031Sdim    }
579280031Sdim  }
580280031Sdim
581296417Sdim  void InstrumentMemOperandSmall(X86Operand &Op, unsigned AccessSize,
582296417Sdim                                 bool IsWrite,
583296417Sdim                                 const RegisterContext &RegCtx,
584296417Sdim                                 MCContext &Ctx,
585296417Sdim                                 MCStreamer &Out) override;
586296417Sdim  void InstrumentMemOperandLarge(X86Operand &Op, unsigned AccessSize,
587296417Sdim                                 bool IsWrite,
588296417Sdim                                 const RegisterContext &RegCtx,
589296417Sdim                                 MCContext &Ctx,
590296417Sdim                                 MCStreamer &Out) override;
591296417Sdim  void InstrumentMOVSImpl(unsigned AccessSize, MCContext &Ctx,
592296417Sdim                          MCStreamer &Out) override;
593280031Sdim
594280031Sdimprivate:
595280031Sdim  void EmitCallAsanReport(unsigned AccessSize, bool IsWrite, MCContext &Ctx,
596280031Sdim                          MCStreamer &Out, const RegisterContext &RegCtx) {
597274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::CLD));
598274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::MMX_EMMS));
599274955Ssvnmir
600280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::AND64ri8)
601280031Sdim                             .addReg(X86::ESP)
602280031Sdim                             .addReg(X86::ESP)
603280031Sdim                             .addImm(-16));
604280031Sdim    EmitInstruction(
605296417Sdim        Out, MCInstBuilder(X86::PUSH32r).addReg(RegCtx.AddressReg(32)));
606274955Ssvnmir
607296417Sdim    MCSymbol *FnSym = Ctx.getOrCreateSymbol(llvm::Twine("__asan_report_") +
608296417Sdim                                            (IsWrite ? "store" : "load") +
609296417Sdim                                            llvm::Twine(AccessSize));
610274955Ssvnmir    const MCSymbolRefExpr *FnExpr =
611288943Sdim        MCSymbolRefExpr::create(FnSym, MCSymbolRefExpr::VK_PLT, Ctx);
612274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::CALLpcrel32).addExpr(FnExpr));
613274955Ssvnmir  }
614274955Ssvnmir};
615274955Ssvnmir
616280031Sdimvoid X86AddressSanitizer32::InstrumentMemOperandSmall(
617280031Sdim    X86Operand &Op, unsigned AccessSize, bool IsWrite,
618280031Sdim    const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
619296417Sdim  unsigned AddressRegI32 = RegCtx.AddressReg(32);
620296417Sdim  unsigned ShadowRegI32 = RegCtx.ShadowReg(32);
621296417Sdim  unsigned ShadowRegI8 = RegCtx.ShadowReg(8);
622274955Ssvnmir
623296417Sdim  assert(RegCtx.ScratchReg(32) != X86::NoRegister);
624296417Sdim  unsigned ScratchRegI32 = RegCtx.ScratchReg(32);
625274955Ssvnmir
626296417Sdim  ComputeMemOperandAddress(Op, 32, AddressRegI32, Ctx, Out);
627274955Ssvnmir
628280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ShadowRegI32).addReg(
629280031Sdim                           AddressRegI32));
630280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::SHR32ri)
631280031Sdim                           .addReg(ShadowRegI32)
632280031Sdim                           .addReg(ShadowRegI32)
633280031Sdim                           .addImm(3));
634280031Sdim
635274955Ssvnmir  {
636274955Ssvnmir    MCInst Inst;
637274955Ssvnmir    Inst.setOpcode(X86::MOV8rm);
638288943Sdim    Inst.addOperand(MCOperand::createReg(ShadowRegI8));
639288943Sdim    const MCExpr *Disp = MCConstantExpr::create(kShadowOffset, Ctx);
640274955Ssvnmir    std::unique_ptr<X86Operand> Op(
641280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI32, 0, 1,
642280031Sdim                              SMLoc(), SMLoc()));
643274955Ssvnmir    Op->addMemOperands(Inst, 5);
644274955Ssvnmir    EmitInstruction(Out, Inst);
645274955Ssvnmir  }
646274955Ssvnmir
647280031Sdim  EmitInstruction(
648280031Sdim      Out, MCInstBuilder(X86::TEST8rr).addReg(ShadowRegI8).addReg(ShadowRegI8));
649288943Sdim  MCSymbol *DoneSym = Ctx.createTempSymbol();
650288943Sdim  const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
651280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
652274955Ssvnmir
653280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ScratchRegI32).addReg(
654280031Sdim                           AddressRegI32));
655280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::AND32ri)
656280031Sdim                           .addReg(ScratchRegI32)
657280031Sdim                           .addReg(ScratchRegI32)
658280031Sdim                           .addImm(7));
659274955Ssvnmir
660274955Ssvnmir  switch (AccessSize) {
661280031Sdim  default: llvm_unreachable("Incorrect access size");
662274955Ssvnmir  case 1:
663274955Ssvnmir    break;
664274955Ssvnmir  case 2: {
665288943Sdim    const MCExpr *Disp = MCConstantExpr::create(1, Ctx);
666274955Ssvnmir    std::unique_ptr<X86Operand> Op(
667280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ScratchRegI32, 0, 1,
668280031Sdim                              SMLoc(), SMLoc()));
669296417Sdim    EmitLEA(*Op, 32, ScratchRegI32, Out);
670274955Ssvnmir    break;
671274955Ssvnmir  }
672274955Ssvnmir  case 4:
673280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::ADD32ri8)
674280031Sdim                             .addReg(ScratchRegI32)
675280031Sdim                             .addReg(ScratchRegI32)
676280031Sdim                             .addImm(3));
677274955Ssvnmir    break;
678274955Ssvnmir  }
679274955Ssvnmir
680274955Ssvnmir  EmitInstruction(
681280031Sdim      Out,
682280031Sdim      MCInstBuilder(X86::MOVSX32rr8).addReg(ShadowRegI32).addReg(ShadowRegI8));
683280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::CMP32rr).addReg(ScratchRegI32).addReg(
684280031Sdim                           ShadowRegI32));
685280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JL_1).addExpr(DoneExpr));
686274955Ssvnmir
687280031Sdim  EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
688274955Ssvnmir  EmitLabel(Out, DoneSym);
689274955Ssvnmir}
690274955Ssvnmir
691280031Sdimvoid X86AddressSanitizer32::InstrumentMemOperandLarge(
692280031Sdim    X86Operand &Op, unsigned AccessSize, bool IsWrite,
693280031Sdim    const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
694296417Sdim  unsigned AddressRegI32 = RegCtx.AddressReg(32);
695296417Sdim  unsigned ShadowRegI32 = RegCtx.ShadowReg(32);
696274955Ssvnmir
697296417Sdim  ComputeMemOperandAddress(Op, 32, AddressRegI32, Ctx, Out);
698280031Sdim
699280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ShadowRegI32).addReg(
700280031Sdim                           AddressRegI32));
701280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::SHR32ri)
702280031Sdim                           .addReg(ShadowRegI32)
703280031Sdim                           .addReg(ShadowRegI32)
704280031Sdim                           .addImm(3));
705274955Ssvnmir  {
706274955Ssvnmir    MCInst Inst;
707274955Ssvnmir    switch (AccessSize) {
708280031Sdim    default: llvm_unreachable("Incorrect access size");
709280031Sdim    case 8:
710280031Sdim      Inst.setOpcode(X86::CMP8mi);
711280031Sdim      break;
712280031Sdim    case 16:
713280031Sdim      Inst.setOpcode(X86::CMP16mi);
714280031Sdim      break;
715274955Ssvnmir    }
716288943Sdim    const MCExpr *Disp = MCConstantExpr::create(kShadowOffset, Ctx);
717274955Ssvnmir    std::unique_ptr<X86Operand> Op(
718280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI32, 0, 1,
719280031Sdim                              SMLoc(), SMLoc()));
720274955Ssvnmir    Op->addMemOperands(Inst, 5);
721288943Sdim    Inst.addOperand(MCOperand::createImm(0));
722274955Ssvnmir    EmitInstruction(Out, Inst);
723274955Ssvnmir  }
724288943Sdim  MCSymbol *DoneSym = Ctx.createTempSymbol();
725288943Sdim  const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
726280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
727274955Ssvnmir
728280031Sdim  EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
729274955Ssvnmir  EmitLabel(Out, DoneSym);
730280031Sdim}
731274955Ssvnmir
732280031Sdimvoid X86AddressSanitizer32::InstrumentMOVSImpl(unsigned AccessSize,
733280031Sdim                                               MCContext &Ctx,
734280031Sdim                                               MCStreamer &Out) {
735280031Sdim  StoreFlags(Out);
736280031Sdim
737280031Sdim  // No need to test when ECX is equals to zero.
738288943Sdim  MCSymbol *DoneSym = Ctx.createTempSymbol();
739288943Sdim  const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
740280031Sdim  EmitInstruction(
741280031Sdim      Out, MCInstBuilder(X86::TEST32rr).addReg(X86::ECX).addReg(X86::ECX));
742280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
743280031Sdim
744280031Sdim  // Instrument first and last elements in src and dst range.
745280031Sdim  InstrumentMOVSBase(X86::EDI /* DstReg */, X86::ESI /* SrcReg */,
746280031Sdim                     X86::ECX /* CntReg */, AccessSize, Ctx, Out);
747280031Sdim
748280031Sdim  EmitLabel(Out, DoneSym);
749280031Sdim  RestoreFlags(Out);
750274955Ssvnmir}
751274955Ssvnmir
752274955Ssvnmirclass X86AddressSanitizer64 : public X86AddressSanitizer {
753274955Ssvnmirpublic:
754274955Ssvnmir  static const long kShadowOffset = 0x7fff8000;
755274955Ssvnmir
756296417Sdim  X86AddressSanitizer64(const MCSubtargetInfo *&STI)
757274955Ssvnmir      : X86AddressSanitizer(STI) {}
758280031Sdim
759296417Sdim  ~X86AddressSanitizer64() override {}
760274955Ssvnmir
761280031Sdim  unsigned GetFrameReg(const MCContext &Ctx, MCStreamer &Out) {
762280031Sdim    unsigned FrameReg = GetFrameRegGeneric(Ctx, Out);
763280031Sdim    if (FrameReg == X86::NoRegister)
764280031Sdim      return FrameReg;
765296417Sdim    return getX86SubSuperRegister(FrameReg, 64);
766280031Sdim  }
767274955Ssvnmir
768280031Sdim  void SpillReg(MCStreamer &Out, unsigned Reg) {
769280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(Reg));
770280031Sdim    OrigSPOffset -= 8;
771280031Sdim  }
772280031Sdim
773280031Sdim  void RestoreReg(MCStreamer &Out, unsigned Reg) {
774280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(Reg));
775280031Sdim    OrigSPOffset += 8;
776280031Sdim  }
777280031Sdim
778280031Sdim  void StoreFlags(MCStreamer &Out) {
779280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::PUSHF64));
780280031Sdim    OrigSPOffset -= 8;
781280031Sdim  }
782280031Sdim
783280031Sdim  void RestoreFlags(MCStreamer &Out) {
784280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::POPF64));
785280031Sdim    OrigSPOffset += 8;
786280031Sdim  }
787280031Sdim
788296417Sdim  void InstrumentMemOperandPrologue(const RegisterContext &RegCtx,
789296417Sdim                                    MCContext &Ctx,
790296417Sdim                                    MCStreamer &Out) override {
791296417Sdim    unsigned LocalFrameReg = RegCtx.ChooseFrameReg(64);
792280031Sdim    assert(LocalFrameReg != X86::NoRegister);
793280031Sdim
794280031Sdim    const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
795280031Sdim    unsigned FrameReg = GetFrameReg(Ctx, Out);
796280031Sdim    if (MRI && FrameReg != X86::NoRegister) {
797280031Sdim      SpillReg(Out, X86::RBP);
798280031Sdim      if (FrameReg == X86::RSP) {
799280031Sdim        Out.EmitCFIAdjustCfaOffset(8 /* byte size of the LocalFrameReg */);
800280031Sdim        Out.EmitCFIRelOffset(
801280031Sdim            MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */), 0);
802280031Sdim      }
803280031Sdim      EmitInstruction(
804280031Sdim          Out,
805280031Sdim          MCInstBuilder(X86::MOV64rr).addReg(LocalFrameReg).addReg(FrameReg));
806280031Sdim      Out.EmitCFIRememberState();
807280031Sdim      Out.EmitCFIDefCfaRegister(
808280031Sdim          MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */));
809280031Sdim    }
810280031Sdim
811280031Sdim    EmitAdjustRSP(Ctx, Out, -128);
812296417Sdim    SpillReg(Out, RegCtx.ShadowReg(64));
813296417Sdim    SpillReg(Out, RegCtx.AddressReg(64));
814296417Sdim    if (RegCtx.ScratchReg(64) != X86::NoRegister)
815296417Sdim      SpillReg(Out, RegCtx.ScratchReg(64));
816280031Sdim    StoreFlags(Out);
817280031Sdim  }
818280031Sdim
819296417Sdim  void InstrumentMemOperandEpilogue(const RegisterContext &RegCtx,
820296417Sdim                                    MCContext &Ctx,
821296417Sdim                                    MCStreamer &Out) override {
822296417Sdim    unsigned LocalFrameReg = RegCtx.ChooseFrameReg(64);
823280031Sdim    assert(LocalFrameReg != X86::NoRegister);
824280031Sdim
825280031Sdim    RestoreFlags(Out);
826296417Sdim    if (RegCtx.ScratchReg(64) != X86::NoRegister)
827296417Sdim      RestoreReg(Out, RegCtx.ScratchReg(64));
828296417Sdim    RestoreReg(Out, RegCtx.AddressReg(64));
829296417Sdim    RestoreReg(Out, RegCtx.ShadowReg(64));
830280031Sdim    EmitAdjustRSP(Ctx, Out, 128);
831280031Sdim
832280031Sdim    unsigned FrameReg = GetFrameReg(Ctx, Out);
833280031Sdim    if (Ctx.getRegisterInfo() && FrameReg != X86::NoRegister) {
834280031Sdim      RestoreReg(Out, LocalFrameReg);
835280031Sdim      Out.EmitCFIRestoreState();
836280031Sdim      if (FrameReg == X86::RSP)
837280031Sdim        Out.EmitCFIAdjustCfaOffset(-8 /* byte size of the LocalFrameReg */);
838280031Sdim    }
839280031Sdim  }
840280031Sdim
841296417Sdim  void InstrumentMemOperandSmall(X86Operand &Op, unsigned AccessSize,
842296417Sdim                                 bool IsWrite,
843296417Sdim                                 const RegisterContext &RegCtx,
844296417Sdim                                 MCContext &Ctx,
845296417Sdim                                 MCStreamer &Out) override;
846296417Sdim  void InstrumentMemOperandLarge(X86Operand &Op, unsigned AccessSize,
847296417Sdim                                 bool IsWrite,
848296417Sdim                                 const RegisterContext &RegCtx,
849296417Sdim                                 MCContext &Ctx,
850296417Sdim                                 MCStreamer &Out) override;
851296417Sdim  void InstrumentMOVSImpl(unsigned AccessSize, MCContext &Ctx,
852296417Sdim                          MCStreamer &Out) override;
853280031Sdim
854274955Ssvnmirprivate:
855274955Ssvnmir  void EmitAdjustRSP(MCContext &Ctx, MCStreamer &Out, long Offset) {
856288943Sdim    const MCExpr *Disp = MCConstantExpr::create(Offset, Ctx);
857274955Ssvnmir    std::unique_ptr<X86Operand> Op(
858280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, X86::RSP, 0, 1,
859280031Sdim                              SMLoc(), SMLoc()));
860296417Sdim    EmitLEA(*Op, 64, X86::RSP, Out);
861280031Sdim    OrigSPOffset += Offset;
862274955Ssvnmir  }
863274955Ssvnmir
864280031Sdim  void EmitCallAsanReport(unsigned AccessSize, bool IsWrite, MCContext &Ctx,
865280031Sdim                          MCStreamer &Out, const RegisterContext &RegCtx) {
866274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::CLD));
867274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::MMX_EMMS));
868274955Ssvnmir
869280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::AND64ri8)
870280031Sdim                             .addReg(X86::RSP)
871280031Sdim                             .addReg(X86::RSP)
872280031Sdim                             .addImm(-16));
873274955Ssvnmir
874296417Sdim    if (RegCtx.AddressReg(64) != X86::RDI) {
875280031Sdim      EmitInstruction(Out, MCInstBuilder(X86::MOV64rr).addReg(X86::RDI).addReg(
876296417Sdim                               RegCtx.AddressReg(64)));
877280031Sdim    }
878296417Sdim    MCSymbol *FnSym = Ctx.getOrCreateSymbol(llvm::Twine("__asan_report_") +
879296417Sdim                                            (IsWrite ? "store" : "load") +
880296417Sdim                                            llvm::Twine(AccessSize));
881274955Ssvnmir    const MCSymbolRefExpr *FnExpr =
882288943Sdim        MCSymbolRefExpr::create(FnSym, MCSymbolRefExpr::VK_PLT, Ctx);
883274955Ssvnmir    EmitInstruction(Out, MCInstBuilder(X86::CALL64pcrel32).addExpr(FnExpr));
884274955Ssvnmir  }
885274955Ssvnmir};
886274955Ssvnmir
887280031Sdimvoid X86AddressSanitizer64::InstrumentMemOperandSmall(
888280031Sdim    X86Operand &Op, unsigned AccessSize, bool IsWrite,
889280031Sdim    const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
890296417Sdim  unsigned AddressRegI64 = RegCtx.AddressReg(64);
891296417Sdim  unsigned AddressRegI32 = RegCtx.AddressReg(32);
892296417Sdim  unsigned ShadowRegI64 = RegCtx.ShadowReg(64);
893296417Sdim  unsigned ShadowRegI32 = RegCtx.ShadowReg(32);
894296417Sdim  unsigned ShadowRegI8 = RegCtx.ShadowReg(8);
895280031Sdim
896296417Sdim  assert(RegCtx.ScratchReg(32) != X86::NoRegister);
897296417Sdim  unsigned ScratchRegI32 = RegCtx.ScratchReg(32);
898280031Sdim
899296417Sdim  ComputeMemOperandAddress(Op, 64, AddressRegI64, Ctx, Out);
900280031Sdim
901280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV64rr).addReg(ShadowRegI64).addReg(
902280031Sdim                           AddressRegI64));
903280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::SHR64ri)
904280031Sdim                           .addReg(ShadowRegI64)
905280031Sdim                           .addReg(ShadowRegI64)
906280031Sdim                           .addImm(3));
907274955Ssvnmir  {
908274955Ssvnmir    MCInst Inst;
909274955Ssvnmir    Inst.setOpcode(X86::MOV8rm);
910288943Sdim    Inst.addOperand(MCOperand::createReg(ShadowRegI8));
911288943Sdim    const MCExpr *Disp = MCConstantExpr::create(kShadowOffset, Ctx);
912274955Ssvnmir    std::unique_ptr<X86Operand> Op(
913280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI64, 0, 1,
914280031Sdim                              SMLoc(), SMLoc()));
915274955Ssvnmir    Op->addMemOperands(Inst, 5);
916274955Ssvnmir    EmitInstruction(Out, Inst);
917274955Ssvnmir  }
918274955Ssvnmir
919280031Sdim  EmitInstruction(
920280031Sdim      Out, MCInstBuilder(X86::TEST8rr).addReg(ShadowRegI8).addReg(ShadowRegI8));
921288943Sdim  MCSymbol *DoneSym = Ctx.createTempSymbol();
922288943Sdim  const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
923280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
924274955Ssvnmir
925280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ScratchRegI32).addReg(
926280031Sdim                           AddressRegI32));
927280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::AND32ri)
928280031Sdim                           .addReg(ScratchRegI32)
929280031Sdim                           .addReg(ScratchRegI32)
930280031Sdim                           .addImm(7));
931274955Ssvnmir
932274955Ssvnmir  switch (AccessSize) {
933280031Sdim  default: llvm_unreachable("Incorrect access size");
934274955Ssvnmir  case 1:
935274955Ssvnmir    break;
936274955Ssvnmir  case 2: {
937288943Sdim    const MCExpr *Disp = MCConstantExpr::create(1, Ctx);
938274955Ssvnmir    std::unique_ptr<X86Operand> Op(
939280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ScratchRegI32, 0, 1,
940280031Sdim                              SMLoc(), SMLoc()));
941296417Sdim    EmitLEA(*Op, 32, ScratchRegI32, Out);
942274955Ssvnmir    break;
943274955Ssvnmir  }
944274955Ssvnmir  case 4:
945280031Sdim    EmitInstruction(Out, MCInstBuilder(X86::ADD32ri8)
946280031Sdim                             .addReg(ScratchRegI32)
947280031Sdim                             .addReg(ScratchRegI32)
948280031Sdim                             .addImm(3));
949274955Ssvnmir    break;
950274955Ssvnmir  }
951274955Ssvnmir
952274955Ssvnmir  EmitInstruction(
953280031Sdim      Out,
954280031Sdim      MCInstBuilder(X86::MOVSX32rr8).addReg(ShadowRegI32).addReg(ShadowRegI8));
955280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::CMP32rr).addReg(ScratchRegI32).addReg(
956280031Sdim                           ShadowRegI32));
957280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JL_1).addExpr(DoneExpr));
958274955Ssvnmir
959280031Sdim  EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
960274955Ssvnmir  EmitLabel(Out, DoneSym);
961274955Ssvnmir}
962274955Ssvnmir
963280031Sdimvoid X86AddressSanitizer64::InstrumentMemOperandLarge(
964280031Sdim    X86Operand &Op, unsigned AccessSize, bool IsWrite,
965280031Sdim    const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
966296417Sdim  unsigned AddressRegI64 = RegCtx.AddressReg(64);
967296417Sdim  unsigned ShadowRegI64 = RegCtx.ShadowReg(64);
968274955Ssvnmir
969296417Sdim  ComputeMemOperandAddress(Op, 64, AddressRegI64, Ctx, Out);
970280031Sdim
971280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::MOV64rr).addReg(ShadowRegI64).addReg(
972280031Sdim                           AddressRegI64));
973280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::SHR64ri)
974280031Sdim                           .addReg(ShadowRegI64)
975280031Sdim                           .addReg(ShadowRegI64)
976280031Sdim                           .addImm(3));
977274955Ssvnmir  {
978274955Ssvnmir    MCInst Inst;
979274955Ssvnmir    switch (AccessSize) {
980280031Sdim    default: llvm_unreachable("Incorrect access size");
981274955Ssvnmir    case 8:
982274955Ssvnmir      Inst.setOpcode(X86::CMP8mi);
983274955Ssvnmir      break;
984274955Ssvnmir    case 16:
985274955Ssvnmir      Inst.setOpcode(X86::CMP16mi);
986274955Ssvnmir      break;
987274955Ssvnmir    }
988288943Sdim    const MCExpr *Disp = MCConstantExpr::create(kShadowOffset, Ctx);
989274955Ssvnmir    std::unique_ptr<X86Operand> Op(
990280031Sdim        X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI64, 0, 1,
991280031Sdim                              SMLoc(), SMLoc()));
992274955Ssvnmir    Op->addMemOperands(Inst, 5);
993288943Sdim    Inst.addOperand(MCOperand::createImm(0));
994274955Ssvnmir    EmitInstruction(Out, Inst);
995274955Ssvnmir  }
996274955Ssvnmir
997288943Sdim  MCSymbol *DoneSym = Ctx.createTempSymbol();
998288943Sdim  const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
999280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
1000274955Ssvnmir
1001280031Sdim  EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
1002274955Ssvnmir  EmitLabel(Out, DoneSym);
1003280031Sdim}
1004274955Ssvnmir
1005280031Sdimvoid X86AddressSanitizer64::InstrumentMOVSImpl(unsigned AccessSize,
1006280031Sdim                                               MCContext &Ctx,
1007280031Sdim                                               MCStreamer &Out) {
1008280031Sdim  StoreFlags(Out);
1009280031Sdim
1010280031Sdim  // No need to test when RCX is equals to zero.
1011288943Sdim  MCSymbol *DoneSym = Ctx.createTempSymbol();
1012288943Sdim  const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
1013280031Sdim  EmitInstruction(
1014280031Sdim      Out, MCInstBuilder(X86::TEST64rr).addReg(X86::RCX).addReg(X86::RCX));
1015280031Sdim  EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
1016280031Sdim
1017280031Sdim  // Instrument first and last elements in src and dst range.
1018280031Sdim  InstrumentMOVSBase(X86::RDI /* DstReg */, X86::RSI /* SrcReg */,
1019280031Sdim                     X86::RCX /* CntReg */, AccessSize, Ctx, Out);
1020280031Sdim
1021280031Sdim  EmitLabel(Out, DoneSym);
1022280031Sdim  RestoreFlags(Out);
1023274955Ssvnmir}
1024274955Ssvnmir
1025274955Ssvnmir} // End anonymous namespace
1026274955Ssvnmir
1027296417SdimX86AsmInstrumentation::X86AsmInstrumentation(const MCSubtargetInfo *&STI)
1028280031Sdim    : STI(STI), InitialFrameReg(0) {}
1029280031Sdim
1030274955SsvnmirX86AsmInstrumentation::~X86AsmInstrumentation() {}
1031274955Ssvnmir
1032280031Sdimvoid X86AsmInstrumentation::InstrumentAndEmitInstruction(
1033274955Ssvnmir    const MCInst &Inst, OperandVector &Operands, MCContext &Ctx,
1034280031Sdim    const MCInstrInfo &MII, MCStreamer &Out) {
1035280031Sdim  EmitInstruction(Out, Inst);
1036280031Sdim}
1037274955Ssvnmir
1038280031Sdimvoid X86AsmInstrumentation::EmitInstruction(MCStreamer &Out,
1039280031Sdim                                            const MCInst &Inst) {
1040296417Sdim  Out.EmitInstruction(Inst, *STI);
1041280031Sdim}
1042280031Sdim
1043280031Sdimunsigned X86AsmInstrumentation::GetFrameRegGeneric(const MCContext &Ctx,
1044280031Sdim                                                   MCStreamer &Out) {
1045280031Sdim  if (!Out.getNumFrameInfos()) // No active dwarf frame
1046280031Sdim    return X86::NoRegister;
1047280031Sdim  const MCDwarfFrameInfo &Frame = Out.getDwarfFrameInfos().back();
1048280031Sdim  if (Frame.End) // Active dwarf frame is closed
1049280031Sdim    return X86::NoRegister;
1050280031Sdim  const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
1051280031Sdim  if (!MRI) // No register info
1052280031Sdim    return X86::NoRegister;
1053280031Sdim
1054280031Sdim  if (InitialFrameReg) {
1055280031Sdim    // FrameReg is set explicitly, we're instrumenting a MachineFunction.
1056280031Sdim    return InitialFrameReg;
1057280031Sdim  }
1058280031Sdim
1059280031Sdim  return MRI->getLLVMRegNum(Frame.CurrentCfaRegister, true /* IsEH */);
1060280031Sdim}
1061280031Sdim
1062274955SsvnmirX86AsmInstrumentation *
1063274955SsvnmirCreateX86AsmInstrumentation(const MCTargetOptions &MCOptions,
1064296417Sdim                            const MCContext &Ctx, const MCSubtargetInfo *&STI) {
1065296417Sdim  Triple T(STI->getTargetTriple());
1066274955Ssvnmir  const bool hasCompilerRTSupport = T.isOSLinux();
1067274955Ssvnmir  if (ClAsanInstrumentAssembly && hasCompilerRTSupport &&
1068274955Ssvnmir      MCOptions.SanitizeAddress) {
1069296417Sdim    if (STI->getFeatureBits()[X86::Mode32Bit] != 0)
1070274955Ssvnmir      return new X86AddressSanitizer32(STI);
1071296417Sdim    if (STI->getFeatureBits()[X86::Mode64Bit] != 0)
1072274955Ssvnmir      return new X86AddressSanitizer64(STI);
1073274955Ssvnmir  }
1074280031Sdim  return new X86AsmInstrumentation(STI);
1075274955Ssvnmir}
1076274955Ssvnmir
1077296417Sdim} // end llvm namespace
1078