Skip to content

Commit

Permalink
Reg localization (#661)
Browse files Browse the repository at this point in the history
* bin2llvmir: add register localization pass

* bin2llvmir/value_protect: better protectRegisters() implementation.

* bin2llvmir: implement register localization.

* scripts/retdec-config.py: remove some LLVM passes.

* CHANGELOG.md: fix #652, add entry for #652.
  • Loading branch information
PeterMatula authored Sep 24, 2019
1 parent dee7018 commit 5659ad0
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 38 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* Enhancement: Updated OpenSSL to version 1.1.1c ([#601](https://github.com/avast/retdec/pull/601)). This fixes build of OpenSSL on macOS Mojave ([#439](https://github.com/avast/retdec/issues/439)).
* Enhancement: Added support for relocations that pair multiple `R_MIPS_LO16` against a single `R_MIPS_HI16` ([#627](https://github.com/avast/retdec/issues/627), [#628](https://github.com/avast/retdec/pull/628)).
* Enhancement: Added handling of all x86 FPU instructions in assembly to LLVM IR translation ([#394](https://github.com/avast/retdec/issues/394), [#643](https://github.com/avast/retdec/pull/643)).
* Enhancement: All registers are localized - i.e. transformed from global variables to local variables ([#652](https://github.com/avast/retdec/issues/652)). This significantly (20% on average) speeds up the decompilation process and greatly reduces noise in output.
* Fix: Fixed build on BSD systems ([#598](https://github.com/avast/retdec/pull/598)).
* Fix: Resources which are located in the different section than resource tree are now properly parsed ([#596](https://github.com/avast/retdec/pull/596)).
* Fix: Version information which contained strings shorter than reported are now properly parsed ([#596](https://github.com/avast/retdec/pull/596)).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @file include/retdec/bin2llvmir/optimizations/register_localization/register_localization.h
* @brief Make all registers local.
* @copyright (c) 2019 Avast Software, licensed under the MIT license
*/

#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_REGISTER_LOCALIZATION_REGISTER_LOCALIZATION_H
#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_REGISTER_LOCALIZATION_REGISTER_LOCALIZATION_H

#include <llvm/IR/Function.h>
#include <llvm/IR/Module.h>
#include <llvm/Pass.h>

#include "retdec/bin2llvmir/providers/abi/abi.h"
#include "retdec/bin2llvmir/providers/config.h"

namespace retdec {
namespace bin2llvmir {

class RegisterLocalization : public llvm::ModulePass
{
public:
static char ID;
RegisterLocalization();
virtual bool runOnModule(llvm::Module& M) override;
bool runOnModuleCustom(llvm::Module& M, Abi* a, Config* c);

private:
bool run();
llvm::AllocaInst* getLocalized(
llvm::GlobalVariable* reg,
llvm::Function* fnc,
std::map<llvm::Function*, llvm::AllocaInst*>& fnc2alloca);
bool localize(
llvm::GlobalVariable* reg,
std::map<llvm::Function*, llvm::AllocaInst*>& fnc2alloca,
llvm::Instruction* insn);

private:
llvm::Module* _module = nullptr;
Abi* _abi = nullptr;
Config* _config = nullptr;
static std::map<llvm::Type*, llvm::Function*> _type2fnc;
};

} // namespace bin2llvmir
} // namespace retdec

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class ValueProtect : public llvm::ModulePass
bool run();
bool protect();
bool protectStack();
bool protectRegisters();
bool protectRegisters(bool skipCalledFunctions = true);
bool protectLoadStores();
bool unprotect();

Expand Down
20 changes: 1 addition & 19 deletions scripts/retdec-config.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,15 @@
BIN2LLVMIR_LLVM_PASSES_ONLY = [
'-instcombine',
'-tbaa',
'-targetlibinfo',
'-basicaa',
'-domtree',
'-simplifycfg',
'-domtree',
'-early-cse',
'-lower-expect',
'-targetlibinfo',
'-tbaa',
'-basicaa',
'-globalopt',
'-mem2reg',
'-instcombine',
'-simplifycfg',
'-basiccg',
'-domtree',
'-early-cse',
'-lazy-value-info',
'-jump-threading',
Expand All @@ -74,15 +67,13 @@
'-instcombine',
'-simplifycfg',
'-reassociate',
'-domtree',
'-loops',
'-loop-simplify',
'-lcssa',
'-loop-rotate',
'-licm',
'-lcssa',
'-instcombine',
'-scalar-evolution',
'-loop-simplifycfg',
'-loop-simplify',
'-aa',
Expand All @@ -92,29 +83,21 @@
'-indvars',
'-loop-idiom',
'-loop-deletion',
'-memdep',
'-gvn',
'-memdep',
'-sccp',
'-instcombine',
'-lazy-value-info',
'-jump-threading',
'-correlated-propagation',
'-domtree',
'-memdep',
'-dse',
'-dce',
'-bdce',
'-adce',
'-die',
'-simplifycfg',
'-instcombine',
'-strip-dead-prototypes',
'-globaldce',
'-constmerge',
'-constprop',
'-instnamer',
'-domtree',
'-instcombine',
]

Expand All @@ -141,14 +124,13 @@
'-unreachable-funcs',
'-inst-opt',
'-x86-addr-spaces',
'-register-localization',
'-value-protect',
] + BIN2LLVMIR_LLVM_PASSES_ONLY + BIN2LLVMIR_LLVM_PASSES_ONLY + [
'-inst-opt',
'-simple-types',
'-stack-ptr-op-remove',
'-idioms',
'-global-to-local',
'-dead-global-assign',
'-instcombine',
'-inst-opt',
'-idioms',
Expand Down
1 change: 1 addition & 0 deletions src/bin2llvmir/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ set(BIN2LLVMIR_SOURCES
optimizations/param_return/data_entries.cpp
optimizations/phi2seq/phi2seq.cpp
optimizations/provider_init/provider_init.cpp
optimizations/register_localization/register_localization.cpp
optimizations/x86_addr_spaces/x86_addr_spaces_pass.cpp
optimizations/x86_addr_spaces/x86_addr_spaces.cpp
optimizations/x87_fpu/x87_fpu.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/**
* @file src/bin2llvmir/optimizations/register_localization/register_localization.cpp
* @brief Make all registers local.
* @copyright (c) 2019 Avast Software, licensed under the MIT license
*/

#include <cassert>

#include <llvm/IR/Instruction.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/InstIterator.h>

#include "retdec/bin2llvmir/optimizations/register_localization/register_localization.h"
#include "retdec/bin2llvmir/providers/names.h"
#include "retdec/bin2llvmir/utils/debug.h"
#include "retdec/bin2llvmir/utils/ir_modifier.h"
#include "retdec/bin2llvmir/utils/llvm.h"

using namespace retdec::utils;
using namespace llvm;

namespace retdec {
namespace bin2llvmir {

char RegisterLocalization::ID = 0;

std::map<llvm::Type*, llvm::Function*> RegisterLocalization::_type2fnc;

static RegisterPass<RegisterLocalization> X(
"register-localization",
"Make all registers local",
false, // Only looks at CFG
false // Analysis Pass
);

RegisterLocalization::RegisterLocalization() :
ModulePass(ID)
{

}

bool RegisterLocalization::runOnModule(Module& M)
{
_module = &M;
_abi = AbiProvider::getAbi(_module);
_config = ConfigProvider::getConfig(_module);
return run();
}

bool RegisterLocalization::runOnModuleCustom(llvm::Module& M, Abi* a, Config* c)
{
_module = &M;
_abi = a;
_config = c;
return run();
}

/**
* @return @c True if module @a _module was modified in any way,
* @c false otherwise.
*/
bool RegisterLocalization::run()
{
if (_abi == nullptr || _config == nullptr)
{
return false;
}
const auto& regs = _abi->getRegisters();

bool changed = false;

for (GlobalVariable* reg : regs)
{
std::map<Function*, AllocaInst*> fnc2alloca;

for (auto uIt = reg->user_begin(); uIt != reg->user_end(); )
{
User* user = *uIt;
++uIt;

if (auto* insn = dyn_cast<Instruction>(user))
{
changed = localize(reg, fnc2alloca, insn);
}
else if (auto* expr = dyn_cast<ConstantExpr>(user))
{
for (auto euIt = expr->user_begin(); euIt != expr->user_end(); )
{
User* euser = *euIt;
++euIt;

if (auto* insn = dyn_cast<Instruction>(euser))
{
auto* einsn = expr->getAsInstruction();
einsn->insertBefore(insn);

if (localize(reg, fnc2alloca, einsn))
{
insn->replaceUsesOfWith(expr, einsn);
changed = true;
}
}
}
}
}
}

return changed;
}

llvm::AllocaInst* RegisterLocalization::getLocalized(
llvm::GlobalVariable* reg,
llvm::Function* fnc,
std::map<llvm::Function*, llvm::AllocaInst*>& fnc2alloca)
{
auto fIt = fnc2alloca.find(fnc);
if (fIt != fnc2alloca.end())
{
return fIt->second;
}
else if (!fnc->empty() && !fnc->front().empty())
{
auto* a = new AllocaInst(
reg->getValueType(),
reg->getAddressSpace(),
nullptr,
reg->getName(),
&fnc->front().front());
fnc2alloca.emplace(fnc, a);
return a;
}
else
{
// Should not really happen.
return nullptr;
}
}

bool RegisterLocalization::localize(
llvm::GlobalVariable* reg,
std::map<llvm::Function*, llvm::AllocaInst*>& fnc2alloca,
llvm::Instruction* insn)
{
AllocaInst* localized = getLocalized(
reg,
insn->getFunction(),
fnc2alloca);

if (localized == nullptr)
{
return false;
}

insn->replaceUsesOfWith(reg, localized);
return true;
}

} // namespace bin2llvmir
} // namespace retdec
Loading

0 comments on commit 5659ad0

Please sign in to comment.