2014-03-14 16:58:04 +08:00
|
|
|
//===-- X86AsmInstrumentation.cpp - Instrument X86 inline assembly C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "MCTargetDesc/X86BaseInfo.h"
|
|
|
|
#include "X86AsmInstrumentation.h"
|
|
|
|
#include "X86Operand.h"
|
2014-09-01 20:51:00 +08:00
|
|
|
#include "X86RegisterInfo.h"
|
2014-03-14 16:58:04 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2014-04-30 22:04:31 +08:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2014-09-01 20:51:00 +08:00
|
|
|
#include "llvm/CodeGen/MachineValueType.h"
|
2014-10-07 19:03:09 +08:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
2014-03-14 16:58:04 +08:00
|
|
|
#include "llvm/MC/MCContext.h"
|
|
|
|
#include "llvm/MC/MCInst.h"
|
|
|
|
#include "llvm/MC/MCInstBuilder.h"
|
2014-04-24 21:29:34 +08:00
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
2014-04-23 19:16:03 +08:00
|
|
|
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
2014-03-14 16:58:04 +08:00
|
|
|
#include "llvm/MC/MCStreamer.h"
|
|
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
2014-06-09 00:18:35 +08:00
|
|
|
#include "llvm/MC/MCTargetAsmParser.h"
|
2014-04-23 19:16:03 +08:00
|
|
|
#include "llvm/MC/MCTargetOptions.h"
|
2014-05-07 15:54:11 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2014-10-13 17:37:47 +08:00
|
|
|
#include <algorithm>
|
2014-10-21 18:22:27 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <vector>
|
2014-03-14 16:58:04 +08:00
|
|
|
|
2014-10-27 16:38:54 +08:00
|
|
|
// Following comment describes how assembly instrumentation works.
|
|
|
|
// Currently we have only AddressSanitizer instrumentation, but we're
|
|
|
|
// planning to implement MemorySanitizer for inline assembly too. If
|
|
|
|
// you're not familiar with AddressSanitizer algorithm, please, read
|
|
|
|
// https://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm.
|
|
|
|
//
|
|
|
|
// When inline assembly is parsed by an instance of X86AsmParser, all
|
|
|
|
// instructions are emitted via EmitInstruction method. That's the
|
|
|
|
// place where X86AsmInstrumentation analyzes an instruction and
|
|
|
|
// decides, whether the instruction should be emitted as is or
|
|
|
|
// instrumentation is required. The latter case happens when an
|
|
|
|
// instruction reads from or writes to memory. Now instruction opcode
|
|
|
|
// is explicitly checked, and if an instruction has a memory operand
|
|
|
|
// (for instance, movq (%rsi, %rcx, 8), %rax) - it should be
|
|
|
|
// instrumented. There're also exist instructions that modify
|
|
|
|
// memory but don't have an explicit memory operands, for instance,
|
|
|
|
// movs.
|
|
|
|
//
|
|
|
|
// Let's consider at first 8-byte memory accesses when an instruction
|
|
|
|
// has an explicit memory operand. In this case we need two registers -
|
|
|
|
// AddressReg to compute address of a memory cells which are accessed
|
|
|
|
// and ShadowReg to compute corresponding shadow address. So, we need
|
|
|
|
// to spill both registers before instrumentation code and restore them
|
|
|
|
// after instrumentation. Thus, in general, instrumentation code will
|
|
|
|
// look like this:
|
|
|
|
// PUSHF # Store flags, otherwise they will be overwritten
|
|
|
|
// PUSH AddressReg # spill AddressReg
|
|
|
|
// PUSH ShadowReg # spill ShadowReg
|
|
|
|
// LEA MemOp, AddressReg # compute address of the memory operand
|
|
|
|
// MOV AddressReg, ShadowReg
|
|
|
|
// SHR ShadowReg, 3
|
|
|
|
// # ShadowOffset(AddressReg >> 3) contains address of a shadow
|
|
|
|
// # corresponding to MemOp.
|
|
|
|
// CMP ShadowOffset(ShadowReg), 0 # test shadow value
|
|
|
|
// JZ .Done # when shadow equals to zero, everything is fine
|
|
|
|
// MOV AddressReg, RDI
|
|
|
|
// # Call __asan_report function with AddressReg as an argument
|
|
|
|
// CALL __asan_report
|
|
|
|
// .Done:
|
|
|
|
// POP ShadowReg # Restore ShadowReg
|
|
|
|
// POP AddressReg # Restore AddressReg
|
|
|
|
// POPF # Restore flags
|
|
|
|
//
|
|
|
|
// Memory accesses with different size (1-, 2-, 4- and 16-byte) are
|
|
|
|
// handled in a similar manner, but small memory accesses (less than 8
|
|
|
|
// byte) require an additional ScratchReg, which is used for shadow value.
|
|
|
|
//
|
|
|
|
// If, suppose, we're instrumenting an instruction like movs, only
|
|
|
|
// contents of RDI, RDI + AccessSize * RCX, RSI, RSI + AccessSize *
|
|
|
|
// RCX are checked. In this case there're no need to spill and restore
|
|
|
|
// AddressReg , ShadowReg or flags four times, they're saved on stack
|
|
|
|
// just once, before instrumentation of these four addresses, and restored
|
|
|
|
// at the end of the instrumentation.
|
|
|
|
//
|
|
|
|
// There exist several things which complicate this simple algorithm.
|
|
|
|
// * Instrumented memory operand can have RSP as a base or an index
|
|
|
|
// register. So we need to add a constant offset before computation
|
|
|
|
// of memory address, since flags, AddressReg, ShadowReg, etc. were
|
|
|
|
// already stored on stack and RSP was modified.
|
|
|
|
// * Debug info (usually, DWARF) should be adjusted, because sometimes
|
|
|
|
// RSP is used as a frame register. So, we need to select some
|
|
|
|
// register as a frame register and temprorary override current CFA
|
|
|
|
// register.
|
|
|
|
|
2014-03-14 16:58:04 +08:00
|
|
|
namespace llvm {
|
|
|
|
namespace {
|
|
|
|
|
2014-05-07 15:54:11 +08:00
|
|
|
static cl::opt<bool> ClAsanInstrumentAssembly(
|
|
|
|
"asan-instrument-assembly",
|
|
|
|
cl::desc("instrument assembly with AddressSanitizer checks"), cl::Hidden,
|
|
|
|
cl::init(false));
|
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
const int64_t MinAllowedDisplacement = std::numeric_limits<int32_t>::min();
|
|
|
|
const int64_t MaxAllowedDisplacement = std::numeric_limits<int32_t>::max();
|
|
|
|
|
2014-10-13 19:44:06 +08:00
|
|
|
int64_t ApplyDisplacementBounds(int64_t Displacement) {
|
2014-10-13 17:37:47 +08:00
|
|
|
return std::max(std::min(MaxAllowedDisplacement, Displacement),
|
|
|
|
MinAllowedDisplacement);
|
|
|
|
}
|
|
|
|
|
2014-10-13 19:44:06 +08:00
|
|
|
void CheckDisplacementBounds(int64_t Displacement) {
|
|
|
|
assert(Displacement >= MinAllowedDisplacement &&
|
|
|
|
Displacement <= MaxAllowedDisplacement);
|
2014-03-14 16:58:04 +08:00
|
|
|
}
|
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
bool IsStackReg(unsigned Reg) { return Reg == X86::RSP || Reg == X86::ESP; }
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
bool IsSmallMemAccess(unsigned AccessSize) { return AccessSize < 8; }
|
|
|
|
|
2014-03-14 16:58:04 +08:00
|
|
|
std::string FuncName(unsigned AccessSize, bool IsWrite) {
|
2014-07-07 21:57:37 +08:00
|
|
|
return std::string("__asan_report_") + (IsWrite ? "store" : "load") +
|
|
|
|
utostr(AccessSize);
|
2014-03-14 16:58:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
class X86AddressSanitizer : public X86AsmInstrumentation {
|
2014-08-27 21:11:55 +08:00
|
|
|
public:
|
2014-09-01 20:51:00 +08:00
|
|
|
struct RegisterContext {
|
2014-10-21 18:22:27 +08:00
|
|
|
private:
|
|
|
|
enum RegOffset {
|
|
|
|
REG_OFFSET_ADDRESS = 0,
|
|
|
|
REG_OFFSET_SHADOW,
|
|
|
|
REG_OFFSET_SCRATCH
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
2014-09-01 20:51:00 +08:00
|
|
|
RegisterContext(unsigned AddressReg, unsigned ShadowReg,
|
2014-10-21 18:22:27 +08:00
|
|
|
unsigned ScratchReg) {
|
2014-10-22 00:22:52 +08:00
|
|
|
BusyRegs.push_back(convReg(AddressReg, MVT::i64));
|
|
|
|
BusyRegs.push_back(convReg(ShadowReg, MVT::i64));
|
|
|
|
BusyRegs.push_back(convReg(ScratchReg, MVT::i64));
|
2014-10-21 18:22:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned AddressReg(MVT::SimpleValueType VT) const {
|
|
|
|
return convReg(BusyRegs[REG_OFFSET_ADDRESS], VT);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ShadowReg(MVT::SimpleValueType VT) const {
|
|
|
|
return convReg(BusyRegs[REG_OFFSET_SHADOW], VT);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ScratchReg(MVT::SimpleValueType VT) const {
|
|
|
|
return convReg(BusyRegs[REG_OFFSET_SCRATCH], VT);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddBusyReg(unsigned Reg) {
|
|
|
|
if (Reg != X86::NoRegister)
|
|
|
|
BusyRegs.push_back(convReg(Reg, MVT::i64));
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:22:27 +08:00
|
|
|
void AddBusyRegs(const X86Operand &Op) {
|
|
|
|
AddBusyReg(Op.getMemBaseReg());
|
|
|
|
AddBusyReg(Op.getMemIndexReg());
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:22:27 +08:00
|
|
|
unsigned ChooseFrameReg(MVT::SimpleValueType VT) const {
|
2014-12-26 14:36:23 +08:00
|
|
|
static const MCPhysReg Candidates[] = { X86::RBP, X86::RAX, X86::RBX,
|
|
|
|
X86::RCX, X86::RDX, X86::RDI,
|
|
|
|
X86::RSI };
|
2014-10-21 18:22:27 +08:00
|
|
|
for (unsigned Reg : Candidates) {
|
|
|
|
if (!std::count(BusyRegs.begin(), BusyRegs.end(), Reg))
|
|
|
|
return convReg(Reg, VT);
|
|
|
|
}
|
|
|
|
return X86::NoRegister;
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:22:27 +08:00
|
|
|
private:
|
|
|
|
unsigned convReg(unsigned Reg, MVT::SimpleValueType VT) const {
|
|
|
|
return Reg == X86::NoRegister ? Reg : getX86SubSuperRegister(Reg, VT);
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:22:27 +08:00
|
|
|
std::vector<unsigned> BusyRegs;
|
2014-09-01 20:51:00 +08:00
|
|
|
};
|
|
|
|
|
2014-07-31 17:11:04 +08:00
|
|
|
X86AddressSanitizer(const MCSubtargetInfo &STI)
|
2014-10-13 17:37:47 +08:00
|
|
|
: X86AsmInstrumentation(STI), RepPrefix(false), OrigSPOffset(0) {}
|
|
|
|
|
2015-09-11 00:49:58 +08:00
|
|
|
~X86AddressSanitizer() override {}
|
2014-03-14 16:58:04 +08:00
|
|
|
|
|
|
|
// X86AsmInstrumentation implementation:
|
2015-09-11 00:49:58 +08:00
|
|
|
void InstrumentAndEmitInstruction(const MCInst &Inst,
|
|
|
|
OperandVector &Operands,
|
|
|
|
MCContext &Ctx,
|
|
|
|
const MCInstrInfo &MII,
|
|
|
|
MCStreamer &Out) override {
|
2014-07-31 17:11:04 +08:00
|
|
|
InstrumentMOVS(Inst, Operands, Ctx, MII, Out);
|
2014-08-27 21:11:55 +08:00
|
|
|
if (RepPrefix)
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::REP_PREFIX));
|
2014-07-31 17:11:04 +08:00
|
|
|
|
2014-04-24 21:29:34 +08:00
|
|
|
InstrumentMOV(Inst, Operands, Ctx, MII, Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
|
|
|
|
RepPrefix = (Inst.getOpcode() == X86::REP_PREFIX);
|
2014-08-27 21:11:55 +08:00
|
|
|
if (!RepPrefix)
|
|
|
|
EmitInstruction(Out, Inst);
|
2014-03-14 16:58:04 +08:00
|
|
|
}
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
// Adjusts up stack and saves all registers used in instrumentation.
|
|
|
|
virtual void InstrumentMemOperandPrologue(const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) = 0;
|
|
|
|
|
|
|
|
// Restores all registers used in instrumentation and adjusts stack.
|
|
|
|
virtual void InstrumentMemOperandEpilogue(const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) = 0;
|
|
|
|
|
|
|
|
virtual void InstrumentMemOperandSmall(X86Operand &Op, unsigned AccessSize,
|
|
|
|
bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx, MCStreamer &Out) = 0;
|
|
|
|
virtual void InstrumentMemOperandLarge(X86Operand &Op, unsigned AccessSize,
|
|
|
|
bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx, MCStreamer &Out) = 0;
|
|
|
|
|
2014-07-31 17:11:04 +08:00
|
|
|
virtual void InstrumentMOVSImpl(unsigned AccessSize, MCContext &Ctx,
|
|
|
|
MCStreamer &Out) = 0;
|
2014-03-14 16:58:04 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
void InstrumentMemOperand(X86Operand &Op, unsigned AccessSize, bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx, MCContext &Ctx,
|
|
|
|
MCStreamer &Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
void InstrumentMOVSBase(unsigned DstReg, unsigned SrcReg, unsigned CntReg,
|
|
|
|
unsigned AccessSize, MCContext &Ctx, MCStreamer &Out);
|
2014-09-01 20:51:00 +08:00
|
|
|
|
2014-07-31 17:11:04 +08:00
|
|
|
void InstrumentMOVS(const MCInst &Inst, OperandVector &Operands,
|
|
|
|
MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
|
2014-06-09 00:18:35 +08:00
|
|
|
void InstrumentMOV(const MCInst &Inst, OperandVector &Operands,
|
2014-04-24 21:29:34 +08:00
|
|
|
MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
|
2014-03-14 16:58:04 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
protected:
|
2014-07-07 21:57:37 +08:00
|
|
|
void EmitLabel(MCStreamer &Out, MCSymbol *Label) { Out.EmitLabel(Label); }
|
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
void EmitLEA(X86Operand &Op, MVT::SimpleValueType VT, unsigned Reg,
|
|
|
|
MCStreamer &Out) {
|
|
|
|
assert(VT == MVT::i32 || VT == MVT::i64);
|
|
|
|
MCInst Inst;
|
|
|
|
Inst.setOpcode(VT == MVT::i32 ? X86::LEA32r : X86::LEA64r);
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createReg(getX86SubSuperRegister(Reg, VT)));
|
2014-10-13 17:37:47 +08:00
|
|
|
Op.addMemOperands(Inst, 5);
|
|
|
|
EmitInstruction(Out, Inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComputeMemOperandAddress(X86Operand &Op, MVT::SimpleValueType VT,
|
|
|
|
unsigned Reg, MCContext &Ctx, MCStreamer &Out);
|
|
|
|
|
|
|
|
// Creates new memory operand with Displacement added to an original
|
|
|
|
// displacement. Residue will contain a residue which could happen when the
|
|
|
|
// total displacement exceeds 32-bit limitation.
|
|
|
|
std::unique_ptr<X86Operand> AddDisplacement(X86Operand &Op,
|
|
|
|
int64_t Displacement,
|
|
|
|
MCContext &Ctx, int64_t *Residue);
|
|
|
|
|
2015-01-02 15:02:25 +08:00
|
|
|
bool is64BitMode() const {
|
2015-05-26 18:47:10 +08:00
|
|
|
return STI.getFeatureBits()[X86::Mode64Bit];
|
2015-01-02 15:02:25 +08:00
|
|
|
}
|
|
|
|
bool is32BitMode() const {
|
2015-05-26 18:47:10 +08:00
|
|
|
return STI.getFeatureBits()[X86::Mode32Bit];
|
2015-01-02 15:02:25 +08:00
|
|
|
}
|
|
|
|
bool is16BitMode() const {
|
2015-05-26 18:47:10 +08:00
|
|
|
return STI.getFeatureBits()[X86::Mode16Bit];
|
2015-01-02 15:02:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned getPointerWidth() {
|
|
|
|
if (is16BitMode()) return 16;
|
|
|
|
if (is32BitMode()) return 32;
|
|
|
|
if (is64BitMode()) return 64;
|
|
|
|
llvm_unreachable("invalid mode");
|
|
|
|
}
|
|
|
|
|
2014-07-31 17:11:04 +08:00
|
|
|
// True when previous instruction was actually REP prefix.
|
|
|
|
bool RepPrefix;
|
2014-10-13 17:37:47 +08:00
|
|
|
|
|
|
|
// Offset from the original SP register.
|
|
|
|
int64_t OrigSPOffset;
|
2014-03-14 16:58:04 +08:00
|
|
|
};
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
void X86AddressSanitizer::InstrumentMemOperand(
|
|
|
|
X86Operand &Op, unsigned AccessSize, bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
|
2014-06-09 00:18:35 +08:00
|
|
|
assert(Op.isMem() && "Op should be a memory operand.");
|
2014-03-14 16:58:04 +08:00
|
|
|
assert((AccessSize & (AccessSize - 1)) == 0 && AccessSize <= 16 &&
|
|
|
|
"AccessSize should be a power of two, less or equal than 16.");
|
2014-07-07 21:57:37 +08:00
|
|
|
// FIXME: take into account load/store alignment.
|
2014-09-01 20:51:00 +08:00
|
|
|
if (IsSmallMemAccess(AccessSize))
|
|
|
|
InstrumentMemOperandSmall(Op, AccessSize, IsWrite, RegCtx, Ctx, Out);
|
2014-07-07 21:57:37 +08:00
|
|
|
else
|
2014-09-01 20:51:00 +08:00
|
|
|
InstrumentMemOperandLarge(Op, AccessSize, IsWrite, RegCtx, Ctx, Out);
|
2014-03-14 16:58:04 +08:00
|
|
|
}
|
|
|
|
|
2014-08-27 19:10:54 +08:00
|
|
|
void X86AddressSanitizer::InstrumentMOVSBase(unsigned DstReg, unsigned SrcReg,
|
|
|
|
unsigned CntReg,
|
|
|
|
unsigned AccessSize,
|
|
|
|
MCContext &Ctx, MCStreamer &Out) {
|
2014-07-31 17:11:04 +08:00
|
|
|
// FIXME: check whole ranges [DstReg .. DstReg + AccessSize * (CntReg - 1)]
|
|
|
|
// and [SrcReg .. SrcReg + AccessSize * (CntReg - 1)].
|
2014-09-01 20:51:00 +08:00
|
|
|
RegisterContext RegCtx(X86::RDX /* AddressReg */, X86::RAX /* ShadowReg */,
|
|
|
|
IsSmallMemAccess(AccessSize)
|
|
|
|
? X86::RBX
|
|
|
|
: X86::NoRegister /* ScratchReg */);
|
2014-10-21 18:22:27 +08:00
|
|
|
RegCtx.AddBusyReg(DstReg);
|
|
|
|
RegCtx.AddBusyReg(SrcReg);
|
|
|
|
RegCtx.AddBusyReg(CntReg);
|
2014-07-31 17:11:04 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
InstrumentMemOperandPrologue(RegCtx, Ctx, Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
|
|
|
|
// Test (%SrcReg)
|
|
|
|
{
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(0, Ctx);
|
2014-07-31 17:11:04 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
|
2015-01-02 15:02:25 +08:00
|
|
|
getPointerWidth(), 0, Disp, SrcReg, 0, AccessSize, SMLoc(), SMLoc()));
|
2014-09-01 20:51:00 +08:00
|
|
|
InstrumentMemOperand(*Op, AccessSize, false /* IsWrite */, RegCtx, Ctx,
|
|
|
|
Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test -1(%SrcReg, %CntReg, AccessSize)
|
|
|
|
{
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(-1, Ctx);
|
2014-07-31 17:11:04 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
|
2015-01-02 15:02:25 +08:00
|
|
|
getPointerWidth(), 0, Disp, SrcReg, CntReg, AccessSize, SMLoc(),
|
|
|
|
SMLoc()));
|
2014-09-01 20:51:00 +08:00
|
|
|
InstrumentMemOperand(*Op, AccessSize, false /* IsWrite */, RegCtx, Ctx,
|
|
|
|
Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test (%DstReg)
|
|
|
|
{
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(0, Ctx);
|
2014-07-31 17:11:04 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
|
2015-01-02 15:02:25 +08:00
|
|
|
getPointerWidth(), 0, Disp, DstReg, 0, AccessSize, SMLoc(), SMLoc()));
|
2014-09-01 20:51:00 +08:00
|
|
|
InstrumentMemOperand(*Op, AccessSize, true /* IsWrite */, RegCtx, Ctx, Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test -1(%DstReg, %CntReg, AccessSize)
|
|
|
|
{
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(-1, Ctx);
|
2014-07-31 17:11:04 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(X86Operand::CreateMem(
|
2015-01-02 15:02:25 +08:00
|
|
|
getPointerWidth(), 0, Disp, DstReg, CntReg, AccessSize, SMLoc(),
|
|
|
|
SMLoc()));
|
2014-09-01 20:51:00 +08:00
|
|
|
InstrumentMemOperand(*Op, AccessSize, true /* IsWrite */, RegCtx, Ctx, Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
}
|
2014-09-01 20:51:00 +08:00
|
|
|
|
|
|
|
InstrumentMemOperandEpilogue(RegCtx, Ctx, Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
}
|
|
|
|
|
2014-08-27 19:10:54 +08:00
|
|
|
void X86AddressSanitizer::InstrumentMOVS(const MCInst &Inst,
|
|
|
|
OperandVector &Operands,
|
|
|
|
MCContext &Ctx, const MCInstrInfo &MII,
|
|
|
|
MCStreamer &Out) {
|
2014-07-31 17:11:04 +08:00
|
|
|
// Access size in bytes.
|
|
|
|
unsigned AccessSize = 0;
|
|
|
|
|
|
|
|
switch (Inst.getOpcode()) {
|
2014-08-27 21:11:55 +08:00
|
|
|
case X86::MOVSB:
|
|
|
|
AccessSize = 1;
|
|
|
|
break;
|
|
|
|
case X86::MOVSW:
|
|
|
|
AccessSize = 2;
|
|
|
|
break;
|
|
|
|
case X86::MOVSL:
|
|
|
|
AccessSize = 4;
|
|
|
|
break;
|
|
|
|
case X86::MOVSQ:
|
|
|
|
AccessSize = 8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
2014-07-31 17:11:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
InstrumentMOVSImpl(AccessSize, Ctx, Out);
|
|
|
|
}
|
|
|
|
|
2014-08-27 19:10:54 +08:00
|
|
|
void X86AddressSanitizer::InstrumentMOV(const MCInst &Inst,
|
|
|
|
OperandVector &Operands, MCContext &Ctx,
|
|
|
|
const MCInstrInfo &MII,
|
|
|
|
MCStreamer &Out) {
|
2014-03-14 16:58:04 +08:00
|
|
|
// Access size in bytes.
|
|
|
|
unsigned AccessSize = 0;
|
2014-04-24 17:56:15 +08:00
|
|
|
|
2014-03-14 16:58:04 +08:00
|
|
|
switch (Inst.getOpcode()) {
|
2014-08-27 21:11:55 +08:00
|
|
|
case X86::MOV8mi:
|
|
|
|
case X86::MOV8mr:
|
|
|
|
case X86::MOV8rm:
|
|
|
|
AccessSize = 1;
|
|
|
|
break;
|
|
|
|
case X86::MOV16mi:
|
|
|
|
case X86::MOV16mr:
|
|
|
|
case X86::MOV16rm:
|
|
|
|
AccessSize = 2;
|
|
|
|
break;
|
|
|
|
case X86::MOV32mi:
|
|
|
|
case X86::MOV32mr:
|
|
|
|
case X86::MOV32rm:
|
|
|
|
AccessSize = 4;
|
|
|
|
break;
|
|
|
|
case X86::MOV64mi32:
|
|
|
|
case X86::MOV64mr:
|
|
|
|
case X86::MOV64rm:
|
|
|
|
AccessSize = 8;
|
|
|
|
break;
|
|
|
|
case X86::MOVAPDmr:
|
|
|
|
case X86::MOVAPSmr:
|
|
|
|
case X86::MOVAPDrm:
|
|
|
|
case X86::MOVAPSrm:
|
|
|
|
AccessSize = 16;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
2014-04-24 17:56:15 +08:00
|
|
|
}
|
2014-03-14 16:58:04 +08:00
|
|
|
|
2014-04-24 21:29:34 +08:00
|
|
|
const bool IsWrite = MII.get(Inst.getOpcode()).mayStore();
|
2014-09-01 20:51:00 +08:00
|
|
|
|
2014-04-24 17:56:15 +08:00
|
|
|
for (unsigned Ix = 0; Ix < Operands.size(); ++Ix) {
|
2014-06-09 00:18:35 +08:00
|
|
|
assert(Operands[Ix]);
|
|
|
|
MCParsedAsmOperand &Op = *Operands[Ix];
|
2014-09-01 20:51:00 +08:00
|
|
|
if (Op.isMem()) {
|
|
|
|
X86Operand &MemOp = static_cast<X86Operand &>(Op);
|
2014-10-21 18:22:27 +08:00
|
|
|
RegisterContext RegCtx(
|
|
|
|
X86::RDI /* AddressReg */, X86::RAX /* ShadowReg */,
|
|
|
|
IsSmallMemAccess(AccessSize) ? X86::RCX
|
|
|
|
: X86::NoRegister /* ScratchReg */);
|
|
|
|
RegCtx.AddBusyRegs(MemOp);
|
2014-09-01 20:51:00 +08:00
|
|
|
InstrumentMemOperandPrologue(RegCtx, Ctx, Out);
|
|
|
|
InstrumentMemOperand(MemOp, AccessSize, IsWrite, RegCtx, Ctx, Out);
|
|
|
|
InstrumentMemOperandEpilogue(RegCtx, Ctx, Out);
|
|
|
|
}
|
2014-04-24 17:56:15 +08:00
|
|
|
}
|
2014-03-14 16:58:04 +08:00
|
|
|
}
|
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
void X86AddressSanitizer::ComputeMemOperandAddress(X86Operand &Op,
|
|
|
|
MVT::SimpleValueType VT,
|
|
|
|
unsigned Reg, MCContext &Ctx,
|
|
|
|
MCStreamer &Out) {
|
|
|
|
int64_t Displacement = 0;
|
|
|
|
if (IsStackReg(Op.getMemBaseReg()))
|
|
|
|
Displacement -= OrigSPOffset;
|
|
|
|
if (IsStackReg(Op.getMemIndexReg()))
|
|
|
|
Displacement -= OrigSPOffset * Op.getMemScale();
|
|
|
|
|
|
|
|
assert(Displacement >= 0);
|
|
|
|
|
|
|
|
// Emit Op as is.
|
|
|
|
if (Displacement == 0) {
|
|
|
|
EmitLEA(Op, VT, Reg, Out);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t Residue;
|
|
|
|
std::unique_ptr<X86Operand> NewOp =
|
|
|
|
AddDisplacement(Op, Displacement, Ctx, &Residue);
|
|
|
|
EmitLEA(*NewOp, VT, Reg, Out);
|
|
|
|
|
|
|
|
while (Residue != 0) {
|
|
|
|
const MCConstantExpr *Disp =
|
2015-05-30 09:25:56 +08:00
|
|
|
MCConstantExpr::create(ApplyDisplacementBounds(Residue), Ctx);
|
2014-10-13 17:37:47 +08:00
|
|
|
std::unique_ptr<X86Operand> DispOp =
|
2015-01-02 15:02:25 +08:00
|
|
|
X86Operand::CreateMem(getPointerWidth(), 0, Disp, Reg, 0, 1, SMLoc(),
|
|
|
|
SMLoc());
|
2014-10-13 17:37:47 +08:00
|
|
|
EmitLEA(*DispOp, VT, Reg, Out);
|
|
|
|
Residue -= Disp->getValue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<X86Operand>
|
|
|
|
X86AddressSanitizer::AddDisplacement(X86Operand &Op, int64_t Displacement,
|
|
|
|
MCContext &Ctx, int64_t *Residue) {
|
|
|
|
assert(Displacement >= 0);
|
|
|
|
|
|
|
|
if (Displacement == 0 ||
|
|
|
|
(Op.getMemDisp() && Op.getMemDisp()->getKind() != MCExpr::Constant)) {
|
|
|
|
*Residue = Displacement;
|
2015-01-02 15:02:25 +08:00
|
|
|
return X86Operand::CreateMem(Op.getMemModeSize(), Op.getMemSegReg(),
|
|
|
|
Op.getMemDisp(), Op.getMemBaseReg(),
|
|
|
|
Op.getMemIndexReg(), Op.getMemScale(),
|
|
|
|
SMLoc(), SMLoc());
|
2014-10-13 17:37:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int64_t OrigDisplacement =
|
|
|
|
static_cast<const MCConstantExpr *>(Op.getMemDisp())->getValue();
|
2014-10-13 19:44:06 +08:00
|
|
|
CheckDisplacementBounds(OrigDisplacement);
|
2014-10-13 17:37:47 +08:00
|
|
|
Displacement += OrigDisplacement;
|
|
|
|
|
2014-10-13 19:44:06 +08:00
|
|
|
int64_t NewDisplacement = ApplyDisplacementBounds(Displacement);
|
|
|
|
CheckDisplacementBounds(NewDisplacement);
|
2014-10-13 17:37:47 +08:00
|
|
|
|
|
|
|
*Residue = Displacement - NewDisplacement;
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(NewDisplacement, Ctx);
|
2015-01-02 15:02:25 +08:00
|
|
|
return X86Operand::CreateMem(Op.getMemModeSize(), Op.getMemSegReg(), Disp,
|
|
|
|
Op.getMemBaseReg(), Op.getMemIndexReg(),
|
|
|
|
Op.getMemScale(), SMLoc(), SMLoc());
|
2014-10-13 17:37:47 +08:00
|
|
|
}
|
|
|
|
|
2014-03-14 16:58:04 +08:00
|
|
|
class X86AddressSanitizer32 : public X86AddressSanitizer {
|
2014-08-27 21:11:55 +08:00
|
|
|
public:
|
2014-07-07 21:57:37 +08:00
|
|
|
static const long kShadowOffset = 0x20000000;
|
|
|
|
|
2014-04-23 19:16:03 +08:00
|
|
|
X86AddressSanitizer32(const MCSubtargetInfo &STI)
|
|
|
|
: X86AddressSanitizer(STI) {}
|
2014-09-10 17:45:49 +08:00
|
|
|
|
2015-09-11 00:49:58 +08:00
|
|
|
~X86AddressSanitizer32() override {}
|
2014-03-14 16:58:04 +08:00
|
|
|
|
2014-10-07 19:03:09 +08:00
|
|
|
unsigned GetFrameReg(const MCContext &Ctx, MCStreamer &Out) {
|
|
|
|
unsigned FrameReg = GetFrameRegGeneric(Ctx, Out);
|
|
|
|
if (FrameReg == X86::NoRegister)
|
|
|
|
return FrameReg;
|
|
|
|
return getX86SubSuperRegister(FrameReg, MVT::i32);
|
|
|
|
}
|
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
void SpillReg(MCStreamer &Out, unsigned Reg) {
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(Reg));
|
|
|
|
OrigSPOffset -= 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RestoreReg(MCStreamer &Out, unsigned Reg) {
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(Reg));
|
|
|
|
OrigSPOffset += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StoreFlags(MCStreamer &Out) {
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::PUSHF32));
|
2014-10-13 17:37:47 +08:00
|
|
|
OrigSPOffset -= 4;
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
void RestoreFlags(MCStreamer &Out) {
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::POPF32));
|
2014-10-13 17:37:47 +08:00
|
|
|
OrigSPOffset += 4;
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
|
|
|
|
2015-09-11 00:49:58 +08:00
|
|
|
void InstrumentMemOperandPrologue(const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) override {
|
2014-10-21 18:22:27 +08:00
|
|
|
unsigned LocalFrameReg = RegCtx.ChooseFrameReg(MVT::i32);
|
|
|
|
assert(LocalFrameReg != X86::NoRegister);
|
|
|
|
|
2014-10-07 19:03:09 +08:00
|
|
|
const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
|
|
|
|
unsigned FrameReg = GetFrameReg(Ctx, Out);
|
2014-09-10 17:45:49 +08:00
|
|
|
if (MRI && FrameReg != X86::NoRegister) {
|
2014-10-21 18:22:27 +08:00
|
|
|
SpillReg(Out, LocalFrameReg);
|
2014-09-10 17:45:49 +08:00
|
|
|
if (FrameReg == X86::ESP) {
|
2014-10-21 18:22:27 +08:00
|
|
|
Out.EmitCFIAdjustCfaOffset(4 /* byte size of the LocalFrameReg */);
|
|
|
|
Out.EmitCFIRelOffset(
|
|
|
|
MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */), 0);
|
2014-09-10 17:45:49 +08:00
|
|
|
}
|
|
|
|
EmitInstruction(
|
2014-10-21 18:22:27 +08:00
|
|
|
Out,
|
|
|
|
MCInstBuilder(X86::MOV32rr).addReg(LocalFrameReg).addReg(FrameReg));
|
2014-09-10 17:45:49 +08:00
|
|
|
Out.EmitCFIRememberState();
|
2014-10-21 18:22:27 +08:00
|
|
|
Out.EmitCFIDefCfaRegister(
|
|
|
|
MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */));
|
2014-09-10 17:45:49 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 18:22:27 +08:00
|
|
|
SpillReg(Out, RegCtx.AddressReg(MVT::i32));
|
|
|
|
SpillReg(Out, RegCtx.ShadowReg(MVT::i32));
|
|
|
|
if (RegCtx.ScratchReg(MVT::i32) != X86::NoRegister)
|
|
|
|
SpillReg(Out, RegCtx.ScratchReg(MVT::i32));
|
2014-09-01 20:51:00 +08:00
|
|
|
StoreFlags(Out);
|
|
|
|
}
|
|
|
|
|
2015-09-11 00:49:58 +08:00
|
|
|
void InstrumentMemOperandEpilogue(const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) override {
|
2014-10-21 18:22:27 +08:00
|
|
|
unsigned LocalFrameReg = RegCtx.ChooseFrameReg(MVT::i32);
|
|
|
|
assert(LocalFrameReg != X86::NoRegister);
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
RestoreFlags(Out);
|
2014-10-21 18:22:27 +08:00
|
|
|
if (RegCtx.ScratchReg(MVT::i32) != X86::NoRegister)
|
|
|
|
RestoreReg(Out, RegCtx.ScratchReg(MVT::i32));
|
|
|
|
RestoreReg(Out, RegCtx.ShadowReg(MVT::i32));
|
|
|
|
RestoreReg(Out, RegCtx.AddressReg(MVT::i32));
|
2014-09-10 17:45:49 +08:00
|
|
|
|
2014-10-07 19:03:09 +08:00
|
|
|
unsigned FrameReg = GetFrameReg(Ctx, Out);
|
2014-09-10 17:45:49 +08:00
|
|
|
if (Ctx.getRegisterInfo() && FrameReg != X86::NoRegister) {
|
2014-10-21 18:22:27 +08:00
|
|
|
RestoreReg(Out, LocalFrameReg);
|
2014-09-10 17:45:49 +08:00
|
|
|
Out.EmitCFIRestoreState();
|
|
|
|
if (FrameReg == X86::ESP)
|
2014-10-21 18:22:27 +08:00
|
|
|
Out.EmitCFIAdjustCfaOffset(-4 /* byte size of the LocalFrameReg */);
|
2014-09-10 17:45:49 +08:00
|
|
|
}
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
|
|
|
|
2015-09-11 00:49:58 +08:00
|
|
|
void InstrumentMemOperandSmall(X86Operand &Op, unsigned AccessSize,
|
|
|
|
bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) override;
|
|
|
|
void InstrumentMemOperandLarge(X86Operand &Op, unsigned AccessSize,
|
|
|
|
bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) override;
|
|
|
|
void InstrumentMOVSImpl(unsigned AccessSize, MCContext &Ctx,
|
|
|
|
MCStreamer &Out) override;
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-08-27 21:11:55 +08:00
|
|
|
private:
|
2014-09-01 20:51:00 +08:00
|
|
|
void EmitCallAsanReport(unsigned AccessSize, bool IsWrite, MCContext &Ctx,
|
|
|
|
MCStreamer &Out, const RegisterContext &RegCtx) {
|
2014-07-07 21:57:37 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::CLD));
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::MMX_EMMS));
|
|
|
|
|
2014-08-27 19:10:54 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::AND64ri8)
|
|
|
|
.addReg(X86::ESP)
|
|
|
|
.addReg(X86::ESP)
|
|
|
|
.addImm(-16));
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(
|
2014-10-21 18:22:27 +08:00
|
|
|
Out, MCInstBuilder(X86::PUSH32r).addReg(RegCtx.AddressReg(MVT::i32)));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-07-31 17:11:04 +08:00
|
|
|
const std::string &Fn = FuncName(AccessSize, IsWrite);
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *FnSym = Ctx.getOrCreateSymbol(StringRef(Fn));
|
2014-07-07 21:57:37 +08:00
|
|
|
const MCSymbolRefExpr *FnExpr =
|
2015-05-30 09:25:56 +08:00
|
|
|
MCSymbolRefExpr::create(FnSym, MCSymbolRefExpr::VK_PLT, Ctx);
|
2014-07-07 21:57:37 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::CALLpcrel32).addExpr(FnExpr));
|
|
|
|
}
|
2014-03-14 16:58:04 +08:00
|
|
|
};
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
void X86AddressSanitizer32::InstrumentMemOperandSmall(
|
|
|
|
X86Operand &Op, unsigned AccessSize, bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
|
2014-10-21 18:22:27 +08:00
|
|
|
unsigned AddressRegI32 = RegCtx.AddressReg(MVT::i32);
|
|
|
|
unsigned ShadowRegI32 = RegCtx.ShadowReg(MVT::i32);
|
|
|
|
unsigned ShadowRegI8 = RegCtx.ShadowReg(MVT::i8);
|
2014-09-01 20:51:00 +08:00
|
|
|
|
2014-10-21 18:22:27 +08:00
|
|
|
assert(RegCtx.ScratchReg(MVT::i32) != X86::NoRegister);
|
|
|
|
unsigned ScratchRegI32 = RegCtx.ScratchReg(MVT::i32);
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
ComputeMemOperandAddress(Op, MVT::i32, AddressRegI32, Ctx, Out);
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ShadowRegI32).addReg(
|
|
|
|
AddressRegI32));
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::SHR32ri)
|
|
|
|
.addReg(ShadowRegI32)
|
|
|
|
.addReg(ShadowRegI32)
|
|
|
|
.addImm(3));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-03-14 16:58:04 +08:00
|
|
|
{
|
2014-07-07 21:57:37 +08:00
|
|
|
MCInst Inst;
|
|
|
|
Inst.setOpcode(X86::MOV8rm);
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createReg(ShadowRegI8));
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(kShadowOffset, Ctx);
|
2014-07-07 21:57:37 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(
|
2015-01-02 15:02:25 +08:00
|
|
|
X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI32, 0, 1,
|
|
|
|
SMLoc(), SMLoc()));
|
2014-07-07 21:57:37 +08:00
|
|
|
Op->addMemOperands(Inst, 5);
|
|
|
|
EmitInstruction(Out, Inst);
|
|
|
|
}
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(
|
|
|
|
Out, MCInstBuilder(X86::TEST8rr).addReg(ShadowRegI8).addReg(ShadowRegI8));
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *DoneSym = Ctx.createTempSymbol();
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
|
2015-01-06 12:23:53 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ScratchRegI32).addReg(
|
|
|
|
AddressRegI32));
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::AND32ri)
|
|
|
|
.addReg(ScratchRegI32)
|
|
|
|
.addReg(ScratchRegI32)
|
|
|
|
.addImm(7));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
|
|
|
switch (AccessSize) {
|
2015-01-05 18:15:49 +08:00
|
|
|
default: llvm_unreachable("Incorrect access size");
|
2014-08-27 21:11:55 +08:00
|
|
|
case 1:
|
|
|
|
break;
|
|
|
|
case 2: {
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(1, Ctx);
|
2014-08-27 21:11:55 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(
|
2015-01-02 15:02:25 +08:00
|
|
|
X86Operand::CreateMem(getPointerWidth(), 0, Disp, ScratchRegI32, 0, 1,
|
|
|
|
SMLoc(), SMLoc()));
|
2014-10-13 17:37:47 +08:00
|
|
|
EmitLEA(*Op, MVT::i32, ScratchRegI32, Out);
|
2014-08-27 21:11:55 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 4:
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::ADD32ri8)
|
2014-09-01 20:51:00 +08:00
|
|
|
.addReg(ScratchRegI32)
|
|
|
|
.addReg(ScratchRegI32)
|
2014-08-27 21:11:55 +08:00
|
|
|
.addImm(3));
|
|
|
|
break;
|
2014-07-07 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EmitInstruction(
|
2014-09-01 20:51:00 +08:00
|
|
|
Out,
|
|
|
|
MCInstBuilder(X86::MOVSX32rr8).addReg(ShadowRegI32).addReg(ShadowRegI8));
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::CMP32rr).addReg(ScratchRegI32).addReg(
|
|
|
|
ShadowRegI32));
|
2015-01-06 12:23:53 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::JL_1).addExpr(DoneExpr));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
|
2014-07-07 21:57:37 +08:00
|
|
|
EmitLabel(Out, DoneSym);
|
|
|
|
}
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
void X86AddressSanitizer32::InstrumentMemOperandLarge(
|
|
|
|
X86Operand &Op, unsigned AccessSize, bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
|
2014-10-21 18:22:27 +08:00
|
|
|
unsigned AddressRegI32 = RegCtx.AddressReg(MVT::i32);
|
|
|
|
unsigned ShadowRegI32 = RegCtx.ShadowReg(MVT::i32);
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
ComputeMemOperandAddress(Op, MVT::i32, AddressRegI32, Ctx, Out);
|
2014-09-01 20:51:00 +08:00
|
|
|
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ShadowRegI32).addReg(
|
|
|
|
AddressRegI32));
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::SHR32ri)
|
|
|
|
.addReg(ShadowRegI32)
|
|
|
|
.addReg(ShadowRegI32)
|
|
|
|
.addImm(3));
|
2014-07-07 21:57:37 +08:00
|
|
|
{
|
|
|
|
MCInst Inst;
|
|
|
|
switch (AccessSize) {
|
2015-01-05 18:15:49 +08:00
|
|
|
default: llvm_unreachable("Incorrect access size");
|
2014-08-27 21:11:55 +08:00
|
|
|
case 8:
|
|
|
|
Inst.setOpcode(X86::CMP8mi);
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
Inst.setOpcode(X86::CMP16mi);
|
|
|
|
break;
|
2014-07-07 21:57:37 +08:00
|
|
|
}
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(kShadowOffset, Ctx);
|
2014-07-07 21:57:37 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(
|
2015-01-02 15:02:25 +08:00
|
|
|
X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI32, 0, 1,
|
|
|
|
SMLoc(), SMLoc()));
|
2014-07-07 21:57:37 +08:00
|
|
|
Op->addMemOperands(Inst, 5);
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createImm(0));
|
2014-07-07 21:57:37 +08:00
|
|
|
EmitInstruction(Out, Inst);
|
|
|
|
}
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *DoneSym = Ctx.createTempSymbol();
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
|
2015-01-06 12:23:53 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
|
2014-07-07 21:57:37 +08:00
|
|
|
EmitLabel(Out, DoneSym);
|
2014-03-14 16:58:04 +08:00
|
|
|
}
|
|
|
|
|
2014-08-27 19:10:54 +08:00
|
|
|
void X86AddressSanitizer32::InstrumentMOVSImpl(unsigned AccessSize,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) {
|
2014-09-01 20:51:00 +08:00
|
|
|
StoreFlags(Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
|
|
|
|
// No need to test when ECX is equals to zero.
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *DoneSym = Ctx.createTempSymbol();
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
|
2014-07-31 17:11:04 +08:00
|
|
|
EmitInstruction(
|
|
|
|
Out, MCInstBuilder(X86::TEST32rr).addReg(X86::ECX).addReg(X86::ECX));
|
2015-01-06 12:23:53 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
|
2014-07-31 17:11:04 +08:00
|
|
|
|
|
|
|
// Instrument first and last elements in src and dst range.
|
|
|
|
InstrumentMOVSBase(X86::EDI /* DstReg */, X86::ESI /* SrcReg */,
|
|
|
|
X86::ECX /* CntReg */, AccessSize, Ctx, Out);
|
|
|
|
|
|
|
|
EmitLabel(Out, DoneSym);
|
2014-09-01 20:51:00 +08:00
|
|
|
RestoreFlags(Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
}
|
|
|
|
|
2014-03-14 16:58:04 +08:00
|
|
|
class X86AddressSanitizer64 : public X86AddressSanitizer {
|
2014-08-27 21:11:55 +08:00
|
|
|
public:
|
2014-07-07 21:57:37 +08:00
|
|
|
static const long kShadowOffset = 0x7fff8000;
|
|
|
|
|
2014-04-23 19:16:03 +08:00
|
|
|
X86AddressSanitizer64(const MCSubtargetInfo &STI)
|
|
|
|
: X86AddressSanitizer(STI) {}
|
2014-09-10 17:45:49 +08:00
|
|
|
|
2015-09-11 00:49:58 +08:00
|
|
|
~X86AddressSanitizer64() override {}
|
2014-03-14 16:58:04 +08:00
|
|
|
|
2014-10-07 19:03:09 +08:00
|
|
|
unsigned GetFrameReg(const MCContext &Ctx, MCStreamer &Out) {
|
|
|
|
unsigned FrameReg = GetFrameRegGeneric(Ctx, Out);
|
|
|
|
if (FrameReg == X86::NoRegister)
|
|
|
|
return FrameReg;
|
|
|
|
return getX86SubSuperRegister(FrameReg, MVT::i64);
|
|
|
|
}
|
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
void SpillReg(MCStreamer &Out, unsigned Reg) {
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(Reg));
|
|
|
|
OrigSPOffset -= 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RestoreReg(MCStreamer &Out, unsigned Reg) {
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(Reg));
|
|
|
|
OrigSPOffset += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StoreFlags(MCStreamer &Out) {
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::PUSHF64));
|
2014-10-13 17:37:47 +08:00
|
|
|
OrigSPOffset -= 8;
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
void RestoreFlags(MCStreamer &Out) {
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::POPF64));
|
2014-10-13 17:37:47 +08:00
|
|
|
OrigSPOffset += 8;
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
|
|
|
|
2015-09-11 00:49:58 +08:00
|
|
|
void InstrumentMemOperandPrologue(const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) override {
|
2014-10-21 18:22:27 +08:00
|
|
|
unsigned LocalFrameReg = RegCtx.ChooseFrameReg(MVT::i64);
|
|
|
|
assert(LocalFrameReg != X86::NoRegister);
|
|
|
|
|
2014-10-07 19:03:09 +08:00
|
|
|
const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
|
|
|
|
unsigned FrameReg = GetFrameReg(Ctx, Out);
|
|
|
|
if (MRI && FrameReg != X86::NoRegister) {
|
2014-10-13 17:37:47 +08:00
|
|
|
SpillReg(Out, X86::RBP);
|
2014-09-10 17:45:49 +08:00
|
|
|
if (FrameReg == X86::RSP) {
|
2014-10-21 18:22:27 +08:00
|
|
|
Out.EmitCFIAdjustCfaOffset(8 /* byte size of the LocalFrameReg */);
|
|
|
|
Out.EmitCFIRelOffset(
|
|
|
|
MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */), 0);
|
2014-09-10 17:45:49 +08:00
|
|
|
}
|
|
|
|
EmitInstruction(
|
2014-10-21 18:22:27 +08:00
|
|
|
Out,
|
|
|
|
MCInstBuilder(X86::MOV64rr).addReg(LocalFrameReg).addReg(FrameReg));
|
2014-09-10 17:45:49 +08:00
|
|
|
Out.EmitCFIRememberState();
|
2014-10-21 18:22:27 +08:00
|
|
|
Out.EmitCFIDefCfaRegister(
|
|
|
|
MRI->getDwarfRegNum(LocalFrameReg, true /* IsEH */));
|
2014-09-10 17:45:49 +08:00
|
|
|
}
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitAdjustRSP(Ctx, Out, -128);
|
2014-10-21 18:22:27 +08:00
|
|
|
SpillReg(Out, RegCtx.ShadowReg(MVT::i64));
|
|
|
|
SpillReg(Out, RegCtx.AddressReg(MVT::i64));
|
|
|
|
if (RegCtx.ScratchReg(MVT::i64) != X86::NoRegister)
|
|
|
|
SpillReg(Out, RegCtx.ScratchReg(MVT::i64));
|
2014-09-01 20:51:00 +08:00
|
|
|
StoreFlags(Out);
|
|
|
|
}
|
|
|
|
|
2015-09-11 00:49:58 +08:00
|
|
|
void InstrumentMemOperandEpilogue(const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) override {
|
2014-10-21 18:22:27 +08:00
|
|
|
unsigned LocalFrameReg = RegCtx.ChooseFrameReg(MVT::i64);
|
|
|
|
assert(LocalFrameReg != X86::NoRegister);
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
RestoreFlags(Out);
|
2014-10-21 18:22:27 +08:00
|
|
|
if (RegCtx.ScratchReg(MVT::i64) != X86::NoRegister)
|
|
|
|
RestoreReg(Out, RegCtx.ScratchReg(MVT::i64));
|
|
|
|
RestoreReg(Out, RegCtx.AddressReg(MVT::i64));
|
|
|
|
RestoreReg(Out, RegCtx.ShadowReg(MVT::i64));
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitAdjustRSP(Ctx, Out, 128);
|
2014-09-10 17:45:49 +08:00
|
|
|
|
2014-10-07 19:03:09 +08:00
|
|
|
unsigned FrameReg = GetFrameReg(Ctx, Out);
|
2014-09-10 17:45:49 +08:00
|
|
|
if (Ctx.getRegisterInfo() && FrameReg != X86::NoRegister) {
|
2014-10-21 18:22:27 +08:00
|
|
|
RestoreReg(Out, LocalFrameReg);
|
2014-09-10 17:45:49 +08:00
|
|
|
Out.EmitCFIRestoreState();
|
|
|
|
if (FrameReg == X86::RSP)
|
2014-10-21 18:22:27 +08:00
|
|
|
Out.EmitCFIAdjustCfaOffset(-8 /* byte size of the LocalFrameReg */);
|
2014-09-10 17:45:49 +08:00
|
|
|
}
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
|
|
|
|
2015-09-11 00:49:58 +08:00
|
|
|
void InstrumentMemOperandSmall(X86Operand &Op, unsigned AccessSize,
|
|
|
|
bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) override;
|
|
|
|
void InstrumentMemOperandLarge(X86Operand &Op, unsigned AccessSize,
|
|
|
|
bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) override;
|
|
|
|
void InstrumentMOVSImpl(unsigned AccessSize, MCContext &Ctx,
|
|
|
|
MCStreamer &Out) override;
|
2014-05-08 17:55:24 +08:00
|
|
|
|
2014-08-27 21:11:55 +08:00
|
|
|
private:
|
2014-07-07 21:57:37 +08:00
|
|
|
void EmitAdjustRSP(MCContext &Ctx, MCStreamer &Out, long Offset) {
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(Offset, Ctx);
|
2014-05-09 17:48:03 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(
|
2015-01-02 15:02:25 +08:00
|
|
|
X86Operand::CreateMem(getPointerWidth(), 0, Disp, X86::RSP, 0, 1,
|
|
|
|
SMLoc(), SMLoc()));
|
2014-10-13 17:37:47 +08:00
|
|
|
EmitLEA(*Op, MVT::i64, X86::RSP, Out);
|
|
|
|
OrigSPOffset += Offset;
|
2014-05-08 17:55:24 +08:00
|
|
|
}
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
void EmitCallAsanReport(unsigned AccessSize, bool IsWrite, MCContext &Ctx,
|
|
|
|
MCStreamer &Out, const RegisterContext &RegCtx) {
|
2014-07-07 21:57:37 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::CLD));
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::MMX_EMMS));
|
|
|
|
|
2014-08-27 19:10:54 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::AND64ri8)
|
|
|
|
.addReg(X86::RSP)
|
|
|
|
.addReg(X86::RSP)
|
|
|
|
.addImm(-16));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-10-21 18:22:27 +08:00
|
|
|
if (RegCtx.AddressReg(MVT::i64) != X86::RDI) {
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::MOV64rr).addReg(X86::RDI).addReg(
|
2014-10-21 18:22:27 +08:00
|
|
|
RegCtx.AddressReg(MVT::i64)));
|
2014-09-01 20:51:00 +08:00
|
|
|
}
|
2014-07-31 17:11:04 +08:00
|
|
|
const std::string &Fn = FuncName(AccessSize, IsWrite);
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *FnSym = Ctx.getOrCreateSymbol(StringRef(Fn));
|
2014-07-07 21:57:37 +08:00
|
|
|
const MCSymbolRefExpr *FnExpr =
|
2015-05-30 09:25:56 +08:00
|
|
|
MCSymbolRefExpr::create(FnSym, MCSymbolRefExpr::VK_PLT, Ctx);
|
2014-07-07 21:57:37 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::CALL64pcrel32).addExpr(FnExpr));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
void X86AddressSanitizer64::InstrumentMemOperandSmall(
|
|
|
|
X86Operand &Op, unsigned AccessSize, bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
|
2014-10-21 18:22:27 +08:00
|
|
|
unsigned AddressRegI64 = RegCtx.AddressReg(MVT::i64);
|
|
|
|
unsigned AddressRegI32 = RegCtx.AddressReg(MVT::i32);
|
|
|
|
unsigned ShadowRegI64 = RegCtx.ShadowReg(MVT::i64);
|
|
|
|
unsigned ShadowRegI32 = RegCtx.ShadowReg(MVT::i32);
|
|
|
|
unsigned ShadowRegI8 = RegCtx.ShadowReg(MVT::i8);
|
2014-09-01 20:51:00 +08:00
|
|
|
|
2014-10-21 18:22:27 +08:00
|
|
|
assert(RegCtx.ScratchReg(MVT::i32) != X86::NoRegister);
|
|
|
|
unsigned ScratchRegI32 = RegCtx.ScratchReg(MVT::i32);
|
2014-09-01 20:51:00 +08:00
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
ComputeMemOperandAddress(Op, MVT::i64, AddressRegI64, Ctx, Out);
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::MOV64rr).addReg(ShadowRegI64).addReg(
|
|
|
|
AddressRegI64));
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::SHR64ri)
|
|
|
|
.addReg(ShadowRegI64)
|
|
|
|
.addReg(ShadowRegI64)
|
|
|
|
.addImm(3));
|
2014-03-14 16:58:04 +08:00
|
|
|
{
|
2014-07-07 21:57:37 +08:00
|
|
|
MCInst Inst;
|
|
|
|
Inst.setOpcode(X86::MOV8rm);
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createReg(ShadowRegI8));
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(kShadowOffset, Ctx);
|
2014-07-07 21:57:37 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(
|
2015-01-02 15:02:25 +08:00
|
|
|
X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI64, 0, 1,
|
|
|
|
SMLoc(), SMLoc()));
|
2014-07-07 21:57:37 +08:00
|
|
|
Op->addMemOperands(Inst, 5);
|
|
|
|
EmitInstruction(Out, Inst);
|
2014-03-14 16:58:04 +08:00
|
|
|
}
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(
|
|
|
|
Out, MCInstBuilder(X86::TEST8rr).addReg(ShadowRegI8).addReg(ShadowRegI8));
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *DoneSym = Ctx.createTempSymbol();
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
|
2015-01-06 12:23:53 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::MOV32rr).addReg(ScratchRegI32).addReg(
|
|
|
|
AddressRegI32));
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::AND32ri)
|
|
|
|
.addReg(ScratchRegI32)
|
|
|
|
.addReg(ScratchRegI32)
|
|
|
|
.addImm(7));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
|
|
|
switch (AccessSize) {
|
2015-01-05 18:15:49 +08:00
|
|
|
default: llvm_unreachable("Incorrect access size");
|
2014-08-27 21:11:55 +08:00
|
|
|
case 1:
|
|
|
|
break;
|
|
|
|
case 2: {
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(1, Ctx);
|
2014-08-27 21:11:55 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(
|
2015-01-02 15:02:25 +08:00
|
|
|
X86Operand::CreateMem(getPointerWidth(), 0, Disp, ScratchRegI32, 0, 1,
|
|
|
|
SMLoc(), SMLoc()));
|
2014-10-13 17:37:47 +08:00
|
|
|
EmitLEA(*Op, MVT::i32, ScratchRegI32, Out);
|
2014-08-27 21:11:55 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 4:
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::ADD32ri8)
|
2014-09-01 20:51:00 +08:00
|
|
|
.addReg(ScratchRegI32)
|
|
|
|
.addReg(ScratchRegI32)
|
2014-08-27 21:11:55 +08:00
|
|
|
.addImm(3));
|
|
|
|
break;
|
2014-07-07 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EmitInstruction(
|
2014-09-01 20:51:00 +08:00
|
|
|
Out,
|
|
|
|
MCInstBuilder(X86::MOVSX32rr8).addReg(ShadowRegI32).addReg(ShadowRegI8));
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::CMP32rr).addReg(ScratchRegI32).addReg(
|
|
|
|
ShadowRegI32));
|
2015-01-06 12:23:53 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::JL_1).addExpr(DoneExpr));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
|
2014-07-07 21:57:37 +08:00
|
|
|
EmitLabel(Out, DoneSym);
|
|
|
|
}
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
void X86AddressSanitizer64::InstrumentMemOperandLarge(
|
|
|
|
X86Operand &Op, unsigned AccessSize, bool IsWrite,
|
|
|
|
const RegisterContext &RegCtx, MCContext &Ctx, MCStreamer &Out) {
|
2014-10-21 18:22:27 +08:00
|
|
|
unsigned AddressRegI64 = RegCtx.AddressReg(MVT::i64);
|
|
|
|
unsigned ShadowRegI64 = RegCtx.ShadowReg(MVT::i64);
|
2014-05-08 17:55:24 +08:00
|
|
|
|
2014-10-13 17:37:47 +08:00
|
|
|
ComputeMemOperandAddress(Op, MVT::i64, AddressRegI64, Ctx, Out);
|
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::MOV64rr).addReg(ShadowRegI64).addReg(
|
|
|
|
AddressRegI64));
|
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::SHR64ri)
|
|
|
|
.addReg(ShadowRegI64)
|
|
|
|
.addReg(ShadowRegI64)
|
|
|
|
.addImm(3));
|
2014-07-07 21:57:37 +08:00
|
|
|
{
|
|
|
|
MCInst Inst;
|
|
|
|
switch (AccessSize) {
|
2015-01-05 18:15:49 +08:00
|
|
|
default: llvm_unreachable("Incorrect access size");
|
2014-08-27 21:11:55 +08:00
|
|
|
case 8:
|
|
|
|
Inst.setOpcode(X86::CMP8mi);
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
Inst.setOpcode(X86::CMP16mi);
|
|
|
|
break;
|
2014-07-07 21:57:37 +08:00
|
|
|
}
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *Disp = MCConstantExpr::create(kShadowOffset, Ctx);
|
2014-05-09 17:48:03 +08:00
|
|
|
std::unique_ptr<X86Operand> Op(
|
2015-01-02 15:02:25 +08:00
|
|
|
X86Operand::CreateMem(getPointerWidth(), 0, Disp, ShadowRegI64, 0, 1,
|
|
|
|
SMLoc(), SMLoc()));
|
2014-05-08 17:55:24 +08:00
|
|
|
Op->addMemOperands(Inst, 5);
|
2015-05-14 02:37:00 +08:00
|
|
|
Inst.addOperand(MCOperand::createImm(0));
|
2014-05-08 17:55:24 +08:00
|
|
|
EmitInstruction(Out, Inst);
|
|
|
|
}
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *DoneSym = Ctx.createTempSymbol();
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
|
2015-01-06 12:23:53 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
|
2014-07-07 21:57:37 +08:00
|
|
|
|
2014-09-01 20:51:00 +08:00
|
|
|
EmitCallAsanReport(AccessSize, IsWrite, Ctx, Out, RegCtx);
|
2014-07-07 21:57:37 +08:00
|
|
|
EmitLabel(Out, DoneSym);
|
2014-03-14 16:58:04 +08:00
|
|
|
}
|
|
|
|
|
2014-08-27 19:10:54 +08:00
|
|
|
void X86AddressSanitizer64::InstrumentMOVSImpl(unsigned AccessSize,
|
|
|
|
MCContext &Ctx,
|
|
|
|
MCStreamer &Out) {
|
2014-09-01 20:51:00 +08:00
|
|
|
StoreFlags(Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
|
|
|
|
// No need to test when RCX is equals to zero.
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *DoneSym = Ctx.createTempSymbol();
|
2015-05-30 09:25:56 +08:00
|
|
|
const MCExpr *DoneExpr = MCSymbolRefExpr::create(DoneSym, Ctx);
|
2014-07-31 17:11:04 +08:00
|
|
|
EmitInstruction(
|
|
|
|
Out, MCInstBuilder(X86::TEST64rr).addReg(X86::RCX).addReg(X86::RCX));
|
2015-01-06 12:23:53 +08:00
|
|
|
EmitInstruction(Out, MCInstBuilder(X86::JE_1).addExpr(DoneExpr));
|
2014-07-31 17:11:04 +08:00
|
|
|
|
|
|
|
// Instrument first and last elements in src and dst range.
|
|
|
|
InstrumentMOVSBase(X86::RDI /* DstReg */, X86::RSI /* SrcReg */,
|
|
|
|
X86::RCX /* CntReg */, AccessSize, Ctx, Out);
|
|
|
|
|
|
|
|
EmitLabel(Out, DoneSym);
|
2014-09-01 20:51:00 +08:00
|
|
|
RestoreFlags(Out);
|
2014-07-31 17:11:04 +08:00
|
|
|
}
|
|
|
|
|
2014-08-27 21:11:55 +08:00
|
|
|
} // End anonymous namespace
|
2014-03-14 16:58:04 +08:00
|
|
|
|
2014-07-31 17:11:04 +08:00
|
|
|
X86AsmInstrumentation::X86AsmInstrumentation(const MCSubtargetInfo &STI)
|
2014-10-07 19:03:09 +08:00
|
|
|
: STI(STI), InitialFrameReg(0) {}
|
2014-07-31 17:11:04 +08:00
|
|
|
|
2014-03-14 16:58:04 +08:00
|
|
|
X86AsmInstrumentation::~X86AsmInstrumentation() {}
|
|
|
|
|
2014-07-31 17:11:04 +08:00
|
|
|
void X86AsmInstrumentation::InstrumentAndEmitInstruction(
|
2014-07-07 21:57:37 +08:00
|
|
|
const MCInst &Inst, OperandVector &Operands, MCContext &Ctx,
|
2014-07-31 17:11:04 +08:00
|
|
|
const MCInstrInfo &MII, MCStreamer &Out) {
|
|
|
|
EmitInstruction(Out, Inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
void X86AsmInstrumentation::EmitInstruction(MCStreamer &Out,
|
|
|
|
const MCInst &Inst) {
|
|
|
|
Out.EmitInstruction(Inst, STI);
|
|
|
|
}
|
2014-03-14 16:58:04 +08:00
|
|
|
|
2014-10-07 19:03:09 +08:00
|
|
|
unsigned X86AsmInstrumentation::GetFrameRegGeneric(const MCContext &Ctx,
|
|
|
|
MCStreamer &Out) {
|
|
|
|
if (!Out.getNumFrameInfos()) // No active dwarf frame
|
|
|
|
return X86::NoRegister;
|
|
|
|
const MCDwarfFrameInfo &Frame = Out.getDwarfFrameInfos().back();
|
|
|
|
if (Frame.End) // Active dwarf frame is closed
|
|
|
|
return X86::NoRegister;
|
|
|
|
const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
|
|
|
|
if (!MRI) // No register info
|
|
|
|
return X86::NoRegister;
|
|
|
|
|
|
|
|
if (InitialFrameReg) {
|
|
|
|
// FrameReg is set explicitly, we're instrumenting a MachineFunction.
|
|
|
|
return InitialFrameReg;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MRI->getLLVMRegNum(Frame.CurrentCfaRegister, true /* IsEH */);
|
|
|
|
}
|
|
|
|
|
2014-08-27 21:11:55 +08:00
|
|
|
X86AsmInstrumentation *
|
|
|
|
CreateX86AsmInstrumentation(const MCTargetOptions &MCOptions,
|
|
|
|
const MCContext &Ctx, const MCSubtargetInfo &STI) {
|
Re-commit r247683: Replace Triple with a new TargetTuple in MCTargetDesc/* and related. NFC.
Summary:
This is the first patch in the series to migrate Triple's (which are ambiguous)
to TargetTuple's (which aren't).
For the moment, TargetTuple simply passes all requests to the Triple object it
holds. Once it has replaced Triple, it will start to implement the interface in
a more suitable way.
This change makes some changes to the public C++ API. In particular,
InitMCSubtargetInfo(), createMCRelocationInfo(), and createMCSymbolizer()
now take TargetTuples instead of Triples. The other public C++ API's have
been left as-is for the moment to reduce patch size.
This commit also contains a trivial patch to clang to account for the C++ API
change. Thanks go to Pavel Labath for fixing LLDB for me.
Reviewers: rengolin
Subscribers: jyknight, dschuff, arsenm, rampitec, danalbert, srhines, javed.absar, dsanders, echristo, emaste, jholewinski, tberghammer, ted, jfb, llvm-commits, rengolin
Differential Revision: http://reviews.llvm.org/D10969
llvm-svn: 247692
2015-09-15 22:08:28 +08:00
|
|
|
const TargetTuple &TT = STI.getTargetTuple();
|
|
|
|
const bool hasCompilerRTSupport = TT.isOSLinux();
|
2014-05-07 15:54:11 +08:00
|
|
|
if (ClAsanInstrumentAssembly && hasCompilerRTSupport &&
|
|
|
|
MCOptions.SanitizeAddress) {
|
2015-05-26 18:47:10 +08:00
|
|
|
if (STI.getFeatureBits()[X86::Mode32Bit] != 0)
|
2014-03-14 16:58:04 +08:00
|
|
|
return new X86AddressSanitizer32(STI);
|
2015-05-26 18:47:10 +08:00
|
|
|
if (STI.getFeatureBits()[X86::Mode64Bit] != 0)
|
2014-03-14 16:58:04 +08:00
|
|
|
return new X86AddressSanitizer64(STI);
|
|
|
|
}
|
2014-07-31 17:11:04 +08:00
|
|
|
return new X86AsmInstrumentation(STI);
|
2014-03-14 16:58:04 +08:00
|
|
|
}
|
|
|
|
|
2015-09-11 00:49:58 +08:00
|
|
|
} // end llvm namespace
|