blob: 137b83b0179f49948d42a52223e1d533690148bd [file] [log] [blame]
//===- bolt/Passes/ValidateInternalCalls.h ----------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef BOLT_PASSES_VALIDATEINTERNALCALLS_H
#define BOLT_PASSES_VALIDATEINTERNALCALLS_H
#include "bolt/Passes/BinaryPasses.h"
namespace llvm {
namespace bolt {
/// Post-processing for internal calls. What are those? They are call
/// instructions that do not transfer control to another function, but
/// rather branch to a basic block inside the caller function itself.
/// This pass checks that the internal calls observed in a function are
/// manageable. We support two types:
///
/// 1. Position Independent Code (PIC) tricks: in this type of internal
/// call, we don't really have a call because the return address is
/// not utilized for branching to, but only as a base address to
/// reference other objects. We call it a "trick" because this is not
/// the standard way a compiler would do this and this will often come
/// from awkwardly written assembly code.
///
/// 2. Real internal calls: in this case, a function was inlined inside
/// a caller, but the CALL instruction wasn't removed. This pair of
/// caller-callee is treated as a single function and is analyzed
/// here.
///
/// In general, the rest of the BOLT pipeline (other optimizations, including
/// code reordering) will not support neither of these cases. In this pass,
/// we just identify them, verify they are safe (do not reference objects
/// that will be moved after reordering) and freeze these functions in the
/// way they were read. We do this by marking them as non-simple.
///
/// Why do we freeze them?
///
/// Type 1 is not safe to optimize because any changed offsets will break the
/// PIC references made in this code. Type 2 is not safe to optimize because
/// it requires BOLT to understand a new CFG format where internal calls are
/// broken into two BBs (calling block and returning block), and we currently do
/// not support this elsewhere. Only this pass is able to make sense of these
/// non-canonical CFGs (specifically, fixBranches does not support them).
///
class ValidateInternalCalls : public BinaryFunctionPass {
public:
explicit ValidateInternalCalls(const cl::opt<bool> &PrintPass)
: BinaryFunctionPass(PrintPass) {}
const char *getName() const override { return "validate-internal-calls"; }
void runOnFunctions(BinaryContext &BC) override;
private:
/// Fix the CFG to take into consideration internal calls that do not
/// return, but are only used as a trick to perform Position Independent
/// Code (PIC) computations. This will change internal calls to be treated
/// as unconditional jumps.
void fixCFGForPIC(BinaryFunction &Function) const;
/// Fix the CFG to take into consideration real internal calls (whole
/// functions that got inlined inside its caller, but the CALL instruction
/// wasn't removed).
bool fixCFGForIC(BinaryFunction &Function) const;
/// Detect tail calls in the range of the PIC access and fail to validate if
/// one is detected. Tail calls are dangerous because they may be emitted
/// with a different size in comparison with the original code.
/// FIXME: shortenInstructions and NOP sizes can impact offsets too
bool hasTailCallsInRange(BinaryFunction &Function) const;
/// Check that the PIC computations performed by Type 1 internal calls are
/// safe
bool analyzeFunction(BinaryFunction &Function) const;
/// The annotation tag we use to keep track of internal calls we already
/// processed.
StringRef getProcessedICTag() const { return "ProcessedInternalCall"; }
void clearAnnotations(BinaryFunction &Function) const {
const BinaryContext &BC = Function.getBinaryContext();
for (BinaryBasicBlock &BB : Function)
for (MCInst &Inst : BB)
BC.MIB->removeAnnotation(Inst, getProcessedICTag());
}
};
} // namespace bolt
} // namespace llvm
#endif