blob: 623479361c29c24643590e3ad8623af7ec77859f [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"
David Blaikie960ea3f2014-06-08 16:18:35 +000023#include "llvm/MC/MCTargetAsmParser.h"
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000024#include "llvm/MC/MCTargetOptions.h"
Evgeniy Stepanov3819f022014-05-07 07:54:11 +000025#include "llvm/Support/CommandLine.h"
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000026
27namespace llvm {
28namespace {
29
Evgeniy Stepanov3819f022014-05-07 07:54:11 +000030static cl::opt<bool> ClAsanInstrumentAssembly(
31 "asan-instrument-assembly",
32 cl::desc("instrument assembly with AddressSanitizer checks"), cl::Hidden,
33 cl::init(false));
34
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000035bool IsStackReg(unsigned Reg) {
36 return Reg == X86::RSP || Reg == X86::ESP || Reg == X86::SP;
37}
38
39std::string FuncName(unsigned AccessSize, bool IsWrite) {
40 return std::string("__sanitizer_sanitize_") + (IsWrite ? "store" : "load") +
41 (utostr(AccessSize));
42}
43
44class X86AddressSanitizer : public X86AsmInstrumentation {
45public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000046 X86AddressSanitizer(const MCSubtargetInfo &STI) : STI(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000047 virtual ~X86AddressSanitizer() {}
48
49 // X86AsmInstrumentation implementation:
David Blaikie960ea3f2014-06-08 16:18:35 +000050 virtual void InstrumentInstruction(const MCInst &Inst,
51 OperandVector &Operands, MCContext &Ctx,
52 const MCInstrInfo &MII,
53 MCStreamer &Out) override {
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000054 InstrumentMOV(Inst, Operands, Ctx, MII, Out);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000055 }
56
57 // Should be implemented differently in x86_32 and x86_64 subclasses.
David Blaikie960ea3f2014-06-08 16:18:35 +000058 virtual void InstrumentMemOperandImpl(X86Operand &Op, unsigned AccessSize,
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000059 bool IsWrite, MCContext &Ctx,
60 MCStreamer &Out) = 0;
61
David Blaikie960ea3f2014-06-08 16:18:35 +000062 void InstrumentMemOperand(MCParsedAsmOperand &Op, unsigned AccessSize,
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000063 bool IsWrite, MCContext &Ctx, MCStreamer &Out);
David Blaikie960ea3f2014-06-08 16:18:35 +000064 void InstrumentMOV(const MCInst &Inst, OperandVector &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000065 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000066 void EmitInstruction(MCStreamer &Out, const MCInst &Inst) {
67 Out.EmitInstruction(Inst, STI);
68 }
69
70protected:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000071 const MCSubtargetInfo &STI;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000072};
73
David Blaikie960ea3f2014-06-08 16:18:35 +000074void X86AddressSanitizer::InstrumentMemOperand(MCParsedAsmOperand &Op,
75 unsigned AccessSize,
76 bool IsWrite, MCContext &Ctx,
77 MCStreamer &Out) {
78 assert(Op.isMem() && "Op should be a memory operand.");
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000079 assert((AccessSize & (AccessSize - 1)) == 0 && AccessSize <= 16 &&
80 "AccessSize should be a power of two, less or equal than 16.");
81
David Blaikie960ea3f2014-06-08 16:18:35 +000082 X86Operand &MemOp = static_cast<X86Operand &>(Op);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000083 // FIXME: get rid of this limitation.
David Blaikie960ea3f2014-06-08 16:18:35 +000084 if (IsStackReg(MemOp.getMemBaseReg()) || IsStackReg(MemOp.getMemIndexReg()))
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000085 return;
86
87 InstrumentMemOperandImpl(MemOp, AccessSize, IsWrite, Ctx, Out);
88}
89
David Blaikie960ea3f2014-06-08 16:18:35 +000090void X86AddressSanitizer::InstrumentMOV(const MCInst &Inst,
91 OperandVector &Operands, MCContext &Ctx,
92 const MCInstrInfo &MII,
93 MCStreamer &Out) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000094 // Access size in bytes.
95 unsigned AccessSize = 0;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +000096
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000097 switch (Inst.getOpcode()) {
98 case X86::MOV8mi:
99 case X86::MOV8mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000100 case X86::MOV8rm:
101 AccessSize = 1;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000102 break;
103 case X86::MOV16mi:
104 case X86::MOV16mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000105 case X86::MOV16rm:
106 AccessSize = 2;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000107 break;
108 case X86::MOV32mi:
109 case X86::MOV32mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000110 case X86::MOV32rm:
111 AccessSize = 4;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000112 break;
113 case X86::MOV64mi32:
114 case X86::MOV64mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000115 case X86::MOV64rm:
116 AccessSize = 8;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000117 break;
118 case X86::MOVAPDmr:
119 case X86::MOVAPSmr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000120 case X86::MOVAPDrm:
121 case X86::MOVAPSrm:
122 AccessSize = 16;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000123 break;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000124 default:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000125 return;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000126 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000127
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +0000128 const bool IsWrite = MII.get(Inst.getOpcode()).mayStore();
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000129 for (unsigned Ix = 0; Ix < Operands.size(); ++Ix) {
David Blaikie960ea3f2014-06-08 16:18:35 +0000130 assert(Operands[Ix]);
131 MCParsedAsmOperand &Op = *Operands[Ix];
132 if (Op.isMem())
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000133 InstrumentMemOperand(Op, AccessSize, IsWrite, Ctx, Out);
134 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000135}
136
137class X86AddressSanitizer32 : public X86AddressSanitizer {
138public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000139 X86AddressSanitizer32(const MCSubtargetInfo &STI)
140 : X86AddressSanitizer(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000141 virtual ~X86AddressSanitizer32() {}
142
David Blaikie960ea3f2014-06-08 16:18:35 +0000143 virtual void InstrumentMemOperandImpl(X86Operand &Op, unsigned AccessSize,
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000144 bool IsWrite, MCContext &Ctx,
145 MCStreamer &Out) override;
146};
147
David Blaikie960ea3f2014-06-08 16:18:35 +0000148void X86AddressSanitizer32::InstrumentMemOperandImpl(X86Operand &Op,
149 unsigned AccessSize,
150 bool IsWrite,
151 MCContext &Ctx,
152 MCStreamer &Out) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000153 // FIXME: emit .cfi directives for correct stack unwinding.
154 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
155 {
156 MCInst Inst;
157 Inst.setOpcode(X86::LEA32r);
158 Inst.addOperand(MCOperand::CreateReg(X86::EAX));
David Blaikie960ea3f2014-06-08 16:18:35 +0000159 Op.addMemOperands(Inst, 5);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000160 EmitInstruction(Out, Inst);
161 }
162 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
163 {
164 const std::string Func = FuncName(AccessSize, IsWrite);
165 const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
166 const MCSymbolRefExpr *FuncExpr =
167 MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
168 EmitInstruction(Out, MCInstBuilder(X86::CALLpcrel32).addExpr(FuncExpr));
169 }
Evgeniy Stepanovfc9c78a2014-05-21 08:14:24 +0000170 EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EAX));
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000171 EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EAX));
172}
173
174class X86AddressSanitizer64 : public X86AddressSanitizer {
175public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000176 X86AddressSanitizer64(const MCSubtargetInfo &STI)
177 : X86AddressSanitizer(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000178 virtual ~X86AddressSanitizer64() {}
179
David Blaikie960ea3f2014-06-08 16:18:35 +0000180 virtual void InstrumentMemOperandImpl(X86Operand &Op, unsigned AccessSize,
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000181 bool IsWrite, MCContext &Ctx,
182 MCStreamer &Out) override;
183};
184
David Blaikie960ea3f2014-06-08 16:18:35 +0000185void X86AddressSanitizer64::InstrumentMemOperandImpl(X86Operand &Op,
Evgeniy Stepanov9661ec02014-05-08 09:55:24 +0000186 unsigned AccessSize,
187 bool IsWrite,
188 MCContext &Ctx,
189 MCStreamer &Out) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000190 // FIXME: emit .cfi directives for correct stack unwinding.
Evgeniy Stepanov9661ec02014-05-08 09:55:24 +0000191
192 // Set %rsp below current red zone (128 bytes wide) using LEA instruction to
193 // preserve flags.
194 {
195 MCInst Inst;
196 Inst.setOpcode(X86::LEA64r);
197 Inst.addOperand(MCOperand::CreateReg(X86::RSP));
198
199 const MCExpr *Disp = MCConstantExpr::Create(-128, Ctx);
Benjamin Kramer8bbadc02014-05-09 09:48:03 +0000200 std::unique_ptr<X86Operand> Op(
201 X86Operand::CreateMem(0, Disp, X86::RSP, 0, 1, SMLoc(), SMLoc()));
Evgeniy Stepanov9661ec02014-05-08 09:55:24 +0000202 Op->addMemOperands(Inst, 5);
203 EmitInstruction(Out, Inst);
204 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000205 EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(X86::RDI));
206 {
207 MCInst Inst;
208 Inst.setOpcode(X86::LEA64r);
209 Inst.addOperand(MCOperand::CreateReg(X86::RDI));
David Blaikie960ea3f2014-06-08 16:18:35 +0000210 Op.addMemOperands(Inst, 5);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000211 EmitInstruction(Out, Inst);
212 }
213 {
214 const std::string Func = FuncName(AccessSize, IsWrite);
215 const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
216 const MCSymbolRefExpr *FuncExpr =
217 MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
218 EmitInstruction(Out, MCInstBuilder(X86::CALL64pcrel32).addExpr(FuncExpr));
219 }
220 EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(X86::RDI));
Evgeniy Stepanov9661ec02014-05-08 09:55:24 +0000221
222 // Restore old %rsp value.
223 {
224 MCInst Inst;
225 Inst.setOpcode(X86::LEA64r);
226 Inst.addOperand(MCOperand::CreateReg(X86::RSP));
227
228 const MCExpr *Disp = MCConstantExpr::Create(128, Ctx);
Benjamin Kramer8bbadc02014-05-09 09:48:03 +0000229 std::unique_ptr<X86Operand> Op(
230 X86Operand::CreateMem(0, Disp, X86::RSP, 0, 1, SMLoc(), SMLoc()));
Evgeniy Stepanov9661ec02014-05-08 09:55:24 +0000231 Op->addMemOperands(Inst, 5);
232 EmitInstruction(Out, Inst);
233 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000234}
235
236} // End anonymous namespace
237
238X86AsmInstrumentation::X86AsmInstrumentation() {}
239X86AsmInstrumentation::~X86AsmInstrumentation() {}
240
David Blaikie960ea3f2014-06-08 16:18:35 +0000241void X86AsmInstrumentation::InstrumentInstruction(const MCInst &Inst,
242 OperandVector &Operands,
243 MCContext &Ctx,
244 const MCInstrInfo &MII,
245 MCStreamer &Out) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000246
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000247X86AsmInstrumentation *
Evgeniy Stepanov29865f72014-04-30 14:04:31 +0000248CreateX86AsmInstrumentation(const MCTargetOptions &MCOptions,
249 const MCContext &Ctx, const MCSubtargetInfo &STI) {
250 Triple T(STI.getTargetTriple());
251 const bool hasCompilerRTSupport = T.isOSLinux();
Evgeniy Stepanov3819f022014-05-07 07:54:11 +0000252 if (ClAsanInstrumentAssembly && hasCompilerRTSupport &&
253 MCOptions.SanitizeAddress) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000254 if ((STI.getFeatureBits() & X86::Mode32Bit) != 0)
255 return new X86AddressSanitizer32(STI);
256 if ((STI.getFeatureBits() & X86::Mode64Bit) != 0)
257 return new X86AddressSanitizer64(STI);
258 }
259 return new X86AsmInstrumentation();
260}
261
262} // End llvm namespace