mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
28a0fa5b7d
This commit switches the approach with which we run the ABI analyses: we now run them until we reach a fixed point. This enables proper interprocedural propagation of arguments and return values. Basically, we now inject reads before call sites, so that, if a function immediately calls another one, the arguments of the callee are propagated to the caller. This commit also updates the logic with which we propagate function prototypes (and names) to callers. The main advantage of this, is that function wrappers (in particular, PLT entries) now have the same name as the function they wrap.
139 lines
4.3 KiB
C++
139 lines
4.3 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "revng/EarlyFunctionAnalysis/CallHandler.h"
|
|
#include "revng/EarlyFunctionAnalysis/Outliner.h"
|
|
#include "revng/EarlyFunctionAnalysis/TemporaryOpaqueFunction.h"
|
|
#include "revng/Model/Binary.h"
|
|
#include "revng/Support/OpaqueFunctionsPool.h"
|
|
#include "revng/Support/OpaqueRegisterUser.h"
|
|
|
|
class GeneratedCodeBasicInfo;
|
|
class ProgramCounterHandler;
|
|
class FunctionSummaryOracle;
|
|
|
|
namespace llvm {
|
|
class Module;
|
|
class GlobalVariable;
|
|
class Function;
|
|
} // namespace llvm
|
|
|
|
namespace efa {
|
|
|
|
class CallSummarizer : public CallHandler {
|
|
private:
|
|
llvm::Module *M = nullptr;
|
|
llvm::Function *PreCallHook = nullptr;
|
|
llvm::Function *PostCallHook = nullptr;
|
|
llvm::Function *RetHook = nullptr;
|
|
llvm::GlobalVariable *SPCSV = nullptr;
|
|
llvm::SmallSet<MetaAddress, 4> *ReturnBlocks = nullptr;
|
|
OpaqueRegisterUser Clobberer;
|
|
|
|
public:
|
|
CallSummarizer(llvm::Module *M,
|
|
llvm::Function *PreCallHook,
|
|
llvm::Function *PostCallHook,
|
|
llvm::Function *RetHook,
|
|
llvm::GlobalVariable *SPCSV,
|
|
llvm::SmallSet<MetaAddress, 4> *ReturnBlocks);
|
|
|
|
public:
|
|
void handleCall(MetaAddress CallerBlock,
|
|
llvm::IRBuilder<> &Builder,
|
|
MetaAddress Callee,
|
|
const std::set<llvm::GlobalVariable *> &ClobberedRegisters,
|
|
const std::optional<int64_t> &MaybeFSO,
|
|
bool IsNoReturn,
|
|
bool IsTailCall,
|
|
llvm::Value *SymbolNamePointer) final;
|
|
|
|
void handlePostNoReturn(llvm::IRBuilder<> &Builder) final;
|
|
|
|
void
|
|
handleIndirectJump(llvm::IRBuilder<> &Builder,
|
|
MetaAddress Block,
|
|
const std::set<llvm::GlobalVariable *> &ClobberedRegisters,
|
|
llvm::Value *SymbolNamePointer) final;
|
|
};
|
|
|
|
/// This class, given an Oracle, analyzes a function returning its CFG, the set
|
|
/// of callee saved registers, whether it's noreturn or not and its final stack
|
|
/// offset
|
|
class CFGAnalyzer {
|
|
private:
|
|
llvm::Module &M;
|
|
GeneratedCodeBasicInfo &GCBI;
|
|
const ProgramCounterHandler *PCH;
|
|
const FunctionSummaryOracle &Oracle;
|
|
const TupleTree<model::Binary> &Binary;
|
|
|
|
llvm::SmallVector<llvm::GlobalVariable *, 16> ABICSVs;
|
|
|
|
/// PreCallHook and PostCallHook mark the presence of an original function
|
|
/// call, and surround a basic block containing the registers clobbered by the
|
|
/// function called. They take the MetaAddress of the callee and the
|
|
/// call-site.
|
|
TemporaryOpaqueFunction PreCallHook;
|
|
TemporaryOpaqueFunction PostCallHook;
|
|
TemporaryOpaqueFunction RetHook;
|
|
|
|
Outliner Outliner;
|
|
|
|
OpaqueFunctionsPool<llvm::Type *> OpaqueBranchConditionsPool;
|
|
std::unique_ptr<llvm::raw_ostream> OutputAAWriter;
|
|
std::unique_ptr<llvm::raw_ostream> OutputIBI;
|
|
|
|
public:
|
|
CFGAnalyzer(llvm::Module &M,
|
|
GeneratedCodeBasicInfo &GCBI,
|
|
const TupleTree<model::Binary> &Binary,
|
|
const FunctionSummaryOracle &Oracle);
|
|
|
|
public:
|
|
llvm::Function *preCallHook() const { return PreCallHook.get(); }
|
|
llvm::Function *postCallHook() const { return PostCallHook.get(); }
|
|
llvm::Function *retHook() const { return RetHook.get(); }
|
|
const auto &abiCSVs() const { return ABICSVs; }
|
|
|
|
public:
|
|
FunctionSummary analyze(llvm::BasicBlock *Entry);
|
|
|
|
OutlinedFunction outline(llvm::BasicBlock *Entry);
|
|
|
|
private:
|
|
static llvm::FunctionType *createCallMarkerType(llvm::Module &M);
|
|
static llvm::FunctionType *createRetMarkerType(llvm::Module &M);
|
|
|
|
private:
|
|
std::optional<UpcastablePointer<efa::FunctionEdgeBase>>
|
|
handleCall(llvm::CallInst *PreCallHookCall);
|
|
|
|
SortedVector<efa::BasicBlock> collectDirectCFG(OutlinedFunction *F);
|
|
|
|
void createIBIMarker(OutlinedFunction *F);
|
|
|
|
void opaqueBranchConditions(llvm::Function *F, llvm::IRBuilder<> &);
|
|
|
|
void materializePCValues(llvm::Function *F, llvm::IRBuilder<> &);
|
|
|
|
void runOptimizationPipeline(llvm::Function *F);
|
|
|
|
FunctionSummary milkInfo(OutlinedFunction *F,
|
|
SortedVector<efa::BasicBlock> &&CFG);
|
|
|
|
struct State {
|
|
llvm::Value *StackPointer;
|
|
llvm::Value *ReturnPC;
|
|
llvm::SmallVector<llvm::Value *, 16> CSVs;
|
|
};
|
|
State loadState(llvm::IRBuilder<> &Builder) const;
|
|
};
|
|
|
|
} // namespace efa
|