1 //===-- X86AsmInstrumentation.cpp - Instrument X86 inline assembly C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "MCTargetDesc/X86BaseInfo.h"
11 #include "X86AsmInstrumentation.h"
12 #include "X86Operand.h"
13 #include "llvm/ADT/StringExtras.h"
14 #include "llvm/ADT/Triple.h"
15 #include "llvm/IR/Function.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCInst.h"
18 #include "llvm/MC/MCInstBuilder.h"
19 #include "llvm/MC/MCInstrInfo.h"
20 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
21 #include "llvm/MC/MCStreamer.h"
22 #include "llvm/MC/MCSubtargetInfo.h"
23 #include "llvm/MC/MCTargetAsmParser.h"
24 #include "llvm/MC/MCTargetOptions.h"
25 #include "llvm/Support/CommandLine.h"
30 static cl::opt<bool> ClAsanInstrumentAssembly(
31 "asan-instrument-assembly",
32 cl::desc("instrument assembly with AddressSanitizer checks"), cl::Hidden,
35 bool IsStackReg(unsigned Reg) {
36 return Reg == X86::RSP || Reg == X86::ESP || Reg == X86::SP;
39 std::string FuncName(unsigned AccessSize, bool IsWrite) {
40 return std::string("__asan_report_") + (IsWrite ? "store" : "load") +
44 class X86AddressSanitizer : public X86AsmInstrumentation {
46 X86AddressSanitizer(const MCSubtargetInfo &STI) : STI(STI) {}
47 virtual ~X86AddressSanitizer() {}
49 // X86AsmInstrumentation implementation:
50 virtual void InstrumentInstruction(
51 const MCInst &Inst, OperandVector &Operands, MCContext &Ctx,
52 const MCInstrInfo &MII, MCStreamer &Out) override {
53 InstrumentMOV(Inst, Operands, Ctx, MII, Out);
56 // Should be implemented differently in x86_32 and x86_64 subclasses.
57 virtual void InstrumentMemOperandSmallImpl(
58 X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
60 virtual void InstrumentMemOperandLargeImpl(
61 X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
64 void InstrumentMemOperand(MCParsedAsmOperand &Op, unsigned AccessSize,
65 bool IsWrite, MCContext &Ctx, MCStreamer &Out);
66 void InstrumentMOV(const MCInst &Inst, OperandVector &Operands,
67 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
68 void EmitInstruction(MCStreamer &Out, const MCInst &Inst) {
69 Out.EmitInstruction(Inst, STI);
72 void EmitLabel(MCStreamer &Out, MCSymbol *Label) { Out.EmitLabel(Label); }
75 const MCSubtargetInfo &STI;
78 void X86AddressSanitizer::InstrumentMemOperand(
79 MCParsedAsmOperand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
81 assert(Op.isMem() && "Op should be a memory operand.");
82 assert((AccessSize & (AccessSize - 1)) == 0 && AccessSize <= 16 &&
83 "AccessSize should be a power of two, less or equal than 16.");
85 X86Operand &MemOp = static_cast<X86Operand &>(Op);
86 // FIXME: get rid of this limitation.
87 if (IsStackReg(MemOp.getMemBaseReg()) || IsStackReg(MemOp.getMemIndexReg()))
90 // FIXME: take into account load/store alignment.
92 InstrumentMemOperandSmallImpl(MemOp, AccessSize, IsWrite, Ctx, Out);
94 InstrumentMemOperandLargeImpl(MemOp, AccessSize, IsWrite, Ctx, Out);
97 void X86AddressSanitizer::InstrumentMOV(
98 const MCInst &Inst, OperandVector &Operands, MCContext &Ctx,
99 const MCInstrInfo &MII, MCStreamer &Out) {
100 // Access size in bytes.
101 unsigned AccessSize = 0;
103 switch (Inst.getOpcode()) {
134 const bool IsWrite = MII.get(Inst.getOpcode()).mayStore();
135 for (unsigned Ix = 0; Ix < Operands.size(); ++Ix) {
136 assert(Operands[Ix]);
137 MCParsedAsmOperand &Op = *Operands[Ix];
139 InstrumentMemOperand(Op, AccessSize, IsWrite, Ctx, Out);
143 class X86AddressSanitizer32 : public X86AddressSanitizer {
145 static const long kShadowOffset = 0x20000000;
147 X86AddressSanitizer32(const MCSubtargetInfo &STI)
148 : X86AddressSanitizer(STI) {}
149 virtual ~X86AddressSanitizer32() {}
151 virtual void InstrumentMemOperandSmallImpl(
152 X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
153 MCStreamer &Out) override;
154 virtual void InstrumentMemOperandLargeImpl(
155 X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
156 MCStreamer &Out) override;
159 void EmitCallAsanReport(MCContext &Ctx, MCStreamer &Out, unsigned AccessSize,
160 bool IsWrite, unsigned AddressReg) {
161 EmitInstruction(Out, MCInstBuilder(X86::CLD));
162 EmitInstruction(Out, MCInstBuilder(X86::MMX_EMMS));
164 EmitInstruction(Out, MCInstBuilder(X86::AND64ri8).addReg(X86::ESP)
165 .addReg(X86::ESP).addImm(-16));
166 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(AddressReg));
169 const std::string& Fn = FuncName(AccessSize, IsWrite);
170 MCSymbol *FnSym = Ctx.GetOrCreateSymbol(StringRef(Fn));
171 const MCSymbolRefExpr *FnExpr =
172 MCSymbolRefExpr::Create(FnSym, MCSymbolRefExpr::VK_PLT, Ctx);
173 EmitInstruction(Out, MCInstBuilder(X86::CALLpcrel32).addExpr(FnExpr));
177 void X86AddressSanitizer32::InstrumentMemOperandSmallImpl(
178 X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
180 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
181 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::ECX));
182 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EDX));
183 EmitInstruction(Out, MCInstBuilder(X86::PUSHF32));
187 Inst.setOpcode(X86::LEA32r);
188 Inst.addOperand(MCOperand::CreateReg(X86::EAX));
189 Op.addMemOperands(Inst, 5);
190 EmitInstruction(Out, Inst);
194 Out, MCInstBuilder(X86::MOV32rr).addReg(X86::ECX).addReg(X86::EAX));
195 EmitInstruction(Out, MCInstBuilder(X86::SHR32ri).addReg(X86::ECX)
196 .addReg(X86::ECX).addImm(3));
200 Inst.setOpcode(X86::MOV8rm);
201 Inst.addOperand(MCOperand::CreateReg(X86::CL));
202 const MCExpr *Disp = MCConstantExpr::Create(kShadowOffset, Ctx);
203 std::unique_ptr<X86Operand> Op(
204 X86Operand::CreateMem(0, Disp, X86::ECX, 0, 1, SMLoc(), SMLoc()));
205 Op->addMemOperands(Inst, 5);
206 EmitInstruction(Out, Inst);
210 MCInstBuilder(X86::TEST8rr).addReg(X86::CL).addReg(X86::CL));
211 MCSymbol *DoneSym = Ctx.CreateTempSymbol();
212 const MCExpr *DoneExpr = MCSymbolRefExpr::Create(DoneSym, Ctx);
213 EmitInstruction(Out, MCInstBuilder(X86::JE_4).addExpr(DoneExpr));
216 Out, MCInstBuilder(X86::MOV32rr).addReg(X86::EDX).addReg(X86::EAX));
217 EmitInstruction(Out, MCInstBuilder(X86::AND32ri).addReg(X86::EDX)
218 .addReg(X86::EDX).addImm(7));
220 switch (AccessSize) {
225 Inst.setOpcode(X86::LEA32r);
226 Inst.addOperand(MCOperand::CreateReg(X86::EDX));
228 const MCExpr *Disp = MCConstantExpr::Create(1, Ctx);
229 std::unique_ptr<X86Operand> Op(
230 X86Operand::CreateMem(0, Disp, X86::EDX, 0, 1, SMLoc(), SMLoc()));
231 Op->addMemOperands(Inst, 5);
232 EmitInstruction(Out, Inst);
236 EmitInstruction(Out, MCInstBuilder(X86::ADD32ri8).addReg(X86::EDX)
237 .addReg(X86::EDX).addImm(3));
240 assert(false && "Incorrect access size");
245 Out, MCInstBuilder(X86::MOVSX32rr8).addReg(X86::ECX).addReg(X86::CL));
247 Out, MCInstBuilder(X86::CMP32rr).addReg(X86::EDX).addReg(X86::ECX));
248 EmitInstruction(Out, MCInstBuilder(X86::JL_4).addExpr(DoneExpr));
250 EmitCallAsanReport(Ctx, Out, AccessSize, IsWrite, X86::EAX);
251 EmitLabel(Out, DoneSym);
253 EmitInstruction(Out, MCInstBuilder(X86::POPF32));
254 EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EDX));
255 EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::ECX));
256 EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EAX));
259 void X86AddressSanitizer32::InstrumentMemOperandLargeImpl(
260 X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
262 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
263 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::ECX));
264 EmitInstruction(Out, MCInstBuilder(X86::PUSHF32));
268 Inst.setOpcode(X86::LEA32r);
269 Inst.addOperand(MCOperand::CreateReg(X86::EAX));
270 Op.addMemOperands(Inst, 5);
271 EmitInstruction(Out, Inst);
274 Out, MCInstBuilder(X86::MOV32rr).addReg(X86::ECX).addReg(X86::EAX));
275 EmitInstruction(Out, MCInstBuilder(X86::SHR32ri).addReg(X86::ECX)
276 .addReg(X86::ECX).addImm(3));
279 switch (AccessSize) {
281 Inst.setOpcode(X86::CMP8mi);
284 Inst.setOpcode(X86::CMP16mi);
287 assert(false && "Incorrect access size");
290 const MCExpr *Disp = MCConstantExpr::Create(kShadowOffset, Ctx);
291 std::unique_ptr<X86Operand> Op(
292 X86Operand::CreateMem(0, Disp, X86::ECX, 0, 1, SMLoc(), SMLoc()));
293 Op->addMemOperands(Inst, 5);
294 Inst.addOperand(MCOperand::CreateImm(0));
295 EmitInstruction(Out, Inst);
297 MCSymbol *DoneSym = Ctx.CreateTempSymbol();
298 const MCExpr *DoneExpr = MCSymbolRefExpr::Create(DoneSym, Ctx);
299 EmitInstruction(Out, MCInstBuilder(X86::JE_4).addExpr(DoneExpr));
301 EmitCallAsanReport(Ctx, Out, AccessSize, IsWrite, X86::EAX);
302 EmitLabel(Out, DoneSym);
304 EmitInstruction(Out, MCInstBuilder(X86::POPF32));
305 EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::ECX));
306 EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EAX));
309 class X86AddressSanitizer64 : public X86AddressSanitizer {
311 static const long kShadowOffset = 0x7fff8000;
313 X86AddressSanitizer64(const MCSubtargetInfo &STI)
314 : X86AddressSanitizer(STI) {}
315 virtual ~X86AddressSanitizer64() {}
317 virtual void InstrumentMemOperandSmallImpl(
318 X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
319 MCStreamer &Out) override;
320 virtual void InstrumentMemOperandLargeImpl(
321 X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
322 MCStreamer &Out) override;
325 void EmitAdjustRSP(MCContext &Ctx, MCStreamer &Out, long Offset) {
327 Inst.setOpcode(X86::LEA64r);
328 Inst.addOperand(MCOperand::CreateReg(X86::RSP));
330 const MCExpr *Disp = MCConstantExpr::Create(Offset, Ctx);
331 std::unique_ptr<X86Operand> Op(
332 X86Operand::CreateMem(0, Disp, X86::RSP, 0, 1, SMLoc(), SMLoc()));
333 Op->addMemOperands(Inst, 5);
334 EmitInstruction(Out, Inst);
337 void EmitCallAsanReport(MCContext &Ctx, MCStreamer &Out, unsigned AccessSize,
339 EmitInstruction(Out, MCInstBuilder(X86::CLD));
340 EmitInstruction(Out, MCInstBuilder(X86::MMX_EMMS));
342 EmitInstruction(Out, MCInstBuilder(X86::AND64ri8).addReg(X86::RSP)
343 .addReg(X86::RSP).addImm(-16));
345 const std::string& Fn = FuncName(AccessSize, IsWrite);
346 MCSymbol *FnSym = Ctx.GetOrCreateSymbol(StringRef(Fn));
347 const MCSymbolRefExpr *FnExpr =
348 MCSymbolRefExpr::Create(FnSym, MCSymbolRefExpr::VK_PLT, Ctx);
349 EmitInstruction(Out, MCInstBuilder(X86::CALL64pcrel32).addExpr(FnExpr));
353 void X86AddressSanitizer64::InstrumentMemOperandSmallImpl(
354 X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
356 EmitAdjustRSP(Ctx, Out, -128);
357 EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(X86::RAX));
358 EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(X86::RCX));
359 EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(X86::RDI));
360 EmitInstruction(Out, MCInstBuilder(X86::PUSHF64));
363 Inst.setOpcode(X86::LEA64r);
364 Inst.addOperand(MCOperand::CreateReg(X86::RDI));
365 Op.addMemOperands(Inst, 5);
366 EmitInstruction(Out, Inst);
369 Out, MCInstBuilder(X86::MOV64rr).addReg(X86::RAX).addReg(X86::RDI));
370 EmitInstruction(Out, MCInstBuilder(X86::SHR64ri).addReg(X86::RAX)
371 .addReg(X86::RAX).addImm(3));
374 Inst.setOpcode(X86::MOV8rm);
375 Inst.addOperand(MCOperand::CreateReg(X86::AL));
376 const MCExpr *Disp = MCConstantExpr::Create(kShadowOffset, Ctx);
377 std::unique_ptr<X86Operand> Op(
378 X86Operand::CreateMem(0, Disp, X86::RAX, 0, 1, SMLoc(), SMLoc()));
379 Op->addMemOperands(Inst, 5);
380 EmitInstruction(Out, Inst);
384 MCInstBuilder(X86::TEST8rr).addReg(X86::AL).addReg(X86::AL));
385 MCSymbol *DoneSym = Ctx.CreateTempSymbol();
386 const MCExpr *DoneExpr = MCSymbolRefExpr::Create(DoneSym, Ctx);
387 EmitInstruction(Out, MCInstBuilder(X86::JE_4).addExpr(DoneExpr));
390 Out, MCInstBuilder(X86::MOV32rr).addReg(X86::ECX).addReg(X86::EDI));
391 EmitInstruction(Out, MCInstBuilder(X86::AND32ri).addReg(X86::ECX)
392 .addReg(X86::ECX).addImm(7));
394 switch (AccessSize) {
399 Inst.setOpcode(X86::LEA32r);
400 Inst.addOperand(MCOperand::CreateReg(X86::ECX));
402 const MCExpr *Disp = MCConstantExpr::Create(1, Ctx);
403 std::unique_ptr<X86Operand> Op(
404 X86Operand::CreateMem(0, Disp, X86::ECX, 0, 1, SMLoc(), SMLoc()));
405 Op->addMemOperands(Inst, 5);
406 EmitInstruction(Out, Inst);
410 EmitInstruction(Out, MCInstBuilder(X86::ADD32ri8).addReg(X86::ECX)
411 .addReg(X86::ECX).addImm(3));
414 assert(false && "Incorrect access size");
419 Out, MCInstBuilder(X86::MOVSX32rr8).addReg(X86::EAX).addReg(X86::AL));
421 Out, MCInstBuilder(X86::CMP32rr).addReg(X86::ECX).addReg(X86::EAX));
422 EmitInstruction(Out, MCInstBuilder(X86::JL_4).addExpr(DoneExpr));
424 EmitCallAsanReport(Ctx, Out, AccessSize, IsWrite);
425 EmitLabel(Out, DoneSym);
427 EmitInstruction(Out, MCInstBuilder(X86::POPF64));
428 EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(X86::RDI));
429 EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(X86::RCX));
430 EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(X86::RAX));
431 EmitAdjustRSP(Ctx, Out, 128);
434 void X86AddressSanitizer64::InstrumentMemOperandLargeImpl(
435 X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
437 EmitAdjustRSP(Ctx, Out, -128);
438 EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(X86::RAX));
439 EmitInstruction(Out, MCInstBuilder(X86::PUSHF64));
443 Inst.setOpcode(X86::LEA64r);
444 Inst.addOperand(MCOperand::CreateReg(X86::RAX));
445 Op.addMemOperands(Inst, 5);
446 EmitInstruction(Out, Inst);
448 EmitInstruction(Out, MCInstBuilder(X86::SHR64ri).addReg(X86::RAX)
449 .addReg(X86::RAX).addImm(3));
452 switch (AccessSize) {
454 Inst.setOpcode(X86::CMP8mi);
457 Inst.setOpcode(X86::CMP16mi);
460 assert(false && "Incorrect access size");
463 const MCExpr *Disp = MCConstantExpr::Create(kShadowOffset, Ctx);
464 std::unique_ptr<X86Operand> Op(
465 X86Operand::CreateMem(0, Disp, X86::RAX, 0, 1, SMLoc(), SMLoc()));
466 Op->addMemOperands(Inst, 5);
467 Inst.addOperand(MCOperand::CreateImm(0));
468 EmitInstruction(Out, Inst);
471 MCSymbol *DoneSym = Ctx.CreateTempSymbol();
472 const MCExpr *DoneExpr = MCSymbolRefExpr::Create(DoneSym, Ctx);
473 EmitInstruction(Out, MCInstBuilder(X86::JE_4).addExpr(DoneExpr));
475 EmitCallAsanReport(Ctx, Out, AccessSize, IsWrite);
476 EmitLabel(Out, DoneSym);
478 EmitInstruction(Out, MCInstBuilder(X86::POPF64));
479 EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(X86::RAX));
480 EmitAdjustRSP(Ctx, Out, 128);
483 } // End anonymous namespace
485 X86AsmInstrumentation::X86AsmInstrumentation() {}
486 X86AsmInstrumentation::~X86AsmInstrumentation() {}
488 void X86AsmInstrumentation::InstrumentInstruction(
489 const MCInst &Inst, OperandVector &Operands, MCContext &Ctx,
490 const MCInstrInfo &MII, MCStreamer &Out) {}
492 X86AsmInstrumentation *
493 CreateX86AsmInstrumentation(const MCTargetOptions &MCOptions,
494 const MCContext &Ctx, const MCSubtargetInfo &STI) {
495 Triple T(STI.getTargetTriple());
496 const bool hasCompilerRTSupport = T.isOSLinux();
497 if (ClAsanInstrumentAssembly && hasCompilerRTSupport &&
498 MCOptions.SanitizeAddress) {
499 if ((STI.getFeatureBits() & X86::Mode32Bit) != 0)
500 return new X86AddressSanitizer32(STI);
501 if ((STI.getFeatureBits() & X86::Mode64Bit) != 0)
502 return new X86AddressSanitizer64(STI);
504 return new X86AsmInstrumentation();
507 } // End llvm namespace