mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
Purge instructions to save return address
This commit is contained in:
@@ -5,10 +5,13 @@
|
||||
//
|
||||
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/ModRef.h"
|
||||
#include "llvm/Transforms/Utils/CodeExtractor.h"
|
||||
|
||||
#include "revng/EarlyFunctionAnalysis/FunctionSummaryOracle.h"
|
||||
#include "revng/EarlyFunctionAnalysis/TemporaryOpaqueFunction.h"
|
||||
#include "revng/Model/NamedTypedRegister.h"
|
||||
#include "revng/Support/OpaqueFunctionsPool.h"
|
||||
#include "revng/Support/UniqueValuePtr.h"
|
||||
|
||||
class GeneratedCodeBasicInfo;
|
||||
@@ -83,6 +86,8 @@ private:
|
||||
/// `unexpectedpc` of their caller.
|
||||
TemporaryOpaqueFunction UnexpectedPCMarker;
|
||||
|
||||
OpaqueFunctionsPool<llvm::Type *> OpaqueReturnAddress;
|
||||
|
||||
llvm::CodeExtractorAnalysisCache CEAC;
|
||||
|
||||
public:
|
||||
@@ -93,7 +98,18 @@ public:
|
||||
GCBI(GCBI),
|
||||
Oracle(Oracle),
|
||||
UnexpectedPCMarker(initializeUnexpectedPCMarker(M)),
|
||||
CEAC(*M.getFunction("root")) {}
|
||||
OpaqueReturnAddress(&M, false),
|
||||
CEAC(*M.getFunction("root")) {
|
||||
|
||||
using namespace llvm;
|
||||
auto Effects = MemoryEffects::inaccessibleMemOnly(llvm::ModRefInfo::Ref);
|
||||
OpaqueReturnAddress.setMemoryEffects(Effects);
|
||||
OpaqueReturnAddress.addFnAttribute(Attribute::NoUnwind);
|
||||
OpaqueReturnAddress.addFnAttribute(Attribute::WillReturn);
|
||||
OpaqueReturnAddress.setTags({ &FunctionTags::OpaqueReturnAddressFunction });
|
||||
OpaqueReturnAddress
|
||||
.initializeFromReturnType(FunctionTags::OpaqueReturnAddressFunction);
|
||||
}
|
||||
|
||||
public:
|
||||
OutlinedFunction outline(llvm::BasicBlock *BB, CallHandler *TheCallHandler);
|
||||
|
||||
@@ -204,6 +204,7 @@ inline Tag DynamicFunction("dynamic-function");
|
||||
inline Tag ClobbererFunction("clobberer-function");
|
||||
inline Tag WriterFunction("writer-function");
|
||||
inline Tag ReaderFunction("reader-function");
|
||||
inline Tag OpaqueReturnAddressFunction("opaque-return-address");
|
||||
|
||||
inline Tag CSV("csv");
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
//
|
||||
|
||||
#include "llvm/ADT/SCCIterator.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/ScopedPrinter.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
#include "llvm/Transforms/Utils/CodeExtractor.h"
|
||||
@@ -15,6 +18,7 @@
|
||||
#include "revng/EarlyFunctionAnalysis/CallHandler.h"
|
||||
#include "revng/EarlyFunctionAnalysis/Outliner.h"
|
||||
#include "revng/Model/IRHelpers.h"
|
||||
#include "revng/Support/OpaqueRegisterUser.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@@ -187,6 +191,39 @@ void Outliner::integrateFunctionCallee(CallHandler *TheCallHandler,
|
||||
} else {
|
||||
Instruction *Term = BB->getTerminator();
|
||||
IRBuilder<> Builder(Term);
|
||||
|
||||
if (FunctionCall != nullptr) {
|
||||
// This is a proper call, storing the return address somewhere: inject a
|
||||
// store clobbering the return address. This will make the instruction
|
||||
// saving the return address dead, the optimizer will collect it and then
|
||||
// we'll drop this store too, resulting in an IR free of return addresses
|
||||
// being written around.
|
||||
Value *LinkRegister = FunctionCall->getArgOperand(3);
|
||||
Value *Pointer = nullptr;
|
||||
Type *PointeeType = nullptr;
|
||||
|
||||
// Are we using the link register or storing the return address on the top
|
||||
// of the stack?
|
||||
if (auto *CSV = dyn_cast_or_null<GlobalVariable>(LinkRegister)) {
|
||||
Pointer = CSV;
|
||||
PointeeType = CSV->getValueType();
|
||||
} else {
|
||||
PointeeType = GCBI.spReg()->getValueType();
|
||||
Pointer = Builder.CreateIntToPtr(createLoad(Builder, GCBI.spReg()),
|
||||
PointeeType->getPointerTo());
|
||||
}
|
||||
|
||||
// Inject the store
|
||||
std::string Name = ("opaque_"
|
||||
+ to_string(PointeeType->getIntegerBitWidth()));
|
||||
auto *OpaqueReturnAddressFunction = OpaqueReturnAddress.get(PointeeType,
|
||||
PointeeType,
|
||||
{},
|
||||
Name);
|
||||
Builder.CreateStore(Builder.CreateCall(OpaqueReturnAddressFunction),
|
||||
Pointer);
|
||||
}
|
||||
|
||||
TheCallHandler->handleCall(CallerBlockAddress,
|
||||
Builder,
|
||||
Callee,
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#
|
||||
|
||||
revng_add_library_internal(
|
||||
revngFunctionCallIdentification STATIC FunctionCallIdentification.cpp
|
||||
PruneRetSuccessors.cpp)
|
||||
revngFunctionCallIdentification SHARED DropOpaqueReturnAddress.cpp
|
||||
FunctionCallIdentification.cpp PruneRetSuccessors.cpp)
|
||||
|
||||
target_link_libraries(revngFunctionCallIdentification revngSupport
|
||||
revngBasicAnalyses)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
|
||||
#include "revng/Support/FunctionTags.h"
|
||||
#include "revng/Support/IRHelpers.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
class DropOpaqueReturnAddress : public ModulePass {
|
||||
public:
|
||||
static char ID;
|
||||
DropOpaqueReturnAddress() : ModulePass(ID) {}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {}
|
||||
|
||||
bool runOnModule(Module &M) override {
|
||||
SmallVector<llvm::Function *, 16> FunctionsToPurge;
|
||||
|
||||
auto &OpaqueReturnAddress = FunctionTags::OpaqueReturnAddressFunction;
|
||||
SmallVector<Function *, 16> Functions;
|
||||
for (Function &F : OpaqueReturnAddress.functions(&M))
|
||||
Functions.push_back(&F);
|
||||
|
||||
for (Function *F : Functions) {
|
||||
auto *Undef = UndefValue::get(F->getReturnType());
|
||||
|
||||
SmallVector<CallBase *, 16> Callers;
|
||||
llvm::copy(callers(F), std::back_inserter(Callers));
|
||||
|
||||
for (CallBase *Caller : Callers)
|
||||
Caller->replaceAllUsesWith(Undef);
|
||||
|
||||
for (CallBase *Caller : Callers)
|
||||
eraseFromParent(Caller);
|
||||
|
||||
eraseFromParent(F);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
char DropOpaqueReturnAddress::ID;
|
||||
|
||||
using Register = RegisterPass<DropOpaqueReturnAddress>;
|
||||
static Register R("drop-opaque-return-address", "", false, false);
|
||||
@@ -171,6 +171,9 @@ Branches:
|
||||
UsedContainers: [module.ll]
|
||||
Passes: [O2]
|
||||
EnabledWhen: [O2]
|
||||
- Type: llvm-pipe
|
||||
UsedContainers: [module.ll]
|
||||
Passes: [drop-opaque-return-address]
|
||||
- Type: compile
|
||||
UsedContainers: [module.ll, object.o]
|
||||
- Type: link-for-translation
|
||||
@@ -189,6 +192,9 @@ Branches:
|
||||
UsedContainers: [module.ll]
|
||||
Passes: [O2]
|
||||
EnabledWhen: [O2]
|
||||
- Type: llvm-pipe
|
||||
UsedContainers: [module.ll]
|
||||
Passes: [drop-opaque-return-address]
|
||||
- Type: compile-isolated
|
||||
UsedContainers: [module.ll, object.o]
|
||||
- Type: link-for-translation
|
||||
|
||||
Reference in New Issue
Block a user