1 //===- bolt/Passes/ValidateInternalCalls.h ----------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef BOLT_PASSES_VALIDATEINTERNALCALLS_H 10 #define BOLT_PASSES_VALIDATEINTERNALCALLS_H 11 12 #include "bolt/Passes/BinaryPasses.h" 13 14 namespace llvm { 15 namespace bolt { 16 17 /// Post-processing for internal calls. What are those? They are call 18 /// instructions that do not transfer control to another function, but 19 /// rather branch to a basic block inside the caller function itself. 20 /// This pass checks that the internal calls observed in a function are 21 /// manageable. We support two types: 22 /// 23 /// 1. Position Independent Code (PIC) tricks: in this type of internal 24 /// call, we don't really have a call because the return address is 25 /// not utilized for branching to, but only as a base address to 26 /// reference other objects. We call it a "trick" because this is not 27 /// the standard way a compiler would do this and this will often come 28 /// from awkwardly written assembly code. 29 /// 30 /// 2. Real internal calls: in this case, a function was inlined inside 31 /// a caller, but the CALL instruction wasn't removed. This pair of 32 /// caller-callee is treated as a single function and is analyzed 33 /// here. 34 /// 35 /// In general, the rest of the BOLT pipeline (other optimizations, including 36 /// code reordering) will not support neither of these cases. In this pass, 37 /// we just identify them, verify they are safe (do not reference objects 38 /// that will be moved after reordering) and freeze these functions in the 39 /// way they were read. We do this by marking them as non-simple. 40 /// 41 /// Why do we freeze them? 42 /// 43 /// Type 1 is not safe to optimize because any changed offsets will break the 44 /// PIC references made in this code. Type 2 is not safe to optimize because 45 /// it requires BOLT to understand a new CFG format where internal calls are 46 /// broken into two BBs (calling block and returning block), and we currently do 47 /// not support this elsewhere. Only this pass is able to make sense of these 48 /// non-canonical CFGs (specifically, fixBranches does not support them). 49 /// 50 class ValidateInternalCalls : public BinaryFunctionPass { 51 public: ValidateInternalCalls(const cl::opt<bool> & PrintPass)52 explicit ValidateInternalCalls(const cl::opt<bool> &PrintPass) 53 : BinaryFunctionPass(PrintPass) {} 54 getName()55 const char *getName() const override { return "validate-internal-calls"; } 56 57 Error runOnFunctions(BinaryContext &BC) override; 58 59 private: 60 /// Fix the CFG to take into consideration internal calls that do not 61 /// return, but are only used as a trick to perform Position Independent 62 /// Code (PIC) computations. This will change internal calls to be treated 63 /// as unconditional jumps. 64 void fixCFGForPIC(BinaryFunction &Function) const; 65 66 /// Fix the CFG to take into consideration real internal calls (whole 67 /// functions that got inlined inside its caller, but the CALL instruction 68 /// wasn't removed). 69 bool fixCFGForIC(BinaryFunction &Function) const; 70 71 /// Detect tail calls in the range of the PIC access and fail to validate if 72 /// one is detected. Tail calls are dangerous because they may be emitted 73 /// with a different size in comparison with the original code. 74 /// FIXME: shortenInstructions and NOP sizes can impact offsets too 75 bool hasTailCallsInRange(BinaryFunction &Function) const; 76 77 /// Check that the PIC computations performed by Type 1 internal calls are 78 /// safe 79 bool analyzeFunction(BinaryFunction &Function) const; 80 81 /// The annotation tag we use to keep track of internal calls we already 82 /// processed. getProcessedICTag()83 StringRef getProcessedICTag() const { return "ProcessedInternalCall"; } 84 clearAnnotations(BinaryFunction & Function)85 void clearAnnotations(BinaryFunction &Function) const { 86 const BinaryContext &BC = Function.getBinaryContext(); 87 for (BinaryBasicBlock &BB : Function) 88 for (MCInst &Inst : BB) 89 BC.MIB->removeAnnotation(Inst, getProcessedICTag()); 90 } 91 }; 92 93 } // namespace bolt 94 } // namespace llvm 95 96 #endif 97