10b57cec5SDimitry Andric //===-- CodeGen/AsmPrinter/WinCFGuard.cpp - Control Flow Guard Impl ------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 9*480093f4SDimitry Andric // This file contains support for writing the metadata for Windows Control Flow 10*480093f4SDimitry Andric // Guard, including address-taken functions, and valid longjmp targets. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "WinCFGuard.h" 150b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 190b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 200b57cec5SDimitry Andric #include "llvm/IR/Metadata.h" 21*480093f4SDimitry Andric #include "llvm/IR/Instructions.h" 220b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 230b57cec5SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h" 240b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric #include <vector> 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric using namespace llvm; 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric WinCFGuard::WinCFGuard(AsmPrinter *A) : AsmPrinterHandler(), Asm(A) {} 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric WinCFGuard::~WinCFGuard() {} 330b57cec5SDimitry Andric 34*480093f4SDimitry Andric void WinCFGuard::endFunction(const MachineFunction *MF) { 35*480093f4SDimitry Andric 36*480093f4SDimitry Andric // Skip functions without any longjmp targets. 37*480093f4SDimitry Andric if (MF->getLongjmpTargets().empty()) 38*480093f4SDimitry Andric return; 39*480093f4SDimitry Andric 40*480093f4SDimitry Andric // Copy the function's longjmp targets to a module-level list. 41*480093f4SDimitry Andric LongjmpTargets.insert(LongjmpTargets.end(), MF->getLongjmpTargets().begin(), 42*480093f4SDimitry Andric MF->getLongjmpTargets().end()); 43*480093f4SDimitry Andric } 44*480093f4SDimitry Andric 45*480093f4SDimitry Andric /// Returns true if this function's address is escaped in a way that might make 46*480093f4SDimitry Andric /// it an indirect call target. Function::hasAddressTaken gives different 47*480093f4SDimitry Andric /// results when a function is called directly with a function prototype 48*480093f4SDimitry Andric /// mismatch, which requires a cast. 49*480093f4SDimitry Andric static bool isPossibleIndirectCallTarget(const Function *F) { 50*480093f4SDimitry Andric SmallVector<const Value *, 4> Users{F}; 51*480093f4SDimitry Andric while (!Users.empty()) { 52*480093f4SDimitry Andric const Value *FnOrCast = Users.pop_back_val(); 53*480093f4SDimitry Andric for (const Use &U : FnOrCast->uses()) { 54*480093f4SDimitry Andric const User *FnUser = U.getUser(); 55*480093f4SDimitry Andric if (isa<BlockAddress>(FnUser)) 56*480093f4SDimitry Andric continue; 57*480093f4SDimitry Andric if (const auto *Call = dyn_cast<CallBase>(FnUser)) { 58*480093f4SDimitry Andric if (!Call->isCallee(&U)) 59*480093f4SDimitry Andric return true; 60*480093f4SDimitry Andric } else if (isa<Instruction>(FnUser)) { 61*480093f4SDimitry Andric // Consider any other instruction to be an escape. This has some weird 62*480093f4SDimitry Andric // consequences like no-op intrinsics being an escape or a store *to* a 63*480093f4SDimitry Andric // function address being an escape. 64*480093f4SDimitry Andric return true; 65*480093f4SDimitry Andric } else if (const auto *C = dyn_cast<Constant>(FnUser)) { 66*480093f4SDimitry Andric // If this is a constant pointer cast of the function, don't consider 67*480093f4SDimitry Andric // this escape. Analyze the uses of the cast as well. This ensures that 68*480093f4SDimitry Andric // direct calls with mismatched prototypes don't end up in the CFG 69*480093f4SDimitry Andric // table. Consider other constants, such as vtable initializers, to 70*480093f4SDimitry Andric // escape the function. 71*480093f4SDimitry Andric if (C->stripPointerCasts() == F) 72*480093f4SDimitry Andric Users.push_back(FnUser); 73*480093f4SDimitry Andric else 74*480093f4SDimitry Andric return true; 75*480093f4SDimitry Andric } 76*480093f4SDimitry Andric } 77*480093f4SDimitry Andric } 78*480093f4SDimitry Andric return false; 79*480093f4SDimitry Andric } 80*480093f4SDimitry Andric 810b57cec5SDimitry Andric void WinCFGuard::endModule() { 820b57cec5SDimitry Andric const Module *M = Asm->MMI->getModule(); 830b57cec5SDimitry Andric std::vector<const Function *> Functions; 840b57cec5SDimitry Andric for (const Function &F : *M) 85*480093f4SDimitry Andric if (isPossibleIndirectCallTarget(&F)) 860b57cec5SDimitry Andric Functions.push_back(&F); 87*480093f4SDimitry Andric if (Functions.empty() && LongjmpTargets.empty()) 880b57cec5SDimitry Andric return; 890b57cec5SDimitry Andric auto &OS = *Asm->OutStreamer; 900b57cec5SDimitry Andric OS.SwitchSection(Asm->OutContext.getObjectFileInfo()->getGFIDsSection()); 910b57cec5SDimitry Andric for (const Function *F : Functions) 920b57cec5SDimitry Andric OS.EmitCOFFSymbolIndex(Asm->getSymbol(F)); 93*480093f4SDimitry Andric 94*480093f4SDimitry Andric // Emit the symbol index of each longjmp target. 95*480093f4SDimitry Andric OS.SwitchSection(Asm->OutContext.getObjectFileInfo()->getGLJMPSection()); 96*480093f4SDimitry Andric for (const MCSymbol *S : LongjmpTargets) { 97*480093f4SDimitry Andric OS.EmitCOFFSymbolIndex(S); 98*480093f4SDimitry Andric } 990b57cec5SDimitry Andric } 100