blob: c8b541f3af611dc361ee5d8eb7ddd619a7c09480 [file] [log] [blame]
Evgeniy Stepanov49e26252014-03-14 08:58:04 +00001//===-- X86AsmInstrumentation.cpp - Instrument X86 inline assembly C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "MCTargetDesc/X86BaseInfo.h"
11#include "X86AsmInstrumentation.h"
12#include "X86Operand.h"
13#include "llvm/ADT/StringExtras.h"
Evgeniy Stepanov29865f72014-04-30 14:04:31 +000014#include "llvm/ADT/Triple.h"
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000015#include "llvm/IR/Function.h"
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000016#include "llvm/MC/MCContext.h"
17#include "llvm/MC/MCInst.h"
18#include "llvm/MC/MCInstBuilder.h"
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000019#include "llvm/MC/MCInstrInfo.h"
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000020#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000021#include "llvm/MC/MCStreamer.h"
22#include "llvm/MC/MCSubtargetInfo.h"
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000023#include "llvm/MC/MCTargetOptions.h"
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000024
25namespace llvm {
26namespace {
27
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000028bool IsStackReg(unsigned Reg) {
29 return Reg == X86::RSP || Reg == X86::ESP || Reg == X86::SP;
30}
31
32std::string FuncName(unsigned AccessSize, bool IsWrite) {
33 return std::string("__sanitizer_sanitize_") + (IsWrite ? "store" : "load") +
34 (utostr(AccessSize));
35}
36
37class X86AddressSanitizer : public X86AsmInstrumentation {
38public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000039 X86AddressSanitizer(const MCSubtargetInfo &STI) : STI(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000040 virtual ~X86AddressSanitizer() {}
41
42 // X86AsmInstrumentation implementation:
43 virtual void InstrumentInstruction(
44 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000045 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out) override {
46 InstrumentMOV(Inst, Operands, Ctx, MII, Out);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000047 }
48
49 // Should be implemented differently in x86_32 and x86_64 subclasses.
50 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
51 bool IsWrite, MCContext &Ctx,
52 MCStreamer &Out) = 0;
53
54 void InstrumentMemOperand(MCParsedAsmOperand *Op, unsigned AccessSize,
55 bool IsWrite, MCContext &Ctx, MCStreamer &Out);
56 void InstrumentMOV(const MCInst &Inst,
57 SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000058 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000059 void EmitInstruction(MCStreamer &Out, const MCInst &Inst) {
60 Out.EmitInstruction(Inst, STI);
61 }
62
63protected:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000064 const MCSubtargetInfo &STI;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000065};
66
67void X86AddressSanitizer::InstrumentMemOperand(
68 MCParsedAsmOperand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
69 MCStreamer &Out) {
70 assert(Op && Op->isMem() && "Op should be a memory operand.");
71 assert((AccessSize & (AccessSize - 1)) == 0 && AccessSize <= 16 &&
72 "AccessSize should be a power of two, less or equal than 16.");
73
74 X86Operand *MemOp = static_cast<X86Operand *>(Op);
75 // FIXME: get rid of this limitation.
76 if (IsStackReg(MemOp->getMemBaseReg()) || IsStackReg(MemOp->getMemIndexReg()))
77 return;
78
79 InstrumentMemOperandImpl(MemOp, AccessSize, IsWrite, Ctx, Out);
80}
81
82void X86AddressSanitizer::InstrumentMOV(
83 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000084 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000085 // Access size in bytes.
86 unsigned AccessSize = 0;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +000087
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000088 switch (Inst.getOpcode()) {
89 case X86::MOV8mi:
90 case X86::MOV8mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000091 case X86::MOV8rm:
92 AccessSize = 1;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000093 break;
94 case X86::MOV16mi:
95 case X86::MOV16mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000096 case X86::MOV16rm:
97 AccessSize = 2;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000098 break;
99 case X86::MOV32mi:
100 case X86::MOV32mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000101 case X86::MOV32rm:
102 AccessSize = 4;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000103 break;
104 case X86::MOV64mi32:
105 case X86::MOV64mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000106 case X86::MOV64rm:
107 AccessSize = 8;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000108 break;
109 case X86::MOVAPDmr:
110 case X86::MOVAPSmr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000111 case X86::MOVAPDrm:
112 case X86::MOVAPSrm:
113 AccessSize = 16;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000114 break;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000115 default:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000116 return;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000117 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000118
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +0000119 const bool IsWrite = MII.get(Inst.getOpcode()).mayStore();
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000120 for (unsigned Ix = 0; Ix < Operands.size(); ++Ix) {
121 MCParsedAsmOperand *Op = Operands[Ix];
122 if (Op && Op->isMem())
123 InstrumentMemOperand(Op, AccessSize, IsWrite, Ctx, Out);
124 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000125}
126
127class X86AddressSanitizer32 : public X86AddressSanitizer {
128public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000129 X86AddressSanitizer32(const MCSubtargetInfo &STI)
130 : X86AddressSanitizer(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000131 virtual ~X86AddressSanitizer32() {}
132
133 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
134 bool IsWrite, MCContext &Ctx,
135 MCStreamer &Out) override;
136};
137
138void X86AddressSanitizer32::InstrumentMemOperandImpl(
139 X86Operand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
140 MCStreamer &Out) {
141 // FIXME: emit .cfi directives for correct stack unwinding.
142 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
143 {
144 MCInst Inst;
145 Inst.setOpcode(X86::LEA32r);
146 Inst.addOperand(MCOperand::CreateReg(X86::EAX));
147 Op->addMemOperands(Inst, 5);
148 EmitInstruction(Out, Inst);
149 }
150 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
151 {
152 const std::string Func = FuncName(AccessSize, IsWrite);
153 const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
154 const MCSymbolRefExpr *FuncExpr =
155 MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
156 EmitInstruction(Out, MCInstBuilder(X86::CALLpcrel32).addExpr(FuncExpr));
157 }
158 EmitInstruction(Out, MCInstBuilder(X86::ADD32ri).addReg(X86::ESP)
159 .addReg(X86::ESP).addImm(4));
160 EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EAX));
161}
162
163class X86AddressSanitizer64 : public X86AddressSanitizer {
164public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000165 X86AddressSanitizer64(const MCSubtargetInfo &STI)
166 : X86AddressSanitizer(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000167 virtual ~X86AddressSanitizer64() {}
168
169 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
170 bool IsWrite, MCContext &Ctx,
171 MCStreamer &Out) override;
172};
173
174void X86AddressSanitizer64::InstrumentMemOperandImpl(
175 X86Operand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
176 MCStreamer &Out) {
177 // FIXME: emit .cfi directives for correct stack unwinding.
178 // Set %rsp below current red zone (128 bytes wide)
179 EmitInstruction(Out, MCInstBuilder(X86::SUB64ri32).addReg(X86::RSP)
180 .addReg(X86::RSP).addImm(128));
181 EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(X86::RDI));
182 {
183 MCInst Inst;
184 Inst.setOpcode(X86::LEA64r);
185 Inst.addOperand(MCOperand::CreateReg(X86::RDI));
186 Op->addMemOperands(Inst, 5);
187 EmitInstruction(Out, Inst);
188 }
189 {
190 const std::string Func = FuncName(AccessSize, IsWrite);
191 const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
192 const MCSymbolRefExpr *FuncExpr =
193 MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
194 EmitInstruction(Out, MCInstBuilder(X86::CALL64pcrel32).addExpr(FuncExpr));
195 }
196 EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(X86::RDI));
197 EmitInstruction(Out, MCInstBuilder(X86::ADD64ri32).addReg(X86::RSP)
198 .addReg(X86::RSP).addImm(128));
199}
200
201} // End anonymous namespace
202
203X86AsmInstrumentation::X86AsmInstrumentation() {}
204X86AsmInstrumentation::~X86AsmInstrumentation() {}
205
206void X86AsmInstrumentation::InstrumentInstruction(
207 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +0000208 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000209
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000210X86AsmInstrumentation *
Evgeniy Stepanov29865f72014-04-30 14:04:31 +0000211CreateX86AsmInstrumentation(const MCTargetOptions &MCOptions,
212 const MCContext &Ctx, const MCSubtargetInfo &STI) {
213 Triple T(STI.getTargetTriple());
214 const bool hasCompilerRTSupport = T.isOSLinux();
215 if (hasCompilerRTSupport && MCOptions.SanitizeAddress) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000216 if ((STI.getFeatureBits() & X86::Mode32Bit) != 0)
217 return new X86AddressSanitizer32(STI);
218 if ((STI.getFeatureBits() & X86::Mode64Bit) != 0)
219 return new X86AddressSanitizer64(STI);
220 }
221 return new X86AsmInstrumentation();
222}
223
224} // End llvm namespace