blob: 303bbf249b51bb269bfebe92340d1eaf9ecc662e [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 Stepanov3819f022014-05-07 07:54:11 +000024#include "llvm/Support/CommandLine.h"
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000025
26namespace llvm {
27namespace {
28
Evgeniy Stepanov3819f022014-05-07 07:54:11 +000029static cl::opt<bool> ClAsanInstrumentAssembly(
30 "asan-instrument-assembly",
31 cl::desc("instrument assembly with AddressSanitizer checks"), cl::Hidden,
32 cl::init(false));
33
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000034bool IsStackReg(unsigned Reg) {
35 return Reg == X86::RSP || Reg == X86::ESP || Reg == X86::SP;
36}
37
38std::string FuncName(unsigned AccessSize, bool IsWrite) {
39 return std::string("__sanitizer_sanitize_") + (IsWrite ? "store" : "load") +
40 (utostr(AccessSize));
41}
42
43class X86AddressSanitizer : public X86AsmInstrumentation {
44public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000045 X86AddressSanitizer(const MCSubtargetInfo &STI) : STI(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000046 virtual ~X86AddressSanitizer() {}
47
48 // X86AsmInstrumentation implementation:
49 virtual void InstrumentInstruction(
50 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000051 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out) override {
52 InstrumentMOV(Inst, Operands, Ctx, MII, Out);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000053 }
54
55 // Should be implemented differently in x86_32 and x86_64 subclasses.
56 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
57 bool IsWrite, MCContext &Ctx,
58 MCStreamer &Out) = 0;
59
60 void InstrumentMemOperand(MCParsedAsmOperand *Op, unsigned AccessSize,
61 bool IsWrite, MCContext &Ctx, MCStreamer &Out);
62 void InstrumentMOV(const MCInst &Inst,
63 SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000064 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000065 void EmitInstruction(MCStreamer &Out, const MCInst &Inst) {
66 Out.EmitInstruction(Inst, STI);
67 }
68
69protected:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000070 const MCSubtargetInfo &STI;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000071};
72
73void X86AddressSanitizer::InstrumentMemOperand(
74 MCParsedAsmOperand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
75 MCStreamer &Out) {
76 assert(Op && Op->isMem() && "Op should be a memory operand.");
77 assert((AccessSize & (AccessSize - 1)) == 0 && AccessSize <= 16 &&
78 "AccessSize should be a power of two, less or equal than 16.");
79
80 X86Operand *MemOp = static_cast<X86Operand *>(Op);
81 // FIXME: get rid of this limitation.
82 if (IsStackReg(MemOp->getMemBaseReg()) || IsStackReg(MemOp->getMemIndexReg()))
83 return;
84
85 InstrumentMemOperandImpl(MemOp, AccessSize, IsWrite, Ctx, Out);
86}
87
88void X86AddressSanitizer::InstrumentMOV(
89 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000090 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000091 // Access size in bytes.
92 unsigned AccessSize = 0;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +000093
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000094 switch (Inst.getOpcode()) {
95 case X86::MOV8mi:
96 case X86::MOV8mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000097 case X86::MOV8rm:
98 AccessSize = 1;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000099 break;
100 case X86::MOV16mi:
101 case X86::MOV16mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000102 case X86::MOV16rm:
103 AccessSize = 2;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000104 break;
105 case X86::MOV32mi:
106 case X86::MOV32mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000107 case X86::MOV32rm:
108 AccessSize = 4;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000109 break;
110 case X86::MOV64mi32:
111 case X86::MOV64mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000112 case X86::MOV64rm:
113 AccessSize = 8;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000114 break;
115 case X86::MOVAPDmr:
116 case X86::MOVAPSmr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000117 case X86::MOVAPDrm:
118 case X86::MOVAPSrm:
119 AccessSize = 16;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000120 break;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000121 default:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000122 return;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000123 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000124
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +0000125 const bool IsWrite = MII.get(Inst.getOpcode()).mayStore();
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000126 for (unsigned Ix = 0; Ix < Operands.size(); ++Ix) {
127 MCParsedAsmOperand *Op = Operands[Ix];
128 if (Op && Op->isMem())
129 InstrumentMemOperand(Op, AccessSize, IsWrite, Ctx, Out);
130 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000131}
132
133class X86AddressSanitizer32 : public X86AddressSanitizer {
134public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000135 X86AddressSanitizer32(const MCSubtargetInfo &STI)
136 : X86AddressSanitizer(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000137 virtual ~X86AddressSanitizer32() {}
138
139 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
140 bool IsWrite, MCContext &Ctx,
141 MCStreamer &Out) override;
142};
143
144void X86AddressSanitizer32::InstrumentMemOperandImpl(
145 X86Operand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
146 MCStreamer &Out) {
147 // FIXME: emit .cfi directives for correct stack unwinding.
148 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
149 {
150 MCInst Inst;
151 Inst.setOpcode(X86::LEA32r);
152 Inst.addOperand(MCOperand::CreateReg(X86::EAX));
153 Op->addMemOperands(Inst, 5);
154 EmitInstruction(Out, Inst);
155 }
156 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
157 {
158 const std::string Func = FuncName(AccessSize, IsWrite);
159 const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
160 const MCSymbolRefExpr *FuncExpr =
161 MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
162 EmitInstruction(Out, MCInstBuilder(X86::CALLpcrel32).addExpr(FuncExpr));
163 }
164 EmitInstruction(Out, MCInstBuilder(X86::ADD32ri).addReg(X86::ESP)
165 .addReg(X86::ESP).addImm(4));
166 EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EAX));
167}
168
169class X86AddressSanitizer64 : public X86AddressSanitizer {
170public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000171 X86AddressSanitizer64(const MCSubtargetInfo &STI)
172 : X86AddressSanitizer(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000173 virtual ~X86AddressSanitizer64() {}
174
175 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
176 bool IsWrite, MCContext &Ctx,
177 MCStreamer &Out) override;
178};
179
Evgeniy Stepanov9661ec02014-05-08 09:55:24 +0000180void X86AddressSanitizer64::InstrumentMemOperandImpl(X86Operand *Op,
181 unsigned AccessSize,
182 bool IsWrite,
183 MCContext &Ctx,
184 MCStreamer &Out) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000185 // FIXME: emit .cfi directives for correct stack unwinding.
Evgeniy Stepanov9661ec02014-05-08 09:55:24 +0000186
187 // Set %rsp below current red zone (128 bytes wide) using LEA instruction to
188 // preserve flags.
189 {
190 MCInst Inst;
191 Inst.setOpcode(X86::LEA64r);
192 Inst.addOperand(MCOperand::CreateReg(X86::RSP));
193
194 const MCExpr *Disp = MCConstantExpr::Create(-128, Ctx);
195 X86Operand *Op =
196 X86Operand::CreateMem(0, Disp, X86::RSP, 0, 1, SMLoc(), SMLoc());
197 Op->addMemOperands(Inst, 5);
198 EmitInstruction(Out, Inst);
199 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000200 EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(X86::RDI));
201 {
202 MCInst Inst;
203 Inst.setOpcode(X86::LEA64r);
204 Inst.addOperand(MCOperand::CreateReg(X86::RDI));
205 Op->addMemOperands(Inst, 5);
206 EmitInstruction(Out, Inst);
207 }
208 {
209 const std::string Func = FuncName(AccessSize, IsWrite);
210 const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
211 const MCSymbolRefExpr *FuncExpr =
212 MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
213 EmitInstruction(Out, MCInstBuilder(X86::CALL64pcrel32).addExpr(FuncExpr));
214 }
215 EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(X86::RDI));
Evgeniy Stepanov9661ec02014-05-08 09:55:24 +0000216
217 // Restore old %rsp value.
218 {
219 MCInst Inst;
220 Inst.setOpcode(X86::LEA64r);
221 Inst.addOperand(MCOperand::CreateReg(X86::RSP));
222
223 const MCExpr *Disp = MCConstantExpr::Create(128, Ctx);
224 X86Operand *Op =
225 X86Operand::CreateMem(0, Disp, X86::RSP, 0, 1, SMLoc(), SMLoc());
226 Op->addMemOperands(Inst, 5);
227 EmitInstruction(Out, Inst);
228 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000229}
230
231} // End anonymous namespace
232
233X86AsmInstrumentation::X86AsmInstrumentation() {}
234X86AsmInstrumentation::~X86AsmInstrumentation() {}
235
236void X86AsmInstrumentation::InstrumentInstruction(
237 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +0000238 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000239
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000240X86AsmInstrumentation *
Evgeniy Stepanov29865f72014-04-30 14:04:31 +0000241CreateX86AsmInstrumentation(const MCTargetOptions &MCOptions,
242 const MCContext &Ctx, const MCSubtargetInfo &STI) {
243 Triple T(STI.getTargetTriple());
244 const bool hasCompilerRTSupport = T.isOSLinux();
Evgeniy Stepanov3819f022014-05-07 07:54:11 +0000245 if (ClAsanInstrumentAssembly && hasCompilerRTSupport &&
246 MCOptions.SanitizeAddress) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000247 if ((STI.getFeatureBits() & X86::Mode32Bit) != 0)
248 return new X86AddressSanitizer32(STI);
249 if ((STI.getFeatureBits() & X86::Mode64Bit) != 0)
250 return new X86AddressSanitizer64(STI);
251 }
252 return new X86AsmInstrumentation();
253}
254
255} // End llvm namespace