Purge instructions to save return address

This commit is contained in:
Alessandro Di Federico
2024-04-19 17:50:02 +02:00
parent f777eaf00f
commit 452036edf1
6 changed files with 116 additions and 3 deletions
+17 -1
View File
@@ -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);
+1
View File
@@ -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");
+37
View File
@@ -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