From eed349c8f2e21630140e9bdd3f225059ff44e296 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 16 Aug 2018 12:56:24 +0200 Subject: [PATCH 001/159] decoder: fix condition --- src/bin2llvmir/optimizations/decoder/decoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin2llvmir/optimizations/decoder/decoder.cpp b/src/bin2llvmir/optimizations/decoder/decoder.cpp index f24293855..e892048d0 100644 --- a/src/bin2llvmir/optimizations/decoder/decoder.cpp +++ b/src/bin2llvmir/optimizations/decoder/decoder.cpp @@ -781,8 +781,8 @@ bool Decoder::getJumpTargetsFromInstruction( SymbolicTree st(_RDA, l->getPointerOperand(), nullptr, 8); st.simplifyNode(); - ConstantInt* ci = nullptr; - if (match(st, m_ConstantInt(ci))) + auto* ci = dyn_cast(st.value); + if (ci && !ci->isNegative()) { Address t(ci->getZExtValue()); auto sz = _abi->getTypeByteSize(l->getType()); From 47b3b0dfe7085378355cdeb80461cd7b9267e644 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 12 Jul 2018 17:29:54 +0200 Subject: [PATCH 002/159] llvmir_tests: clean abi Test cases share same module so it means that by not cleaning AbiProvider two test cases maight obtain same abi which can lead to failure of test. --- tests/bin2llvmir/utils/llvmir_tests.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/bin2llvmir/utils/llvmir_tests.h b/tests/bin2llvmir/utils/llvmir_tests.h index 9f58965bf..00fce3a33 100644 --- a/tests/bin2llvmir/utils/llvmir_tests.h +++ b/tests/bin2llvmir/utils/llvmir_tests.h @@ -53,6 +53,7 @@ class LlvmIrTests : public ::testing::Test */ void clearAllStaticData() { + AbiProvider::clear(); ConfigProvider::clear(); DebugFormatProvider::clear(); DemanglerProvider::clear(); From 1b8559d4799eaf80c02165d8df308e9d4d16ff9f Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 14:21:05 +0200 Subject: [PATCH 003/159] abi: make method const --- include/retdec/bin2llvmir/providers/abi/abi.h | 8 ++++---- src/bin2llvmir/providers/abi/abi.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 8e0bc2e81..5a080aa24 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -39,15 +39,15 @@ class Abi // Registers. // public: - bool isRegister(const llvm::Value* val); - bool isRegister(const llvm::Value* val, uint32_t r); + bool isRegister(const llvm::Value* val) const; + bool isRegister(const llvm::Value* val, uint32_t r) const; bool isFlagRegister(const llvm::Value* val); bool isStackPointerRegister(const llvm::Value* val); bool isZeroRegister(const llvm::Value* val); virtual bool isGeneralPurposeRegister(const llvm::Value* val) = 0; - llvm::GlobalVariable* getRegister(uint32_t r, bool use = true); - uint32_t getRegisterId(const llvm::Value* r); + llvm::GlobalVariable* getRegister(uint32_t r, bool use = true) const; + uint32_t getRegisterId(const llvm::Value* r) const; const std::vector& getRegisters() const; llvm::GlobalVariable* getStackPointerRegister(); llvm::GlobalVariable* getZeroRegister(); diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index e27d69fe7..99c26c8af 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -36,12 +36,12 @@ Abi::~Abi() } -bool Abi::isRegister(const llvm::Value* val) +bool Abi::isRegister(const llvm::Value* val) const { return _regs2id.count(val); } -bool Abi::isRegister(const llvm::Value* val, uint32_t r) +bool Abi::isRegister(const llvm::Value* val, uint32_t r) const { return getRegister(r) == val; } @@ -70,7 +70,7 @@ bool Abi::isZeroRegister(const llvm::Value* val) * This solves the problem with overlapping IDs when used like this: * Abi::getRegister(MIPS_REG_GP, Abi::isMips()) */ -llvm::GlobalVariable* Abi::getRegister(uint32_t r, bool use) +llvm::GlobalVariable* Abi::getRegister(uint32_t r, bool use) const { if (!use) { @@ -80,7 +80,7 @@ llvm::GlobalVariable* Abi::getRegister(uint32_t r, bool use) return _id2regs[r]; } -uint32_t Abi::getRegisterId(const llvm::Value* r) +uint32_t Abi::getRegisterId(const llvm::Value* r) const { auto it = _regs2id.find(r); return it != _regs2id.end() ? it->second : Abi::REG_INVALID; From bea9c7c6a0bcac4383b952c90a532f25439f4e15 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 14:24:59 +0200 Subject: [PATCH 004/159] abi: value can be parameter --- include/retdec/bin2llvmir/providers/abi/abi.h | 9 ++++++ src/bin2llvmir/providers/abi/abi.cpp | 13 +++++++++ src/bin2llvmir/providers/abi/arm.cpp | 6 ++++ src/bin2llvmir/providers/abi/mips.cpp | 29 +++++++++++++++++++ src/bin2llvmir/providers/abi/powerpc.cpp | 11 +++++++ 5 files changed, 68 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 5a080aa24..bc4d80398 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -58,6 +58,11 @@ class Abi llvm::GlobalVariable* getSyscallReturnRegister(); llvm::GlobalVariable* getSyscallArgumentRegister(unsigned n); + + // Values. + public: + bool valueCanBeParameter(const llvm::Value* val) const; + // Instructions. // public: @@ -116,6 +121,10 @@ class Abi uint32_t _regSyscallId = REG_INVALID; /// Register that is always equal to zero - not every arch have this. uint32_t _regZeroReg = REG_INVALID; + /// Registers that can be used as parameter according to abi. + std::vector _paramRegs {}; + /// Floating Point registers that can be used as parameter according to abi. + std::vector _paramFPRegs {}; }; class AbiProvider diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 99c26c8af..63cf87b50 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -197,6 +197,19 @@ bool Abi::isPowerPC() const return _config->getConfig().architecture.isPpc(); } +bool Abi::valueCanBeParameter(const llvm::Value *val) const +{ + if (_config->isStackVariable(val)) + { + return true; + } + + bool isParamReg = find(_paramRegs.begin(), _paramRegs.end(), getRegisterId(val)) != _paramRegs.end(); + bool isFpParamReg = find(_paramFPRegs.begin(), _paramFPRegs.end(), getRegisterId(val)) != _paramFPRegs.end(); + + return isParamReg || isFpParamReg; +} + // //============================================================================== // AbiProvider diff --git a/src/bin2llvmir/providers/abi/arm.cpp b/src/bin2llvmir/providers/abi/arm.cpp index 70d3284a3..383e56269 100644 --- a/src/bin2llvmir/providers/abi/arm.cpp +++ b/src/bin2llvmir/providers/abi/arm.cpp @@ -28,6 +28,12 @@ AbiArm::AbiArm(llvm::Module* m, Config* c) : ARM_REG_R3, ARM_REG_R4, ARM_REG_R5}; + + _paramRegs = { + ARM_REG_R0, + ARM_REG_R1, + ARM_REG_R2, + ARM_REG_R3}; } AbiArm::~AbiArm() diff --git a/src/bin2llvmir/providers/abi/mips.cpp b/src/bin2llvmir/providers/abi/mips.cpp index bd2abc5b0..29bfbdb7a 100644 --- a/src/bin2llvmir/providers/abi/mips.cpp +++ b/src/bin2llvmir/providers/abi/mips.cpp @@ -27,6 +27,35 @@ AbiMips::AbiMips(llvm::Module* m, Config* c) : MIPS_REG_A1, MIPS_REG_A2, MIPS_REG_A3}; + + if (_config->getConfig().tools.isPspGcc()) + { + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3, + MIPS_REG_T0, + MIPS_REG_T1, + MIPS_REG_T2, + MIPS_REG_T3}; + } + else + { + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3}; + } + + _paramFPRegs = { + MIPS_REG_F12, + MIPS_REG_F14, + MIPS_REG_F16, + MIPS_REG_F18 + }; + } AbiMips::~AbiMips() diff --git a/src/bin2llvmir/providers/abi/powerpc.cpp b/src/bin2llvmir/providers/abi/powerpc.cpp index 92cbae6d8..3b66cf5c6 100644 --- a/src/bin2llvmir/providers/abi/powerpc.cpp +++ b/src/bin2llvmir/providers/abi/powerpc.cpp @@ -17,6 +17,17 @@ AbiPowerpc::AbiPowerpc(llvm::Module* m, Config* c) : _regs.reserve(PPC_REG_ENDING); _id2regs.resize(PPC_REG_ENDING, nullptr); _regStackPointerId = PPC_REG_R1; + + _paramRegs = { + PPC_REG_R3, + PPC_REG_R4, + PPC_REG_R5, + PPC_REG_R6, + PPC_REG_R7, + PPC_REG_R8, + PPC_REG_R9, + PPC_REG_R10}; + } AbiPowerpc::~AbiPowerpc() From 88b929356d852bba9b493723f892aba82fa8fbb7 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 14:27:23 +0200 Subject: [PATCH 005/159] abi: provide method parameterRegisters() --- include/retdec/bin2llvmir/providers/abi/abi.h | 1 + src/bin2llvmir/providers/abi/abi.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index bc4d80398..afb592364 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -41,6 +41,7 @@ class Abi public: bool isRegister(const llvm::Value* val) const; bool isRegister(const llvm::Value* val, uint32_t r) const; + std::vector parameterRegisters() const; bool isFlagRegister(const llvm::Value* val); bool isStackPointerRegister(const llvm::Value* val); bool isZeroRegister(const llvm::Value* val); diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 63cf87b50..7f1e87539 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -210,6 +210,11 @@ bool Abi::valueCanBeParameter(const llvm::Value *val) const return isParamReg || isFpParamReg; } +std::vector Abi::parameterRegisters() const +{ + return _paramRegs; +} + // //============================================================================== // AbiProvider From 3ef60025bc1ae369c23e76b12d94753f728c1d35 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 14:28:52 +0200 Subject: [PATCH 006/159] abi: provide return info --- include/retdec/bin2llvmir/providers/abi/abi.h | 9 +++++++++ src/bin2llvmir/providers/abi/abi.cpp | 15 +++++++++++++++ src/bin2llvmir/providers/abi/arm.cpp | 3 +++ src/bin2llvmir/providers/abi/mips.cpp | 3 +++ src/bin2llvmir/providers/abi/powerpc.cpp | 2 ++ src/bin2llvmir/providers/abi/x86.cpp | 3 +++ 6 files changed, 35 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index afb592364..63c181a00 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -63,6 +63,7 @@ class Abi // Values. public: bool valueCanBeParameter(const llvm::Value* val) const; + virtual bool canHoldReturnValue(const llvm::Value* val) const; // Instructions. // @@ -122,10 +123,18 @@ class Abi uint32_t _regSyscallId = REG_INVALID; /// Register that is always equal to zero - not every arch have this. uint32_t _regZeroReg = REG_INVALID; + /// Register used for returning values from functions. + uint32_t _regReturn = REG_INVALID; + /// Register used for returning floating point values from functions. + uint32_t _regFPReturn = REG_INVALID; /// Registers that can be used as parameter according to abi. std::vector _paramRegs {}; /// Floating Point registers that can be used as parameter according to abi. std::vector _paramFPRegs {}; + + /// Specifies if abi returns value on stack. + bool returnsOnStack = false; + }; class AbiProvider diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 7f1e87539..6f9bf18f6 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -215,6 +215,21 @@ std::vector Abi::parameterRegisters() const return _paramRegs; } +bool Abi::canHoldReturnValue(const llvm::Value* val) const +{ + if (returnsOnStack) + { + return _config->isStackVariable(val); + } + + if (!_config->isRegister(val)) + { + return false; + } + + return getRegisterId(val) == _regReturn || getRegisterId(val) == _regFPReturn; +} + // //============================================================================== // AbiProvider diff --git a/src/bin2llvmir/providers/abi/arm.cpp b/src/bin2llvmir/providers/abi/arm.cpp index 383e56269..2a95c25bb 100644 --- a/src/bin2llvmir/providers/abi/arm.cpp +++ b/src/bin2llvmir/providers/abi/arm.cpp @@ -29,6 +29,9 @@ AbiArm::AbiArm(llvm::Module* m, Config* c) : ARM_REG_R4, ARM_REG_R5}; + _regReturn = ARM_REG_R0; + _regFPReturn = ARM_REG_R0; + _paramRegs = { ARM_REG_R0, ARM_REG_R1, diff --git a/src/bin2llvmir/providers/abi/mips.cpp b/src/bin2llvmir/providers/abi/mips.cpp index 29bfbdb7a..37054ce26 100644 --- a/src/bin2llvmir/providers/abi/mips.cpp +++ b/src/bin2llvmir/providers/abi/mips.cpp @@ -28,6 +28,9 @@ AbiMips::AbiMips(llvm::Module* m, Config* c) : MIPS_REG_A2, MIPS_REG_A3}; + _regReturn = MIPS_REG_V0; + _regFPReturn = MIPS_REG_V0; + if (_config->getConfig().tools.isPspGcc()) { _paramRegs = { diff --git a/src/bin2llvmir/providers/abi/powerpc.cpp b/src/bin2llvmir/providers/abi/powerpc.cpp index 3b66cf5c6..3cdaa6bb4 100644 --- a/src/bin2llvmir/providers/abi/powerpc.cpp +++ b/src/bin2llvmir/providers/abi/powerpc.cpp @@ -28,6 +28,8 @@ AbiPowerpc::AbiPowerpc(llvm::Module* m, Config* c) : PPC_REG_R9, PPC_REG_R10}; + _regReturn = PPC_REG_R3; + _regFPReturn = PPC_REG_R3; } AbiPowerpc::~AbiPowerpc() diff --git a/src/bin2llvmir/providers/abi/x86.cpp b/src/bin2llvmir/providers/abi/x86.cpp index d1dde441a..913d4ab90 100644 --- a/src/bin2llvmir/providers/abi/x86.cpp +++ b/src/bin2llvmir/providers/abi/x86.cpp @@ -28,6 +28,9 @@ AbiX86::AbiX86(llvm::Module* m, Config* c) : X86_REG_ESI, X86_REG_EDI, X86_REG_EBP}; + + _regReturn = X86_REG_EAX; + _regFPReturn = X86_REG_ST0; } AbiX86::~AbiX86() From b41862e96ed5bcd7ae64dbf4d0cf2011e2568e90 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 14:30:02 +0200 Subject: [PATCH 007/159] abi: provide value of return register --- include/retdec/bin2llvmir/providers/abi/abi.h | 2 ++ src/bin2llvmir/providers/abi/abi.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 63c181a00..e6b15c1b6 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -59,6 +59,8 @@ class Abi llvm::GlobalVariable* getSyscallReturnRegister(); llvm::GlobalVariable* getSyscallArgumentRegister(unsigned n); + llvm::GlobalVariable* getReturnRegister() const; + llvm::GlobalVariable* getFPReturnRegister() const; // Values. public: diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 6f9bf18f6..fab134b80 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -127,6 +127,16 @@ llvm::GlobalVariable* Abi::getSyscallArgumentRegister(unsigned n) return n < _syscallRegs.size() ? getRegister(_syscallRegs[n]) : nullptr; } +llvm::GlobalVariable* Abi::getReturnRegister() const +{ + return getRegister(_regReturn); +} + +llvm::GlobalVariable* Abi::getFPReturnRegister() const +{ + return getRegister(_regFPReturn); +} + bool Abi::isNopInstruction(AsmInstruction ai) { return isNopInstruction(ai.getCapstoneInsn()); From 43efa158934a885b7a43824b15728693f46b279a Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 25 Jul 2018 15:16:26 +0200 Subject: [PATCH 008/159] abi: provide info about FPU parameter registers --- include/retdec/bin2llvmir/providers/abi/abi.h | 1 + src/bin2llvmir/providers/abi/abi.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index e6b15c1b6..67156be9a 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -42,6 +42,7 @@ class Abi bool isRegister(const llvm::Value* val) const; bool isRegister(const llvm::Value* val, uint32_t r) const; std::vector parameterRegisters() const; + std::vector parameterFPRegisters() const; bool isFlagRegister(const llvm::Value* val); bool isStackPointerRegister(const llvm::Value* val); bool isZeroRegister(const llvm::Value* val); diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index fab134b80..c6ef41089 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -225,6 +225,11 @@ std::vector Abi::parameterRegisters() const return _paramRegs; } +std::vector Abi::parameterFPRegisters() const +{ + return _paramFPRegs; +} + bool Abi::canHoldReturnValue(const llvm::Value* val) const { if (returnsOnStack) From 624dcb10dbf8ab035cc1a2fb00c0679314970018 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 25 Jul 2018 16:08:37 +0200 Subject: [PATCH 009/159] abi: provide special info about usage of FP registers --- include/retdec/bin2llvmir/providers/abi/abi.h | 3 +++ src/bin2llvmir/providers/abi/abi.cpp | 5 +++++ src/bin2llvmir/providers/abi/mips.cpp | 2 ++ 3 files changed, 10 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 67156be9a..5ddd2fdd9 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -63,6 +63,8 @@ class Abi llvm::GlobalVariable* getReturnRegister() const; llvm::GlobalVariable* getFPReturnRegister() const; + bool usesFPRegistersForParameters() const; + // Values. public: bool valueCanBeParameter(const llvm::Value* val) const; @@ -137,6 +139,7 @@ class Abi /// Specifies if abi returns value on stack. bool returnsOnStack = false; + bool _fpRegsAsParams = false; }; diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index c6ef41089..2abc24309 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -137,6 +137,11 @@ llvm::GlobalVariable* Abi::getFPReturnRegister() const return getRegister(_regFPReturn); } +bool Abi::usesFPRegistersForParameters() const +{ + return _fpRegsAsParams; +} + bool Abi::isNopInstruction(AsmInstruction ai) { return isNopInstruction(ai.getCapstoneInsn()); diff --git a/src/bin2llvmir/providers/abi/mips.cpp b/src/bin2llvmir/providers/abi/mips.cpp index 37054ce26..827f12225 100644 --- a/src/bin2llvmir/providers/abi/mips.cpp +++ b/src/bin2llvmir/providers/abi/mips.cpp @@ -19,6 +19,8 @@ AbiMips::AbiMips(llvm::Module* m, Config* c) : _regStackPointerId = MIPS_REG_SP; _regZeroReg = MIPS_REG_ZERO; + _fpRegsAsParams = true; + // system calls _regSyscallId = MIPS_REG_V0; _regSyscallReturn = MIPS_REG_V0; From fc19d346d03dfdfe961357878d4c12c8648f9ff6 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 13:55:37 +0200 Subject: [PATCH 010/159] abi: provide info about double registers Some architectures (for example MIPS) are modeled with special double registers that are created as merge of two FP registers. ABI must provide information about possible double register so that parameter analysis may use this information to find double parameters. --- include/retdec/bin2llvmir/providers/abi/abi.h | 2 ++ src/bin2llvmir/providers/abi/abi.cpp | 5 +++++ src/bin2llvmir/providers/abi/mips.cpp | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 5ddd2fdd9..c6aa174b4 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -43,6 +43,7 @@ class Abi bool isRegister(const llvm::Value* val, uint32_t r) const; std::vector parameterRegisters() const; std::vector parameterFPRegisters() const; + std::vector doubleParameterRegisters() const; bool isFlagRegister(const llvm::Value* val); bool isStackPointerRegister(const llvm::Value* val); bool isZeroRegister(const llvm::Value* val); @@ -136,6 +137,7 @@ class Abi std::vector _paramRegs {}; /// Floating Point registers that can be used as parameter according to abi. std::vector _paramFPRegs {}; + std::vector _doubleParamRegs {}; /// Specifies if abi returns value on stack. bool returnsOnStack = false; diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 2abc24309..88f1d5625 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -230,6 +230,11 @@ std::vector Abi::parameterRegisters() const return _paramRegs; } +std::vector Abi::doubleParameterRegisters() const +{ + return _doubleParamRegs; +} + std::vector Abi::parameterFPRegisters() const { return _paramFPRegs; diff --git a/src/bin2llvmir/providers/abi/mips.cpp b/src/bin2llvmir/providers/abi/mips.cpp index 827f12225..f6d684728 100644 --- a/src/bin2llvmir/providers/abi/mips.cpp +++ b/src/bin2llvmir/providers/abi/mips.cpp @@ -61,6 +61,11 @@ AbiMips::AbiMips(llvm::Module* m, Config* c) : MIPS_REG_F18 }; + _doubleParamRegs = { + MIPS_REG_FD12, + MIPS_REG_FD14, + MIPS_REG_FD16, + }; } AbiMips::~AbiMips() From 2be2dbb1e2ed6a93691fef1bd85c17a2556ee701 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 26 Jul 2018 12:45:00 +0200 Subject: [PATCH 011/159] abi: pic32: new class Provides special ABI for Pic32. This type of Mips architecture passes parameters differently than regular Mips and to reflect this we should have separated Pic32 ABI that would be suitable for other changes that my emerge by deompilation of sufficient Pic32 binary files. --- .../retdec/bin2llvmir/providers/abi/pic32.h | 37 +++++++++ src/bin2llvmir/CMakeLists.txt | 1 + src/bin2llvmir/providers/abi/pic32.cpp | 81 +++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/abi/pic32.h create mode 100644 src/bin2llvmir/providers/abi/pic32.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/pic32.h b/include/retdec/bin2llvmir/providers/abi/pic32.h new file mode 100644 index 000000000..e78b7bcaa --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/pic32.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/mips.h + * @brief ABI information for MIPS. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_PIC32_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_PIC32_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiPic32 : public Abi +{ + // Ctors, dtors. + // + public: + AbiPic32(llvm::Module* m, Config* c); + virtual ~AbiPic32(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index f71322fdb..7153ce913 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -67,6 +67,7 @@ set(BIN2LLVMIR_SOURCES providers/abi/abi.cpp providers/abi/arm.cpp providers/abi/mips.cpp + providers/abi/pic32.cpp providers/abi/powerpc.cpp providers/abi/x86.cpp providers/asm_instruction.cpp diff --git a/src/bin2llvmir/providers/abi/pic32.cpp b/src/bin2llvmir/providers/abi/pic32.cpp new file mode 100644 index 000000000..66063dbd6 --- /dev/null +++ b/src/bin2llvmir/providers/abi/pic32.cpp @@ -0,0 +1,81 @@ +/** + * @file src/bin2llvmir/providers/abi/mips.h + * @brief ABI information for MIPS. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/pic32.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiPic32::AbiPic32(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(MIPS_REG_ENDING); + _id2regs.resize(MIPS_REG_ENDING, nullptr); + _regStackPointerId = MIPS_REG_SP; + _regZeroReg = MIPS_REG_ZERO; + + // system calls + _regSyscallId = MIPS_REG_V0; + _regSyscallReturn = MIPS_REG_V0; + _syscallRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3}; + + _regReturn = MIPS_REG_V0; + _regFPReturn = MIPS_REG_V0; + + if (_config->getConfig().tools.isPspGcc()) + { + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3, + MIPS_REG_T0, + MIPS_REG_T1, + MIPS_REG_T2, + MIPS_REG_T3}; + } + else + { + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3}; + } +} + +AbiPic32::~AbiPic32() +{ + +} + +bool AbiPic32::isGeneralPurposeRegister(const llvm::Value* val) +{ + uint32_t rid = getRegisterId(val); + return MIPS_REG_0 <= rid && rid <= MIPS_REG_31; +} + +bool AbiPic32::isNopInstruction(cs_insn* insn) +{ + // True NOP variants. + // + if (insn->id == MIPS_INS_NOP + || insn->id == MIPS_INS_SSNOP) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec From 2d38d790b478240a220bd2462816685a2f56c76e Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 26 Jul 2018 12:45:57 +0200 Subject: [PATCH 012/159] abi: provide support for pic32 abi --- src/bin2llvmir/providers/abi/abi.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 88f1d5625..07fc1817c 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -9,6 +9,7 @@ #include "retdec/bin2llvmir/providers/abi/mips.h" #include "retdec/bin2llvmir/providers/abi/powerpc.h" #include "retdec/bin2llvmir/providers/abi/x86.h" +#include "retdec/bin2llvmir/providers/abi/pic32.h" using namespace llvm; @@ -277,11 +278,16 @@ Abi* AbiProvider::addAbi( auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); } - else if (c->getConfig().architecture.isMipsOrPic32()) + else if (c->getConfig().architecture.isMips()) { auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); } + else if (c->getConfig().architecture.isPic32()) + { + auto p = _module2abi.emplace(m, std::make_unique(m, c)); + return p.first->second.get(); + } else if (c->getConfig().architecture.isPpc()) { auto p = _module2abi.emplace(m, std::make_unique(m, c)); From 2d6632d61d6ddc8ec1a4abd2a2c6223ff76eb6e0 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 7 Aug 2018 10:52:24 +0200 Subject: [PATCH 013/159] abi: provide info about FP register for return --- include/retdec/bin2llvmir/providers/abi/abi.h | 1 + src/bin2llvmir/providers/abi/abi.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index c6aa174b4..0ad1cfd44 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -88,6 +88,7 @@ class Abi static std::size_t getTypeByteSize(llvm::Module* m, llvm::Type* t); static std::size_t getTypeBitSize(llvm::Module* m, llvm::Type* t); static llvm::IntegerType* getDefaultType(llvm::Module* m); + static llvm::Type* getDefaultFPType(llvm::Module* m); static llvm::PointerType* getDefaultPointerType(llvm::Module* m); // Architectures. diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 07fc1817c..c867c000d 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -187,6 +187,12 @@ llvm::IntegerType* Abi::getDefaultType(llvm::Module* m) return Type::getIntNTy(m->getContext(), s); } +llvm::Type* Abi::getDefaultFPType(llvm::Module* m) +{ + assert(m); + return Type::getFloatTy(m->getContext()); +} + llvm::PointerType* Abi::getDefaultPointerType(llvm::Module* m) { assert(m); From e08e58dc2aeb5b85c0c30ee9ec45dc37cf169b7a Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 2 Jul 2018 10:50:07 +0200 Subject: [PATCH 014/159] param_return: rafacor - use abi instead of config Using abi makes code more readable than gaining informations from configuration. It is clear that abi module contains abi specific informations. --- .../optimizations/param_return/param_return.h | 12 +- .../param_return/param_return.cpp | 621 ++-- src/bin2llvmir/providers/abi/abi.cpp | 2 +- src/bin2llvmir/providers/abi/x86.cpp | 2 +- .../param_return/param_return_tests.cpp | 2814 ++++++++++------- 5 files changed, 1892 insertions(+), 1559 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 78ee990fe..4038a9702 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -31,10 +31,10 @@ class CallEntry CallEntry(llvm::CallInst* c); public: - void filterRegisters(Abi* _abi, Config* _config); - void filterSort(Config* _config); - void filterLeaveOnlyContinuousStackOffsets(Config* _config); - void filterLeaveOnlyNeededStackOffsets(Abi* _abi, Config* _config); + void filterRegisters(Abi* _abi); + void filterSort(Config* _config, Abi* _abi); + void filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi *_abi); + void filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi); void extractFormatString(ReachingDefinitionsAnalysis& _RDA); @@ -100,6 +100,10 @@ class DataFlowEntry void filterRegistersArgLoads(); void filterSortArgLoads(); + void replaceCalls(); + std::map> + fetchLoadsOfCalls() const; + llvm::CallInst* isSimpleWrapper(llvm::Function* fnc); public: diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index df4507900..6afedb66b 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -280,55 +280,16 @@ CallEntry::CallEntry(llvm::CallInst* c) : } -bool registerCanBeParameterAccordingToAbi(Abi* _abi, Config* _config, llvm::Value* val) -{ - if (!_abi->isRegister(val)) - { - return true; - } - - if (_config->getConfig().architecture.isX86()) - { - return false; - } - else if (_config->getConfig().architecture.isPpc()) - { - static std::set names = {"r3", "r4", "r5", "r6", "r7", "r8", "r9"}; - if (names.find(val->getName()) == names.end()) - { - return false; - } - } - else if (_config->getConfig().architecture.isArmOrThumb()) - { - static std::set names = {"r0", "r1", "r2", "r3"}; - if (names.find(val->getName()) == names.end()) - { - return false; - } - } - else if (_config->getConfig().architecture.isMipsOrPic32()) - { - static std::set names = {"a0", "a1", "a2", "a3"}; - if (names.find(val->getName()) == names.end()) - { - return false; - } - } - - return true; -} - /** * Remove all registers that are not used to pass argument according to ABI. */ -void CallEntry::filterRegisters(Abi* _abi, Config* _config) +void CallEntry::filterRegisters(Abi* _abi) { auto it = possibleArgStores.begin(); while (it != possibleArgStores.end()) { auto* op = (*it)->getPointerOperand(); - if (!registerCanBeParameterAccordingToAbi(_abi, _config, op)) + if (_abi->valueCanBeParameter(op) == false) { it = possibleArgStores.erase(it); } @@ -345,7 +306,7 @@ void DataFlowEntry::filterRegistersArgLoads() while (it != argLoads.end()) { auto* op = (*it)->getPointerOperand(); - if (!registerCanBeParameterAccordingToAbi(_abi, _config, op)) + if (_abi->valueCanBeParameter(op) == false) { it = argLoads.erase(it); } @@ -367,22 +328,22 @@ void DataFlowEntry::filterRegistersArgLoads() /** * Stack with the lowest (highest negative) offset is the first call argument. */ -void CallEntry::filterSort(Config* _config) +void CallEntry::filterSort(Config* _config, Abi* _abi) { auto& stores = possibleArgStores; std::stable_sort( stores.begin(), stores.end(), - [_config](StoreInst* a, StoreInst* b) -> bool + [_config, _abi](StoreInst* a, StoreInst* b) -> bool { auto aOff = _config->getStackVariableOffset(a->getPointerOperand()); auto bOff = _config->getStackVariableOffset(b->getPointerOperand()); if (aOff.isUndefined() && bOff.isUndefined()) { - return _config->getConfigRegisterNumber(a->getPointerOperand()) < - _config->getConfigRegisterNumber(b->getPointerOperand()); + return _abi->getRegisterId(a->getPointerOperand()) < + _abi->getRegisterId(b->getPointerOperand()); } else if (aOff.isUndefined() && bOff.isDefined()) { @@ -411,8 +372,9 @@ void DataFlowEntry::filterSortArgLoads() if (aOff.isUndefined() && bOff.isUndefined()) { - return _config->getConfigRegisterNumber(a->getPointerOperand()) < - _config->getConfigRegisterNumber(b->getPointerOperand()); + + return _abi->getRegisterId(a->getPointerOperand()) < + _abi->getRegisterId(b->getPointerOperand()); } else if (aOff.isUndefined() && bOff.isDefined()) { @@ -433,7 +395,7 @@ void DataFlowEntry::filterSortArgLoads() * Arguments are stored into stack variables which go one after another, * there can be no big stack offset gaps. */ -void CallEntry::filterLeaveOnlyContinuousStackOffsets(Config* _config) +void CallEntry::filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi* _abi) { retdec::utils::Maybe prevOff; auto it = possibleArgStores.begin(); @@ -443,12 +405,8 @@ void CallEntry::filterLeaveOnlyContinuousStackOffsets(Config* _config) auto off = _config->getStackVariableOffset(s->getPointerOperand()); auto* val = llvm_utils::skipCasts(s->getValueOperand()); - int gap = 8; -// int gap = 4; - if (val->getType()->isFloatingPointTy()) - { - gap = 8; - } + int gap = _abi->getTypeByteSize(val->getType())*2; + // static int gap = _abi->wordSize()*2/8; if (off.isUndefined()) { @@ -473,9 +431,9 @@ void CallEntry::filterLeaveOnlyContinuousStackOffsets(Config* _config) } } -void CallEntry::filterLeaveOnlyNeededStackOffsets(Abi* _abi, Config* _config) +void CallEntry::filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi) { - int regNum = 0; + size_t regNum = 0; auto it = possibleArgStores.begin(); while (it != possibleArgStores.end()) { @@ -491,38 +449,10 @@ void CallEntry::filterLeaveOnlyNeededStackOffsets(Abi* _abi, Config* _config) } else if (off.isDefined()) { - if (_config->getConfig().architecture.isX86()) - { - // nothing - } - else if (_config->getConfig().architecture.isPpc()) - { - if (regNum == 7) - { - // nothing - } - else - { - it = possibleArgStores.erase(it); - continue; - } - } - else if (_config->getConfig().architecture.isArmOrThumb() - || _config->getConfig().architecture.isMipsOrPic32()) + if (regNum < _abi->parameterRegisters().size()) { - if (regNum == 4) - { - // nothing - } - else - { - it = possibleArgStores.erase(it); - continue; - } - } - else - { - // nothing + it = possibleArgStores.erase(it); + continue; } } @@ -711,11 +641,7 @@ void DataFlowEntry::addArgLoads() if (auto* l = dyn_cast(&*it)) { auto* ptr = l->getPointerOperand(); - if (!_config->isStackVariable(ptr) && !_abi->isRegister(ptr)) - { - continue; - } - if (_abi->isFlagRegister(ptr)) + if (!_abi->valueCanBeParameter(ptr)) { continue; } @@ -789,8 +715,7 @@ void DataFlowEntry::addRetStores() auto* ptr = store->getPointerOperand(); if (disqualifiedValues.hasNot(ptr) - && !_abi->isFlagRegister(ptr) - && (_config->isStackVariable(ptr) || _abi->isRegister(ptr))) + && _abi->canHoldReturnValue(ptr)) { re.possibleRetStores.push_back(store); disqualifiedValues.insert(ptr); @@ -821,7 +746,7 @@ void DataFlowEntry::addCall(llvm::CallInst* call) // TODO: // => ignore - this is an ugly hack, solve somehow better. // - if (_config->getConfig().architecture.isArmOrThumb()) + if (_abi->isArm()) { if (auto ai = AsmInstruction(call)) { @@ -890,18 +815,22 @@ void DataFlowEntry::addCallArgs(llvm::CallInst* call, CallEntry& ce) auto* val = store->getValueOperand(); auto* ptr = store->getPointerOperand(); - if (!_config->isStackVariable(ptr) && !_abi->isRegister(ptr)) + if (!_abi->valueCanBeParameter(ptr)) { disqualifiedValues.insert(ptr); } if (auto* l = dyn_cast(val)) { - if (l->getPointerOperand()->getName() == "ebp" - || l->getPointerOperand()->getName() == "rbp") + if (_abi->isX86()) { - disqualifiedValues.insert(ptr); + if (_abi->getRegisterId(l->getPointerOperand()) == X86_REG_EBP + || _abi->getRegisterId(l->getPointerOperand()) == X86_REG_RBP) + { + disqualifiedValues.insert(ptr); + } } + if (_abi->isRegister(ptr) && _abi->isRegister(l->getPointerOperand()) && ptr != l->getPointerOperand()) @@ -984,8 +913,7 @@ void DataFlowEntry::addCallReturns(llvm::CallInst* call, CallEntry& ce) auto* ptr = load->getPointerOperand(); if (disqualifiedValues.hasNot(ptr) - && !_abi->isFlagRegister(ptr) - && (_config->isStackVariable(ptr) || _abi->isRegister(ptr))) + && _abi->canHoldReturnValue(ptr)) { ce.possibleRetLoads.push_back(load); disqualifiedValues.insert(ptr); @@ -1006,10 +934,10 @@ void DataFlowEntry::filter() for (CallEntry& e : calls) { - e.filterRegisters(_abi, _config); - e.filterSort(_config); - e.filterLeaveOnlyContinuousStackOffsets(_config); - e.filterLeaveOnlyNeededStackOffsets(_abi, _config); + e.filterRegisters(_abi); + e.filterSort(_config, _abi); + e.filterLeaveOnlyContinuousStackOffsets(_config, _abi); + e.filterLeaveOnlyNeededStackOffsets(_config, _abi); if (isVarArg) { @@ -1048,19 +976,18 @@ void DataFlowEntry::filter() } else { - if (_config->getConfig().architecture.isArmOrThumb()) + if (_abi->isArm()) { - static std::vector armNames = - {"r0", "r1", "r2", "r3"}; + auto armRegs = _abi->parameterRegisters(); for (CallEntry& e : calls) { std::size_t idx = 0; auto sIt = e.possibleArgStores.begin(); - while (sIt != e.possibleArgStores.end() && idx < armNames.size()) + while (sIt != e.possibleArgStores.end() && idx < armRegs.size()) { StoreInst* s = *sIt; - if (s->getPointerOperand()->getName() != armNames[idx]) + if (_abi->getRegisterId(s->getPointerOperand()) != armRegs[idx]) { e.possibleArgStores.erase(sIt, e.possibleArgStores.end()); break; @@ -1124,41 +1051,17 @@ void DataFlowEntry::callsFilterCommonRegisters() commonRegs = std::move(intersect); } - // If common contains r3, then it should also contain r2, r1, and r0. - // Example for MIPS: if contains a2, it should a1 and a0. - // - static std::vector regNames; - if (regNames.empty()) - { - if (_config->getConfig().architecture.isMipsOrPic32()) - { - if (_config->getConfig().tools.isPspGcc()) - { - regNames = {"a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3"}; - } - else - { - regNames = {"a0", "a1", "a2", "a3"}; - } - } - else if (_config->getConfig().architecture.isArmOrThumb()) - { - regNames = {"r0", "r1", "r2", "r3"}; - } - else if (_config->getConfig().architecture.isPpc()) - { - regNames = {"r3", "r4", "r5", "r6", "r7", "r8", "r9"}; - } - } - for (auto it = regNames.rbegin(); it != regNames.rend(); ++it) + auto regIds = _abi->parameterRegisters(); + + for (auto it = regIds.rbegin(); it != regIds.rend(); ++it) { - auto* r = _config->getLlvmRegister(*it); + auto* r = _abi->getRegister(*it); if (commonRegs.count(r)) { ++it; - while (it != regNames.rend()) + while (it != regIds.rend()) { - r = _config->getLlvmRegister(*it); + r = _abi->getRegister(*it); commonRegs.insert(r); ++it; } @@ -1263,251 +1166,217 @@ void DataFlowEntry::applyToIr() } } -void DataFlowEntry::applyToIrOrdinary() +std::map> DataFlowEntry::fetchLoadsOfCalls() const { - if (Function* fnc = getFunction()) - { - if (fnc->arg_size() > 0) - { - return; - } + std::map> loadsOfCalls; - std::map> calls2vals; - for (auto& e : calls) + for (auto& e : calls) + { + std::vector loads; + auto* call = e.call; + for (auto* s : e.possibleArgStores) { - std::vector loads; - auto* call = e.call; - for (auto* s : e.possibleArgStores) + auto fIt = specialArgStorage.find(loads.size()); + while (fIt != specialArgStorage.end()) { - auto fIt = specialArgStorage.find(loads.size()); - while (fIt != specialArgStorage.end()) - { - auto* sl = new LoadInst(fIt->second, "", call); - loads.push_back(sl); - fIt = specialArgStorage.find(loads.size()); - } - - auto* l = new LoadInst(s->getPointerOperand(), "", call); - loads.push_back(l); + auto* sl = new LoadInst(fIt->second, "", call); + loads.push_back(sl); + fIt = specialArgStorage.find(loads.size()); } - calls2vals[call] = loads; + auto* l = new LoadInst(s->getPointerOperand(), "", call); + loads.push_back(l); } - llvm::Value* retVal = nullptr; - std::map rets2vals; - if (_config->getConfig().architecture.isX86()) - { - if (retType->isFloatingPointTy()) - { - retVal = _config->getLlvmRegister("st7"); - } - else if (_config->getConfig().architecture.isX86_32()) - { - retVal = _config->getLlvmRegister("eax"); - } - else if (_config->getConfig().architecture.isX86_64()) - { - retVal = _config->getLlvmRegister("rax"); - } - } - else if (_config->getConfig().architecture.isMipsOrPic32()) - { - retVal = _config->getLlvmRegister("v0"); - } - else if (_config->getConfig().architecture.isArmOrThumb()) - { - retVal = _config->getLlvmRegister("r0"); - } - else if (_config->getConfig().architecture.isPpc()) + loadsOfCalls[call] = loads; + } + + return loadsOfCalls; +} + +void DataFlowEntry::replaceCalls() +{ + auto loadsOfCalls = fetchLoadsOfCalls(); + + for (auto l : loadsOfCalls) + IrModifier::modifyCallInst(l.first, l.first->getType(), l.second); +} + +void DataFlowEntry::applyToIrOrdinary() +{ + Function* analysedFunction = getFunction(); + + if (analysedFunction == nullptr) + { + replaceCalls(); + + return; + } + + if (analysedFunction->arg_size() > 0) + { + return; + } + + auto loadsOfCalls = fetchLoadsOfCalls(); + + llvm::Value* retVal = retType->isFloatingPointTy() ? + _abi->getFPReturnRegister() : _abi->getReturnRegister(); + + std::map rets2vals; + + if (retVal) + { + for (auto& e : retStores) { - retVal = _config->getLlvmRegister("r3"); + auto* l = new LoadInst(retVal, "", e.ret); + rets2vals[e.ret] = l; } - if (retVal) + } + + std::vector argStores; + for (LoadInst* l : argLoads) + { + auto fIt = specialArgStorage.find(argStores.size()); + while (fIt != specialArgStorage.end()) { - for (auto& e : retStores) - { - auto* l = new LoadInst(retVal, "", e.ret); - rets2vals[e.ret] = l; - } + argStores.push_back(fIt->second); + fIt = specialArgStorage.find(argStores.size()); } - std::vector argStores; - for (LoadInst* l : argLoads) - { - auto fIt = specialArgStorage.find(argStores.size()); - while (fIt != specialArgStorage.end()) - { - argStores.push_back(fIt->second); - fIt = specialArgStorage.find(argStores.size()); - } + argStores.push_back(l->getPointerOperand()); + } - argStores.push_back(l->getPointerOperand()); - } + auto paramRegs = _abi->parameterRegisters(); - static std::vector ppcNames = - {"r3", "r4", "r5", "r6", "r7", "r8", "r9"}; - static std::vector armNames = - {"r0", "r1", "r2", "r3"}; - static std::vector mipsNames = - {"a0", "a1", "a2", "a3"}; - if (_config->getConfig().tools.isPspGcc()) - { - mipsNames = {"a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3"}; - } - for (auto& p : calls2vals) + for (auto& p : loadsOfCalls) + { + retdec::utils::Maybe stackOff; + if (_abi->isX86()) { - retdec::utils::Maybe stackOff; - if (_config->getConfig().architecture.isX86()) + if (!p.second.empty()) { - if (!p.second.empty()) + auto* l = cast(p.second.back()); + if (_config->isStackVariable(l->getPointerOperand())) { - auto* l = cast(p.second.back()); - if (_config->isStackVariable(l->getPointerOperand())) - { - stackOff = _config->getStackVariableOffset(l->getPointerOperand()); - stackOff = stackOff + 4; - } + stackOff = _config->getStackVariableOffset(l->getPointerOperand()); + stackOff = stackOff + 4; } + } - if (stackOff.isUndefined()) + if (stackOff.isUndefined()) + { + AsmInstruction ai(p.first); + while (ai.isValid()) { - AsmInstruction ai(p.first); - while (ai.isValid()) + for (auto& i : ai) { - for (auto& i : ai) + if (auto* s = dyn_cast(&i)) { - if (auto* s = dyn_cast(&i)) + if (_config->isStackVariable(s->getPointerOperand())) { - if (_config->isStackVariable(s->getPointerOperand())) - { - stackOff = _config->getStackVariableOffset(s->getPointerOperand()); - break; - } + stackOff = _config->getStackVariableOffset(s->getPointerOperand()); + break; } } - if (stackOff.isDefined()) - { - break; - } - ai = ai.getPrev(); } + if (stackOff.isDefined()) + { + break; + } + ai = ai.getPrev(); } } + } - std::size_t idx = 0; - for (auto* t : argTypes) + std::size_t idx = 0; + for (auto* t : argTypes) + { + (void) t; + if (p.second.size() <= idx) { - (void) t; - if (p.second.size() <= idx) + if (_abi->isArm()) { - if (_config->getConfig().architecture.isArmOrThumb()) + if (idx < paramRegs.size()) { - if (idx < armNames.size()) - { - auto* r = _config->getLlvmRegister(armNames[idx]); - auto* l = new LoadInst(r, "", p.first); - p.second.push_back(l); - } + auto* r = _abi->getRegister(paramRegs[idx]); + auto* l = new LoadInst(r, "", p.first); + p.second.push_back(l); } - else if (_config->getConfig().architecture.isMipsOrPic32()) + } + else if (_abi->isMips()) + { + if (idx < paramRegs.size()) { - if (idx < mipsNames.size()) - { - auto* r = _config->getLlvmRegister(mipsNames[idx]); - auto* l = new LoadInst(r, "", p.first); - p.second.push_back(l); - } + auto* r = _abi->getRegister(paramRegs[idx]); + auto* l = new LoadInst(r, "", p.first); + p.second.push_back(l); } - else if (_config->getConfig().architecture.isPpc()) + } + else if (_abi->isPowerPC()) + { + if (idx < paramRegs.size()) { - if (idx < ppcNames.size()) - { - auto* r = _config->getLlvmRegister(ppcNames[idx]); - auto* l = new LoadInst(r, "", p.first); - p.second.push_back(l); - } + auto* r = _abi->getRegister(paramRegs[idx]); + auto* l = new LoadInst(r, "", p.first); + p.second.push_back(l); } - else if (_config->getConfig().architecture.isX86() - && stackOff.isDefined()) + } + else if (_abi->isX86() + && stackOff.isDefined()) + { + auto* s = _config->getLlvmStackVariable(p.first->getFunction(), stackOff); + if (s) { - auto* s = _config->getLlvmStackVariable(p.first->getFunction(), stackOff); - if (s) - { - auto* l = new LoadInst(s, "", p.first); - p.second.push_back(l); - stackOff = stackOff + 4; - } - else - { - stackOff.setUndefined(); - } + auto* l = new LoadInst(s, "", p.first); + p.second.push_back(l); + stackOff = stackOff + 4; + } + else + { + stackOff.setUndefined(); } } - ++idx; } + ++idx; } - - auto* oldType = fnc->getType(); - IrModifier irm(_module, _config); - auto* newFnc = irm.modifyFunction( - fnc, - retType, - argTypes, - isVarArg, - rets2vals, - calls2vals, - retVal, - argStores, - argNames).first; - - LOG << "modify fnc: " << newFnc->getName().str() << " = " - << llvmObjToString(oldType) << " -> " - << llvmObjToString(newFnc->getType()) << std::endl; - - called = newFnc; } - else - { - for (auto& e : calls) - { - auto* call = e.call; - LOG << "\tmodify call: " << llvmObjToString(call) << std::endl; - std::vector loads; - for (auto* s : e.possibleArgStores) - { - auto* l = new LoadInst(s->getPointerOperand(), "", call); - loads.push_back(l); - LOG << "\t\t" << llvmObjToString(l) << std::endl; - } + auto* oldType = analysedFunction->getType(); + IrModifier irm(_module, _config); + auto* newFnc = irm.modifyFunction( + analysedFunction, + retType, + argTypes, + isVarArg, + rets2vals, + loadsOfCalls, + retVal, + argStores, + argNames).first; - auto* ret = fnc ? fnc->getReturnType() : call->getType(); - IrModifier::modifyCallInst(call, ret, loads); - } - } + LOG << "modify fnc: " << newFnc->getName().str() << " = " + << llvmObjToString(oldType) << " -> " + << llvmObjToString(newFnc->getType()) << std::endl; + + called = newFnc; } void DataFlowEntry::applyToIrVariadic() { - std::vector ppcNames = - {"r3", "r4", "r5", "r6", "r7", "r8", "r9"}; - std::vector armNames = - {"r0", "r1", "r2", "r3"}; - std::vector mipsNames = - {"a0", "a1", "a2", "a3"}; - if (_config->getConfig().tools.isPspGcc()) - { - mipsNames = {"a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3"}; - } + auto paramRegs = _abi->parameterRegisters(); - std::vector mipsFpNames = - {"fd12", "fd13", "fd14", "fd15", "fd16", "fd17", "fd18", "fd19", "fd20"}; + static std::vector mipsFpRegs = { + MIPS_REG_FD12, + MIPS_REG_FD14, + MIPS_REG_FD16, + MIPS_REG_FD18, + MIPS_REG_FD20}; llvm::Value* retVal = nullptr; std::map rets2vals; std::vector argStores; - std::map> calls2vals; + std::map> loadsOfCalls; for (CallEntry& ce : calls) { @@ -1570,7 +1439,7 @@ void DataFlowEntry::applyToIrVariadic() int sz = static_cast(_abi->getTypeByteSize(t)); sz = sz > 4 ? 8 : 4; - if (_config->getConfig().architecture.isX86()) + if (_abi->isX86()) { auto* st = _config->getLlvmStackVariable(fnc, off); if (st) @@ -1580,11 +1449,11 @@ void DataFlowEntry::applyToIrVariadic() off += sz; } - else if (_config->getConfig().architecture.isPpc()) + else if (_abi->isPowerPC()) { - if (aIdx < ppcNames.size()) + if (aIdx < paramRegs.size()) { - auto* r = _module->getNamedGlobal(ppcNames[aIdx]); + auto* r = _abi->getRegister(paramRegs[aIdx]); if (r) { args.push_back(r); @@ -1601,11 +1470,11 @@ void DataFlowEntry::applyToIrVariadic() off += sz; } } - else if (_config->getConfig().architecture.isArmOrThumb()) + else if (_abi->isArm()) { - if (aIdx < armNames.size()) + if (aIdx < paramRegs.size()) { - auto* r = _module->getNamedGlobal(armNames[aIdx]); + auto* r = _abi->getRegister(paramRegs[aIdx]); if (r) { args.push_back(r); @@ -1629,9 +1498,9 @@ void DataFlowEntry::applyToIrVariadic() } else if (_config->getConfig().architecture.isPic32()) { - if (aIdx < mipsNames.size()) + if (aIdx < paramRegs.size()) { - auto* r = _module->getNamedGlobal(mipsNames[aIdx]); + auto* r = _abi->getRegister(paramRegs[aIdx]); if (r) { args.push_back(r); @@ -1648,16 +1517,16 @@ void DataFlowEntry::applyToIrVariadic() off += sz; } } - else if (_config->getConfig().architecture.isMips()) + else if (_abi->isMips()) { bool useStack = false; if (t->isFloatingPointTy()) { --aIdx; - if (faIdx < mipsFpNames.size()) + if (faIdx < mipsFpRegs.size()) { - auto* r = _module->getNamedGlobal(mipsFpNames[faIdx]); + auto* r = _abi->getRegister(mipsFpRegs[faIdx]); if (r) { args.push_back(r); @@ -1677,9 +1546,9 @@ void DataFlowEntry::applyToIrVariadic() } else { - if (aIdx < mipsNames.size()) + if (aIdx < paramRegs.size()) { - auto* r = _module->getNamedGlobal(mipsNames[aIdx]); + auto* r = _abi->getRegister(paramRegs[aIdx]); if (r) { args.push_back(r); @@ -1726,37 +1595,13 @@ void DataFlowEntry::applyToIrVariadic() if (!loads.empty()) { - calls2vals[ce.call] = loads; + loadsOfCalls[ce.call] = loads; } } - if (_config->getConfig().architecture.isX86()) - { - if (retType->isFloatingPointTy()) - { - retVal = _config->getLlvmRegister("st7"); - } - else if (_config->getConfig().architecture.isX86_32()) - { - retVal = _config->getLlvmRegister("eax"); - } - else if (_config->getConfig().architecture.isX86_64()) - { - retVal = _config->getLlvmRegister("rax"); - } - } - else if (_config->getConfig().architecture.isMipsOrPic32()) - { - retVal = _config->getLlvmRegister("v0"); - } - else if (_config->getConfig().architecture.isArmOrThumb()) - { - retVal = _config->getLlvmRegister("r0"); - } - else if (_config->getConfig().architecture.isPpc()) - { - retVal = _config->getLlvmRegister("r3"); - } + retVal = retType->isFloatingPointTy() ? + _abi->getFPReturnRegister() : _abi->getReturnRegister(); + if (retVal) { for (auto& e : retStores) @@ -1776,7 +1621,7 @@ void DataFlowEntry::applyToIrVariadic() argTypes, isVarArg, rets2vals, - calls2vals, + loadsOfCalls, retVal, argStores, argNames).first; @@ -2148,7 +1993,7 @@ void DataFlowEntry::setTypeFromUseContext() void DataFlowEntry::setReturnType() { llvm::Value* retVal = nullptr; - if (_config->getConfig().architecture.isX86()) + if (_abi->isX86()) { bool hasEax = false; bool hasRax = false; @@ -2157,17 +2002,17 @@ void DataFlowEntry::setReturnType() { for (StoreInst* s : re.possibleRetStores) { - if (s->getPointerOperand()->getName() == "eax") + if (_abi->getRegisterId(s) == X86_REG_EAX) { hasEax = true; break; } - else if (s->getPointerOperand()->getName() == "rax") + else if (_abi->getRegisterId(s) == X86_REG_RAX) { hasRax = true; break; } - else if (s->getPointerOperand()->getName() == "st7") + else if (_abi->getRegisterId(s) == X86_REG_ST7) { hasSt0 = true; } @@ -2175,28 +2020,28 @@ void DataFlowEntry::setReturnType() } if (!hasEax && !hasRax && hasSt0) { - retVal = _config->getLlvmRegister("st7"); + retVal = _abi->getRegister(X86_REG_ST7); } - else if (_config->getLlvmRegister("rax")) + else if (_abi->getRegister(X86_REG_RAX)) { - retVal = _config->getLlvmRegister("rax"); + retVal = _abi->getRegister(X86_REG_RAX); } else { - retVal = _config->getLlvmRegister("eax"); + retVal = _abi->getRegister(X86_REG_EAX); } } - else if (_config->getConfig().architecture.isMipsOrPic32()) + else if (_abi->isMips()) { - retVal = _config->getLlvmRegister("v0"); + retVal = _abi->getRegister(MIPS_REG_V0); } - else if (_config->getConfig().architecture.isArmOrThumb()) + else if (_abi->isArm()) { - retVal = _config->getLlvmRegister("r0"); + retVal = _abi->getRegister(ARM_REG_R0); } - else if (_config->getConfig().architecture.isPpc()) + else if (_abi->isPowerPC()) { - retVal = _config->getLlvmRegister("r3"); + retVal = _abi->getRegister(PPC_REG_R3); } retType = retVal ? diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index c867c000d..c1c8bcb4d 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -254,7 +254,7 @@ bool Abi::canHoldReturnValue(const llvm::Value* val) const return _config->isStackVariable(val); } - if (!_config->isRegister(val)) + if (!isRegister(val)) { return false; } diff --git a/src/bin2llvmir/providers/abi/x86.cpp b/src/bin2llvmir/providers/abi/x86.cpp index 913d4ab90..03d6afc44 100644 --- a/src/bin2llvmir/providers/abi/x86.cpp +++ b/src/bin2llvmir/providers/abi/x86.cpp @@ -30,7 +30,7 @@ AbiX86::AbiX86(llvm::Module* m, Config* c) : X86_REG_EBP}; _regReturn = X86_REG_EAX; - _regFPReturn = X86_REG_ST0; + _regFPReturn = X86_REG_ST7; } AbiX86::~AbiX86() diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 1baef1ba9..539f39b2d 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -27,7 +27,553 @@ class ParamReturnTests: public LlvmIrTests //// x86 //// // -//TEST_F(ParamReturnTests, x86PtrCallBasicFunctionality) +// x86 +// + +TEST_F(ParamReturnTests, x86PtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-8 + %2 = load i32, i32* %stack_-4 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PtrCallPrevBbIsUsedOnlyIfItIsASinglePredecessor) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + br label %lab1 + lab1: + store i32 123, i32* %stack_-4 + br label %lab2 + lab2: + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + br label %lab1 + lab1: + store i32 123, i32* %stack_-4 + br label %lab2 + lab2: + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-8 + %2 = load i32, i32* %stack_-4 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PtrCallPrevBbIsNotUsedIfItIsNotASinglePredecessor) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + br label %lab1 + lab1: + store i32 123, i32* %stack_-4 + br label %lab2 + lab2: + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + br label %lab2 + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + br label %lab1 + lab1: + store i32 123, i32* %stack_-4 + br label %lab2 + lab2: + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-8 + %2 = bitcast void ()* %a to void (i32)* + call void %2(i32 %1) + br label %lab2 + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PtrCallOnlyStackStoresAreUsed) +{ + parseInput(R"( + @eax = global i32 0 + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %local = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %local + store i32 789, i32* @eax + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + } + ] + } + ], + "registers" : [ + { + "name" : "eax", + "storage" : { "type" : "register", "value" : "eax", + "registerClass" : "gpr", "registerNumber" : 0 } + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @eax = global i32 0 + @r = global i32 0 + define i32 @fnc() { + %stack_-4 = alloca i32 + %local = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %local + store i32 789, i32* @eax + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-4 + %2 = bitcast void ()* %a to void (i32)* + call void %2(i32 %1) + %3 = load i32, i32* @eax + ret i32 %3 + } + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PtrCallStackAreUsedAsArgumentsInCorrectOrder) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-8 + %2 = load i32, i32* %stack_-4 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PtrCallOnlyContinuousStackOffsetsAreUsed) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-16 = alloca i32 + %stack_-20 = alloca i32 + %stack_-24 = alloca i32 + store i32 1, i32* %stack_-16 + store i32 2, i32* %stack_-20 + store i32 3, i32* %stack_-24 + store i32 4, i32* %stack_-4 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-16", + "storage" : { "type" : "stack", "value" : -16 } + }, + { + "name" : "stack_-20", + "storage" : { "type" : "stack", "value" : -20 } + }, + { + "name" : "stack_-24", + "storage" : { "type" : "stack", "value" : -24 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-16 = alloca i32 + %stack_-20 = alloca i32 + %stack_-24 = alloca i32 + store i32 1, i32* %stack_-16 + store i32 2, i32* %stack_-20 + store i32 3, i32* %stack_-24 + store i32 4, i32* %stack_-4 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-24 + %2 = load i32, i32* %stack_-20 + %3 = load i32, i32* %stack_-16 + %4 = bitcast void ()* %a to void (i32, i32, i32)* + call void %4(i32 %1, i32 %2, i32 %3) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86ExternalCallBasicFunctionality) +{ + parseInput(R"( + declare void @print() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + declare void @print(i32, i32) + declare void @0() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %1 = load i32, i32* %stack_-8 + %2 = load i32, i32* %stack_-4 + call void @print(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86ExternalCallFixOnMultiplePlaces) +{ + parseInput(R"( + declare void @print() + define void @fnc1() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + call void @print() + ret void + } + define void @fnc2() { + %stack_-16 = alloca i32 + %stack_-20 = alloca i32 + %stack_-24 = alloca i32 + store i32 456, i32* %stack_-20 + store i32 123, i32* %stack_-16 + store i32 123, i32* %stack_-24 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc1", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + }, + { + "name" : "fnc2", + "locals" : [ + { + "name" : "stack_-16", + "storage" : { "type" : "stack", "value" : -16 } + }, + { + "name" : "stack_-20", + "storage" : { "type" : "stack", "value" : -20 } + }, + { + "name" : "stack_-24", + "storage" : { "type" : "stack", "value" : -24 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + declare void @print(i32, i32) + declare void @0() + define void @fnc1() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %1 = load i32, i32* %stack_-8 + %2 = load i32, i32* %stack_-4 + call void @print(i32 %1, i32 %2) + ret void + } + define void @fnc2() { + %stack_-16 = alloca i32 + %stack_-20 = alloca i32 + %stack_-24 = alloca i32 + store i32 456, i32* %stack_-20 + store i32 123, i32* %stack_-16 + store i32 123, i32* %stack_-24 + %1 = load i32, i32* %stack_-24 + %2 = load i32, i32* %stack_-20 + call void @print(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +//TEST_F(ParamReturnTests, x86ExternalCallSomeFunctionCallsAreNotModified) //{ // parseInput(R"( // @r = global i32 0 @@ -390,7 +936,618 @@ class ParamReturnTests: public LlvmIrTests // })"); // auto abi = AbiProvider::addAbi(module.get(), &config); // -// pass.runOnModuleCustom(*module, &config, abi); + +TEST_F(ParamReturnTests, ppcPtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + define void @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + }, + "registers" : [ + { + "name" : "r3", + "storage" : { "type" : "register", "value" : "r3", + "registerClass" : "gpregs", "registerNumber" : 3 } + }, + { + "name" : "r4", + "storage" : { "type" : "register", "value" : "r4", + "registerClass" : "gpregs", "registerNumber" : 4 } + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + + define i32 @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + %a = bitcast i32* @r to void ()* + %1 = load i32, i32* @r3 + %2 = load i32, i32* @r4 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + %4 = load i32, i32* @r3 + ret i32 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallBasicFunctionality) +{ + parseInput(R"( + @r3 = global i32 0 + @r4 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + }, + "registers" : [ + { + "name" : "r3", + "storage" : { "type" : "register", "value" : "r3", + "registerClass" : "gpregs", "registerNumber" : 3 } + }, + { + "name" : "r4", + "storage" : { "type" : "register", "value" : "r4", + "registerClass" : "gpregs", "registerNumber" : 4 } + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + @r4 = global i32 0 + + declare i32 @print(i32, i32) + declare void @0() + + define i32 @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + %1 = load i32, i32* @r3 + %2 = load i32, i32* @r4 + %3 = call i32 @print(i32 %1, i32 %2) + store i32 %3, i32* @r3 + %4 = load i32, i32* @r3 + ret i32 %4 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallDoNotUseObjectsIfTheyAreNotRegisters) +{ + parseInput(R"( + @r3 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r3 + call void @print() + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallFilterRegistersOnMultiplePlaces) +{ + parseInput(R"( + @r3 = global i32 0 + @r4 = global i32 0 + @r5 = global i32 0 + declare void @print() + define void @fnc1() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + call void @print() + ret void + } + define void @fnc2() { + store i32 123, i32* @r3 + store i32 456, i32* @r5 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + }, + "registers" : [ + { + "name" : "r3", + "storage" : { "type" : "register", "value" : "r3", + "registerClass" : "gpregs", "registerNumber" : 3 } + }, + { + "name" : "r4", + "storage" : { "type" : "register", "value" : "r4", + "registerClass" : "gpregs", "registerNumber" : 4 } + }, + { + "name" : "r5", + "storage" : { "type" : "register", "value" : "r5", + "registerClass" : "gpregs", "registerNumber" : 5 } + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + abi->addRegister(PPC_REG_R5, getGlobalByName("r5")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + @r4 = global i32 0 + @r5 = global i32 0 + + declare i32 @print(i32) + + declare void @0() + + define i32 @fnc1() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + %1 = load i32, i32* @r3 + %2 = call i32 @print(i32 %1) + store i32 %2, i32* @r3 + %3 = load i32, i32* @r3 + ret i32 %3 + } + + declare void @1() + + define i32 @fnc2() { + store i32 123, i32* @r3 + store i32 456, i32* @r5 + %1 = load i32, i32* @r3 + %2 = call i32 @print(i32 %1) + store i32 %2, i32* @r3 + %3 = load i32, i32* @r3 + ret i32 %3 + } + + declare void @2() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallDoNotUseAllRegisters) +{ + parseInput(R"( + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r1 + store i32 456, i32* @r3 + store i32 789, i32* @r2 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + }, + "registers" : [ + { + "name" : "r1", + "storage" : { "type" : "register", "value" : "r1", + "registerClass" : "gpregs", "registerNumber" : 1 } + }, + { + "name" : "r2", + "storage" : { "type" : "register", "value" : "r2", + "registerClass" : "gpregs", "registerNumber" : 2 } + }, + { + "name" : "r3", + "storage" : { "type" : "register", "value" : "r3", + "registerClass" : "gpregs", "registerNumber" : 3 } + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R1, getGlobalByName("r1")); + abi->addRegister(PPC_REG_R2, getGlobalByName("r2")); + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + + declare i32 @print(i32) + + declare void @0() + + define i32 @fnc() { + store i32 123, i32* @r1 + store i32 456, i32* @r3 + store i32 789, i32* @r2 + %1 = load i32, i32* @r3 + %2 = call i32 @print(i32 %1) + store i32 %2, i32* @r3 + %3 = load i32, i32* @r3 + ret i32 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallSortRegistersIntoCorrectOrder) +{ + parseInput(R"( + @r3 = global i32 0 + @r4 = global i32 0 + @r5 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r5 + store i32 456, i32* @r3 + store i32 789, i32* @r4 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + }, + "registers" : [ + { + "name" : "r3", + "storage" : { "type" : "register", "value" : "r3", + "registerClass" : "gpregs", "registerNumber" : 3 } + }, + { + "name" : "r4", + "storage" : { "type" : "register", "value" : "r4", + "registerClass" : "gpregs", "registerNumber" : 4 } + }, + { + "name" : "r5", + "storage" : { "type" : "register", "value" : "r5", + "registerClass" : "gpregs", "registerNumber" : 5 } + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + abi->addRegister(PPC_REG_R5, getGlobalByName("r5")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + @r4 = global i32 0 + @r5 = global i32 0 + + declare i32 @print(i32, i32, i32) + + declare void @0() + + define i32 @fnc() { + store i32 123, i32* @r5 + store i32 456, i32* @r3 + store i32 789, i32* @r4 + %1 = load i32, i32* @r3 + %2 = load i32, i32* @r4 + %3 = load i32, i32* @r5 + %4 = call i32 @print(i32 %1, i32 %2, i32 %3) + store i32 %4, i32* @r3 + %5 = load i32, i32* @r3 + ret i32 %5 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallDoNotUseStacksIfLessThan7RegistersUsed) +{ + parseInput(R"( + @r3 = global i32 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i32 + store i32 123, i32* @r3 + store i32 456, i32* %stack_-4 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + } + ] + } + ], + "registers" : [ + { + "name" : "r3", + "storage" : { "type" : "register", "value" : "r3", + "registerClass" : "gpregs", "registerNumber" : 3 } + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + + declare i32 @print(i32) + + declare void @0() + + define i32 @fnc() { + %stack_-4 = alloca i32 + store i32 123, i32* @r3 + store i32 456, i32* %stack_-4 + %1 = load i32, i32* @r3 + %2 = call i32 @print(i32 %1) + store i32 %2, i32* @r3 + %3 = load i32, i32* @r3 + ret i32 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallUseStacksIf7RegistersUsed) +{ + parseInput(R"( + @r3 = global i32 0 + @r4 = global i32 0 + @r5 = global i32 0 + @r6 = global i32 0 + @r7 = global i32 0 + @r8 = global i32 0 + @r9 = global i32 0 + @r10 = global i32 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @r3 + store i32 1, i32* @r4 + store i32 1, i32* @r5 + store i32 2, i32* %stack_-4 + store i32 1, i32* @r6 + store i32 1, i32* @r7 + store i32 1, i32* @r8 + store i32 2, i32* %stack_-8 + store i32 1, i32* @r9 + store i32 1, i32* @r10 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ], + "registers" : [ + { + "name" : "r3", + "storage" : { "type" : "register", "value" : "r3", + "registerClass" : "gpregs", "registerNumber" : 3 } + }, + { + "name" : "r4", + "storage" : { "type" : "register", "value" : "r4", + "registerClass" : "gpregs", "registerNumber" : 4 } + }, + { + "name" : "r5", + "storage" : { "type" : "register", "value" : "r5", + "registerClass" : "gpregs", "registerNumber" : 5 } + }, + { + "name" : "r6", + "storage" : { "type" : "register", "value" : "r6", + "registerClass" : "gpregs", "registerNumber" : 6 } + }, + { + "name" : "r7", + "storage" : { "type" : "register", "value" : "r7", + "registerClass" : "gpregs", "registerNumber" : 7 } + }, + { + "name" : "r8", + "storage" : { "type" : "register", "value" : "r8", + "registerClass" : "gpregs", "registerNumber" : 8 } + }, + { + "name" : "r9", + "storage" : { "type" : "register", "value" : "r9", + "registerClass" : "gpregs", "registerNumber" : 9 } + }, + { + "name" : "r10", + "storage" : { "type" : "register", "value" : "r10", + "registerClass" : "gpregs", "registerNumber" : 10 } + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + abi->addRegister(PPC_REG_R5, getGlobalByName("r5")); + abi->addRegister(PPC_REG_R6, getGlobalByName("r6")); + abi->addRegister(PPC_REG_R7, getGlobalByName("r7")); + abi->addRegister(PPC_REG_R8, getGlobalByName("r8")); + abi->addRegister(PPC_REG_R9, getGlobalByName("r9")); + abi->addRegister(PPC_REG_R10, getGlobalByName("r10")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + @r4 = global i32 0 + @r5 = global i32 0 + @r6 = global i32 0 + @r7 = global i32 0 + @r8 = global i32 0 + @r9 = global i32 0 + @r10 = global i32 0 + + declare i32 @print(i32, i32, i32, i32, i32, i32, i32, i32, i32) + + declare void @0() + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @r3 + store i32 1, i32* @r4 + store i32 1, i32* @r5 + store i32 2, i32* %stack_-4 + store i32 1, i32* @r6 + store i32 1, i32* @r7 + store i32 1, i32* @r8 + store i32 2, i32* %stack_-8 + store i32 1, i32* @r9 + store i32 1, i32* @r10 + %1 = load i32, i32* @r3 + %2 = load i32, i32* @r4 + %3 = load i32, i32* @r5 + %4 = load i32, i32* @r6 + %5 = load i32, i32* @r7 + %6 = load i32, i32* @r8 + %7 = load i32, i32* @r9 + %8 = load i32, i32* %stack_-8 + %9 = load i32, i32* %stack_-4 + %10 = call i32 @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9) + store i32 %10, i32* @r3 + %11 = load i32, i32* @r3 + ret i32 %11 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + // // std::string exp = R"( // @r = global i32 0 @@ -415,15 +1572,255 @@ class ParamReturnTests: public LlvmIrTests // checkModuleAgainstExpectedIr(exp); //} // -//TEST_F(ParamReturnTests, x86ExternalCallBasicFunctionality) + +TEST_F(ParamReturnTests, armPtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i32 0 + @r0 = global i32 0 + @r1 = global i32 0 + define void @fnc() { + store i32 123, i32* @r0 + store i32 456, i32* @r1 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "arm" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(ARM_REG_R0, getGlobalByName("r0")); + abi->addRegister(ARM_REG_R1, getGlobalByName("r1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + @r0 = global i32 0 + @r1 = global i32 0 + + define i32 @fnc() { + store i32 123, i32* @r0 + store i32 456, i32* @r1 + %a = bitcast i32* @r to void ()* + %1 = load i32, i32* @r0 + %2 = load i32, i32* @r1 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + %4 = load i32, i32* @r0 + ret i32 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, armExternalCallBasicFunctionality) +{ + parseInput(R"( + @r0 = global i32 0 + @r1 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r0 + store i32 456, i32* @r1 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "arm" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(ARM_REG_R0, getGlobalByName("r0")); + abi->addRegister(ARM_REG_R1, getGlobalByName("r1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r0 = global i32 0 + @r1 = global i32 0 + + declare i32 @print(i32, i32) + + declare void @0() + + define i32 @fnc() { + store i32 123, i32* @r0 + store i32 456, i32* @r1 + %1 = load i32, i32* @r0 + %2 = load i32, i32* @r1 + %3 = call i32 @print(i32 %1, i32 %2) + store i32 %3, i32* @r0 + %4 = load i32, i32* @r0 + ret i32 %4 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, armExternalCallUseStacksIf4RegistersUsed) +{ + parseInput(R"( + @r0 = global i32 0 + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @r2 + store i32 1, i32* @r1 + store i32 2, i32* %stack_-4 + store i32 1, i32* @r4 + store i32 1, i32* @r0 + store i32 2, i32* %stack_-8 + store i32 1, i32* @r3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "arm" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ], + "registers" : [ + { + "name" : "r0", + "storage" : { "type" : "register", "value" : "r0", + "registerClass" : "regs", "registerNumber" : 0 } + }, + { + "name" : "r1", + "storage" : { "type" : "register", "value" : "r1", + "registerClass" : "regs", "registerNumber" : 1 } + }, + { + "name" : "r2", + "storage" : { "type" : "register", "value" : "r2", + "registerClass" : "regs", "registerNumber" : 2 } + }, + { + "name" : "r3", + "storage" : { "type" : "register", "value" : "r3", + "registerClass" : "regs", "registerNumber" : 3 } + }, + { + "name" : "r4", + "storage" : { "type" : "register", "value" : "r4", + "registerClass" : "regs", "registerNumber" : 4 } + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(ARM_REG_R0, getGlobalByName("r0")); + abi->addRegister(ARM_REG_R1, getGlobalByName("r1")); + abi->addRegister(ARM_REG_R2, getGlobalByName("r2")); + abi->addRegister(ARM_REG_R3, getGlobalByName("r3")); + abi->addRegister(ARM_REG_R4, getGlobalByName("r4")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r0 = global i32 0 + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + + declare i32 @print(i32, i32, i32, i32, i32, i32) + + declare void @0() + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @r2 + store i32 1, i32* @r1 + store i32 2, i32* %stack_-4 + store i32 1, i32* @r4 + store i32 1, i32* @r0 + store i32 2, i32* %stack_-8 + store i32 1, i32* @r3 + %1 = load i32, i32* @r0 + %2 = load i32, i32* @r1 + %3 = load i32, i32* @r2 + %4 = load i32, i32* @r3 + %5 = load i32, i32* %stack_-8 + %6 = load i32, i32* %stack_-4 + %7 = call i32 @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) + store i32 %7, i32* @r0 + %8 = load i32, i32* @r0 + ret i32 %8 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +// +//TEST_F(ParamReturnTests, ppcExternalCallUseStacksIf7RegistersUsed) //{ // parseInput(R"( +// @r3 = global i32 0 +// @r4 = global i32 0 +// @r5 = global i32 0 +// @r6 = global i32 0 +// @r7 = global i32 0 +// @r8 = global i32 0 +// @r9 = global i32 0 +// @r10 = global i32 0 // declare void @print() // define void @fnc() { // %stack_-4 = alloca i32 // %stack_-8 = alloca i32 -// store i32 123, i32* %stack_-4 -// store i32 456, i32* %stack_-8 +// store i32 1, i32* @r3 +// store i32 1, i32* @r4 +// store i32 1, i32* @r5 +// store i32 2, i32* %stack_-4 +// store i32 1, i32* @r6 +// store i32 1, i32* @r7 +// store i32 1, i32* @r8 +// store i32 2, i32* %stack_-8 +// store i32 1, i32* @r9 +// store i32 1, i32* @r10 // call void @print() // ret void // } @@ -431,8 +1828,8 @@ class ParamReturnTests: public LlvmIrTests // auto config = Config::fromJsonString(module.get(), R"({ // "architecture" : { // "bitSize" : 32, -// "endian" : "little", -// "name" : "x86" +// "endian" : "big", +// "name" : "powerpc" // }, // "functions" : [ // { @@ -448,1168 +1845,255 @@ class ParamReturnTests: public LlvmIrTests // } // ] // } +// ], +// "registers" : [ +// { +// "name" : "r3", +// "storage" : { "type" : "register", "value" : "r3", +// "registerClass" : "gpregs", "registerNumber" : 3 } +// }, +// { +// "name" : "r4", +// "storage" : { "type" : "register", "value" : "r4", +// "registerClass" : "gpregs", "registerNumber" : 4 } +// }, +// { +// "name" : "r5", +// "storage" : { "type" : "register", "value" : "r5", +// "registerClass" : "gpregs", "registerNumber" : 5 } +// }, +// { +// "name" : "r6", +// "storage" : { "type" : "register", "value" : "r6", +// "registerClass" : "gpregs", "registerNumber" : 6 } +// }, +// { +// "name" : "r7", +// "storage" : { "type" : "register", "value" : "r7", +// "registerClass" : "gpregs", "registerNumber" : 7 } +// }, +// { +// "name" : "r8", +// "storage" : { "type" : "register", "value" : "r8", +// "registerClass" : "gpregs", "registerNumber" : 8 } +// }, +// { +// "name" : "r9", +// "storage" : { "type" : "register", "value" : "r9", +// "registerClass" : "gpregs", "registerNumber" : 9 } +// }, +// { +// "name" : "r10", +// "storage" : { "type" : "register", "value" : "r10", +// "registerClass" : "gpregs", "registerNumber" : 10 } +// } // ] // })"); // auto abi = AbiProvider::addAbi(module.get(), &config); // -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// declare void @print(i32, i32) -// declare void @0() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 123, i32* %stack_-4 -// store i32 456, i32* %stack_-8 -// %1 = load i32, i32* %stack_-8 -// %2 = load i32, i32* %stack_-4 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, x86ExternalCallFixOnMultiplePlaces) -//{ -// parseInput(R"( -// declare void @print() -// define void @fnc1() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 123, i32* %stack_-4 -// store i32 456, i32* %stack_-8 -// call void @print() -// ret void -// } -// define void @fnc2() { -// %stack_-16 = alloca i32 -// %stack_-20 = alloca i32 -// %stack_-24 = alloca i32 -// store i32 456, i32* %stack_-20 -// store i32 123, i32* %stack_-16 -// store i32 123, i32* %stack_-24 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "x86" -// }, -// "functions" : [ -// { -// "name" : "fnc1", -// "locals" : [ -// { -// "name" : "stack_-4", -// "storage" : { "type" : "stack", "value" : -4 } -// }, -// { -// "name" : "stack_-8", -// "storage" : { "type" : "stack", "value" : -8 } -// } -// ] -// }, -// { -// "name" : "fnc2", -// "locals" : [ -// { -// "name" : "stack_-16", -// "storage" : { "type" : "stack", "value" : -16 } -// }, -// { -// "name" : "stack_-20", -// "storage" : { "type" : "stack", "value" : -20 } -// }, -// { -// "name" : "stack_-24", -// "storage" : { "type" : "stack", "value" : -24 } -// } -// ] -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// declare void @print(i32, i32) -// declare void @0() -// define void @fnc1() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 123, i32* %stack_-4 -// store i32 456, i32* %stack_-8 -// %1 = load i32, i32* %stack_-8 -// %2 = load i32, i32* %stack_-4 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// define void @fnc2() { -// %stack_-16 = alloca i32 -// %stack_-20 = alloca i32 -// %stack_-24 = alloca i32 -// store i32 456, i32* %stack_-20 -// store i32 123, i32* %stack_-16 -// store i32 123, i32* %stack_-24 -// %1 = load i32, i32* %stack_-24 -// %2 = load i32, i32* %stack_-20 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -////TEST_F(ParamReturnTests, x86ExternalCallSomeFunctionCallsAreNotModified) -////{ -//// auto module = parseInput(R"( -//// declare void @print1() -//// declare void @print2() -//// declare void @print3(i32) -//// define void @fnc() { -//// %stack_-4 = alloca i32 -//// store i32 123, i32* %stack_-4 -//// call void @print1() -//// store i32 123, i32* %stack_-4 -//// call void @print2() -//// store i32 123, i32* %stack_-4 -//// call void @print3(i32 123) -//// ret void -//// } -//// )"); -//// auto config = Config::fromJsonString(module.get(), R"({ -//// "architecture" : { -//// "bitSize" : 32, -//// "endian" : "little", -//// "name" : "x86" -//// }, -//// "functions" : [ -//// { -//// "name" : "fnc", -//// "locals" : [ -//// { -//// "name" : "stack_-4", -//// "storage" : { "type" : "stack", "value" : -4 } -//// } -//// ] -//// }, -//// { -//// "name" : "print1", -//// "fncType" : "dynamicallyLinked", -//// "declarationStr" : "whatever" -//// }, -//// { -//// "name" : "print2", -//// "fncType" : "dynamicallyLinked", -//// "isFromDebug" : true -//// }, -//// { -//// "name" : "print3", -//// "fncType" : "dynamicallyLinked" -//// } -//// ] -//// })"); -//// -//// pass.runOnModuleCustom(*module, &config, abi); -//// -//// std::string exp = R"( -//// declare void @print1() -//// declare void @print2() -//// declare void @print3(i32) -//// define void @fnc() { -//// %stack_-4 = alloca i32 -//// store i32 123, i32* %stack_-4 -//// call void @print1() -//// store i32 123, i32* %stack_-4 -//// call void @print2() -//// store i32 123, i32* %stack_-4 -//// call void @print3(i32 123) -//// ret void -//// } -//// )"; -//// checkModuleAgainstExpectedIr(exp, module.get()); -////} -// -//// -//// PowerPC -//// -// -//TEST_F(ParamReturnTests, ppcPtrCallBasicFunctionality) -//{ -// parseInput(R"( -// @r = global i32 0 -// @r3 = global i32 0 -// @r4 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// %a = bitcast i32* @r to void()* -// call void %a() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r = global i32 0 -// @r3 = global i32 0 -// @r4 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// %a = bitcast i32* @r to void()* -// %1 = load i32, i32* @r3 -// %2 = load i32, i32* @r4 -// %3 = bitcast void ()* %a to void (i32, i32)* -// call void %3(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallBasicFunctionality) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// declare void @print(i32, i32) -// declare void @0() -// define void @fnc() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// %1 = load i32, i32* @r3 -// %2 = load i32, i32* @r4 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallDoNotUseObjectsIfTheyAreNotRegisters) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r3 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// } -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r3 -// call void @print() -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallFilterRegistersOnMultiplePlaces) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// declare void @print() -// define void @fnc1() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// call void @print() -// ret void -// } -// define void @fnc2() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r5 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "r5", -// "storage" : { "type" : "register", "value" : "r5", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// declare void @print(i32) -// declare void @0() -// define void @fnc1() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// %1 = load i32, i32* @r3 -// call void @print(i32 %1) -// ret void -// } -// define void @fnc2() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r5 -// %1 = load i32, i32* @r3 -// call void @print(i32 %1) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallDoNotUseAllRegisters) -//{ -// parseInput(R"( -// @r1 = global i32 0 -// @r2 = global i32 0 -// @r3 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r1 -// store i32 456, i32* @r3 -// store i32 789, i32* @r2 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "registers" : [ -// { -// "name" : "r1", -// "storage" : { "type" : "register", "value" : "r1", -// "registerClass" : "gpregs", "registerNumber" : 1 } -// }, -// { -// "name" : "r2", -// "storage" : { "type" : "register", "value" : "r2", -// "registerClass" : "gpregs", "registerNumber" : 2 } -// }, -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r1 = global i32 0 -// @r2 = global i32 0 -// @r3 = global i32 0 -// declare void @print(i32) -// declare void @0() -// define void @fnc() { -// store i32 123, i32* @r1 -// store i32 456, i32* @r3 -// store i32 789, i32* @r2 -// %1 = load i32, i32* @r3 -// call void @print(i32 %1) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallSortRegistersIntoCorrectOrder) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r5 -// store i32 456, i32* @r3 -// store i32 789, i32* @r4 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "r5", -// "storage" : { "type" : "register", "value" : "r5", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// declare void @print(i32, i32, i32) -// declare void @0() -// define void @fnc() { -// store i32 123, i32* @r5 -// store i32 456, i32* @r3 -// store i32 789, i32* @r4 -// %1 = load i32, i32* @r3 -// %2 = load i32, i32* @r4 -// %3 = load i32, i32* @r5 -// call void @print(i32 %1, i32 %2, i32 %3) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallDoNotUseStacksIfLessThan7RegistersUsed) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// declare void @print() -// define void @fnc() { -// %stack_-4 = alloca i32 -// store i32 123, i32* @r3 -// store i32 456, i32* %stack_-4 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "functions" : [ -// { -// "name" : "fnc", -// "locals" : [ -// { -// "name" : "stack_-4", -// "storage" : { "type" : "stack", "value" : -4 } -// } -// ] -// } -// ], -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// declare void @print(i32) -// declare void @0() -// define void @fnc() { -// %stack_-4 = alloca i32 -// store i32 123, i32* @r3 -// store i32 456, i32* %stack_-4 -// %1 = load i32, i32* @r3 -// call void @print(i32 %1) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallUseStacksIf7RegistersUsed) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// @r6 = global i32 0 -// @r7 = global i32 0 -// @r8 = global i32 0 -// @r9 = global i32 0 -// @r10 = global i32 0 -// declare void @print() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @r3 -// store i32 1, i32* @r4 -// store i32 1, i32* @r5 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @r6 -// store i32 1, i32* @r7 -// store i32 1, i32* @r8 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @r9 -// store i32 1, i32* @r10 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "functions" : [ -// { -// "name" : "fnc", -// "locals" : [ -// { -// "name" : "stack_-4", -// "storage" : { "type" : "stack", "value" : -4 } -// }, -// { -// "name" : "stack_-8", -// "storage" : { "type" : "stack", "value" : -8 } -// } -// ] -// } -// ], -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "r5", -// "storage" : { "type" : "register", "value" : "r5", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// }, -// { -// "name" : "r6", -// "storage" : { "type" : "register", "value" : "r6", -// "registerClass" : "gpregs", "registerNumber" : 6 } -// }, -// { -// "name" : "r7", -// "storage" : { "type" : "register", "value" : "r7", -// "registerClass" : "gpregs", "registerNumber" : 7 } -// }, -// { -// "name" : "r8", -// "storage" : { "type" : "register", "value" : "r8", -// "registerClass" : "gpregs", "registerNumber" : 8 } -// }, -// { -// "name" : "r9", -// "storage" : { "type" : "register", "value" : "r9", -// "registerClass" : "gpregs", "registerNumber" : 9 } -// }, -// { -// "name" : "r10", -// "storage" : { "type" : "register", "value" : "r10", -// "registerClass" : "gpregs", "registerNumber" : 10 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// @r6 = global i32 0 -// @r7 = global i32 0 -// @r8 = global i32 0 -// @r9 = global i32 0 -// @r10 = global i32 0 -// declare void @print(i32, i32, i32, i32, i32, i32, i32, i32, i32) -// declare void @0() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @r3 -// store i32 1, i32* @r4 -// store i32 1, i32* @r5 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @r6 -// store i32 1, i32* @r7 -// store i32 1, i32* @r8 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @r9 -// store i32 1, i32* @r10 -// %1 = load i32, i32* @r3 -// %2 = load i32, i32* @r4 -// %3 = load i32, i32* @r5 -// %4 = load i32, i32* @r6 -// %5 = load i32, i32* @r7 -// %6 = load i32, i32* @r8 -// %7 = load i32, i32* @r9 -// %8 = load i32, i32* %stack_-8 -// %9 = load i32, i32* %stack_-4 -// call void @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//// -//// ARM (+THUMB) -//// -// -//TEST_F(ParamReturnTests, armPtrCallBasicFunctionality) -//{ -// parseInput(R"( -// @r = global i32 0 -// @r0 = global i32 0 -// @r1 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @r0 -// store i32 456, i32* @r1 -// %a = bitcast i32* @r to void()* -// call void %a() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "arm" -// }, -// "registers" : [ -// { -// "name" : "r0", -// "storage" : { "type" : "register", "value" : "r0", -// "registerClass" : "regs", "registerNumber" : 0 } -// }, -// { -// "name" : "r1", -// "storage" : { "type" : "register", "value" : "r1", -// "registerClass" : "regs", "registerNumber" : 1 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r = global i32 0 -// @r0 = global i32 0 -// @r1 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @r0 -// store i32 456, i32* @r1 -// %a = bitcast i32* @r to void()* -// %1 = load i32, i32* @r0 -// %2 = load i32, i32* @r1 -// %3 = bitcast void ()* %a to void (i32, i32)* -// call void %3(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, armExternalCallBasicFunctionality) -//{ -// parseInput(R"( -// @r0 = global i32 0 -// @r1 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r0 -// store i32 456, i32* @r1 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "arm" -// }, -// "registers" : [ -// { -// "name" : "r0", -// "storage" : { "type" : "register", "value" : "r0", -// "registerClass" : "regs", "registerNumber" : 0 } -// }, -// { -// "name" : "r1", -// "storage" : { "type" : "register", "value" : "r1", -// "registerClass" : "regs", "registerNumber" : 1 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r0 = global i32 0 -// @r1 = global i32 0 -// declare void @print(i32, i32) -// declare void @0() -// define void @fnc() { -// store i32 123, i32* @r0 -// store i32 456, i32* @r1 -// %1 = load i32, i32* @r0 -// %2 = load i32, i32* @r1 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, armExternalCallUseStacksIf4RegistersUsed) -//{ -// parseInput(R"( -// @r0 = global i32 0 -// @r1 = global i32 0 -// @r2 = global i32 0 -// @r3 = global i32 0 -// @r4 = global i32 0 -// declare void @print() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @r2 -// store i32 1, i32* @r1 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @r4 -// store i32 1, i32* @r0 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @r3 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "arm" -// }, -// "functions" : [ -// { -// "name" : "fnc", -// "locals" : [ -// { -// "name" : "stack_-4", -// "storage" : { "type" : "stack", "value" : -4 } -// }, -// { -// "name" : "stack_-8", -// "storage" : { "type" : "stack", "value" : -8 } -// } -// ] -// } -// ], -// "registers" : [ -// { -// "name" : "r0", -// "storage" : { "type" : "register", "value" : "r0", -// "registerClass" : "regs", "registerNumber" : 0 } -// }, -// { -// "name" : "r1", -// "storage" : { "type" : "register", "value" : "r1", -// "registerClass" : "regs", "registerNumber" : 1 } -// }, -// { -// "name" : "r2", -// "storage" : { "type" : "register", "value" : "r2", -// "registerClass" : "regs", "registerNumber" : 2 } -// }, -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "regs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "regs", "registerNumber" : 4 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r0 = global i32 0 -// @r1 = global i32 0 -// @r2 = global i32 0 -// @r3 = global i32 0 -// @r4 = global i32 0 -// declare void @print(i32, i32, i32, i32, i32, i32) -// declare void @0() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @r2 -// store i32 1, i32* @r1 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @r4 -// store i32 1, i32* @r0 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @r3 -// %1 = load i32, i32* @r0 -// %2 = load i32, i32* @r1 -// %3 = load i32, i32* @r2 -// %4 = load i32, i32* @r3 -// %5 = load i32, i32* %stack_-8 -// %6 = load i32, i32* %stack_-4 -// call void @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//// -//// MIPS (+Pic32) -//// -// -//TEST_F(ParamReturnTests, mipsPtrCallBasicFunctionality) -//{ -// parseInput(R"( -// @r = global i32 0 -// @a0 = global i32 0 -// @a1 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @a0 -// store i32 456, i32* @a1 -// %a = bitcast i32* @r to void()* -// call void %a() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "mips" -// }, -// "registers" : [ -// { -// "name" : "a0", -// "storage" : { "type" : "register", "value" : "a0", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "a1", -// "storage" : { "type" : "register", "value" : "a1", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r = global i32 0 -// @a0 = global i32 0 -// @a1 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @a0 -// store i32 456, i32* @a1 -// %a = bitcast i32* @r to void()* -// %1 = load i32, i32* @a0 -// %2 = load i32, i32* @a1 -// %3 = bitcast void ()* %a to void (i32, i32)* -// call void %3(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, mipsExternalCallBasicFunctionality) -//{ -// parseInput(R"( -// @a0 = global i32 0 -// @a1 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @a0 -// store i32 456, i32* @a1 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "mips" -// }, -// "registers" : [ -// { -// "name" : "a0", -// "storage" : { "type" : "register", "value" : "a0", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "a1", -// "storage" : { "type" : "register", "value" : "a1", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @a0 = global i32 0 -// @a1 = global i32 0 -// declare void @print(i32, i32) -// declare void @0() -// define void @fnc() { -// store i32 123, i32* @a0 -// store i32 456, i32* @a1 -// %1 = load i32, i32* @a0 -// %2 = load i32, i32* @a1 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, mipsExternalCallUseStacksIf4RegistersUsed) -//{ -// parseInput(R"( -// @a0 = global i32 0 -// @a1 = global i32 0 -// @a2 = global i32 0 -// @a3 = global i32 0 -// @t0 = global i32 0 -// declare void @print() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @a2 -// store i32 1, i32* @a1 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @t0 -// store i32 1, i32* @a0 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @a3 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "mips" -// }, -// "functions" : [ -// { -// "name" : "fnc", -// "locals" : [ -// { -// "name" : "stack_-4", -// "storage" : { "type" : "stack", "value" : -4 } -// }, -// { -// "name" : "stack_-8", -// "storage" : { "type" : "stack", "value" : -8 } -// } -// ] -// } -// ], -// "registers" : [ -// { -// "name" : "a0", -// "storage" : { "type" : "register", "value" : "a0", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "a1", -// "storage" : { "type" : "register", "value" : "a1", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// }, -// { -// "name" : "a2", -// "storage" : { "type" : "register", "value" : "a2", -// "registerClass" : "gpregs", "registerNumber" : 6 } -// }, -// { -// "name" : "a3", -// "storage" : { "type" : "register", "value" : "a3", -// "registerClass" : "gpregs", "registerNumber" : 7 } -// }, -// { -// "name" : "t0", -// "storage" : { "type" : "register", "value" : "t0", -// "registerClass" : "gpregs", "registerNumber" : 8 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @a0 = global i32 0 -// @a1 = global i32 0 -// @a2 = global i32 0 -// @a3 = global i32 0 -// @t0 = global i32 0 -// declare void @print(i32, i32, i32, i32, i32, i32) -// declare void @0() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @a2 -// store i32 1, i32* @a1 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @t0 -// store i32 1, i32* @a0 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @a3 -// %1 = load i32, i32* @a0 -// %2 = load i32, i32* @a1 -// %3 = load i32, i32* @a2 -// %4 = load i32, i32* @a3 -// %5 = load i32, i32* %stack_-8 -// %6 = load i32, i32* %stack_-4 -// call void @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} + +TEST_F(ParamReturnTests, mipsPtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i32 0 + @a0 = global i32 0 + @a1 = global i32 0 + define void @fnc() { + store i32 123, i32* @a0 + store i32 456, i32* @a1 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "mips" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi->addRegister(MIPS_REG_A1, getGlobalByName("a1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + @a0 = global i32 0 + @a1 = global i32 0 + define void @fnc() { + store i32 123, i32* @a0 + store i32 456, i32* @a1 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* @a0 + %2 = load i32, i32* @a1 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mipsExternalCallBasicFunctionality) +{ + parseInput(R"( + @a0 = global i32 0 + @a1 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @a0 + store i32 456, i32* @a1 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "mips" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi->addRegister(MIPS_REG_A1, getGlobalByName("a1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @a0 = global i32 0 + @a1 = global i32 0 + declare void @print(i32, i32) + declare void @0() + define void @fnc() { + store i32 123, i32* @a0 + store i32 456, i32* @a1 + %1 = load i32, i32* @a0 + %2 = load i32, i32* @a1 + call void @print(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mipsExternalCallUseStacksIf4RegistersUsed) +{ + parseInput(R"( + @a0 = global i32 0 + @a1 = global i32 0 + @a2 = global i32 0 + @a3 = global i32 0 + @t0 = global i32 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @a2 + store i32 1, i32* @a1 + store i32 2, i32* %stack_-4 + store i32 1, i32* @t0 + store i32 1, i32* @a0 + store i32 2, i32* %stack_-8 + store i32 1, i32* @a3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "mips" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ], + "registers" : [ + { + "name" : "a0", + "storage" : { "type" : "register", "value" : "a0", + "registerClass" : "gpregs", "registerNumber" : 4 } + }, + { + "name" : "a1", + "storage" : { "type" : "register", "value" : "a1", + "registerClass" : "gpregs", "registerNumber" : 5 } + }, + { + "name" : "a2", + "storage" : { "type" : "register", "value" : "a2", + "registerClass" : "gpregs", "registerNumber" : 6 } + }, + { + "name" : "a3", + "storage" : { "type" : "register", "value" : "a3", + "registerClass" : "gpregs", "registerNumber" : 7 } + }, + { + "name" : "t0", + "storage" : { "type" : "register", "value" : "t0", + "registerClass" : "gpregs", "registerNumber" : 8 } + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi->addRegister(MIPS_REG_A1, getGlobalByName("a1")); + abi->addRegister(MIPS_REG_A2, getGlobalByName("a2")); + abi->addRegister(MIPS_REG_A3, getGlobalByName("a3")); + abi->addRegister(MIPS_REG_T0, getGlobalByName("t0")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @a0 = global i32 0 + @a1 = global i32 0 + @a2 = global i32 0 + @a3 = global i32 0 + @t0 = global i32 0 + declare void @print(i32, i32, i32, i32, i32, i32) + declare void @0() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @a2 + store i32 1, i32* @a1 + store i32 2, i32* %stack_-4 + store i32 1, i32* @t0 + store i32 1, i32* @a0 + store i32 2, i32* %stack_-8 + store i32 1, i32* @a3 + %1 = load i32, i32* @a0 + %2 = load i32, i32* @a1 + %3 = load i32, i32* @a2 + %4 = load i32, i32* @a3 + %5 = load i32, i32* %stack_-8 + %6 = load i32, i32* %stack_-4 + call void @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} } // namespace tests } // namespace bin2llvmir From dad21d2a9b4fbc02457d83f63b9b843c1f28c3de Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Fri, 29 Jun 2018 14:43:29 +0200 Subject: [PATCH 015/159] param_return: get rid of redundant operations module param_return contains block counting registers which result is not used anywhere in code and thus it is unnecessary to do so. --- .../optimizations/param_return/param_return.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 6afedb66b..a1c764602 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -772,7 +772,6 @@ void DataFlowEntry::addCall(llvm::CallInst* call) void DataFlowEntry::addCallArgs(llvm::CallInst* call, CallEntry& ce) { NonIterableSet disqualifiedValues; - unsigned maxUsedRegNum = 0; auto* b = call->getParent(); Instruction* prev = call; std::set seen; @@ -846,18 +845,6 @@ void DataFlowEntry::addCallArgs(llvm::CallInst* call, CallEntry& ce) ce.possibleArgStores.push_back(store); disqualifiedValues.insert(ptr); disqualifiedValues.insert(store); - - if (_abi->isGeneralPurposeRegister(ptr) - || (_config->getConfig().architecture.isMipsOrPic32() - && _abi->isRegister(ptr) - && ptr->getType()->isFloatingPointTy())) - { - auto rn = _config->getConfigRegisterNumber(ptr); - if (rn.isDefined() && rn > maxUsedRegNum) - { - maxUsedRegNum = rn; - } - } } } } From a693d66ff812e6740a5c6ef2541e214bf34fe80f Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 17 Jul 2018 14:43:57 +0200 Subject: [PATCH 016/159] param_return: redundant code code that searched for register to which store return value was redundant and should be be done better. For example if abi can tell to which register store value it can be searched in module for appropriate store or perhaps manually create one. --- .../param_return/param_return.cpp | 52 +------------------ 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index a1c764602..29945dd5c 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1979,57 +1979,7 @@ void DataFlowEntry::setTypeFromUseContext() void DataFlowEntry::setReturnType() { - llvm::Value* retVal = nullptr; - if (_abi->isX86()) - { - bool hasEax = false; - bool hasRax = false; - bool hasSt0 = false; - for (auto& re : retStores) - { - for (StoreInst* s : re.possibleRetStores) - { - if (_abi->getRegisterId(s) == X86_REG_EAX) - { - hasEax = true; - break; - } - else if (_abi->getRegisterId(s) == X86_REG_RAX) - { - hasRax = true; - break; - } - else if (_abi->getRegisterId(s) == X86_REG_ST7) - { - hasSt0 = true; - } - } - } - if (!hasEax && !hasRax && hasSt0) - { - retVal = _abi->getRegister(X86_REG_ST7); - } - else if (_abi->getRegister(X86_REG_RAX)) - { - retVal = _abi->getRegister(X86_REG_RAX); - } - else - { - retVal = _abi->getRegister(X86_REG_EAX); - } - } - else if (_abi->isMips()) - { - retVal = _abi->getRegister(MIPS_REG_V0); - } - else if (_abi->isArm()) - { - retVal = _abi->getRegister(ARM_REG_R0); - } - else if (_abi->isPowerPC()) - { - retVal = _abi->getRegister(PPC_REG_R3); - } + llvm::Value* retVal = _abi->getReturnRegister(); retType = retVal ? retVal->getType()->getPointerElementType() : From d19f4e99fb6f7a67b907519b4b46df9a64b138c1 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 16 Jul 2018 15:18:05 +0200 Subject: [PATCH 017/159] param_return: redundant code There is redundant code in param_return module which purpose is to cleverly identify parameters on stack. This is probably not wanted as it may unwillingly take arguments from stack which were not intended for called function. --- .../param_return/param_return.cpp | 82 +------------------ 1 file changed, 4 insertions(+), 78 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 29945dd5c..d8247aa39 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1238,91 +1238,17 @@ void DataFlowEntry::applyToIrOrdinary() for (auto& p : loadsOfCalls) { - retdec::utils::Maybe stackOff; - if (_abi->isX86()) - { - if (!p.second.empty()) - { - auto* l = cast(p.second.back()); - if (_config->isStackVariable(l->getPointerOperand())) - { - stackOff = _config->getStackVariableOffset(l->getPointerOperand()); - stackOff = stackOff + 4; - } - } - - if (stackOff.isUndefined()) - { - AsmInstruction ai(p.first); - while (ai.isValid()) - { - for (auto& i : ai) - { - if (auto* s = dyn_cast(&i)) - { - if (_config->isStackVariable(s->getPointerOperand())) - { - stackOff = _config->getStackVariableOffset(s->getPointerOperand()); - break; - } - } - } - if (stackOff.isDefined()) - { - break; - } - ai = ai.getPrev(); - } - } - } - std::size_t idx = 0; for (auto* t : argTypes) { (void) t; if (p.second.size() <= idx) { - if (_abi->isArm()) - { - if (idx < paramRegs.size()) - { - auto* r = _abi->getRegister(paramRegs[idx]); - auto* l = new LoadInst(r, "", p.first); - p.second.push_back(l); - } - } - else if (_abi->isMips()) - { - if (idx < paramRegs.size()) - { - auto* r = _abi->getRegister(paramRegs[idx]); - auto* l = new LoadInst(r, "", p.first); - p.second.push_back(l); - } - } - else if (_abi->isPowerPC()) + if (idx < paramRegs.size()) { - if (idx < paramRegs.size()) - { - auto* r = _abi->getRegister(paramRegs[idx]); - auto* l = new LoadInst(r, "", p.first); - p.second.push_back(l); - } - } - else if (_abi->isX86() - && stackOff.isDefined()) - { - auto* s = _config->getLlvmStackVariable(p.first->getFunction(), stackOff); - if (s) - { - auto* l = new LoadInst(s, "", p.first); - p.second.push_back(l); - stackOff = stackOff + 4; - } - else - { - stackOff.setUndefined(); - } + auto* r = _abi->getRegister(paramRegs[idx]); + auto* l = new LoadInst(r, "", p.first); + p.second.push_back(l); } } ++idx; From 4f8a1be19040b1436dbc3e3e5afa2ed9fa0172dc Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 12 Jul 2018 17:46:03 +0200 Subject: [PATCH 018/159] param_return_tests: get rid of unused register configuration Old module param_return used informations from configuraton but with change of usage abi there is no need to include register configuration in tests. --- .../param_return/param_return_tests.cpp | 195 +----------------- 1 file changed, 5 insertions(+), 190 deletions(-) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 539f39b2d..659e5e63d 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -253,13 +253,6 @@ TEST_F(ParamReturnTests, x86PtrCallOnlyStackStoresAreUsed) } ] } - ], - "registers" : [ - { - "name" : "eax", - "storage" : { "type" : "register", "value" : "eax", - "registerClass" : "gpr", "registerNumber" : 0 } - } ] })"); auto abi = AbiProvider::addAbi(module.get(), &config); @@ -956,19 +949,7 @@ TEST_F(ParamReturnTests, ppcPtrCallBasicFunctionality) "bitSize" : 32, "endian" : "big", "name" : "powerpc" - }, - "registers" : [ - { - "name" : "r3", - "storage" : { "type" : "register", "value" : "r3", - "registerClass" : "gpregs", "registerNumber" : 3 } - }, - { - "name" : "r4", - "storage" : { "type" : "register", "value" : "r4", - "registerClass" : "gpregs", "registerNumber" : 4 } - } - ] + } })"); auto abi = AbiProvider::addAbi(module.get(), &config); @@ -1017,19 +998,7 @@ TEST_F(ParamReturnTests, ppcExternalCallBasicFunctionality) "bitSize" : 32, "endian" : "big", "name" : "powerpc" - }, - "registers" : [ - { - "name" : "r3", - "storage" : { "type" : "register", "value" : "r3", - "registerClass" : "gpregs", "registerNumber" : 3 } - }, - { - "name" : "r4", - "storage" : { "type" : "register", "value" : "r4", - "registerClass" : "gpregs", "registerNumber" : 4 } - } - ] + } })"); auto abi = AbiProvider::addAbi(module.get(), &config); @@ -1120,24 +1089,7 @@ TEST_F(ParamReturnTests, ppcExternalCallFilterRegistersOnMultiplePlaces) "bitSize" : 32, "endian" : "big", "name" : "powerpc" - }, - "registers" : [ - { - "name" : "r3", - "storage" : { "type" : "register", "value" : "r3", - "registerClass" : "gpregs", "registerNumber" : 3 } - }, - { - "name" : "r4", - "storage" : { "type" : "register", "value" : "r4", - "registerClass" : "gpregs", "registerNumber" : 4 } - }, - { - "name" : "r5", - "storage" : { "type" : "register", "value" : "r5", - "registerClass" : "gpregs", "registerNumber" : 5 } - } - ] + } })"); auto abi = AbiProvider::addAbi(module.get(), &config); abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); @@ -1202,24 +1154,7 @@ TEST_F(ParamReturnTests, ppcExternalCallDoNotUseAllRegisters) "bitSize" : 32, "endian" : "big", "name" : "powerpc" - }, - "registers" : [ - { - "name" : "r1", - "storage" : { "type" : "register", "value" : "r1", - "registerClass" : "gpregs", "registerNumber" : 1 } - }, - { - "name" : "r2", - "storage" : { "type" : "register", "value" : "r2", - "registerClass" : "gpregs", "registerNumber" : 2 } - }, - { - "name" : "r3", - "storage" : { "type" : "register", "value" : "r3", - "registerClass" : "gpregs", "registerNumber" : 3 } - } - ] + } })"); auto abi = AbiProvider::addAbi(module.get(), &config); @@ -1274,24 +1209,7 @@ TEST_F(ParamReturnTests, ppcExternalCallSortRegistersIntoCorrectOrder) "bitSize" : 32, "endian" : "big", "name" : "powerpc" - }, - "registers" : [ - { - "name" : "r3", - "storage" : { "type" : "register", "value" : "r3", - "registerClass" : "gpregs", "registerNumber" : 3 } - }, - { - "name" : "r4", - "storage" : { "type" : "register", "value" : "r4", - "registerClass" : "gpregs", "registerNumber" : 4 } - }, - { - "name" : "r5", - "storage" : { "type" : "register", "value" : "r5", - "registerClass" : "gpregs", "registerNumber" : 5 } - } - ] + } })"); auto abi = AbiProvider::addAbi(module.get(), &config); @@ -1357,13 +1275,6 @@ TEST_F(ParamReturnTests, ppcExternalCallDoNotUseStacksIfLessThan7RegistersUsed) } ] } - ], - "registers" : [ - { - "name" : "r3", - "storage" : { "type" : "register", "value" : "r3", - "registerClass" : "gpregs", "registerNumber" : 3 } - } ] })"); auto abi = AbiProvider::addAbi(module.get(), &config); @@ -1444,48 +1355,6 @@ TEST_F(ParamReturnTests, ppcExternalCallUseStacksIf7RegistersUsed) } ] } - ], - "registers" : [ - { - "name" : "r3", - "storage" : { "type" : "register", "value" : "r3", - "registerClass" : "gpregs", "registerNumber" : 3 } - }, - { - "name" : "r4", - "storage" : { "type" : "register", "value" : "r4", - "registerClass" : "gpregs", "registerNumber" : 4 } - }, - { - "name" : "r5", - "storage" : { "type" : "register", "value" : "r5", - "registerClass" : "gpregs", "registerNumber" : 5 } - }, - { - "name" : "r6", - "storage" : { "type" : "register", "value" : "r6", - "registerClass" : "gpregs", "registerNumber" : 6 } - }, - { - "name" : "r7", - "storage" : { "type" : "register", "value" : "r7", - "registerClass" : "gpregs", "registerNumber" : 7 } - }, - { - "name" : "r8", - "storage" : { "type" : "register", "value" : "r8", - "registerClass" : "gpregs", "registerNumber" : 8 } - }, - { - "name" : "r9", - "storage" : { "type" : "register", "value" : "r9", - "registerClass" : "gpregs", "registerNumber" : 9 } - }, - { - "name" : "r10", - "storage" : { "type" : "register", "value" : "r10", - "registerClass" : "gpregs", "registerNumber" : 10 } - } ] })"); auto abi = AbiProvider::addAbi(module.get(), &config); @@ -1718,33 +1587,6 @@ TEST_F(ParamReturnTests, armExternalCallUseStacksIf4RegistersUsed) } ] } - ], - "registers" : [ - { - "name" : "r0", - "storage" : { "type" : "register", "value" : "r0", - "registerClass" : "regs", "registerNumber" : 0 } - }, - { - "name" : "r1", - "storage" : { "type" : "register", "value" : "r1", - "registerClass" : "regs", "registerNumber" : 1 } - }, - { - "name" : "r2", - "storage" : { "type" : "register", "value" : "r2", - "registerClass" : "regs", "registerNumber" : 2 } - }, - { - "name" : "r3", - "storage" : { "type" : "register", "value" : "r3", - "registerClass" : "regs", "registerNumber" : 3 } - }, - { - "name" : "r4", - "storage" : { "type" : "register", "value" : "r4", - "registerClass" : "regs", "registerNumber" : 4 } - } ] })"); auto abi = AbiProvider::addAbi(module.get(), &config); @@ -2025,33 +1867,6 @@ TEST_F(ParamReturnTests, mipsExternalCallUseStacksIf4RegistersUsed) } ] } - ], - "registers" : [ - { - "name" : "a0", - "storage" : { "type" : "register", "value" : "a0", - "registerClass" : "gpregs", "registerNumber" : 4 } - }, - { - "name" : "a1", - "storage" : { "type" : "register", "value" : "a1", - "registerClass" : "gpregs", "registerNumber" : 5 } - }, - { - "name" : "a2", - "storage" : { "type" : "register", "value" : "a2", - "registerClass" : "gpregs", "registerNumber" : 6 } - }, - { - "name" : "a3", - "storage" : { "type" : "register", "value" : "a3", - "registerClass" : "gpregs", "registerNumber" : 7 } - }, - { - "name" : "t0", - "storage" : { "type" : "register", "value" : "t0", - "registerClass" : "gpregs", "registerNumber" : 8 } - } ] })"); auto abi = AbiProvider::addAbi(module.get(), &config); From 01c246ced5abe936e7215abd9e86581df1a9e21f Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Fri, 27 Jul 2018 09:51:18 +0200 Subject: [PATCH 019/159] param_return: remove unnecessary comments --- src/bin2llvmir/optimizations/param_return/param_return.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index d8247aa39..b8db2edbf 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -153,8 +153,6 @@ bool ParamReturn::run() _RDA.runOnModule(*_module, AbiProvider::getAbi(_module)); -//dumpModuleToFile(_module); - collectAllCalls(); dumpInfo(); filterCalls(); @@ -163,9 +161,6 @@ bool ParamReturn::run() _RDA.clear(); -//dumpModuleToFile(_module); -//exit(1); - return false; } From 9468cea1739dee8d2469945fc4d25875169db4aa Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Fri, 27 Jul 2018 10:13:03 +0200 Subject: [PATCH 020/159] param_return_tests: remove misleading test Test expects that powerpc uses just 7 registers as parameters for function. The truth is that powerpc uses 8 registers and test forced module to generate incorrect output. --- .../param_return/param_return_tests.cpp | 111 ------------------ 1 file changed, 111 deletions(-) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 659e5e63d..a93107d37 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -1306,117 +1306,6 @@ TEST_F(ParamReturnTests, ppcExternalCallDoNotUseStacksIfLessThan7RegistersUsed) checkModuleAgainstExpectedIr(exp); } -TEST_F(ParamReturnTests, ppcExternalCallUseStacksIf7RegistersUsed) -{ - parseInput(R"( - @r3 = global i32 0 - @r4 = global i32 0 - @r5 = global i32 0 - @r6 = global i32 0 - @r7 = global i32 0 - @r8 = global i32 0 - @r9 = global i32 0 - @r10 = global i32 0 - declare void @print() - define void @fnc() { - %stack_-4 = alloca i32 - %stack_-8 = alloca i32 - store i32 1, i32* @r3 - store i32 1, i32* @r4 - store i32 1, i32* @r5 - store i32 2, i32* %stack_-4 - store i32 1, i32* @r6 - store i32 1, i32* @r7 - store i32 1, i32* @r8 - store i32 2, i32* %stack_-8 - store i32 1, i32* @r9 - store i32 1, i32* @r10 - call void @print() - ret void - } - )"); - auto config = Config::fromJsonString(module.get(), R"({ - "architecture" : { - "bitSize" : 32, - "endian" : "big", - "name" : "powerpc" - }, - "functions" : [ - { - "name" : "fnc", - "locals" : [ - { - "name" : "stack_-4", - "storage" : { "type" : "stack", "value" : -4 } - }, - { - "name" : "stack_-8", - "storage" : { "type" : "stack", "value" : -8 } - } - ] - } - ] - })"); - auto abi = AbiProvider::addAbi(module.get(), &config); - - abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); - abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); - abi->addRegister(PPC_REG_R5, getGlobalByName("r5")); - abi->addRegister(PPC_REG_R6, getGlobalByName("r6")); - abi->addRegister(PPC_REG_R7, getGlobalByName("r7")); - abi->addRegister(PPC_REG_R8, getGlobalByName("r8")); - abi->addRegister(PPC_REG_R9, getGlobalByName("r9")); - abi->addRegister(PPC_REG_R10, getGlobalByName("r10")); - - pass.runOnModuleCustom(*module, &config, abi); - - std::string exp = R"( - @r3 = global i32 0 - @r4 = global i32 0 - @r5 = global i32 0 - @r6 = global i32 0 - @r7 = global i32 0 - @r8 = global i32 0 - @r9 = global i32 0 - @r10 = global i32 0 - - declare i32 @print(i32, i32, i32, i32, i32, i32, i32, i32, i32) - - declare void @0() - - define i32 @fnc() { - %stack_-4 = alloca i32 - %stack_-8 = alloca i32 - store i32 1, i32* @r3 - store i32 1, i32* @r4 - store i32 1, i32* @r5 - store i32 2, i32* %stack_-4 - store i32 1, i32* @r6 - store i32 1, i32* @r7 - store i32 1, i32* @r8 - store i32 2, i32* %stack_-8 - store i32 1, i32* @r9 - store i32 1, i32* @r10 - %1 = load i32, i32* @r3 - %2 = load i32, i32* @r4 - %3 = load i32, i32* @r5 - %4 = load i32, i32* @r6 - %5 = load i32, i32* @r7 - %6 = load i32, i32* @r8 - %7 = load i32, i32* @r9 - %8 = load i32, i32* %stack_-8 - %9 = load i32, i32* %stack_-4 - %10 = call i32 @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9) - store i32 %10, i32* @r3 - %11 = load i32, i32* @r3 - ret i32 %11 - } - - declare void @1() - )"; - checkModuleAgainstExpectedIr(exp); -} - // // std::string exp = R"( // @r = global i32 0 From 16d7795df106a01c57043ee42f2edbe17cf4831a Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Fri, 27 Jul 2018 10:47:43 +0200 Subject: [PATCH 021/159] param_return: rename method filterRegisters Method filterRegisters() is filtering all values, not just registers and thus shuld jave appropriate name. --- .../bin2llvmir/optimizations/param_return/param_return.h | 2 +- src/bin2llvmir/optimizations/param_return/param_return.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 4038a9702..944297a5c 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -31,7 +31,7 @@ class CallEntry CallEntry(llvm::CallInst* c); public: - void filterRegisters(Abi* _abi); + void filterStoreValues(Abi* _abi); void filterSort(Config* _config, Abi* _abi); void filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi *_abi); void filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi); diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index b8db2edbf..dca025e8f 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -278,7 +278,7 @@ CallEntry::CallEntry(llvm::CallInst* c) : /** * Remove all registers that are not used to pass argument according to ABI. */ -void CallEntry::filterRegisters(Abi* _abi) +void CallEntry::filterStoreValues(Abi* _abi) { auto it = possibleArgStores.begin(); while (it != possibleArgStores.end()) @@ -916,7 +916,7 @@ void DataFlowEntry::filter() for (CallEntry& e : calls) { - e.filterRegisters(_abi); + e.filterStoreValues(_abi); e.filterSort(_config, _abi); e.filterLeaveOnlyContinuousStackOffsets(_config, _abi); e.filterLeaveOnlyNeededStackOffsets(_config, _abi); From 5148b839c92abb7d7323a01c37d7281fe3cb69a1 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Fri, 27 Jul 2018 10:50:11 +0200 Subject: [PATCH 022/159] param_return: use remove_if instead of manually searching vector --- .../param_return/param_return.cpp | 54 ++++++++----------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index dca025e8f..d947c5ac6 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -280,44 +280,32 @@ CallEntry::CallEntry(llvm::CallInst* c) : */ void CallEntry::filterStoreValues(Abi* _abi) { - auto it = possibleArgStores.begin(); - while (it != possibleArgStores.end()) - { - auto* op = (*it)->getPointerOperand(); - if (_abi->valueCanBeParameter(op) == false) - { - it = possibleArgStores.erase(it); - } - else - { - ++it; - } - } + possibleArgStores.erase( + std::remove_if(possibleArgStores.begin(), possibleArgStores.end(), + [_abi](const StoreInst* si) + { + auto op = si->getPointerOperand(); + return !_abi->valueCanBeParameter(op); + }), + possibleArgStores.end()); } void DataFlowEntry::filterRegistersArgLoads() { - auto it = argLoads.begin(); - while (it != argLoads.end()) - { - auto* op = (*it)->getPointerOperand(); - if (_abi->valueCanBeParameter(op) == false) - { - it = argLoads.erase(it); - } - else - { - auto aOff = _config->getStackVariableOffset(op); - if (aOff.isDefined() && aOff < 0) + argLoads.erase( + std::remove_if(argLoads.begin(), argLoads.end(), + [this](const LoadInst* li) { - it = argLoads.erase(it); - } - else - { - ++it; - } - } - } + auto* op = li->getPointerOperand(); + if (_abi->valueCanBeParameter(op)) + { + auto aOff = _config->getStackVariableOffset(op); + return aOff.isDefined() && aOff < 0; + } + + return true; + }), + argLoads.end()); } /** From a7091edf43ab49d39d83ab12c73dcac6b5830838 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 1 Aug 2018 08:04:54 +0200 Subject: [PATCH 023/159] param_return: remove redundant code --- .../param_return/param_return.cpp | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index d947c5ac6..6ba9f492a 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -718,32 +718,6 @@ void DataFlowEntry::addRetStores() void DataFlowEntry::addCall(llvm::CallInst* call) { - // Pattern: - // bc pc // call prantf() - // align 4 - // prantf(): - // ... - // Call has no args because it is stub, if we let it, it will destroy - // all arg from all other calls. - // - // TODO: - // => ignore - this is an ugly hack, solve somehow better. - // - if (_abi->isArm()) - { - if (auto ai = AsmInstruction(call)) - { - auto* cs = ai.getCapstoneInsn(); - if ((cs->id == ARM_INS_B || cs->id == ARM_INS_BX) - && cs->detail->arm.op_count == 1 - && cs->detail->arm.operands[0].type == ARM_OP_REG - && cs->detail->arm.operands[0].reg == ARM_REG_PC) - { - return; - } - } - } - CallEntry ce(call); addCallArgs(call, ce); From 324b5ceb809107dbefcca5bba99810b5ef4a5e55 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 1 Aug 2018 10:15:26 +0200 Subject: [PATCH 024/159] param_return: remove code based on bad assumption This code assumes that paramter registers will be returned from abi sorted from lowest to highest. This is not true as values of regsiters are dependent on their value in capstone. --- .../param_return/param_return.cpp | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 6ba9f492a..108d9fb21 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -918,31 +918,6 @@ void DataFlowEntry::filter() } } } - else - { - if (_abi->isArm()) - { - auto armRegs = _abi->parameterRegisters(); - - for (CallEntry& e : calls) - { - std::size_t idx = 0; - auto sIt = e.possibleArgStores.begin(); - while (sIt != e.possibleArgStores.end() && idx < armRegs.size()) - { - StoreInst* s = *sIt; - if (_abi->getRegisterId(s->getPointerOperand()) != armRegs[idx]) - { - e.possibleArgStores.erase(sIt, e.possibleArgStores.end()); - break; - } - - ++sIt; - ++idx; - } - } - } - } setTypeFromUseContext(); } From 8337e7bf6a13dd08dc4ca2e142540e3f98ede7c8 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 13:23:12 +0200 Subject: [PATCH 025/159] param_return: refactor generation of params in variadic functions --- .../param_return/param_return.cpp | 147 ++++-------------- 1 file changed, 27 insertions(+), 120 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 108d9fb21..8876ccaa6 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1210,13 +1210,8 @@ void DataFlowEntry::applyToIrOrdinary() void DataFlowEntry::applyToIrVariadic() { auto paramRegs = _abi->parameterRegisters(); - - static std::vector mipsFpRegs = { - MIPS_REG_FD12, - MIPS_REG_FD14, - MIPS_REG_FD16, - MIPS_REG_FD18, - MIPS_REG_FD20}; + auto paramFPRegs = _abi->parameterFPRegisters(); + auto doubleParamRegs = _abi->doubleParameterRegisters(); llvm::Value* retVal = nullptr; std::map rets2vals; @@ -1284,140 +1279,52 @@ void DataFlowEntry::applyToIrVariadic() int sz = static_cast(_abi->getTypeByteSize(t)); sz = sz > 4 ? 8 : 4; - if (_abi->isX86()) + if (t->isFloatTy() && _abi->usesFPRegistersForParameters() && faIdx < paramFPRegs.size()) { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) + + auto* r = _abi->getRegister(paramFPRegs[faIdx]); + if (r) { - args.push_back(st); + args.push_back(r); } - - off += sz; + ++faIdx; } - else if (_abi->isPowerPC()) + else if (t->isDoubleTy() && _abi->usesFPRegistersForParameters() && faIdx < doubleParamRegs.size()) { - if (aIdx < paramRegs.size()) + auto* r = _abi->getRegister(doubleParamRegs[faIdx]); + if (r) { - auto* r = _abi->getRegister(paramRegs[aIdx]); - if (r) - { - args.push_back(r); - } - } - else - { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) - { - args.push_back(st); - } - - off += sz; + args.push_back(r); } + ++faIdx; + ++faIdx; } - else if (_abi->isArm()) + else if (aIdx < paramRegs.size()) { - if (aIdx < paramRegs.size()) + auto* r = _abi->getRegister(paramRegs[aIdx]); + if (r) { - auto* r = _abi->getRegister(paramRegs[aIdx]); - if (r) - { - args.push_back(r); - } - - if (sz > 4) - { - ++aIdx; - } + args.push_back(r); } - else - { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) - { - args.push_back(st); - } - off += sz; - } - } - else if (_config->getConfig().architecture.isPic32()) - { - if (aIdx < paramRegs.size()) + // TODO: register pairs -> if size is more than arch size + if (sz > ws) { - auto* r = _abi->getRegister(paramRegs[aIdx]); - if (r) - { - args.push_back(r); - } + ++aIdx; } - else - { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) - { - args.push_back(st); - } - off += sz; - } + ++aIdx; } - else if (_abi->isMips()) + else { - bool useStack = false; - if (t->isFloatingPointTy()) - { - --aIdx; - - if (faIdx < mipsFpRegs.size()) - { - auto* r = _abi->getRegister(mipsFpRegs[faIdx]); - if (r) - { - args.push_back(r); - } - - if (sz > 4) - { - ++faIdx; - } - } - else - { - useStack = true; - } - - ++faIdx; - } - else + auto* st = _config->getLlvmStackVariable(fnc, off); + if (st) { - if (aIdx < paramRegs.size()) - { - auto* r = _abi->getRegister(paramRegs[aIdx]); - if (r) - { - args.push_back(r); - } - } - else - { - useStack = true; - } + args.push_back(st); } - if (useStack) - { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) - { - args.push_back(st); - } - - off += sz; - } + off += sz; } - - ++aIdx; } // From 4043c2023455d8e229fa49b06da60ff2a47e70ca Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 17 Oct 2018 11:50:19 +0200 Subject: [PATCH 026/159] abi/x64: provide support for Intel x86-64 Provides support for Intel x86-64 architecture. Specifically represents System V ABI and conventions that are present in this ABI. --- include/retdec/bin2llvmir/providers/abi/x64.h | 37 +++++ src/bin2llvmir/CMakeLists.txt | 1 + src/bin2llvmir/providers/abi/x64.cpp | 127 ++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/abi/x64.h create mode 100644 src/bin2llvmir/providers/abi/x64.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/x64.h b/include/retdec/bin2llvmir/providers/abi/x64.h new file mode 100644 index 000000000..529e300c3 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/x64.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/x86_64.h + * @brief ABI information for x86_64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_X64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_X64_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiX64 : public Abi +{ + // Ctors, dtors. + // + public: + AbiX64(llvm::Module* m, Config* c); + virtual ~AbiX64(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 7153ce913..49556a742 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -70,6 +70,7 @@ set(BIN2LLVMIR_SOURCES providers/abi/pic32.cpp providers/abi/powerpc.cpp providers/abi/x86.cpp + providers/abi/x64.cpp providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/providers/abi/x64.cpp b/src/bin2llvmir/providers/abi/x64.cpp new file mode 100644 index 000000000..d00c38a58 --- /dev/null +++ b/src/bin2llvmir/providers/abi/x64.cpp @@ -0,0 +1,127 @@ +/** + * @file src/bin2llvmir/providers/abi/x86_64.cp + * @brief ABI information for x86_64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/x64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiX64::AbiX64(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _fpRegsAsParams = true; + _regs.reserve(X86_REG_ENDING); + _id2regs.resize(X86_REG_ENDING, nullptr); + _regStackPointerId = X86_REG_RSP; + + // system calls + _regSyscallId = X86_REG_EAX; + _regSyscallReturn = X86_REG_EAX; + _syscallRegs = { + X86_REG_RDI, + X86_REG_RSI, + X86_REG_RDX, + X86_REG_R10, + X86_REG_R8, + X86_REG_R9}; + + _paramRegs = { + X86_REG_RDI, + X86_REG_RSI, + X86_REG_RDX, + X86_REG_RCX, + X86_REG_R8, + X86_REG_R9}; + + _paramFPRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3, + X86_REG_XMM4, + X86_REG_XMM5, + X86_REG_XMM6, + X86_REG_XMM7 + }; + + _regReturn = X86_REG_RAX; + + _regFPReturn = X86_REG_ST0; +} + +AbiX64::~AbiX64() +{ +} + +bool AbiX64::isGeneralPurposeRegister(const llvm::Value* val) +{ + uint32_t rid = getRegisterId(val); + return rid == X86_REG_RAX + || rid == X86_REG_RBX + || rid == X86_REG_RCX + || rid == X86_REG_RDX + || rid == X86_REG_RSP + || rid == X86_REG_RBP + || rid == X86_REG_RSI + || rid == X86_REG_RDI + || rid == X86_REG_R8 + || rid == X86_REG_R9 + || rid == X86_REG_R10 + || rid == X86_REG_R11 + || rid == X86_REG_R12 + || rid == X86_REG_R13 + || rid == X86_REG_R14 + || rid == X86_REG_R15; +} + +bool AbiX64::isNopInstruction(cs_insn* insn) +{ + cs_x86& insn86 = insn->detail->x86; + + // True NOP variants. + // + if (insn->id == X86_INS_NOP + || insn->id == X86_INS_FNOP + || insn->id == X86_INS_FDISI8087_NOP + || insn->id == X86_INS_FENI8087_NOP + || insn->id == X86_INS_INT3) + { + return true; + } + // e.g. lea esi, [esi] + // + else if (insn->id == X86_INS_LEA + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_MEM + && insn86.operands[1].mem.segment == X86_REG_INVALID + && insn86.operands[1].mem.index == X86_REG_INVALID + && insn86.operands[1].mem.scale == 1 + && insn86.operands[1].mem.disp == 0 + && insn86.operands[1].mem.base == insn86.operands[0].reg) + { + return true; + } + // e.g. mov esi. esi + // + else if (insn->id == X86_INS_MOV + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_REG + && insn86.operands[0].reg == insn86.operands[1].reg) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec From 743934e7bdcfcb11802f97fdb5db620d1af9566d Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 1 Aug 2018 16:41:00 +0200 Subject: [PATCH 027/159] abi: provide support for Intel x64 architecutre Provides integration of class Abi X64 into general class ABI. --- src/bin2llvmir/providers/abi/abi.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index c1c8bcb4d..e745b9f4f 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -9,6 +9,7 @@ #include "retdec/bin2llvmir/providers/abi/mips.h" #include "retdec/bin2llvmir/providers/abi/powerpc.h" #include "retdec/bin2llvmir/providers/abi/x86.h" +#include "retdec/bin2llvmir/providers/abi/x64.h" #include "retdec/bin2llvmir/providers/abi/pic32.h" using namespace llvm; @@ -299,6 +300,11 @@ Abi* AbiProvider::addAbi( auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); } + else if (c->getConfig().architecture.isX86_64()) + { + auto p = _module2abi.emplace(m, std::make_unique(m, c)); + return p.first->second.get(); + } else if (c->getConfig().architecture.isX86()) { auto p = _module2abi.emplace(m, std::make_unique(m, c)); From 83c8fa891771d105717913c96eba8fec832012dc Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 6 Aug 2018 15:24:29 +0200 Subject: [PATCH 028/159] param_return_tests: x64 unit tests This commit proived suport for testing of parameter analysis of x64 binary files. --- .../param_return/param_return_tests.cpp | 410 ++++++++++++++++++ 1 file changed, 410 insertions(+) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index a93107d37..eb3ba5444 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -878,6 +878,416 @@ TEST_F(ParamReturnTests, x86ExternalCallFixOnMultiplePlaces) // )"; // checkModuleAgainstExpectedIr(exp); //} + +TEST_F(ParamReturnTests, x86_64PtrCallBasicFunctionality) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rax = global i64 0 + define void @fnc() { + store i64 123, i64* @rdi + store i64 456, i64* @rsi + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RDI, getGlobalByName("rdi")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rax = global i64 0 + + define i64 @fnc() { + store i64 123, i64* @rdi + store i64 456, i64* @rsi + %a = bitcast i64* @r to void()* + %1 = load i64, i64* @rdi + %2 = load i64, i64* @rsi + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @rax + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86_64PtrCallPrevBbIsUsedOnlyIfItIsASinglePredecessor) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rax = global i64 0 + + define void @fnc() { + br label %lab1 + lab1: + store i64 123, i64* @rdi + br label %lab2 + lab2: + store i64 456, i64* @rsi + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + } + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RDI, getGlobalByName("rdi")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rax = global i64 0 + + define i64 @fnc() { + br label %lab1 + + lab1: + store i64 123, i64* @rdi + br label %lab2 + + lab2: + store i64 456, i64* @rsi + %a = bitcast i64* @r to void ()* + %1 = load i64, i64* @rdi + %2 = load i64, i64* @rsi + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @rax + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86_64ExternalCallUseStacksIf6RegistersUsed) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @r10 = global i64 0 + @rax = global i64 0 + declare void @print() + define void @fnc() { + store i64 1, i64* @rdi + %stack_-8 = alloca i64 + %stack_-16 = alloca i64 + store i64 1, i64* @r9 + store i64 2, i64* @r10 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store i64 2, i64* %stack_-8 + store i64 1, i64* @rdx + store i64 2, i64* %stack_-16 + store i64 1, i64* @rcx + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + }, + { + "name" : "stack_-16", + "storage" : { "type" : "stack", "value" : -16 } + } + + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_RDI, getGlobalByName("rdi")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); + abi->addRegister(X86_REG_R10, getGlobalByName("r10")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @r10 = global i64 0 + @rax = global i64 0 + + declare i64 @print(i64, i64, i64, i64, i64, i64, i64, i64) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @rdi + %stack_-8 = alloca i64 + %stack_-16 = alloca i64 + store i64 1, i64* @r9 + store i64 2, i64* @r10 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store i64 2, i64* %stack_-8 + store i64 1, i64* @rdx + store i64 2, i64* %stack_-16 + store i64 1, i64* @rcx + %1 = load i64, i64* @rdi + %2 = load i64, i64* @rsi + %3 = load i64, i64* @rdx + %4 = load i64, i64* @rcx + %5 = load i64, i64* @r8 + %6 = load i64, i64* @r9 + %7 = load i64, i64* %stack_-16 + %8 = load i64, i64* %stack_-8 + %9 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i64 %8) + store i64 %9, i64* @rax + %10 = load i64, i64* @rax + ret i64 %10 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86_64ExternalCallUsesFPRegisters) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @r10 = global i64 0 + @rax = global i64 0 + @xmm0 = global double 0.0 + @xmm1 = global double 0.0 + + declare void @print() + define void @fnc() { + store i64 1, i64* @rdi + store i64 1, i64* @r9 + store i64 2, i64* @r10 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store double 2.0, double* @xmm1 + store i64 1, i64* @rdx + store double 2.0, double* @xmm0 + store i64 1, i64* @rcx + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + } + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_RDI, getGlobalByName("rdi")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); + abi->addRegister(X86_REG_R10, getGlobalByName("r10")); + abi->addRegister(X86_REG_XMM0, getGlobalByName("xmm0")); + abi->addRegister(X86_REG_XMM1, getGlobalByName("xmm1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @r10 = global i64 0 + @rax = global i64 0 + @xmm0 = global double 0.000000e+00 + @xmm1 = global double 0.000000e+00 + + declare i64 @print(i64, i64, i64, i64, i64, i64, float, float) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @rdi + store i64 1, i64* @r9 + store i64 2, i64* @r10 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store double 2.000000e+00, double* @xmm1 + store i64 1, i64* @rdx + store double 2.000000e+00, double* @xmm0 + store i64 1, i64* @rcx + %1 = load i64, i64* @rdi + %2 = load i64, i64* @rsi + %3 = load i64, i64* @rdx + %4 = load i64, i64* @rcx + %5 = load i64, i64* @r8 + %6 = load i64, i64* @r9 + %7 = load double, double* @xmm0 + %8 = load double, double* @xmm1 + %9 = fptrunc double %7 to float + %10 = fptrunc double %8 to float + %11 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, float %9, float %10) + store i64 %11, i64* @rax + %12 = load i64, i64* @rax + ret i64 %12 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86_64UsesJustContinuousSequenceOfRegisters) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + + declare void @print() + define void @fnc() { + store i64 1, i64* @rdi + store i64 1, i64* @rdx + store i64 1, i64* @rcx + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_RDI, getGlobalByName("rdi")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + + declare i64 @print(i64) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @rdi + store i64 1, i64* @rdx + store i64 1, i64* @rcx + %1 = load i64, i64* @rdi + %2 = call i64 @print(i64 %1) + store i64 %2, i64* @rax + %3 = load i64, i64* @rax + ret i64 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + // //TEST_F(ParamReturnTests, x86PtrCallOnlyContinuousStackOffsetsAreUsed) //{ From 31696ed1c223d016acbe184e9dfe7fc411591afe Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 16 Aug 2018 12:59:00 +0200 Subject: [PATCH 029/159] retdec-decompiler: make x64 files go through --- scripts/retdec-decompiler.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/retdec-decompiler.py b/scripts/retdec-decompiler.py index b03bfd7ef..5c00cad23 100644 --- a/scripts/retdec-decompiler.py +++ b/scripts/retdec-decompiler.py @@ -38,8 +38,8 @@ def parse_args(args): parser.add_argument('-a', '--arch', dest='arch', metavar='ARCH', - choices=['mips', 'pic32', 'arm', 'thumb', 'powerpc', 'x86'], - help='Specify target architecture [mips|pic32|arm|thumb|powerpc|x86].' + choices=['mips', 'pic32', 'arm', 'thumb', 'powerpc', 'x86', 'x86-64'], + help='Specify target architecture [mips|pic32|arm|thumb|powerpc|x86|x86-64].' ' Required if it cannot be autodetected from the input (e.g. raw mode, Intel HEX).') parser.add_argument('-e', '--endian', @@ -907,7 +907,7 @@ def decompile(self): # Check whether the correct target architecture was specified. if self.arch in ['arm', 'thumb']: ords_dir = config.ARM_ORDS_DIR - elif self.arch in ['x86']: + elif self.arch in ['x86', 'x86-64']: ords_dir = config.X86_ORDS_DIR elif self.arch in ['powerpc', 'mips', 'pic32']: pass @@ -917,20 +917,20 @@ def decompile(self): self._cleanup() utils.print_error('Unsupported target architecture \'%s\'. Supported architectures: ' - 'Intel x86, ARM, ARM + Thumb, MIPS, PIC32, PowerPC.' % self.arch) + 'Intel x86, Intel x86-64, ARM, ARM + Thumb, MIPS, PIC32, PowerPC.' % self.arch) return 1 # Check file class (e.g. 'ELF32', 'ELF64'). At present, we can only decompile 32-bit files. # Note: we prefer to report the 'unsupported architecture' error (above) than this 'generic' error. fileclass, _, _ = CmdRunner.run_cmd([config.CONFIGTOOL, self.config_file, '--read', '--file-class'], buffer_output=True) - if fileclass not in ['16', '32']: + if fileclass not in ['16', '32', '64']: if self.args.generate_log: self._generate_log() self._cleanup() utils.print_error( - 'Unsupported target format \'%s%s\'. Supported formats: ELF32, PE32, Intel HEX 32, Mach-O 32.' % ( + 'Unsupported target format \'%s%s\'. Supported formats: ELF32, ELF64, PE32, Intel HEX 32, Mach-O 32.' % ( self.format.upper(), fileclass)) return 1 From afb1e064e5c3025eba749e3e9819f30f55a8e5a5 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 7 Aug 2018 10:52:53 +0200 Subject: [PATCH 030/159] param_return: detect type of parameter --- .../optimizations/param_return/param_return.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 8876ccaa6..e54d4b697 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1772,10 +1772,19 @@ void DataFlowEntry::setArgumentTypes() } } - argTypes.insert( - argTypes.end(), - ce->possibleArgStores.size(), - Abi::getDefaultType(_module)); + for (auto st: ce->possibleArgStores) + { + auto op = st->getPointerOperand(); + + if (_abi->isRegister(op) && !_abi->isGeneralPurposeRegister(op)) + { + argTypes.push_back(Abi::getDefaultFPType(_module)); + } + else + { + argTypes.push_back(Abi::getDefaultType(_module)); + } + } } } From 890ea38ecad485fb6917326d7d6c5a8ce6d62fe5 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 7 Aug 2018 13:58:05 +0200 Subject: [PATCH 031/159] param_return: correct filtering of stack offsets --- .../param_return/param_return.cpp | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index e54d4b697..916a61531 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -417,7 +417,9 @@ void CallEntry::filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi* _abi void CallEntry::filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi) { size_t regNum = 0; + size_t fpRegNum = 0; auto it = possibleArgStores.begin(); + while (it != possibleArgStores.end()) { auto* s = *it; @@ -426,7 +428,18 @@ void CallEntry::filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi) if (_abi->isRegister(op)) { - ++regNum; + if (_abi->isGeneralPurposeRegister(op)) + { + ++regNum; + } + else + { + if (_abi->usesFPRegistersForParameters()) + { + fpRegNum++; + } + } + ++it; continue; } @@ -434,6 +447,13 @@ void CallEntry::filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi) { if (regNum < _abi->parameterRegisters().size()) { + if (_abi->usesFPRegistersForParameters() + && fpRegNum >= _abi->parameterFPRegisters().size()) + { + ++it; + continue; + } + it = possibleArgStores.erase(it); continue; } From 4efb408e5ed13a15487a5b117f0a727ea3343d44 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 8 Aug 2018 13:00:03 +0200 Subject: [PATCH 032/159] param_return: small refactor --- src/bin2llvmir/optimizations/param_return/param_return.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 916a61531..b3a06707d 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -815,9 +815,7 @@ void DataFlowEntry::addCallArgs(llvm::CallInst* call, CallEntry& ce) } } - if (disqualifiedValues.hasNot(ptr) - && !_abi->isFlagRegister(ptr) - && (isa(ptr) || _abi->isRegister(ptr))) + if (disqualifiedValues.hasNot(ptr)) { ce.possibleArgStores.push_back(store); disqualifiedValues.insert(ptr); From 12b8b4be45a93b5c801cfbd8cc9bf46e19cbe097 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 12:51:00 +0200 Subject: [PATCH 033/159] param_return: new arguments collection algorithm Old algorithm searched for arguments only in one basic block. This algorithm recursively searhes parent blocks and filters found argument sotres by adding found arguments in current block with intersection of found arguments in all parent blocks. Algorithm counts on possible recursive call of blocks and thus uses seenBlocks vector containing all seen blocks. in current branch. This vector is copied to every recursively called branch. --- .../optimizations/param_return/param_return.h | 12 +- .../param_return/param_return.cpp | 307 +++++++++++------- 2 files changed, 201 insertions(+), 118 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 944297a5c..c426d8d4a 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -21,6 +21,7 @@ #include "retdec/bin2llvmir/providers/debugformat.h" #include "retdec/bin2llvmir/providers/fileimage.h" #include "retdec/bin2llvmir/providers/lti.h" +#include "retdec/utils/container.h" namespace retdec { namespace bin2llvmir { @@ -37,9 +38,14 @@ class CallEntry void filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi); void extractFormatString(ReachingDefinitionsAnalysis& _RDA); + bool instructionStoresString( + llvm::StoreInst *si, + std::string& str, + ReachingDefinitionsAnalysis &_RDA) const; public: llvm::CallInst* call = nullptr; + std::vector possibleArgs; std::vector possibleArgStores; std::vector possibleRetLoads; std::string formatStr; @@ -89,6 +95,11 @@ class DataFlowEntry void addCallArgs(llvm::CallInst* call, CallEntry& ce); void addCallReturns(llvm::CallInst* call, CallEntry& ce); + std::set collectArgsFromInstruction( + llvm::Instruction* startInst, + std::map> &seenBlocks, + std::vector *possibleArgStores = nullptr); + void callsFilterCommonRegisters(); void callsFilterSameNumberOfStacks(); @@ -157,7 +168,6 @@ class ParamReturn : public llvm::ModulePass void dumpInfo(); void collectAllCalls(); - std::string extractFormatString(llvm::CallInst* call); void filterCalls(); void filterSort(CallEntry& ce); diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index b3a06707d..94e396a59 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -280,14 +281,13 @@ CallEntry::CallEntry(llvm::CallInst* c) : */ void CallEntry::filterStoreValues(Abi* _abi) { - possibleArgStores.erase( - std::remove_if(possibleArgStores.begin(), possibleArgStores.end(), - [_abi](const StoreInst* si) + possibleArgs.erase( + std::remove_if(possibleArgs.begin(), possibleArgs.end(), + [_abi](const Value* v) { - auto op = si->getPointerOperand(); - return !_abi->valueCanBeParameter(op); + return !_abi->valueCanBeParameter(v); }), - possibleArgStores.end()); + possibleArgs.end()); } void DataFlowEntry::filterRegistersArgLoads() @@ -313,20 +313,19 @@ void DataFlowEntry::filterRegistersArgLoads() */ void CallEntry::filterSort(Config* _config, Abi* _abi) { - auto& stores = possibleArgStores; + auto& stores = possibleArgs; std::stable_sort( stores.begin(), stores.end(), - [_config, _abi](StoreInst* a, StoreInst* b) -> bool + [_config, _abi](Value* a, Value* b) -> bool { - auto aOff = _config->getStackVariableOffset(a->getPointerOperand()); - auto bOff = _config->getStackVariableOffset(b->getPointerOperand()); + auto aOff = _config->getStackVariableOffset(a); + auto bOff = _config->getStackVariableOffset(b); if (aOff.isUndefined() && bOff.isUndefined()) { - return _abi->getRegisterId(a->getPointerOperand()) < - _abi->getRegisterId(b->getPointerOperand()); + return _abi->getRegisterId(a) < _abi->getRegisterId(b); } else if (aOff.isUndefined() && bOff.isDefined()) { @@ -355,7 +354,6 @@ void DataFlowEntry::filterSortArgLoads() if (aOff.isUndefined() && bOff.isUndefined()) { - return _abi->getRegisterId(a->getPointerOperand()) < _abi->getRegisterId(b->getPointerOperand()); } @@ -381,15 +379,15 @@ void DataFlowEntry::filterSortArgLoads() void CallEntry::filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi* _abi) { retdec::utils::Maybe prevOff; - auto it = possibleArgStores.begin(); - while (it != possibleArgStores.end()) + auto it = possibleArgs.begin(); + while (it != possibleArgs.end()) { auto* s = *it; - auto off = _config->getStackVariableOffset(s->getPointerOperand()); - auto* val = llvm_utils::skipCasts(s->getValueOperand()); + auto off = _config->getStackVariableOffset(s); + //auto* val = llvm_utils::skipCasts(s); - int gap = _abi->getTypeByteSize(val->getType())*2; - // static int gap = _abi->wordSize()*2/8; + // int gap = _abi->getTypeByteSize(val->getType())*2; + static int gap = _abi->wordSize()*2/8; if (off.isUndefined()) { @@ -402,7 +400,7 @@ void CallEntry::filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi* _abi } else if (std::abs(prevOff - off) > gap) { - it = possibleArgStores.erase(it); + it = possibleArgs.erase(it); continue; } else @@ -418,12 +416,11 @@ void CallEntry::filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi) { size_t regNum = 0; size_t fpRegNum = 0; - auto it = possibleArgStores.begin(); + auto it = possibleArgs.begin(); - while (it != possibleArgStores.end()) + while (it != possibleArgs.end()) { - auto* s = *it; - auto* op = s->getPointerOperand(); + auto* op = *it; auto off = _config->getStackVariableOffset(op); if (_abi->isRegister(op)) @@ -454,7 +451,7 @@ void CallEntry::filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi) continue; } - it = possibleArgStores.erase(it); + it = possibleArgs.erase(it); continue; } } @@ -465,35 +462,24 @@ void CallEntry::filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi) void CallEntry::extractFormatString(ReachingDefinitionsAnalysis& _RDA) { - for (auto* s : possibleArgStores) + for (auto i : possibleArgs) { - auto* v = getRoot(_RDA, s->getValueOperand()); - auto* gv = dyn_cast_or_null(v); - - if (gv == nullptr || !gv->hasInitializer()) - { - continue; - } + auto inst = std::find_if(possibleArgStores.begin(), + possibleArgStores.end(), + [i](StoreInst *st) + { + return st->getPointerOperand() == i; + }); - auto* init = dyn_cast_or_null(gv->getInitializer()); - if (init == nullptr) + if (inst != possibleArgStores.end()) { - if (auto* i = dyn_cast(gv->getInitializer())) + std::string str; + if (instructionStoresString(*inst, str, _RDA)) { - if (auto* igv = dyn_cast(i->getOperand(0))) - { - init = dyn_cast_or_null(igv->getInitializer()); - } + formatStr = str; + return; } } - - if (init == nullptr || !init->isString()) - { - continue; - } - - formatStr = init->getAsString(); - break; } } @@ -598,7 +584,7 @@ void DataFlowEntry::dump() const { LOG << "\t\t>|" << llvmObjToString(e.call) << std::endl; LOG << "\t\t\targ stores:" << std::endl; - for (auto* s : e.possibleArgStores) + for (auto* s : e.possibleArgs) { LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; } @@ -746,54 +732,38 @@ void DataFlowEntry::addCall(llvm::CallInst* call) calls.push_back(ce); } -void DataFlowEntry::addCallArgs(llvm::CallInst* call, CallEntry& ce) +// std::vector? +std::set DataFlowEntry::collectArgsFromInstruction(Instruction* startInst, std::map> &seenBlocks, std::vector *possibleArgStores) { - NonIterableSet disqualifiedValues; - auto* b = call->getParent(); - Instruction* prev = call; - std::set seen; - seen.insert(b); - while (true) + NonIterableSet excludedValues; + auto* block = startInst->getParent(); + + std::set argStores; + + bool canContinue = true; + for (auto* inst = startInst; canContinue; inst = inst->getPrevNode()) { - if (prev == &b->front()) + if (inst == nullptr) { - auto* spb = b->getSinglePredecessor(); - if (spb && !spb->empty() && spb != b && seen.count(spb) == 0) - { - b = spb; - prev = &b->back(); - seen.insert(b); - } - else - { - break; - } - } - else - { - prev = prev->getPrevNode(); - } - if (prev == nullptr) - { - break; + return argStores; } - if (auto* call = dyn_cast(prev)) + if (auto* call = dyn_cast(inst)) { auto* calledFnc = call->getCalledFunction(); if (calledFnc == nullptr || !calledFnc->isIntrinsic()) { - break; + return argStores; } } - else if (auto* store = dyn_cast(prev)) + else if (auto* store = dyn_cast(inst)) { auto* val = store->getValueOperand(); auto* ptr = store->getPointerOperand(); if (!_abi->valueCanBeParameter(ptr)) { - disqualifiedValues.insert(ptr); + excludedValues.insert(ptr); } if (auto* l = dyn_cast(val)) @@ -803,26 +773,129 @@ void DataFlowEntry::addCallArgs(llvm::CallInst* call, CallEntry& ce) if (_abi->getRegisterId(l->getPointerOperand()) == X86_REG_EBP || _abi->getRegisterId(l->getPointerOperand()) == X86_REG_RBP) { - disqualifiedValues.insert(ptr); + excludedValues.insert(ptr); } } - if (_abi->isRegister(ptr) - && _abi->isRegister(l->getPointerOperand()) - && ptr != l->getPointerOperand()) + if (l->getPointerOperand() != store->getPointerOperand()) { - disqualifiedValues.insert(l->getPointerOperand()); + excludedValues.insert(l->getPointerOperand()); } } - if (disqualifiedValues.hasNot(ptr)) + if (excludedValues.hasNot(ptr)) { - ce.possibleArgStores.push_back(store); - disqualifiedValues.insert(ptr); - disqualifiedValues.insert(store); + argStores.insert(ptr); + excludedValues.insert(ptr); + excludedValues.insert(val); + + if (possibleArgStores != nullptr) + { + possibleArgStores->push_back(store); + } + } + } + + if (inst == &block->front()) + { + canContinue = false; + } + } + + std::set commonArgStores; + // recursive? + seenBlocks[block] = argStores; + + for (auto pred: predecessors(block)) + { + std::set foundArgs; + if (seenBlocks.find(pred) == seenBlocks.end()) + { + foundArgs = collectArgsFromInstruction(&pred->back(), seenBlocks, possibleArgStores); + } + else + { + foundArgs = seenBlocks[pred]; + } + + if (foundArgs.empty()) + { + return argStores; + } + + if (commonArgStores.empty()) + { + commonArgStores = std::move(foundArgs); + } + else + { + std::set intersection; + std::set_intersection( + commonArgStores.begin(), + commonArgStores.end(), + foundArgs.begin(), + foundArgs.end(), + std::inserter(intersection, intersection.begin())); + + commonArgStores = std::move(intersection); + } + } + + argStores.insert(commonArgStores.begin(), commonArgStores.end()); + + seenBlocks[block] = argStores; + return argStores; +} + +bool CallEntry::instructionStoresString( + StoreInst *si, + std::string& str, + ReachingDefinitionsAnalysis &_RDA) const +{ + auto* v = getRoot(_RDA, si->getValueOperand()); + auto* gv = dyn_cast_or_null(v); + + if (gv == nullptr || !gv->hasInitializer()) + { + return false; + } + + auto* init = dyn_cast_or_null(gv->getInitializer()); + if (init == nullptr) + { + if (auto* i = dyn_cast(gv->getInitializer())) + { + if (auto* igv = dyn_cast(i->getOperand(0))) + { + init = dyn_cast_or_null(igv->getInitializer()); } } } + + if (init == nullptr || !init->isString()) + { + return false; + } + + str = init->getAsString(); + return true; +} + +void DataFlowEntry::addCallArgs(llvm::CallInst* call, CallEntry& ce) +{ + std::map> seenBlocks; + + auto fromInst = call->getPrevNode(); + if (fromInst == nullptr) + { + return; + } + + auto wantedStores = isVarArg ? &ce.possibleArgStores : nullptr; + + auto possibleArgs = collectArgsFromInstruction(fromInst, seenBlocks, wantedStores); + + ce.possibleArgs.assign(possibleArgs.begin(), possibleArgs.end()); } void DataFlowEntry::addCallReturns(llvm::CallInst* call, CallEntry& ce) @@ -917,18 +990,18 @@ void DataFlowEntry::filter() for (CallEntry& e : calls) { auto tIt = argTypes.begin(); - auto sIt = e.possibleArgStores.begin(); + auto sIt = e.possibleArgs.begin(); - while (tIt != argTypes.end() && sIt != e.possibleArgStores.end()) + while (tIt != argTypes.end() && sIt != e.possibleArgs.end()) { Type* t = *tIt; auto nextIt = sIt; ++nextIt; if (t->isDoubleTy() - && nextIt != e.possibleArgStores.end() - && _abi->isRegister((*nextIt)->getPointerOperand())) + && nextIt != e.possibleArgs.end() + && _abi->isRegister(*nextIt)) { - e.possibleArgStores.erase(nextIt); + e.possibleArgs.erase(nextIt); } ++tIt; @@ -949,9 +1022,9 @@ void DataFlowEntry::callsFilterCommonRegisters() std::set commonRegs; - for (auto* s : calls.front().possibleArgStores) + for (auto* s : calls.front().possibleArgs) { - Value* r = s->getPointerOperand(); + Value* r = s; if (_abi->isRegister(r)) { commonRegs.insert(r); @@ -963,15 +1036,15 @@ void DataFlowEntry::callsFilterCommonRegisters() // TODO: sometimes, we do not find all arg stores. // this is a hack, we should manufacture loads even if we do not have // stores but know there are some arguments (debug, ...). - if (e.possibleArgStores.empty()) + if (e.possibleArgs.empty()) { continue; } std::set regs; - for (auto* s : e.possibleArgStores) + for (auto* s : e.possibleArgs) { - Value* r = s->getPointerOperand(); + Value* r = s; if (_abi->isRegister(r)) { regs.insert(r); @@ -1008,14 +1081,14 @@ void DataFlowEntry::callsFilterCommonRegisters() for (auto& e : calls) { - auto it = e.possibleArgStores.begin(); - for ( ; it != e.possibleArgStores.end(); ) + auto it = e.possibleArgs.begin(); + for ( ; it != e.possibleArgs.end(); ) { - Value* r = (*it)->getPointerOperand(); + Value* r = (*it); if (_abi->isRegister(r) && commonRegs.find(r) == commonRegs.end()) { - it = e.possibleArgStores.erase(it); + it = e.possibleArgs.erase(it); } else { @@ -1045,9 +1118,9 @@ void DataFlowEntry::callsFilterSameNumberOfStacks() for (auto& ce : calls) { std::size_t ss = 0; - for (auto* s : ce.possibleArgStores) + for (auto* s : ce.possibleArgs) { - if (_config->isStackVariable(s->getPointerOperand())) + if (_config->isStackVariable(s)) { ++ss; } @@ -1068,11 +1141,11 @@ void DataFlowEntry::callsFilterSameNumberOfStacks() for (auto& ce : calls) { std::size_t cntr = 0; - auto it = ce.possibleArgStores.begin(); - while (it != ce.possibleArgStores.end()) + auto it = ce.possibleArgs.begin(); + while (it != ce.possibleArgs.end()) { auto* s = *it; - if (!_config->isStackVariable(s->getPointerOperand())) + if (!_config->isStackVariable(s)) { ++it; continue; @@ -1081,7 +1154,7 @@ void DataFlowEntry::callsFilterSameNumberOfStacks() ++cntr; if (cntr > stacks) { - it = ce.possibleArgStores.erase(it); + it = ce.possibleArgs.erase(it); } else { @@ -1111,7 +1184,7 @@ std::map> DataFlowEntry::fetchLoadsOfCalls() cons { std::vector loads; auto* call = e.call; - for (auto* s : e.possibleArgStores) + for (auto* s : e.possibleArgs) { auto fIt = specialArgStorage.find(loads.size()); while (fIt != specialArgStorage.end()) @@ -1121,7 +1194,7 @@ std::map> DataFlowEntry::fetchLoadsOfCalls() cons fIt = specialArgStorage.find(loads.size()); } - auto* l = new LoadInst(s->getPointerOperand(), "", call); + auto* l = new LoadInst(s, "", call); loads.push_back(l); } @@ -1247,11 +1320,11 @@ void DataFlowEntry::applyToIrVariadic() // get lowest stack offset // int stackOff = std::numeric_limits::max(); - for (StoreInst* s : ce.possibleArgStores) + for (Value* s : ce.possibleArgs) { - if (_config->isStackVariable(s->getPointerOperand())) + if (_config->isStackVariable(s)) { - auto so = _config->getStackVariableOffset(s->getPointerOperand()); + auto so = _config->getStackVariableOffset(s); if (so < stackOff) { stackOff = so; @@ -1783,16 +1856,16 @@ void DataFlowEntry::setArgumentTypes() CallEntry* ce = &calls.front(); for (auto& c : calls) { - if (!c.possibleArgStores.empty()) + if (!c.possibleArgs.empty()) { ce = &c; break; } } - for (auto st: ce->possibleArgStores) + for (auto st: ce->possibleArgs) { - auto op = st->getPointerOperand(); + auto op = st; if (_abi->isRegister(op) && !_abi->isGeneralPurposeRegister(op)) { From 1c031452191edafc01926b6ae3e58e8d76a6fd8f Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 12:49:25 +0200 Subject: [PATCH 034/159] param_return: new filter --- .../optimizations/param_return/param_return.h | 1 + .../param_return/param_return.cpp | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index c426d8d4a..7dab794b5 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -35,6 +35,7 @@ class CallEntry void filterStoreValues(Abi* _abi); void filterSort(Config* _config, Abi* _abi); void filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi *_abi); + void filterLeaveOnlyContinuousSequence(Abi* _abi); void filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi); void extractFormatString(ReachingDefinitionsAnalysis& _RDA); diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 94e396a59..9b4ebdadd 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -412,6 +412,54 @@ void CallEntry::filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi* _abi } } +void CallEntry::filterLeaveOnlyContinuousSequence(Abi* _abi) +{ + auto fpRegs = _abi->parameterFPRegisters(); + auto fIt = fpRegs.begin(); + + auto it = possibleArgs.begin(); + + for (auto rId : _abi->parameterRegisters()) + { + if (it == possibleArgs.end()) + { + return; + } + + if (rId != _abi->getRegisterId(*it)) + { + if (_abi->parameterRegistersOverlay()) + { + auto nIt = std::find_if( + possibleArgs.begin(), + possibleArgs.end(), + [_abi, fIt](Value* arg) + { + return _abi->getRegisterId(arg) == *fIt; + }); + + if (nIt != possibleArgs.end()) + { + auto val = *nIt; + possibleArgs.erase(nIt); + it = possibleArgs.insert(it, val); + + it++; + fIt++; + + continue; + } + } + + possibleArgs.erase(it, possibleArgs.end()); + return; + } + + it++; + } + +} + void CallEntry::filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi) { size_t regNum = 0; @@ -972,6 +1020,7 @@ void DataFlowEntry::filter() e.filterStoreValues(_abi); e.filterSort(_config, _abi); e.filterLeaveOnlyContinuousStackOffsets(_config, _abi); + e.filterLeaveOnlyContinuousSequence(_abi); e.filterLeaveOnlyNeededStackOffsets(_config, _abi); if (isVarArg) From f2b072999d0bd334c62f57f69bd39daf60cea7bd Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Fri, 17 Aug 2018 10:03:41 +0200 Subject: [PATCH 035/159] abi: parameter registers overlay --- include/retdec/bin2llvmir/providers/abi/abi.h | 2 ++ src/bin2llvmir/providers/abi/abi.cpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 0ad1cfd44..aeaa56ef5 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -65,6 +65,7 @@ class Abi llvm::GlobalVariable* getFPReturnRegister() const; bool usesFPRegistersForParameters() const; + bool parameterRegistersOverlay() const; // Values. public: @@ -143,6 +144,7 @@ class Abi /// Specifies if abi returns value on stack. bool returnsOnStack = false; bool _fpRegsAsParams = false; + bool _paramRegsOverlay = false; }; diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index e745b9f4f..7543f17a9 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -144,6 +144,11 @@ bool Abi::usesFPRegistersForParameters() const return _fpRegsAsParams; } +bool Abi::parameterRegistersOverlay() const +{ + return _paramRegsOverlay; +} + bool Abi::isNopInstruction(AsmInstruction ai) { return isNopInstruction(ai.getCapstoneInsn()); From 5d2aeb7c3eb047e000803583a56c9e5f41237361 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Fri, 17 Aug 2018 10:13:41 +0200 Subject: [PATCH 036/159] abi: ms_x64: new class provide class representation of Microsoft x64 ABI. --- .../retdec/bin2llvmir/providers/abi/ms_x64.h | 37 ++++++ src/bin2llvmir/CMakeLists.txt | 1 + src/bin2llvmir/providers/abi/ms_x64.cpp | 121 ++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/abi/ms_x64.h create mode 100644 src/bin2llvmir/providers/abi/ms_x64.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/ms_x64.h b/include/retdec/bin2llvmir/providers/abi/ms_x64.h new file mode 100644 index 000000000..e3fb9f27c --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/ms_x64.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/x86_64.h + * @brief ABI information for x86_64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_MS_64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_MS_64_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiMS_X64 : public Abi +{ + // Ctors, dtors. + // + public: + AbiMS_X64(llvm::Module* m, Config* c); + virtual ~AbiMS_X64(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 49556a742..8013cc126 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -67,6 +67,7 @@ set(BIN2LLVMIR_SOURCES providers/abi/abi.cpp providers/abi/arm.cpp providers/abi/mips.cpp + providers/abi/ms_x64.cpp providers/abi/pic32.cpp providers/abi/powerpc.cpp providers/abi/x86.cpp diff --git a/src/bin2llvmir/providers/abi/ms_x64.cpp b/src/bin2llvmir/providers/abi/ms_x64.cpp new file mode 100644 index 000000000..b7fcdaa6e --- /dev/null +++ b/src/bin2llvmir/providers/abi/ms_x64.cpp @@ -0,0 +1,121 @@ +/** + * @file src/bin2llvmir/providers/abi/x86_64.cp + * @brief ABI information for x86_64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/ms_x64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiMS_X64::AbiMS_X64(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _paramRegsOverlay = true; + _fpRegsAsParams = true; + _regs.reserve(X86_REG_ENDING); + _id2regs.resize(X86_REG_ENDING, nullptr); + _regStackPointerId = X86_REG_RSP; + + // system calls + _regSyscallId = X86_REG_EAX; + _regSyscallReturn = X86_REG_EAX; + _syscallRegs = { + X86_REG_RDI, + X86_REG_RSI, + X86_REG_RDX, + X86_REG_R10, + X86_REG_R8, + X86_REG_R9}; + + _paramRegs = { + X86_REG_RCX, + X86_REG_RDX, + X86_REG_R8, + X86_REG_R9}; + + _paramFPRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3}; + + _regReturn = X86_REG_RAX; + + _regFPReturn = X86_REG_ST0; +} + +AbiMS_X64::~AbiMS_X64() +{ +} + +bool AbiMS_X64::isGeneralPurposeRegister(const llvm::Value* val) +{ + uint32_t rid = getRegisterId(val); + return rid == X86_REG_RAX + || rid == X86_REG_RBX + || rid == X86_REG_RCX + || rid == X86_REG_RDX + || rid == X86_REG_RSP + || rid == X86_REG_RBP + || rid == X86_REG_RSI + || rid == X86_REG_RDI + || rid == X86_REG_R8 + || rid == X86_REG_R9 + || rid == X86_REG_R10 + || rid == X86_REG_R11 + || rid == X86_REG_R12 + || rid == X86_REG_R13 + || rid == X86_REG_R14 + || rid == X86_REG_R15; +} + +bool AbiMS_X64::isNopInstruction(cs_insn* insn) +{ + cs_x86& insn86 = insn->detail->x86; + + // True NOP variants. + // + if (insn->id == X86_INS_NOP + || insn->id == X86_INS_FNOP + || insn->id == X86_INS_FDISI8087_NOP + || insn->id == X86_INS_FENI8087_NOP + || insn->id == X86_INS_INT3) + { + return true; + } + // e.g. lea esi, [esi] + // + else if (insn->id == X86_INS_LEA + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_MEM + && insn86.operands[1].mem.segment == X86_REG_INVALID + && insn86.operands[1].mem.index == X86_REG_INVALID + && insn86.operands[1].mem.scale == 1 + && insn86.operands[1].mem.disp == 0 + && insn86.operands[1].mem.base == insn86.operands[0].reg) + { + return true; + } + // e.g. mov esi. esi + // + else if (insn->id == X86_INS_MOV + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_REG + && insn86.operands[0].reg == insn86.operands[1].reg) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec From 341f3c859b812b045f5d62f542edf164f3118d9a Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Fri, 17 Aug 2018 10:35:01 +0200 Subject: [PATCH 037/159] abi: provide support fo microsoft x64 ABI --- src/bin2llvmir/providers/abi/abi.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 7543f17a9..b0ea99bd7 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -7,6 +7,7 @@ #include "retdec/bin2llvmir/providers/abi/abi.h" #include "retdec/bin2llvmir/providers/abi/arm.h" #include "retdec/bin2llvmir/providers/abi/mips.h" +#include "retdec/bin2llvmir/providers/abi/ms_x64.h" #include "retdec/bin2llvmir/providers/abi/powerpc.h" #include "retdec/bin2llvmir/providers/abi/x86.h" #include "retdec/bin2llvmir/providers/abi/x64.h" @@ -307,6 +308,15 @@ Abi* AbiProvider::addAbi( } else if (c->getConfig().architecture.isX86_64()) { + bool isMinGW = c->getConfig().tools.isGcc() + && c->getConfig().fileFormat.isPe(); + + if (isMinGW || c->getConfig().tools.isMsvc()) + { + auto p = _module2abi.emplace(m, std::make_unique(m, c)); + return p.first->second.get(); + } + auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); } From 0105fd2fd2f12dda3c81232aefd40e0a1ebc823d Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 08:29:06 +0100 Subject: [PATCH 038/159] param_return_tests: revert 47277eb93 --- .../optimizations/param_return/param_return_tests.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index eb3ba5444..7bab4501a 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -23,9 +23,6 @@ class ParamReturnTests: public LlvmIrTests ParamReturn pass; }; -//// -//// x86 -//// // // x86 // From bf058d4c5b1cbde3aeb76890f4bfb9b3221bb8fc Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 20 Aug 2018 12:25:42 +0200 Subject: [PATCH 039/159] param_return_tests: x64: microsoft: new tests --- .../param_return/param_return_tests.cpp | 537 ++++++++++++++++++ 1 file changed, 537 insertions(+) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 7bab4501a..8dbf34d0e 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -1115,6 +1115,69 @@ TEST_F(ParamReturnTests, x86_64ExternalCallUseStacksIf6RegistersUsed) checkModuleAgainstExpectedIr(exp); } +TEST_F(ParamReturnTests, x86_64ExternalCallUsesFPRegistersBasic) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @xmm0 = global double 0.0 + @xmm1 = global double 0.0 + + declare void @print() + define void @fnc() { + store double 2.0, double* @xmm1 + store double 2.0, double* @xmm0 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + } + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_XMM0, getGlobalByName("xmm0")); + abi->addRegister(X86_REG_XMM1, getGlobalByName("xmm1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @xmm0 = global double 0.000000e+00 + @xmm1 = global double 0.000000e+00 + + declare i64 @print(float, float) + + declare void @0() + + define i64 @fnc() { + store double 2.000000e+00, double* @xmm1 + store double 2.000000e+00, double* @xmm0 + %1 = load double, double* @xmm0 + %2 = load double, double* @xmm1 + %3 = fptrunc double %1 to float + %4 = fptrunc double %2 to float + %5 = call i64 @print(float %3, float %4) + store i64 %5, i64* @rax + %6 = load i64, i64* @rax + ret i64 %6 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + TEST_F(ParamReturnTests, x86_64ExternalCallUsesFPRegisters) { parseInput(R"( @@ -1285,6 +1348,480 @@ TEST_F(ParamReturnTests, x86_64UsesJustContinuousSequenceOfRegisters) checkModuleAgainstExpectedIr(exp); } +TEST_F(ParamReturnTests, ms_x64PtrCallBasicFunctionality) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + define void @fnc() { + store i64 123, i64* @rcx + store i64 456, i64* @rdx + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + + define i64 @fnc() { + store i64 123, i64* @rcx + store i64 456, i64* @rdx + %a = bitcast i64* @r to void()* + %1 = load i64, i64* @rcx + %2 = load i64, i64* @rdx + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @rax + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64PtrCallPrevBbIsUsedOnlyIfItIsASinglePredecessor) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + + define void @fnc() { + br label %lab1 + lab1: + store i64 123, i64* @rcx + br label %lab2 + lab2: + store i64 456, i64* @rdx + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + + define i64 @fnc() { + br label %lab1 + + lab1: + store i64 123, i64* @rcx + br label %lab2 + + lab2: + store i64 456, i64* @rdx + %a = bitcast i64* @r to void ()* + %1 = load i64, i64* @rcx + %2 = load i64, i64* @rdx + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @rax + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64ExternalCallUseStacksIf4RegistersUsed) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @rax = global i64 0 + declare void @print() + define void @fnc() { + %stack_-8 = alloca i64 + %stack_-16 = alloca i64 + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store i64 2, i64* %stack_-8 + store i64 1, i64* @rdx + store i64 2, i64* %stack_-16 + store i64 1, i64* @rcx + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + }, + { + "name" : "stack_-16", + "storage" : { "type" : "stack", "value" : -16 } + } + + ] + } + ], + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @rax = global i64 0 + + declare i64 @print(i64, i64, i64, i64, i64, i64) + + declare void @0() + + define i64 @fnc() { + %stack_-8 = alloca i64 + %stack_-16 = alloca i64 + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store i64 2, i64* %stack_-8 + store i64 1, i64* @rdx + store i64 2, i64* %stack_-16 + store i64 1, i64* @rcx + %1 = load i64, i64* @rcx + %2 = load i64, i64* @rdx + %3 = load i64, i64* @r8 + %4 = load i64, i64* @r9 + %5 = load i64, i64* %stack_-16 + %6 = load i64, i64* %stack_-8 + %7 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6) + store i64 %7, i64* @rax + %8 = load i64, i64* @rax + ret i64 %8 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegisters) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r8 = global i64 0 + @r9 = global i64 0 + @rax = global i64 0 + @xmm0 = global double 0.0 + @xmm1 = global double 0.0 + + declare void @print() + define void @fnc() { + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store double 2.0, double* @xmm1 + store double 2.0, double* @xmm0 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); + abi->addRegister(X86_REG_XMM0, getGlobalByName("xmm0")); + abi->addRegister(X86_REG_XMM1, getGlobalByName("xmm1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r8 = global i64 0 + @r9 = global i64 0 + @rax = global i64 0 + @xmm0 = global double 0.000000e+00 + @xmm1 = global double 0.000000e+00 + + declare i64 @print(i64, i64, float, float) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store double 2.000000e+00, double* @xmm1 + store double 2.000000e+00, double* @xmm0 + %1 = load i64, i64* @r8 + %2 = load i64, i64* @r9 + %3 = load double, double* @xmm0 + %4 = load double, double* @xmm1 + %5 = fptrunc double %3 to float + %6 = fptrunc double %4 to float + %7 = call i64 @print(i64 %1, i64 %2, float %5, float %6) + store i64 %7, i64* @rax + %8 = load i64, i64* @rax + ret i64 %8 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegistersAdvanced) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + @xmm2 = global double 0.0 + @xmm3 = global double 0.0 + + declare void @print() + define void @fnc() { + store i64 1, i64* @rcx + store i64 1, i64* @rdx + store double 2.0, double* @xmm2 + store double 2.0, double* @xmm3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_XMM2, getGlobalByName("xmm2")); + abi->addRegister(X86_REG_XMM3, getGlobalByName("xmm3")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + @xmm2 = global double 0.000000e+00 + @xmm3 = global double 0.000000e+00 + + declare i64 @print(i64, i64, float, float) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @rcx + store i64 1, i64* @rdx + store double 2.000000e+00, double* @xmm2 + store double 2.000000e+00, double* @xmm3 + %1 = load i64, i64* @rcx + %2 = load i64, i64* @rdx + %3 = load double, double* @xmm2 + %4 = load double, double* @xmm3 + %5 = fptrunc double %3 to float + %6 = fptrunc double %4 to float + %7 = call i64 @print(i64 %1, i64 %2, float %5, float %6) + store i64 %7, i64* @rax + %8 = load i64, i64* @rax + ret i64 %8 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64UsesJustContinuousSequenceOfRegisters) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + + declare void @print() + define void @fnc() { + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store i64 1, i64* @rcx + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + + declare i64 @print(i64) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store i64 1, i64* @rcx + %1 = load i64, i64* @rcx + %2 = call i64 @print(i64 %1) + store i64 %2, i64* @rax + %3 = load i64, i64* @rax + ret i64 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + // //TEST_F(ParamReturnTests, x86PtrCallOnlyContinuousStackOffsetsAreUsed) //{ From 44cd1e0955a158ac3f58a73ba0714114d7602a09 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 21 Aug 2018 09:39:28 +0200 Subject: [PATCH 040/159] param_return: fix sort algorithm Algorithm expected that registerss in abi are sorted by integer value from lowest to highest. This assumption is invalid because there are architectures (for example x64) which has order of registers used as parameters not sorted by integer value. --- .../param_return/param_return.cpp | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 9b4ebdadd..b71f62b4d 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -310,6 +310,8 @@ void DataFlowEntry::filterRegistersArgLoads() /** * Stack with the lowest (highest negative) offset is the first call argument. + * + * Registers are sorted according to position got from abi. */ void CallEntry::filterSort(Config* _config, Abi* _abi) { @@ -325,7 +327,14 @@ void CallEntry::filterSort(Config* _config, Abi* _abi) if (aOff.isUndefined() && bOff.isUndefined()) { - return _abi->getRegisterId(a) < _abi->getRegisterId(b); + auto regs = _abi->parameterRegisters(); + auto aId = _abi->getRegisterId(a); + auto bId = _abi->getRegisterId(b); + + auto it1 = std::find(regs.begin(), regs.end(), aId); + auto it2 = std::find(regs.begin(), regs.end(), bId); + + return std::distance(it1, it2) > 0; } else if (aOff.isUndefined() && bOff.isDefined()) { @@ -354,8 +363,14 @@ void DataFlowEntry::filterSortArgLoads() if (aOff.isUndefined() && bOff.isUndefined()) { - return _abi->getRegisterId(a->getPointerOperand()) < - _abi->getRegisterId(b->getPointerOperand()); + auto regs = _abi->parameterRegisters(); + auto aId = _abi->getRegisterId(a->getPointerOperand()); + auto bId = _abi->getRegisterId(b->getPointerOperand()); + + auto it1 = std::find(regs.begin(), regs.end(), aId); + auto it2 = std::find(regs.begin(), regs.end(), bId); + + return std::distance(it1, it2) > 0; } else if (aOff.isUndefined() && bOff.isDefined()) { From d6783769c99aebeda19c55785d6ae22b7723a1b6 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 21 Aug 2018 12:22:01 +0200 Subject: [PATCH 041/159] param_return: store values instead of whole instructions Signed-off-by: Peter Kubov --- .../optimizations/param_return/param_return.h | 2 +- .../param_return/param_return.cpp | 38 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 7dab794b5..b960c8592 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -136,7 +136,7 @@ class DataFlowEntry // In called function. // - std::vector argLoads; + std::vector args; std::vector retStores; // Result. diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index b71f62b4d..b9982ee76 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -292,11 +292,11 @@ void CallEntry::filterStoreValues(Abi* _abi) void DataFlowEntry::filterRegistersArgLoads() { - argLoads.erase( - std::remove_if(argLoads.begin(), argLoads.end(), - [this](const LoadInst* li) + args.erase( + std::remove_if(args.begin(), args.end(), + [this](const Value* li) { - auto* op = li->getPointerOperand(); + auto* op = li; if (_abi->valueCanBeParameter(op)) { auto aOff = _config->getStackVariableOffset(op); @@ -305,7 +305,7 @@ void DataFlowEntry::filterRegistersArgLoads() return true; }), - argLoads.end()); + args.end()); } /** @@ -354,18 +354,18 @@ void CallEntry::filterSort(Config* _config, Abi* _abi) void DataFlowEntry::filterSortArgLoads() { std::stable_sort( - argLoads.begin(), - argLoads.end(), - [this](LoadInst* a, LoadInst* b) -> bool + args.begin(), + args.end(), + [this](Value* a, Value* b) -> bool { - auto aOff = _config->getStackVariableOffset(a->getPointerOperand()); - auto bOff = _config->getStackVariableOffset(b->getPointerOperand()); + auto aOff = _config->getStackVariableOffset(a); + auto bOff = _config->getStackVariableOffset(b); if (aOff.isUndefined() && bOff.isUndefined()) { auto regs = _abi->parameterRegisters(); - auto aId = _abi->getRegisterId(a->getPointerOperand()); - auto bId = _abi->getRegisterId(b->getPointerOperand()); + auto aId = _abi->getRegisterId(a); + auto bId = _abi->getRegisterId(b); auto it1 = std::find(regs.begin(), regs.end(), aId); auto it2 = std::find(regs.begin(), regs.end(), bId); @@ -663,7 +663,7 @@ void DataFlowEntry::dump() const } LOG << "\t>|arg loads:" << std::endl; - for (auto* l : argLoads) + for (auto* l : args) { LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; } @@ -707,7 +707,7 @@ void DataFlowEntry::addArgLoads() if ((use->defs.empty() || use->isUndef()) && added.find(ptr) == added.end()) { - argLoads.push_back(l); + args.push_back(ptr); added.insert(ptr); } } @@ -1170,9 +1170,9 @@ void DataFlowEntry::callsFilterSameNumberOfStacks() } std::size_t loads = 0; - for (auto* l : argLoads) + for (auto* l : args) { - if (_config->isStackVariable(l->getPointerOperand())) + if (_config->isStackVariable(l)) { ++loads; } @@ -1309,7 +1309,7 @@ void DataFlowEntry::applyToIrOrdinary() } std::vector argStores; - for (LoadInst* l : argLoads) + for (Value* l : args) { auto fIt = specialArgStorage.find(argStores.size()); while (fIt != specialArgStorage.end()) @@ -1318,7 +1318,7 @@ void DataFlowEntry::applyToIrOrdinary() fIt = specialArgStorage.find(argStores.size()); } - argStores.push_back(l->getPointerOperand()); + argStores.push_back(l); } auto paramRegs = _abi->parameterRegisters(); @@ -1912,7 +1912,7 @@ void DataFlowEntry::setArgumentTypes() { argTypes.insert( argTypes.end(), - argLoads.size(), + args.size(), Abi::getDefaultType(_module)); } else From ba7bbaf9303a0c7516963fcc0e0eb0a1450acfd6 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 10:51:18 +0200 Subject: [PATCH 042/159] param_return: get rid of redundant code --- .../optimizations/param_return/param_return.h | 1 - .../optimizations/param_return/param_return.cpp | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index b960c8592..4482a9227 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -32,7 +32,6 @@ class CallEntry CallEntry(llvm::CallInst* c); public: - void filterStoreValues(Abi* _abi); void filterSort(Config* _config, Abi* _abi); void filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi *_abi); void filterLeaveOnlyContinuousSequence(Abi* _abi); diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index b9982ee76..5155a64d6 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -276,20 +276,6 @@ CallEntry::CallEntry(llvm::CallInst* c) : } -/** - * Remove all registers that are not used to pass argument according to ABI. - */ -void CallEntry::filterStoreValues(Abi* _abi) -{ - possibleArgs.erase( - std::remove_if(possibleArgs.begin(), possibleArgs.end(), - [_abi](const Value* v) - { - return !_abi->valueCanBeParameter(v); - }), - possibleArgs.end()); -} - void DataFlowEntry::filterRegistersArgLoads() { args.erase( @@ -1032,7 +1018,6 @@ void DataFlowEntry::filter() for (CallEntry& e : calls) { - e.filterStoreValues(_abi); e.filterSort(_config, _abi); e.filterLeaveOnlyContinuousStackOffsets(_config, _abi); e.filterLeaveOnlyContinuousSequence(_abi); From df9b96dc8932a2b2b5d297572034ccc50508ddc2 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 10:53:45 +0200 Subject: [PATCH 043/159] param_return: change name of method --- .../optimizations/param_return/param_return.h | 2 +- .../optimizations/param_return/param_return.cpp | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 4482a9227..5655542e7 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -108,8 +108,8 @@ class DataFlowEntry void setReturnType(); void setArgumentTypes(); - void filterRegistersArgLoads(); void filterSortArgLoads(); + void filterNegativeStacks(); void replaceCalls(); std::map> diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 5155a64d6..cf4ccbb92 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -276,20 +276,14 @@ CallEntry::CallEntry(llvm::CallInst* c) : } -void DataFlowEntry::filterRegistersArgLoads() +void DataFlowEntry::filterNegativeStacks() { args.erase( std::remove_if(args.begin(), args.end(), [this](const Value* li) { - auto* op = li; - if (_abi->valueCanBeParameter(op)) - { - auto aOff = _config->getStackVariableOffset(op); - return aOff.isDefined() && aOff < 0; - } - - return true; + auto aOff = _config->getStackVariableOffset(li); + return aOff.isDefined() && aOff < 0; }), args.end()); } @@ -1013,7 +1007,7 @@ void DataFlowEntry::filter() callsFilterCommonRegisters(); } - filterRegistersArgLoads(); + filterNegativeStacks(); filterSortArgLoads(); for (CallEntry& e : calls) From 08d8609fdd69a57e42066b5851346b5eee81f4c2 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 10:54:41 +0200 Subject: [PATCH 044/159] param_return: apply DRY principle --- .../optimizations/param_return/param_return.h | 2 +- .../param_return/param_return.cpp | 49 +++---------------- 2 files changed, 8 insertions(+), 43 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 5655542e7..164559ff0 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -32,7 +32,6 @@ class CallEntry CallEntry(llvm::CallInst* c); public: - void filterSort(Config* _config, Abi* _abi); void filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi *_abi); void filterLeaveOnlyContinuousSequence(Abi* _abi); void filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi); @@ -110,6 +109,7 @@ class DataFlowEntry void filterSortArgLoads(); void filterNegativeStacks(); + void sortValues(std::vector &args) const; void replaceCalls(); std::map> diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index cf4ccbb92..f7c3ccf4a 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -293,57 +293,22 @@ void DataFlowEntry::filterNegativeStacks() * * Registers are sorted according to position got from abi. */ -void CallEntry::filterSort(Config* _config, Abi* _abi) +void DataFlowEntry::sortValues(std::vector &args) const { - auto& stores = possibleArgs; - - std::stable_sort( - stores.begin(), - stores.end(), - [_config, _abi](Value* a, Value* b) -> bool - { - auto aOff = _config->getStackVariableOffset(a); - auto bOff = _config->getStackVariableOffset(b); - - if (aOff.isUndefined() && bOff.isUndefined()) - { - auto regs = _abi->parameterRegisters(); - auto aId = _abi->getRegisterId(a); - auto bId = _abi->getRegisterId(b); - - auto it1 = std::find(regs.begin(), regs.end(), aId); - auto it2 = std::find(regs.begin(), regs.end(), bId); - - return std::distance(it1, it2) > 0; - } - else if (aOff.isUndefined() && bOff.isDefined()) - { - return true; - } - else if (aOff.isDefined() && bOff.isUndefined()) - { - return false; - } - else - { - return aOff < bOff; - } - }); -} + auto regs = _abi->parameterRegisters(); + auto fpRegs = _abi->parameterFPRegisters(); + regs.insert(regs.end(), fpRegs.begin(), fpRegs.end()); -void DataFlowEntry::filterSortArgLoads() -{ std::stable_sort( args.begin(), args.end(), - [this](Value* a, Value* b) -> bool + [this, regs, args](Value* a, Value* b) -> bool { auto aOff = _config->getStackVariableOffset(a); auto bOff = _config->getStackVariableOffset(b); if (aOff.isUndefined() && bOff.isUndefined()) { - auto regs = _abi->parameterRegisters(); auto aId = _abi->getRegisterId(a); auto bId = _abi->getRegisterId(b); @@ -1008,11 +973,11 @@ void DataFlowEntry::filter() } filterNegativeStacks(); - filterSortArgLoads(); + sortValues(args); for (CallEntry& e : calls) { - e.filterSort(_config, _abi); + sortValues(e.possibleArgs); e.filterLeaveOnlyContinuousStackOffsets(_config, _abi); e.filterLeaveOnlyContinuousSequence(_abi); e.filterLeaveOnlyNeededStackOffsets(_config, _abi); From 8e5bbacdee6ea626373562176829daeb198769f1 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 21 Aug 2018 13:02:26 +0200 Subject: [PATCH 045/159] param_return: get rid of unnecessary operations In case of missing registers after intersection there was code that generated them. This is no longer valid move because missing registers means that they were not used as parameters and thus should indicate that for example no stack should be used as well. --- .../param_return/param_return.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index f7c3ccf4a..ecdcdc7ec 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1069,24 +1069,6 @@ void DataFlowEntry::callsFilterCommonRegisters() commonRegs = std::move(intersect); } - auto regIds = _abi->parameterRegisters(); - - for (auto it = regIds.rbegin(); it != regIds.rend(); ++it) - { - auto* r = _abi->getRegister(*it); - if (commonRegs.count(r)) - { - ++it; - while (it != regIds.rend()) - { - r = _abi->getRegister(*it); - commonRegs.insert(r); - ++it; - } - break; - } - } - for (auto& e : calls) { auto it = e.possibleArgs.begin(); From 77563f9433ee7d68faa6157763a7369d08c8ef1a Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 21 Aug 2018 13:07:52 +0200 Subject: [PATCH 046/159] param_return: make remove more clear --- .../param_return/param_return.cpp | 65 +++++++++---------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index ecdcdc7ec..47e2487a3 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1030,15 +1030,6 @@ void DataFlowEntry::callsFilterCommonRegisters() std::set commonRegs; - for (auto* s : calls.front().possibleArgs) - { - Value* r = s; - if (_abi->isRegister(r)) - { - commonRegs.insert(r); - } - } - for (auto& e : calls) { // TODO: sometimes, we do not find all arg stores. @@ -1050,41 +1041,49 @@ void DataFlowEntry::callsFilterCommonRegisters() } std::set regs; - for (auto* s : e.possibleArgs) + for (auto r : e.possibleArgs) { - Value* r = s; if (_abi->isRegister(r)) { regs.insert(r); } } - std::set intersect; - std::set_intersection( - commonRegs.begin(), - commonRegs.end(), - regs.begin(), - regs.end(), - std::inserter(intersect, intersect.begin())); - commonRegs = std::move(intersect); + if (regs.empty()) + { + commonRegs.erase(commonRegs.begin(), commonRegs.end()); + break; + } + else if (commonRegs.empty()) + { + commonRegs = std::move(regs); + } + else + { + std::set intersect; + std::set_intersection( + commonRegs.begin(), + commonRegs.end(), + regs.begin(), + regs.end(), + std::inserter(intersect, intersect.begin())); + + commonRegs = std::move(intersect); + } } for (auto& e : calls) { - auto it = e.possibleArgs.begin(); - for ( ; it != e.possibleArgs.end(); ) - { - Value* r = (*it); - if (_abi->isRegister(r) - && commonRegs.find(r) == commonRegs.end()) - { - it = e.possibleArgs.erase(it); - } - else - { - ++it; - } - } + e.possibleArgs.erase( + std::remove_if( + e.possibleArgs.begin(), + e.possibleArgs.end(), + [this, commonRegs](Value* arg) + { + return _abi->isRegister(arg) + && !commonRegs.count(arg); + }), + e.possibleArgs.end()); } } From 4579c5354af6d85f6fe85014485792192a88a43e Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 21 Aug 2018 13:35:08 +0200 Subject: [PATCH 047/159] param_return: move to better place --- src/bin2llvmir/optimizations/param_return/param_return.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 47e2487a3..d69421c52 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -967,11 +967,6 @@ void DataFlowEntry::addCallReturns(llvm::CallInst* call, CallEntry& ce) void DataFlowEntry::filter() { - if (!isVarArg) - { - callsFilterCommonRegisters(); - } - filterNegativeStacks(); sortValues(args); @@ -990,6 +985,7 @@ void DataFlowEntry::filter() if (!isVarArg) { + callsFilterCommonRegisters(); callsFilterSameNumberOfStacks(); } From c13812744877b298bb6603ba91a9eec413f60574 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 21 Aug 2018 13:47:14 +0200 Subject: [PATCH 048/159] param_return: new filter --- .../optimizations/param_return/param_return.h | 2 ++ .../param_return/param_return.cpp | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 164559ff0..bea0f0a45 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -111,6 +111,8 @@ class DataFlowEntry void filterNegativeStacks(); void sortValues(std::vector &args) const; + void filterKnownParamPairs(); + void replaceCalls(); std::map> fetchLoadsOfCalls() const; diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index d69421c52..020d89abb 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -965,6 +965,36 @@ void DataFlowEntry::addCallReturns(llvm::CallInst* call, CallEntry& ce) } } +/** + * TODO: This method just filters register pair of known double type. + * It should also remove another stack variable and not just for double + * but every large type -> wordSize * 2 + */ +void DataFlowEntry::filterKnownParamPairs() +{ + for (CallEntry& e : calls) + { + auto tIt = argTypes.begin(); + auto sIt = e.possibleArgs.begin(); + + while (tIt != argTypes.end() && sIt != e.possibleArgs.end()) + { + Type* t = *tIt; + auto nextIt = sIt; + ++nextIt; + if (t->isDoubleTy() + && nextIt != e.possibleArgs.end() + && _abi->isRegister(*nextIt)) + { + e.possibleArgs.erase(nextIt); + } + + ++tIt; + ++sIt; + } + } +} + void DataFlowEntry::filter() { filterNegativeStacks(); From 51cdc348873a358c826c43f9993313ae31a5ce72 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 21 Aug 2018 13:38:57 +0200 Subject: [PATCH 049/159] param_return: use new filter --- .../param_return/param_return.cpp | 37 ++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 020d89abb..ddc23cd65 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1021,30 +1021,12 @@ void DataFlowEntry::filter() if (typeSet) { - for (CallEntry& e : calls) - { - auto tIt = argTypes.begin(); - auto sIt = e.possibleArgs.begin(); - - while (tIt != argTypes.end() && sIt != e.possibleArgs.end()) - { - Type* t = *tIt; - auto nextIt = sIt; - ++nextIt; - if (t->isDoubleTy() - && nextIt != e.possibleArgs.end() - && _abi->isRegister(*nextIt)) - { - e.possibleArgs.erase(nextIt); - } - - ++tIt; - ++sIt; - } - } + filterKnownParamPairs(); + } + else + { + setTypeFromUseContext(); } - - setTypeFromUseContext(); } void DataFlowEntry::callsFilterCommonRegisters() @@ -1840,12 +1822,9 @@ void DataFlowEntry::setTypeFromExtraInfo() void DataFlowEntry::setTypeFromUseContext() { - if (!typeSet) - { - setReturnType(); - setArgumentTypes(); - typeSet = true; - } + setReturnType(); + setArgumentTypes(); + typeSet = true; } void DataFlowEntry::setReturnType() From caeb804bbcad38d934de210615979eedd2414ebf Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 10:04:56 +0200 Subject: [PATCH 050/159] ParamFilter: new class --- .../optimizations/param_return/param_return.h | 32 +++ .../param_return/param_return.cpp | 211 ++++++++++++++++++ 2 files changed, 243 insertions(+) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index bea0f0a45..6c17bb2fd 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -60,6 +60,38 @@ class ReturnEntry std::vector possibleRetStores; }; +class ParamFilter +{ + public: + ParamFilter( + const std::vector& paramValues, + const Abi& abi, + Config& config); + + void orderStacks(std::vector& stacks, bool asc = true) const; + void orderRegistersBy( + std::vector& regs, + const std::vector& orderedVector) const; + + void leaveOnlyContinuousSequence(); + void leaveOnlyContinuousStackOffsets(); + + std::vector getParamValues() const; + + private: + void separateParamValues(const std::vector& paramValues); + void applyAlternatingRegistersFilter(); + void applySequentialRegistersFilter(); + + private: + const Abi& _abi; + Config& _config; + + std::vector _regValues; + std::vector _fpRegValues; + std::vector _stackValues; +}; + class DataFlowEntry { public: diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index ddc23cd65..f426b0397 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1873,5 +1873,216 @@ void DataFlowEntry::setArgumentTypes() } } +// +//============================================================================= +// ParamFilter +//============================================================================= +// + +ParamFilter::ParamFilter( + const std::vector& paramValues, + const Abi& abi, + Config& config) + : + _abi(abi), + _config(config) +{ + separateParamValues(paramValues); + + orderRegistersBy(_fpRegValues, _abi.parameterFPRegisters()); + orderRegistersBy(_regValues, _abi.parameterRegisters()); + orderStacks(_stackValues); +} + +void ParamFilter::separateParamValues(const std::vector& paramValues) +{ + auto regs = _abi.parameterRegisters(); + + for (auto pv: paramValues) + { + if (_config.isStackVariable(pv)) + { + _stackValues.push_back(pv); + } + else if (std::find(regs.begin(), regs.end(), + _abi.getRegisterId(pv)) != regs.end()) + { + _regValues.push_back(_abi.getRegisterId(pv)); + } + else + { + _fpRegValues.push_back(_abi.getRegisterId(pv)); + } + } +} + +void ParamFilter::orderStacks(std::vector& stacks, bool asc) const +{ + std::stable_sort( + stacks.begin(), + stacks.end(), + [this, asc](Value* a, Value* b) -> bool + { + auto aOff = _config.getStackVariableOffset(a); + auto bOff = _config.getStackVariableOffset(b); + + bool ascOrd = aOff < bOff; + + return asc ? ascOrd : !ascOrd; + }); +} + +void ParamFilter::orderRegistersBy( + std::vector& regs, + const std::vector& orderedVector) const +{ + std::stable_sort( + regs.begin(), + regs.end(), + [this, orderedVector](uint32_t a, uint32_t b) -> bool + { + auto it1 = std::find(orderedVector.begin(), orderedVector.end(), a); + auto it2 = std::find(orderedVector.begin(), orderedVector.end(), b); + + return std::distance(it1, it2) > 0; + }); +} + +void ParamFilter::leaveOnlyContinuousStackOffsets() +{ + retdec::utils::Maybe prevOff; + int gap = _abi.wordSize()*2/8; + + auto it = _stackValues.begin(); + while (it != _stackValues.end()) + { + auto off = _config.getStackVariableOffset(*it); + + if (prevOff.isUndefined()) + { + prevOff = off; + } + else if (std::abs(prevOff - off) > gap) + { + it = _stackValues.erase(it); + continue; + } + else + { + prevOff = off; + } + + ++it; + } +} + +void ParamFilter::leaveOnlyContinuousSequence() +{ + if (_abi.parameterRegistersOverlay()) + { + applyAlternatingRegistersFilter(); + } + else + { + applySequentialRegistersFilter(); + } +} + +void ParamFilter::applyAlternatingRegistersFilter() +{ + auto templRegs = _abi.parameterRegisters(); + auto fpTemplRegs = _abi.parameterFPRegisters(); + + size_t idx = 0; + auto it = _regValues.begin(); + auto fIt = _fpRegValues.begin(); + + while (idx < fpTemplRegs.size() && idx < templRegs.size()) + { + if (it == _regValues.end() && fIt == _fpRegValues.end()) + { + _stackValues.clear(); + return; + } + + if (it != _regValues.end() && *it == templRegs[idx]) + { + it++; + } + else if (fIt != _fpRegValues.end() && *fIt == fpTemplRegs[idx]) + { + fIt++; + } + else + { + _regValues.erase(it, _regValues.end()); + _fpRegValues.erase(fIt, _fpRegValues.end()); + _stackValues.clear(); + + return; + } + + idx++; + } +} + +void ParamFilter::applySequentialRegistersFilter() +{ + auto it = _regValues.begin(); + for (auto regId : _abi.parameterRegisters()) + { + if (it == _regValues.end()) + { + _stackValues.clear(); + break; + } + + if (regId != *it) + { + _regValues.erase(it, _regValues.end()); + _stackValues.clear(); + break; + } + + it++; + } + + auto fIt = _fpRegValues.begin(); + for (auto regId : _abi.parameterFPRegisters()) + { + if (fIt == _fpRegValues.end()) + { + break; + } + + if (regId != *fIt) + { + _fpRegValues.erase(fIt, _fpRegValues.end()); + break; + } + + fIt++; + } +} + +std::vector ParamFilter::getParamValues() const +{ + std::vector paramValues; + + for (auto i : _regValues) + { + paramValues.push_back(_abi.getRegister(i)); + } + + for (auto i : _fpRegValues) + { + paramValues.push_back(_abi.getRegister(i)); + } + + paramValues.insert(paramValues.end(), _stackValues.begin(), _stackValues.end()); + + return paramValues; +} + } // namespace bin2llvmir } // namespace retdec From 231a2af5d2e01657f6ec56d9fdadfff6fb317b9e Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 10:05:34 +0200 Subject: [PATCH 051/159] param_return: use ParamFilter --- .../optimizations/param_return/param_return.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index f426b0397..02461b007 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1002,10 +1002,12 @@ void DataFlowEntry::filter() for (CallEntry& e : calls) { - sortValues(e.possibleArgs); - e.filterLeaveOnlyContinuousStackOffsets(_config, _abi); - e.filterLeaveOnlyContinuousSequence(_abi); - e.filterLeaveOnlyNeededStackOffsets(_config, _abi); + ParamFilter filter(e.possibleArgs, *_abi, *_config); + + filter.leaveOnlyContinuousStackOffsets(); + filter.leaveOnlyContinuousSequence(); + + e.possibleArgs = filter.getParamValues(); if (isVarArg) { From 251a1726625b0a498fdf23c9e5a603744c2916f7 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 27 Aug 2018 09:59:48 +0200 Subject: [PATCH 052/159] param_return: get rid of deprecated methods --- .../optimizations/param_return/param_return.h | 6 - .../param_return/param_return.cpp | 136 ------------------ 2 files changed, 142 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 6c17bb2fd..2ca68ad06 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -32,10 +32,6 @@ class CallEntry CallEntry(llvm::CallInst* c); public: - void filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi *_abi); - void filterLeaveOnlyContinuousSequence(Abi* _abi); - void filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi); - void extractFormatString(ReachingDefinitionsAnalysis& _RDA); bool instructionStoresString( llvm::StoreInst *si, @@ -205,8 +201,6 @@ class ParamReturn : public llvm::ModulePass void filterCalls(); void filterSort(CallEntry& ce); - void filterLeaveOnlyContinuousStackOffsets(CallEntry& ce); - void filterLeaveOnlyNeededStackOffsets(CallEntry& ce); void applyToIr(); diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 02461b007..efe7caa8f 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -332,142 +332,6 @@ void DataFlowEntry::sortValues(std::vector &args) const }); } -/** - * Arguments are stored into stack variables which go one after another, - * there can be no big stack offset gaps. - */ -void CallEntry::filterLeaveOnlyContinuousStackOffsets(Config* _config, Abi* _abi) -{ - retdec::utils::Maybe prevOff; - auto it = possibleArgs.begin(); - while (it != possibleArgs.end()) - { - auto* s = *it; - auto off = _config->getStackVariableOffset(s); - //auto* val = llvm_utils::skipCasts(s); - - // int gap = _abi->getTypeByteSize(val->getType())*2; - static int gap = _abi->wordSize()*2/8; - - if (off.isUndefined()) - { - ++it; - continue; - } - if (prevOff.isUndefined()) - { - prevOff = off; - } - else if (std::abs(prevOff - off) > gap) - { - it = possibleArgs.erase(it); - continue; - } - else - { - prevOff = off; - } - - ++it; - } -} - -void CallEntry::filterLeaveOnlyContinuousSequence(Abi* _abi) -{ - auto fpRegs = _abi->parameterFPRegisters(); - auto fIt = fpRegs.begin(); - - auto it = possibleArgs.begin(); - - for (auto rId : _abi->parameterRegisters()) - { - if (it == possibleArgs.end()) - { - return; - } - - if (rId != _abi->getRegisterId(*it)) - { - if (_abi->parameterRegistersOverlay()) - { - auto nIt = std::find_if( - possibleArgs.begin(), - possibleArgs.end(), - [_abi, fIt](Value* arg) - { - return _abi->getRegisterId(arg) == *fIt; - }); - - if (nIt != possibleArgs.end()) - { - auto val = *nIt; - possibleArgs.erase(nIt); - it = possibleArgs.insert(it, val); - - it++; - fIt++; - - continue; - } - } - - possibleArgs.erase(it, possibleArgs.end()); - return; - } - - it++; - } - -} - -void CallEntry::filterLeaveOnlyNeededStackOffsets(Config* _config, Abi *_abi) -{ - size_t regNum = 0; - size_t fpRegNum = 0; - auto it = possibleArgs.begin(); - - while (it != possibleArgs.end()) - { - auto* op = *it; - auto off = _config->getStackVariableOffset(op); - - if (_abi->isRegister(op)) - { - if (_abi->isGeneralPurposeRegister(op)) - { - ++regNum; - } - else - { - if (_abi->usesFPRegistersForParameters()) - { - fpRegNum++; - } - } - - ++it; - continue; - } - else if (off.isDefined()) - { - if (regNum < _abi->parameterRegisters().size()) - { - if (_abi->usesFPRegistersForParameters() - && fpRegNum >= _abi->parameterFPRegisters().size()) - { - ++it; - continue; - } - - it = possibleArgs.erase(it); - continue; - } - } - - ++it; - } -} - void CallEntry::extractFormatString(ReachingDefinitionsAnalysis& _RDA) { for (auto i : possibleArgs) From b7268c458659379eb532d4b33ebdea18cc391d83 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 24 Jul 2018 11:01:01 +0200 Subject: [PATCH 053/159] param_return: get rid of magic constants There were hard coded constants of byte size of pointer on architecture. This should be replaced with appropriate message to ABI to get the word size of architecture. --- src/bin2llvmir/optimizations/param_return/param_return.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index efe7caa8f..059359b91 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1230,8 +1230,9 @@ void DataFlowEntry::applyToIrVariadic() for (Type* t : types) { LOG << "\ttype : " << llvmObjToString(t) << std::endl; - int sz = static_cast(_abi->getTypeByteSize(t)); - sz = sz > 4 ? 8 : 4; + uint32_t sz = _abi->getTypeByteSize(t); + uint32_t ws = _abi->getTypeByteSize(_abi->getDefaultPointerType()); + sz = sz > ws ? ws*2:ws; if (t->isFloatTy() && _abi->usesFPRegistersForParameters() && faIdx < paramFPRegs.size()) { @@ -1817,7 +1818,7 @@ void ParamFilter::orderRegistersBy( void ParamFilter::leaveOnlyContinuousStackOffsets() { retdec::utils::Maybe prevOff; - int gap = _abi.wordSize()*2/8; + int gap = _abi.getTypeByteSize(_abi.getDefaultPointerType()) * 2; auto it = _stackValues.begin(); while (it != _stackValues.end()) From 993eff69b284a055b85f9796440a8e4d6d5180ab Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 25 Sep 2018 14:23:06 +0200 Subject: [PATCH 054/159] llvm ir: data layout: provide size of pointer on 64 bit architecture --- src/capstone2llvmir/x86/x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/capstone2llvmir/x86/x86.cpp b/src/capstone2llvmir/x86/x86.cpp index 70bfdb589..24688bd41 100644 --- a/src/capstone2llvmir/x86/x86.cpp +++ b/src/capstone2llvmir/x86/x86.cpp @@ -224,7 +224,7 @@ void Capstone2LlvmIrTranslatorX86_impl::generateDataLayout() } case CS_MODE_64: { - _module->setDataLayout("e-i64:64-f80:128-n8:16:32:64-S128"); // clang + _module->setDataLayout("e-m:e-p:64:64-i64:64-f80:128-n8:16:32:64-S128"); // clang break; } default: From 64ad9c6a9462a57df85483d87ae187ce542bd658 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 13 Sep 2018 12:38:02 +0200 Subject: [PATCH 055/159] scripts: retdec-decompiler: new error handle Provides error state checking where unsupported combination of target format and architecture is being decompiled. --- scripts/retdec-decompiler.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/retdec-decompiler.py b/scripts/retdec-decompiler.py index 5c00cad23..4e7247d84 100644 --- a/scripts/retdec-decompiler.py +++ b/scripts/retdec-decompiler.py @@ -934,6 +934,18 @@ def decompile(self): self.format.upper(), fileclass)) return 1 + # TODO this should be somehow connected somewhere else + if fileclass == '64' and self.arch in ['arm', 'mips', 'pic32', 'powerpc', 'x86']: + if self.args.generate_log: + self.generate_log() + + self._cleanup() + utils.print_error( + 'Unsupported target format and architecture combination: \'%s%s\' + \'%s\'.' % ( + self.format.upper(), fileclass, self.arch)) + + return 1 + # Set path to statically linked code signatures. # # TODO: Using ELF for IHEX is ok, but for raw, we probably should somehow decide between ELF and PE, From 4e546700f18458ce012ce37a659989f09afe2f1e Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 23 Oct 2018 10:41:35 +0200 Subject: [PATCH 056/159] param_return: prefer params detected in definition --- .../bin2llvmir/optimizations/param_return/param_return.h | 1 + src/bin2llvmir/optimizations/param_return/param_return.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 2ca68ad06..048855ef3 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -165,6 +165,7 @@ class DataFlowEntry // In called function. // + std::vector regArgs; std::vector args; std::vector retStores; diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 059359b91..105191018 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -517,6 +517,9 @@ void DataFlowEntry::addArgLoads() && added.find(ptr) == added.end()) { args.push_back(ptr); + if (_abi->isRegister(ptr)) + regArgs.push_back(ptr); + added.insert(ptr); } } @@ -1723,8 +1726,9 @@ void DataFlowEntry::setArgumentTypes() break; } } + std::vector &a = args.empty() ? ce->possibleArgs : args; - for (auto st: ce->possibleArgs) + for (auto st: a) { auto op = st; From e503641f16b6053225021a85d5a806d353827307 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 25 Oct 2018 17:36:29 +0200 Subject: [PATCH 057/159] param_return: unify methods to modify IR --- .../optimizations/param_return/param_return.h | 50 +- .../param_return/param_return.cpp | 679 ++++++++++-------- 2 files changed, 413 insertions(+), 316 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 048855ef3..e43dabf05 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -32,18 +32,25 @@ class CallEntry CallEntry(llvm::CallInst* c); public: - void extractFormatString(ReachingDefinitionsAnalysis& _RDA); bool instructionStoresString( - llvm::StoreInst *si, + llvm::StoreInst* si, std::string& str, - ReachingDefinitionsAnalysis &_RDA) const; + ReachingDefinitionsAnalysis& _RDA) const; + + void extractSpecificArgTypes( + llvm::Module* m, + ReachingDefinitionsAnalysis& _RDA, + llvm::CallInst* wrappedCall = nullptr); + + private: + std::string extractFormatString(ReachingDefinitionsAnalysis& _RDA) const; public: llvm::CallInst* call = nullptr; std::vector possibleArgs; std::vector possibleArgStores; std::vector possibleRetLoads; - std::string formatStr; + std::vector specTypes; }; class ReturnEntry @@ -60,9 +67,11 @@ class ParamFilter { public: ParamFilter( + llvm::CallInst* call, const std::vector& paramValues, - const Abi& abi, - Config& config); + const std::vector &types, + const Abi* abi, + Config* config); void orderStacks(std::vector& stacks, bool asc = true) const; void orderRegistersBy( @@ -71,6 +80,11 @@ class ParamFilter void leaveOnlyContinuousSequence(); void leaveOnlyContinuousStackOffsets(); + void leaveOnlyPositiveStacks(); + + void adjustValuesByKnownTypes( + llvm::CallInst* call, + std::vector &types); std::vector getParamValues() const; @@ -78,14 +92,24 @@ class ParamFilter void separateParamValues(const std::vector& paramValues); void applyAlternatingRegistersFilter(); void applySequentialRegistersFilter(); + llvm::Value* stackVariableForType(llvm::CallInst* call, llvm::Type* type) const; + + bool moveRegsByTypeSizeAtIdx(std::vector &destinastion, + const std::vector &sourceTemplate, + llvm::Type* type, + uint32_t* idx); private: - const Abi& _abi; - Config& _config; + const Abi* _abi; + Config* _config; + + llvm::CallInst* _call; std::vector _regValues; std::vector _fpRegValues; std::vector _stackValues; + + std::vector _paramTypes; }; class DataFlowEntry @@ -112,8 +136,6 @@ class DataFlowEntry void filter(); void applyToIr(); - void applyToIrOrdinary(); - void applyToIrVariadic(); void connectWrappers(); private: @@ -135,6 +157,8 @@ class DataFlowEntry void setReturnType(); void setArgumentTypes(); + llvm::CallInst* isSimpleWrapper(llvm::Function* fnc) const; + void filterSortArgLoads(); void filterNegativeStacks(); void sortValues(std::vector &args) const; @@ -145,7 +169,11 @@ class DataFlowEntry std::map> fetchLoadsOfCalls() const; - llvm::CallInst* isSimpleWrapper(llvm::Function* fnc); + llvm::Value* joinParamPair(llvm::Value* low, llvm::Value* high, + llvm::Type *type, llvm::Instruction *before) const; + void splitIntoParamPair( + llvm::AllocaInst* blob, + std::pair ¶mPair) const; public: llvm::Module* _module = nullptr; diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 105191018..e733cb909 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -32,7 +32,7 @@ #include "retdec/utils/container.h" #include "retdec/utils/string.h" #include "retdec/bin2llvmir/optimizations/param_return/param_return.h" -#define debug_enabled false +#define debug_enabled true #include "retdec/bin2llvmir/utils/llvm.h" #include "retdec/bin2llvmir/providers/asm_instruction.h" #include "retdec/bin2llvmir/utils/ir_modifier.h" @@ -124,6 +124,7 @@ bool ParamReturn::runOnModule(Module& m) _image = FileImageProvider::getFileImage(_module); _dbgf = DebugFormatProvider::getDebugFormat(_module); _lti = LtiProvider::getLti(_module); + return run(); } @@ -276,16 +277,21 @@ CallEntry::CallEntry(llvm::CallInst* c) : } -void DataFlowEntry::filterNegativeStacks() +void CallEntry::extractSpecificArgTypes(Module* m, + ReachingDefinitionsAnalysis& _RDA, + CallInst *wrappedCall) { - args.erase( - std::remove_if(args.begin(), args.end(), - [this](const Value* li) - { - auto aOff = _config->getStackVariableOffset(li); - return aOff.isDefined() && aOff < 0; - }), - args.end()); + std::string formatStr = extractFormatString(_RDA); + + if (formatStr.empty()) + return; + + auto trueCall = wrappedCall ? wrappedCall : call; + + specTypes = llvm_utils::parseFormatString( + m, + formatStr, + trueCall->getCalledFunction()); } /** @@ -332,8 +338,10 @@ void DataFlowEntry::sortValues(std::vector &args) const }); } -void CallEntry::extractFormatString(ReachingDefinitionsAnalysis& _RDA) +std::string CallEntry::extractFormatString(ReachingDefinitionsAnalysis& _RDA) const { + std::string str; + for (auto i : possibleArgs) { auto inst = std::find_if(possibleArgStores.begin(), @@ -345,14 +353,14 @@ void CallEntry::extractFormatString(ReachingDefinitionsAnalysis& _RDA) if (inst != possibleArgStores.end()) { - std::string str; if (instructionStoresString(*inst, str, _RDA)) { - formatStr = str; - return; + break; } } } + + return str; } // @@ -465,9 +473,10 @@ void DataFlowEntry::dump() const { LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; } - if (!e.formatStr.empty()) + LOG << "\t\t\targ types:" << std::endl; + for (auto* t : e.specTypes) { - LOG << "\t\t\t>|format str: " << e.formatStr << std::endl; + LOG << "\t\t\t>|" << llvmObjToString(t) << std::endl; } } @@ -608,7 +617,10 @@ void DataFlowEntry::addCall(llvm::CallInst* call) } // std::vector? -std::set DataFlowEntry::collectArgsFromInstruction(Instruction* startInst, std::map> &seenBlocks, std::vector *possibleArgStores) +std::set DataFlowEntry::collectArgsFromInstruction( + Instruction* startInst, + std::map> &seenBlocks, + std::vector *possibleArgStores) { NonIterableSet excludedValues; auto* block = startInst->getParent(); @@ -832,54 +844,36 @@ void DataFlowEntry::addCallReturns(llvm::CallInst* call, CallEntry& ce) } } -/** - * TODO: This method just filters register pair of known double type. - * It should also remove another stack variable and not just for double - * but every large type -> wordSize * 2 - */ -void DataFlowEntry::filterKnownParamPairs() +void DataFlowEntry::filter() { - for (CallEntry& e : calls) + if (!args.empty()) { - auto tIt = argTypes.begin(); - auto sIt = e.possibleArgs.begin(); + ParamFilter filter(nullptr, args, argTypes, _abi, _config); + filter.leaveOnlyPositiveStacks(); + args = filter.getParamValues(); + } - while (tIt != argTypes.end() && sIt != e.possibleArgs.end()) + for (CallEntry& e : calls) + { + if (isVarArg) { - Type* t = *tIt; - auto nextIt = sIt; - ++nextIt; - if (t->isDoubleTy() - && nextIt != e.possibleArgs.end() - && _abi->isRegister(*nextIt)) - { - e.possibleArgs.erase(nextIt); - } - - ++tIt; - ++sIt; + e.extractSpecificArgTypes( + _module, + _RDA, + isSimpleWrapper( + e.call->getCalledFunction())); } - } -} -void DataFlowEntry::filter() -{ - filterNegativeStacks(); - sortValues(args); + auto types = argTypes; + types.insert(types.end(), e.specTypes.begin(), e.specTypes.end()); - for (CallEntry& e : calls) - { - ParamFilter filter(e.possibleArgs, *_abi, *_config); + ParamFilter filter(e.call, e.possibleArgs, types, + _abi, _config); filter.leaveOnlyContinuousStackOffsets(); filter.leaveOnlyContinuousSequence(); e.possibleArgs = filter.getParamValues(); - - if (isVarArg) - { - e.extractFormatString(_RDA); - } } if (!isVarArg) @@ -888,11 +882,7 @@ void DataFlowEntry::filter() callsFilterSameNumberOfStacks(); } - if (typeSet) - { - filterKnownParamPairs(); - } - else + if (!typeSet) { setTypeFromUseContext(); } @@ -1030,16 +1020,45 @@ void DataFlowEntry::callsFilterSameNumberOfStacks() } } -void DataFlowEntry::applyToIr() +Value* DataFlowEntry::joinParamPair(Value* low, Value* high, Type *type, Instruction *before) const { - if (isVarArg) - { - applyToIrVariadic(); - } - else - { - applyToIrOrdinary(); - } + auto ib = _abi->getTypeBitSize(type); + auto intType = IntegerType::get(_module->getContext(), ib); + auto wordSize = _abi->getTypeBitSize( + _abi->getDefaultPointerType()); + + high = IrModifier::convertValueToType(high, intType, before); + low = IrModifier::convertValueToType(low, intType, before); + + high = BinaryOperator::Create(Instruction::Shl, high, llvm::ConstantInt::get(intType, wordSize), "", before); + auto join = BinaryOperator::Create(Instruction::Or, low, high, "", before); + + return IrModifier::convertValueToType(join, type, before); +} + +void DataFlowEntry::splitIntoParamPair(AllocaInst* blob, std::pair ¶mPair) const +{ + auto param1 = paramPair.first; + auto param2 = paramPair.second; + + auto wordSize = _abi->getTypeBitSize( + _abi->getDefaultPointerType()); + + auto halfInt = IntegerType::get(_module->getContext(), wordSize); + auto intType = IntegerType::get(_module->getContext(), wordSize*2); + + auto before = blob->getNextNode(); + + auto load = new LoadInst(blob, "", before); + + auto val = IrModifier::convertValueToType(load, intType, before); + + auto trunc = new TruncInst(val, halfInt, "", before); + new StoreInst(trunc, param1, before); + + auto shift = BinaryOperator::Create(Instruction::LShr, val, llvm::ConstantInt::get(intType, wordSize), "", before); + trunc = new TruncInst(shift, halfInt, "", before); + new StoreInst(trunc, param2, before); } std::map> DataFlowEntry::fetchLoadsOfCalls() const @@ -1050,8 +1069,22 @@ std::map> DataFlowEntry::fetchLoadsOfCalls() cons { std::vector loads; auto* call = e.call; - for (auto* s : e.possibleArgs) + auto paramRegs = _abi->parameterRegisters(); + + auto types = argTypes; + types.insert(types.end(), + e.specTypes.begin(), e.specTypes.end()); + auto tIt = types.begin(); + + auto aIt = e.possibleArgs.begin(); + while (aIt != e.possibleArgs.end()) { + if (*aIt == nullptr) + { + aIt++; + continue; + } + auto fIt = specialArgStorage.find(loads.size()); while (fIt != specialArgStorage.end()) { @@ -1060,7 +1093,33 @@ std::map> DataFlowEntry::fetchLoadsOfCalls() cons fIt = specialArgStorage.find(loads.size()); } - auto* l = new LoadInst(s, "", call); + Value* l = new LoadInst(*aIt, "", call); + aIt++; + + if (tIt != types.end()) + { + auto wordSize = _abi->getTypeByteSize( + _abi->getDefaultPointerType()); + if (wordSize < _abi->getTypeByteSize(*tIt) + && aIt != e.possibleArgs.end()) + { + Value* lp = new LoadInst(*aIt, "", call); + aIt++; + + l = joinParamPair(l, lp, *tIt, call); + } + else + { + l = IrModifier::convertValueToType(l, *tIt, call); + } + + tIt++; + } + else + { + l = IrModifier::convertValueToType(l, _abi->getDefaultType(), call); + } + loads.push_back(l); } @@ -1078,7 +1137,7 @@ void DataFlowEntry::replaceCalls() IrModifier::modifyCallInst(l.first, l.first->getType(), l.second); } -void DataFlowEntry::applyToIrOrdinary() +void DataFlowEntry::applyToIr() { Function* analysedFunction = getFunction(); @@ -1110,223 +1169,54 @@ void DataFlowEntry::applyToIrOrdinary() } } - std::vector argStores; - for (Value* l : args) - { - auto fIt = specialArgStorage.find(argStores.size()); - while (fIt != specialArgStorage.end()) - { - argStores.push_back(fIt->second); - fIt = specialArgStorage.find(argStores.size()); - } - - argStores.push_back(l); - } - auto paramRegs = _abi->parameterRegisters(); - for (auto& p : loadsOfCalls) - { - std::size_t idx = 0; - for (auto* t : argTypes) - { - (void) t; - if (p.second.size() <= idx) - { - if (idx < paramRegs.size()) - { - auto* r = _abi->getRegister(paramRegs[idx]); - auto* l = new LoadInst(r, "", p.first); - p.second.push_back(l); - } - } - ++idx; - } - } - - auto* oldType = analysedFunction->getType(); - IrModifier irm(_module, _config); - auto* newFnc = irm.modifyFunction( - analysedFunction, - retType, - argTypes, - isVarArg, - rets2vals, - loadsOfCalls, - retVal, - argStores, - argNames).first; - - LOG << "modify fnc: " << newFnc->getName().str() << " = " - << llvmObjToString(oldType) << " -> " - << llvmObjToString(newFnc->getType()) << std::endl; - - called = newFnc; -} - -void DataFlowEntry::applyToIrVariadic() -{ - auto paramRegs = _abi->parameterRegisters(); - auto paramFPRegs = _abi->parameterFPRegisters(); - auto doubleParamRegs = _abi->doubleParameterRegisters(); - - llvm::Value* retVal = nullptr; - std::map rets2vals; std::vector argStores; - std::map> loadsOfCalls; - - for (CallEntry& ce : calls) - { - auto* fnc = ce.call->getFunction(); - auto* calledFnc = ce.call->getCalledFunction(); - LOG << llvmObjToString(ce.call) << std::endl; - LOG << "\tformat : " << ce.formatStr << std::endl; + auto aIt = args.begin(); + auto tIt = argTypes.begin(); - // get lowest stack offset - // - int stackOff = std::numeric_limits::max(); - for (Value* s : ce.possibleArgs) - { - if (_config->isStackVariable(s)) - { - auto so = _config->getStackVariableOffset(s); - if (so < stackOff) - { - stackOff = so; - } - } - } - LOG << "\tlowest : " << std::dec << stackOff << std::endl; - - // - // - auto* wrapCall = isSimpleWrapper(calledFnc); - auto* wrapFnc = wrapCall ? wrapCall->getCalledFunction() : calledFnc; - std::vector ttypes = llvm_utils::parseFormatString( - _module, - ce.formatStr, - wrapFnc); + std::map> createdPairs; - if (_config->getConfig().architecture.isPic32()) - { - for (size_t i = 0; i < ttypes.size(); ++i) - { - if (ttypes[i]->isDoubleTy()) - { - ttypes[i] = Type::getFloatTy(_module->getContext()); - } - } + while (aIt != args.end()) + { + if (*aIt == nullptr) { + aIt++; + continue; } - // - // - int off = stackOff; - std::vector args; - - size_t faIdx = 0; - size_t aIdx = 0; - - std::vector types = argTypes; - types.insert(types.end(), ttypes.begin(), ttypes.end()); + Value *l = *aIt; + aIt++; - for (Type* t : types) + auto fIt = specialArgStorage.find(argStores.size()); + while (fIt != specialArgStorage.end()) { - LOG << "\ttype : " << llvmObjToString(t) << std::endl; - uint32_t sz = _abi->getTypeByteSize(t); - uint32_t ws = _abi->getTypeByteSize(_abi->getDefaultPointerType()); - sz = sz > ws ? ws*2:ws; - - if (t->isFloatTy() && _abi->usesFPRegistersForParameters() && faIdx < paramFPRegs.size()) - { - - auto* r = _abi->getRegister(paramFPRegs[faIdx]); - if (r) - { - args.push_back(r); - } - ++faIdx; - } - else if (t->isDoubleTy() && _abi->usesFPRegistersForParameters() && faIdx < doubleParamRegs.size()) - { - auto* r = _abi->getRegister(doubleParamRegs[faIdx]); - if (r) - { - args.push_back(r); - } - ++faIdx; - ++faIdx; - } - else if (aIdx < paramRegs.size()) - { - auto* r = _abi->getRegister(paramRegs[aIdx]); - if (r) - { - args.push_back(r); - } - - // TODO: register pairs -> if size is more than arch size - if (sz > ws) - { - ++aIdx; - } - - ++aIdx; - } - else - { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) - { - args.push_back(st); - } - - off += sz; - } + argStores.push_back(fIt->second); + fIt = specialArgStorage.find(argStores.size()); } + auto wordSize = _abi->getTypeByteSize( + _abi->getDefaultPointerType()); - // - // - unsigned idx = 0; - std::vector loads; - for (auto* a : args) + if (aIt != args.end() && tIt != argTypes.end() + && _abi->getTypeByteSize(*tIt) > wordSize) { - Value* l = new LoadInst(a, "", ce.call); - LOG << "\t\t" << llvmObjToString(l) << std::endl; + auto p1 = l; + auto p2 = *aIt; + aIt++; - if (types.size() > idx) - { - l = IrModifier::convertValueToType(l, types[idx], ce.call); - } - - loads.push_back(l); - ++idx; + auto ai = IrModifier::createAlloca(analysedFunction, *tIt); + createdPairs[ai] = std::make_pair(p1, p2); + splitIntoParamPair(ai, createdPairs[ai]); + l = ai; } - if (!loads.empty()) - { - loadsOfCalls[ce.call] = loads; - } - } - - retVal = retType->isFloatingPointTy() ? - _abi->getFPReturnRegister() : _abi->getReturnRegister(); - - if (retVal) - { - for (auto& e : retStores) - { - auto* l = new LoadInst(retVal, "", e.ret); - rets2vals[e.ret] = l; - } + argStores.push_back(l); } - auto* fnc = getFunction(); - auto* oldType = fnc->getType(); - + auto* oldType = analysedFunction->getType(); IrModifier irm(_module, _config); auto* newFnc = irm.modifyFunction( - fnc, + analysedFunction, retType, argTypes, isVarArg, @@ -1433,7 +1323,7 @@ void DataFlowEntry::connectWrappers() } } -llvm::CallInst* DataFlowEntry::isSimpleWrapper(llvm::Function* fnc) +llvm::CallInst* DataFlowEntry::isSimpleWrapper(llvm::Function* fnc) const { auto ai = AsmInstruction(fnc); if (ai.isInvalid()) @@ -1717,21 +1607,11 @@ void DataFlowEntry::setArgumentTypes() } else { - CallEntry* ce = &calls.front(); - for (auto& c : calls) - { - if (!c.possibleArgs.empty()) - { - ce = &c; - break; - } - } - std::vector &a = args.empty() ? ce->possibleArgs : args; + auto ce = calls.front(); + std::vector &a = args.empty() ? ce.possibleArgs : args; - for (auto st: a) + for (const auto& op: a) { - auto op = st; - if (_abi->isRegister(op) && !_abi->isGeneralPurposeRegister(op)) { argTypes.push_back(Abi::getDefaultFPType(_module)); @@ -1751,38 +1631,47 @@ void DataFlowEntry::setArgumentTypes() // ParamFilter::ParamFilter( + CallInst* call, const std::vector& paramValues, - const Abi& abi, - Config& config) + const std::vector& paramTypes, + const Abi* abi, + Config* config) : _abi(abi), - _config(config) + _config(config), + _call(call), + _paramTypes(paramTypes) { separateParamValues(paramValues); - orderRegistersBy(_fpRegValues, _abi.parameterFPRegisters()); - orderRegistersBy(_regValues, _abi.parameterRegisters()); + orderRegistersBy(_fpRegValues, _abi->parameterFPRegisters()); + orderRegistersBy(_regValues, _abi->parameterRegisters()); orderStacks(_stackValues); + + if (!paramTypes.empty() && call != nullptr) + { + adjustValuesByKnownTypes(call, _paramTypes); + } } void ParamFilter::separateParamValues(const std::vector& paramValues) { - auto regs = _abi.parameterRegisters(); + auto regs = _abi->parameterRegisters(); for (auto pv: paramValues) { - if (_config.isStackVariable(pv)) + if (_config->isStackVariable(pv)) { _stackValues.push_back(pv); } else if (std::find(regs.begin(), regs.end(), - _abi.getRegisterId(pv)) != regs.end()) + _abi->getRegisterId(pv)) != regs.end()) { - _regValues.push_back(_abi.getRegisterId(pv)); + _regValues.push_back(_abi->getRegisterId(pv)); } else { - _fpRegValues.push_back(_abi.getRegisterId(pv)); + _fpRegValues.push_back(_abi->getRegisterId(pv)); } } } @@ -1794,8 +1683,8 @@ void ParamFilter::orderStacks(std::vector& stacks, bool asc) const stacks.end(), [this, asc](Value* a, Value* b) -> bool { - auto aOff = _config.getStackVariableOffset(a); - auto bOff = _config.getStackVariableOffset(b); + auto aOff = _config->getStackVariableOffset(a); + auto bOff = _config->getStackVariableOffset(b); bool ascOrd = aOff < bOff; @@ -1822,12 +1711,12 @@ void ParamFilter::orderRegistersBy( void ParamFilter::leaveOnlyContinuousStackOffsets() { retdec::utils::Maybe prevOff; - int gap = _abi.getTypeByteSize(_abi.getDefaultPointerType()) * 2; + int gap = _abi->getTypeByteSize(_abi->getDefaultPointerType()) * 2; auto it = _stackValues.begin(); while (it != _stackValues.end()) { - auto off = _config.getStackVariableOffset(*it); + auto off = _config->getStackVariableOffset(*it); if (prevOff.isUndefined()) { @@ -1849,7 +1738,7 @@ void ParamFilter::leaveOnlyContinuousStackOffsets() void ParamFilter::leaveOnlyContinuousSequence() { - if (_abi.parameterRegistersOverlay()) + if (_abi->parameterRegistersOverlay()) { applyAlternatingRegistersFilter(); } @@ -1861,8 +1750,8 @@ void ParamFilter::leaveOnlyContinuousSequence() void ParamFilter::applyAlternatingRegistersFilter() { - auto templRegs = _abi.parameterRegisters(); - auto fpTemplRegs = _abi.parameterFPRegisters(); + auto templRegs = _abi->parameterRegisters(); + auto fpTemplRegs = _abi->parameterFPRegisters(); size_t idx = 0; auto it = _regValues.begin(); @@ -1900,7 +1789,7 @@ void ParamFilter::applyAlternatingRegistersFilter() void ParamFilter::applySequentialRegistersFilter() { auto it = _regValues.begin(); - for (auto regId : _abi.parameterRegisters()) + for (auto regId : _abi->parameterRegisters()) { if (it == _regValues.end()) { @@ -1919,7 +1808,7 @@ void ParamFilter::applySequentialRegistersFilter() } auto fIt = _fpRegValues.begin(); - for (auto regId : _abi.parameterFPRegisters()) + for (auto regId : _abi->parameterFPRegisters()) { if (fIt == _fpRegValues.end()) { @@ -1939,21 +1828,201 @@ void ParamFilter::applySequentialRegistersFilter() std::vector ParamFilter::getParamValues() const { std::vector paramValues; + auto ri = _regValues.begin(); + auto fi = _fpRegValues.begin(); + auto si = _stackValues.begin(); + + for (auto t: _paramTypes) + { + bool shouldGetFromStack = false; + + if (t->isFloatingPointTy() && _abi->usesFPRegistersForParameters()) + { + if (fi != _fpRegValues.end()) + { + auto reg = _abi->getRegister(*fi); + paramValues.push_back(reg); + ++fi; + } + else + { + shouldGetFromStack = true; + } + } + else if (ri != _regValues.end()) + { + auto reg = _abi->getRegister(*ri); + paramValues.push_back(reg); + ++ri; + } + else + { + shouldGetFromStack = true; + } + + if (shouldGetFromStack) + { + if (si != _stackValues.end()) + { + paramValues.push_back(*si); + ++si; + } + else + { + paramValues.push_back(nullptr); + } + } + } - for (auto i : _regValues) + while (ri != _regValues.end()) { - paramValues.push_back(_abi.getRegister(i)); + paramValues.push_back(_abi->getRegister(*ri)); + ri++; } - for (auto i : _fpRegValues) + while (fi != _fpRegValues.end()) { - paramValues.push_back(_abi.getRegister(i)); + paramValues.push_back(_abi->getRegister(*fi)); + fi++; } - paramValues.insert(paramValues.end(), _stackValues.begin(), _stackValues.end()); + paramValues.insert(paramValues.end(), si, _stackValues.end()); return paramValues; } +Value* ParamFilter::stackVariableForType(CallInst* call, Type* type) const +{ + uint32_t wordSize = _abi->getTypeByteSize(_abi->getDefaultPointerType()); + + uint32_t off = _abi->getTypeByteSize(type); + off = off > wordSize ? wordSize*2:wordSize; + + if (!_stackValues.empty()) + { + off += _config->getStackVariableOffset(_stackValues.back()); + } + + return _config->getLlvmStackVariable(call->getFunction(), off); +} + +bool ParamFilter::moveRegsByTypeSizeAtIdx(std::vector &destinastion, + const std::vector &sourceTemplate, + Type* type, + uint32_t* idx) +{ + if (idx == nullptr || *idx >= sourceTemplate.size()) + { + return false; + } + + /* + // Register pairs must start with register with even number + if (*idx % reqRegs != 0) + { + (*idx)++; + }*/ + + destinastion.push_back(sourceTemplate[*idx]); + auto templateReg = _abi->getRegister(sourceTemplate[*idx]); + + *idx += 1; + + if (_abi->getTypeByteSize(type) + > _abi->getTypeByteSize(templateReg->getType())) + { + if (*idx >= sourceTemplate.size()) + { + return false; + } + + + destinastion.push_back(sourceTemplate[*idx]); + *idx += 1; + } + + return true; +} + +void ParamFilter::adjustValuesByKnownTypes(CallInst* call, std::vector& types) +{ + std::vector regValues, fpRegValues; + + auto paramRegs = _abi->parameterRegisters(); + auto fpParamRegs = _abi->parameterFPRegisters(); + + // Indexes of registers to be used next as particular parameter. + uint32_t pI = 0; + uint32_t fI = 0; + + auto sI = _stackValues.begin(); + + std::vector paramValues; + for (auto t: types) + { + if (_abi->usesFPRegistersForParameters() + && t->isFloatingPointTy()) + { + // if cannot move to fp regs push on stack + if (!moveRegsByTypeSizeAtIdx(fpRegValues, fpParamRegs, t, &fI)) + { + if (sI != _stackValues.end()) + { + sI++; + } + else + { + auto s = stackVariableForType(call, t); + if (s != nullptr) + { + _stackValues.push_back(s); + sI = _stackValues.end(); + } + } + } + } + else + { + // if cannot move to regs push on stack + if (!moveRegsByTypeSizeAtIdx(regValues, paramRegs, t, &pI)) + { + if (sI != _stackValues.end()) + { + sI++; + } + else + { + auto s = stackVariableForType(call, t); + if (s != nullptr) + { + _stackValues.push_back(s); + sI = _stackValues.end(); + } + } + } + } + } + + _fpRegValues = fpRegValues; + _regValues = regValues; + + if (sI != _stackValues.end()) + { + _stackValues.erase(sI, _stackValues.end()); + } +} + +void ParamFilter::leaveOnlyPositiveStacks() +{ + _stackValues.erase( + std::remove_if(_stackValues.begin(), _stackValues.end(), + [this](const Value* li) + { + auto aOff = _config->getStackVariableOffset(li); + return aOff.isDefined() && aOff < 0; + }), + _stackValues.end()); +} + } // namespace bin2llvmir } // namespace retdec From 64320898806fbe3ff7ab50b0aee0d150b7f254e7 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 30 Jan 2019 09:22:12 +0100 Subject: [PATCH 058/159] x86_fastcall: new abi --- .../bin2llvmir/providers/abi/x86_fastcall.h | 37 +++++++ src/bin2llvmir/CMakeLists.txt | 3 +- src/bin2llvmir/providers/abi/x86_fastcall.cpp | 103 ++++++++++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 include/retdec/bin2llvmir/providers/abi/x86_fastcall.h create mode 100644 src/bin2llvmir/providers/abi/x86_fastcall.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/x86_fastcall.h b/include/retdec/bin2llvmir/providers/abi/x86_fastcall.h new file mode 100644 index 000000000..d3cab4850 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/x86_fastcall.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/x86.h + * @brief ABI information for x86. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_FASTCALL_X86_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_FASTCALL_X86_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiX86Fastcall : public Abi +{ + // Ctors, dtors. + // + public: + AbiX86Fastcall(llvm::Module* m, Config* c); + virtual ~AbiX86Fastcall(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 8013cc126..156fde618 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -70,8 +70,9 @@ set(BIN2LLVMIR_SOURCES providers/abi/ms_x64.cpp providers/abi/pic32.cpp providers/abi/powerpc.cpp - providers/abi/x86.cpp providers/abi/x64.cpp + providers/abi/x86.cpp + providers/abi/x86_fastcall.cpp providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/providers/abi/x86_fastcall.cpp b/src/bin2llvmir/providers/abi/x86_fastcall.cpp new file mode 100644 index 000000000..b3a9da9a3 --- /dev/null +++ b/src/bin2llvmir/providers/abi/x86_fastcall.cpp @@ -0,0 +1,103 @@ +/** + * @file src/bin2llvmir/providers/abi/x86.cpp + * @brief ABI information for x86. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/x86_fastcall.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiX86Fastcall::AbiX86Fastcall(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(X86_REG_ENDING); + _id2regs.resize(X86_REG_ENDING, nullptr); + _regStackPointerId = X86_REG_ESP; + + // system calls + _regSyscallId = X86_REG_EAX; + _regSyscallReturn = X86_REG_EAX; + _syscallRegs = { + X86_REG_EBX, + X86_REG_ECX, + X86_REG_EDX, + X86_REG_ESI, + X86_REG_EDI, + X86_REG_EBP}; + + _paramRegs = { + X86_REG_ECX, + X86_REG_EDX}; + + _regReturn = X86_REG_EAX; + _regFPReturn = X86_REG_ST7; +} + +AbiX86Fastcall::~AbiX86Fastcall() +{ + +} + +bool AbiX86Fastcall::isGeneralPurposeRegister(const llvm::Value* val) +{ + uint32_t rid = getRegisterId(val); + return rid == X86_REG_EAX + || rid == X86_REG_EBX + || rid == X86_REG_ECX + || rid == X86_REG_EDX + || rid == X86_REG_ESP + || rid == X86_REG_EBP + || rid == X86_REG_ESI + || rid == X86_REG_EDI; +} + +bool AbiX86Fastcall::isNopInstruction(cs_insn* insn) +{ + cs_x86& insn86 = insn->detail->x86; + + // True NOP variants. + // + if (insn->id == X86_INS_NOP + || insn->id == X86_INS_FNOP + || insn->id == X86_INS_FDISI8087_NOP + || insn->id == X86_INS_FENI8087_NOP + || insn->id == X86_INS_INT3) + { + return true; + } + // e.g. lea esi, [esi] + // + else if (insn->id == X86_INS_LEA + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_MEM + && insn86.operands[1].mem.segment == X86_REG_INVALID + && insn86.operands[1].mem.index == X86_REG_INVALID + && insn86.operands[1].mem.scale == 1 + && insn86.operands[1].mem.disp == 0 + && insn86.operands[1].mem.base == insn86.operands[0].reg) + { + return true; + } + // e.g. mov esi. esi + // + else if (insn->id == X86_INS_MOV + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_REG + && insn86.operands[0].reg == insn86.operands[1].reg) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec From 06b45eadb1ed36f3d0283431220133171b94868e Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 30 Jan 2019 09:23:28 +0100 Subject: [PATCH 059/159] x86_fastcall: provide unit tests --- .../param_return/param_return_tests.cpp | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 8dbf34d0e..557a59bd3 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -4,6 +4,8 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ +#include "retdec/bin2llvmir/providers/abi/x86_fastcall.h" + #include "retdec/bin2llvmir/optimizations/param_return/param_return.h" #include "bin2llvmir/utils/llvmir_tests.h" @@ -2743,6 +2745,174 @@ TEST_F(ParamReturnTests, mipsExternalCallUseStacksIf4RegistersUsed) checkModuleAgainstExpectedIr(exp); } +/** + * Tests basic parameter sequence of fascall + * calling convention: + * + * - ecx and edx are used for first two parameters + * - other parameters are passed on the stack + */ +TEST_F(ParamReturnTests, x86FastcallBasic) +{ + parseInput(R"( + @eax = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + + AbiX86Fastcall abi(module.get(), &config); + abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); + abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @eax = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* @ecx + %2 = load i32, i32* @edx + %3 = load i32, i32* %stack_-8 + %4 = load i32, i32* %stack_-4 + %5 = bitcast void ()* %a to void (i32, i32, i32, i32)* + call void %5(i32 %1, i32 %2, i32 %3, i32 %4) + %6 = load i32, i32* @eax + ret i32 %6 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + + +/** + * Tests more complex parameter passing. + * When type larger than a size of a 32 bit register + * is passed to the funcion then: + * - this type is split to the more 32 bit parts, + * - each part is passed on the stack separately. + */ +TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) +{ + parseInput(R"( + @r = global i32 0 + @ecx = global i32 0 + @edx = global i32 0 + @eax = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* @ecx + store i32 456, i32* %stack_-4 + store i32 789, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + + })"); + AbiX86Fastcall abi(module.get(), &config); + + abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); + abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @r = global i32 0 + @ecx = global i32 0 + @edx = global i32 0 + @eax = global i32 0 + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* @ecx + store i32 456, i32* %stack_-4 + store i32 789, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* @ecx + %2 = load i32, i32* %stack_-8 + %3 = load i32, i32* %stack_-4 + %4 = bitcast void ()* %a to void (i32, i32, i32)* + call void %4(i32 %1, i32 %2, i32 %3) + %5 = load i32, i32* @eax + ret i32 %5 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + } // namespace tests } // namespace bin2llvmir } // namespace retdec From 75d16f3fc1b60c56d689774e7979720a8b873bc9 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:11:22 +0100 Subject: [PATCH 060/159] arm64: new abi --- .../retdec/bin2llvmir/providers/abi/arm64.h | 37 +++++++++ src/bin2llvmir/CMakeLists.txt | 1 + src/bin2llvmir/providers/abi/arm64.cpp | 80 +++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/abi/arm64.h create mode 100644 src/bin2llvmir/providers/abi/arm64.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/arm64.h b/include/retdec/bin2llvmir/providers/abi/arm64.h new file mode 100644 index 000000000..671812e25 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/arm64.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/arm64.h + * @brief ABI information for ARM64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_ARM64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_ARM64_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiArm64 : public Abi +{ + // Ctors, dtors. + // + public: + AbiArm64(llvm::Module* m, Config* c); + virtual ~AbiArm64(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 156fde618..882f64aa5 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -66,6 +66,7 @@ set(BIN2LLVMIR_SOURCES optimizations/unreachable_funcs/unreachable_funcs.cpp providers/abi/abi.cpp providers/abi/arm.cpp + providers/abi/arm64.cpp providers/abi/mips.cpp providers/abi/ms_x64.cpp providers/abi/pic32.cpp diff --git a/src/bin2llvmir/providers/abi/arm64.cpp b/src/bin2llvmir/providers/abi/arm64.cpp new file mode 100644 index 000000000..a84ab4e42 --- /dev/null +++ b/src/bin2llvmir/providers/abi/arm64.cpp @@ -0,0 +1,80 @@ +/** + * @file src/bin2llvmir/providers/abi/arm64.cpp + * @brief ABI information for ARM64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/arm64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiArm64::AbiArm64(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(ARM64_REG_ENDING); + _id2regs.resize(ARM64_REG_ENDING, nullptr); + _regStackPointerId = ARM64_REG_SP; + + // system calls + _regSyscallId = ARM64_REG_X7; + _regSyscallReturn = ARM64_REG_X0; + _syscallRegs = { + ARM64_REG_X0, + ARM64_REG_X1, + ARM64_REG_X2, + ARM64_REG_X3, + ARM64_REG_X4, + ARM64_REG_X5}; + + _regReturn = ARM64_REG_X0; + _regFPReturn = ARM64_REG_X0; + + _paramRegs = { + ARM64_REG_X0, + ARM64_REG_X1, + ARM64_REG_X2, + ARM64_REG_X3, + ARM64_REG_X4, + ARM64_REG_X5, + ARM64_REG_X6, + ARM64_REG_X7}; + + _paramFPRegs = { + ARM64_REG_V0, + ARM64_REG_V1, + ARM64_REG_V2, + ARM64_REG_V3, + ARM64_REG_V4, + ARM64_REG_V5, + ARM64_REG_V6, + ARM64_REG_V7}; +} + +AbiArm64::~AbiArm64() +{ + +} + +bool AbiArm64::isGeneralPurposeRegister(const llvm::Value* val) +{ + uint32_t rid = getRegisterId(val); + return ARM64_REG_X0 <= rid && rid <= ARM64_REG_X30; +} + +bool AbiArm64::isNopInstruction(cs_insn* insn) +{ + // True NOP variants. + // + if (insn->id == ARM64_INS_NOP) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec From 61acd54fd7094794c50a6e74d5bae43693a8a56a Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:11:53 +0100 Subject: [PATCH 061/159] x86_watcom: new abi --- .../bin2llvmir/providers/abi/x86_watcom.h | 37 ++++++ src/bin2llvmir/providers/abi/x86_watcom.cpp | 106 ++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/abi/x86_watcom.h create mode 100644 src/bin2llvmir/providers/abi/x86_watcom.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/x86_watcom.h b/include/retdec/bin2llvmir/providers/abi/x86_watcom.h new file mode 100644 index 000000000..13e774e28 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/x86_watcom.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/x86.h + * @brief ABI information for x86. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_X86_WATCOM_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_X86_WATCOM_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiX86Watcom : public Abi +{ + // Ctors, dtors. + // + public: + AbiX86Watcom(llvm::Module* m, Config* c); + virtual ~AbiX86Watcom(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/providers/abi/x86_watcom.cpp b/src/bin2llvmir/providers/abi/x86_watcom.cpp new file mode 100644 index 000000000..e417c92e7 --- /dev/null +++ b/src/bin2llvmir/providers/abi/x86_watcom.cpp @@ -0,0 +1,106 @@ +/** + * @file src/bin2llvmir/providers/abi/x86.cpp + * @brief ABI information for x86. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/x86_watcom.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiX86Watcom::AbiX86Watcom(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(X86_REG_ENDING); + _id2regs.resize(X86_REG_ENDING, nullptr); + _regStackPointerId = X86_REG_ESP; + + // system calls + _regSyscallId = X86_REG_EAX; + _regSyscallReturn = X86_REG_EAX; + _syscallRegs = { + X86_REG_EBX, + X86_REG_ECX, + X86_REG_EDX, + X86_REG_ESI, + X86_REG_EDI, + X86_REG_EBP}; + + _paramRegs = { + X86_REG_EAX, + X86_REG_EDX, + X86_REG_EBX, + X86_REG_ECX, + }; + + _regReturn = X86_REG_EAX; + _regFPReturn = X86_REG_ST7; +} + +AbiX86Watcom::~AbiX86Watcom() +{ + +} + +bool AbiX86Watcom::isGeneralPurposeRegister(const llvm::Value* val) +{ + uint32_t rid = getRegisterId(val); + return rid == X86_REG_EAX + || rid == X86_REG_EBX + || rid == X86_REG_ECX + || rid == X86_REG_EDX + || rid == X86_REG_ESP + || rid == X86_REG_EBP + || rid == X86_REG_ESI + || rid == X86_REG_EDI; +} + +bool AbiX86Watcom::isNopInstruction(cs_insn* insn) +{ + cs_x86& insn86 = insn->detail->x86; + + // True NOP variants. + // + if (insn->id == X86_INS_NOP + || insn->id == X86_INS_FNOP + || insn->id == X86_INS_FDISI8087_NOP + || insn->id == X86_INS_FENI8087_NOP + || insn->id == X86_INS_INT3) + { + return true; + } + // e.g. lea esi, [esi] + // + else if (insn->id == X86_INS_LEA + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_MEM + && insn86.operands[1].mem.segment == X86_REG_INVALID + && insn86.operands[1].mem.index == X86_REG_INVALID + && insn86.operands[1].mem.scale == 1 + && insn86.operands[1].mem.disp == 0 + && insn86.operands[1].mem.base == insn86.operands[0].reg) + { + return true; + } + // e.g. mov esi. esi + // + else if (insn->id == X86_INS_MOV + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_REG + && insn86.operands[0].reg == insn86.operands[1].reg) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec From 0a12d2dd7aa4ab98d4f6de4f9962d9ff7af14ecb Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:12:26 +0100 Subject: [PATCH 062/159] powerpc64: new abi --- .../bin2llvmir/providers/abi/powerpc64.h | 37 +++++++++ src/bin2llvmir/CMakeLists.txt | 1 + src/bin2llvmir/providers/abi/powerpc64.cpp | 77 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/abi/powerpc64.h create mode 100644 src/bin2llvmir/providers/abi/powerpc64.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/powerpc64.h b/include/retdec/bin2llvmir/providers/abi/powerpc64.h new file mode 100644 index 000000000..1ad5cb693 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/powerpc64.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/powerpc64.h + * @brief ABI information for PowerPC 64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_POWERPC64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_POWERPC64_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiPowerpc64 : public Abi +{ + // Ctors, dtors. + // + public: + AbiPowerpc64(llvm::Module* m, Config* c); + virtual ~AbiPowerpc64(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 882f64aa5..42888091c 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -71,6 +71,7 @@ set(BIN2LLVMIR_SOURCES providers/abi/ms_x64.cpp providers/abi/pic32.cpp providers/abi/powerpc.cpp + providers/abi/powerpc64.cpp providers/abi/x64.cpp providers/abi/x86.cpp providers/abi/x86_fastcall.cpp diff --git a/src/bin2llvmir/providers/abi/powerpc64.cpp b/src/bin2llvmir/providers/abi/powerpc64.cpp new file mode 100644 index 000000000..daf9a23f4 --- /dev/null +++ b/src/bin2llvmir/providers/abi/powerpc64.cpp @@ -0,0 +1,77 @@ +/** + * @file src/bin2llvmir/providers/abi/powerpc64.cpp + * @brief ABI information for PowerPC 64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/powerpc64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiPowerpc64::AbiPowerpc64(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(PPC_REG_ENDING); + _id2regs.resize(PPC_REG_ENDING, nullptr); + _regStackPointerId = PPC_REG_R1; + _fpRegsAsParams = true; + + _paramRegs = { + PPC_REG_R3, + PPC_REG_R4, + PPC_REG_R5, + PPC_REG_R6, + PPC_REG_R7, + PPC_REG_R8, + PPC_REG_R9, + PPC_REG_R10}; + + _paramFPRegs = { + PPC_REG_F1, + PPC_REG_F2, + PPC_REG_F3, + PPC_REG_F4, + PPC_REG_F5, + PPC_REG_F6, + PPC_REG_F7, + PPC_REG_F8, + PPC_REG_F9, + PPC_REG_F10, + PPC_REG_F11}; + + // TODO paramVectorRegs = + + + _regReturn = PPC_REG_R3; + _regFPReturn = PPC_REG_R3; +} + +AbiPowerpc64::~AbiPowerpc64() +{ + +} + +bool AbiPowerpc64::isGeneralPurposeRegister(const llvm::Value* val) +{ + uint32_t rid = getRegisterId(val); + return PPC_REG_R0 <= rid && rid <= PPC_REG_R31; +} + +bool AbiPowerpc64::isNopInstruction(cs_insn* insn) +{ + // True NOP variants. + // + if (insn->id == PPC_INS_NOP + || insn->id == PPC_INS_XNOP) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec From dcbbffa4748db6fa8aa6d57734b854b605e1ee31 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:12:46 +0100 Subject: [PATCH 063/159] mips64: new abi --- .../retdec/bin2llvmir/providers/abi/mips64.h | 37 ++++++++ src/bin2llvmir/CMakeLists.txt | 1 + src/bin2llvmir/providers/abi/mips64.cpp | 86 +++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/abi/mips64.h create mode 100644 src/bin2llvmir/providers/abi/mips64.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/mips64.h b/include/retdec/bin2llvmir/providers/abi/mips64.h new file mode 100644 index 000000000..86e3ca7c9 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/mips64.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/mips64.h + * @brief ABI information for MIPS. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_MIPS64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_MIPS64_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiMips64 : public Abi +{ + // Ctors, dtors. + // + public: + AbiMips64(llvm::Module* m, Config* c); + virtual ~AbiMips64(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 42888091c..af98b5b9c 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -68,6 +68,7 @@ set(BIN2LLVMIR_SOURCES providers/abi/arm.cpp providers/abi/arm64.cpp providers/abi/mips.cpp + providers/abi/mips64.cpp providers/abi/ms_x64.cpp providers/abi/pic32.cpp providers/abi/powerpc.cpp diff --git a/src/bin2llvmir/providers/abi/mips64.cpp b/src/bin2llvmir/providers/abi/mips64.cpp new file mode 100644 index 000000000..e1234e2f9 --- /dev/null +++ b/src/bin2llvmir/providers/abi/mips64.cpp @@ -0,0 +1,86 @@ +/** + * @file src/bin2llvmir/providers/abi/mips64.cpp + * @brief ABI information for MIPS. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/mips64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiMips64::AbiMips64(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(MIPS_REG_ENDING); + _id2regs.resize(MIPS_REG_ENDING, nullptr); + _regStackPointerId = MIPS_REG_SP; + _regZeroReg = MIPS_REG_ZERO; + + _fpRegsAsParams = true; + + // system calls + _regSyscallId = MIPS_REG_V0; + _regSyscallReturn = MIPS_REG_V0; + _syscallRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3, + MIPS_REG_T0, + MIPS_REG_T1, + MIPS_REG_T2, + MIPS_REG_T3}; + + _regReturn = MIPS_REG_V0; + _regFPReturn = MIPS_REG_V0; + + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3, + MIPS_REG_T0, + MIPS_REG_T1, + MIPS_REG_T2, + MIPS_REG_T3}; + + _paramFPRegs = { + MIPS_REG_F12, + MIPS_REG_F13, + MIPS_REG_F14, + MIPS_REG_F15, + MIPS_REG_F16, + MIPS_REG_F17, + MIPS_REG_F18 + }; +} + +AbiMips64::~AbiMips64() +{ + +} + +bool AbiMips64::isGeneralPurposeRegister(const llvm::Value* val) +{ + uint32_t rid = getRegisterId(val); + return MIPS_REG_0 <= rid && rid <= MIPS_REG_31; +} + +bool AbiMips64::isNopInstruction(cs_insn* insn) +{ + // True NOP variants. + // + if (insn->id == MIPS_INS_NOP + || insn->id == MIPS_INS_SSNOP) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec From 324b034c6e09c394d35ca8a3abb9e35a3683e972 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:13:06 +0100 Subject: [PATCH 064/159] x86_pascal: new abi --- .../bin2llvmir/providers/abi/x86_pascal.h | 37 ++++++ src/bin2llvmir/CMakeLists.txt | 2 + src/bin2llvmir/providers/abi/x86_pascal.cpp | 106 ++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/abi/x86_pascal.h create mode 100644 src/bin2llvmir/providers/abi/x86_pascal.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/x86_pascal.h b/include/retdec/bin2llvmir/providers/abi/x86_pascal.h new file mode 100644 index 000000000..c3a9a1658 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/x86_pascal.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/x86.h + * @brief ABI information for x86. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_PASCAL_X86_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_PASCAL_X86_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiX86Pascal : public Abi +{ + // Ctors, dtors. + // + public: + AbiX86Pascal(llvm::Module* m, Config* c); + virtual ~AbiX86Pascal(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index af98b5b9c..22fd47a91 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -76,6 +76,8 @@ set(BIN2LLVMIR_SOURCES providers/abi/x64.cpp providers/abi/x86.cpp providers/abi/x86_fastcall.cpp + providers/abi/x86_pascal.cpp + providers/abi/x86_watcom.cpp providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/providers/abi/x86_pascal.cpp b/src/bin2llvmir/providers/abi/x86_pascal.cpp new file mode 100644 index 000000000..c4ce85c85 --- /dev/null +++ b/src/bin2llvmir/providers/abi/x86_pascal.cpp @@ -0,0 +1,106 @@ +/** + * @file src/bin2llvmir/providers/abi/x86.cpp + * @brief ABI information for x86. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/x86_pascal.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiX86Pascal::AbiX86Pascal(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(X86_REG_ENDING); + _id2regs.resize(X86_REG_ENDING, nullptr); + _regStackPointerId = X86_REG_ESP; + + // system calls + _regSyscallId = X86_REG_EAX; + _regSyscallReturn = X86_REG_EAX; + _syscallRegs = { + X86_REG_EBX, + X86_REG_ECX, + X86_REG_EDX, + X86_REG_ESI, + X86_REG_EDI, + X86_REG_EBP}; + + _stackParamOrder = LTR; + + _paramRegs = { + X86_REG_EAX, + X86_REG_EDX, + X86_REG_ECX}; + + _regReturn = X86_REG_EAX; + _regFPReturn = X86_REG_ST7; +} + +AbiX86Pascal::~AbiX86Pascal() +{ + +} + +bool AbiX86Pascal::isGeneralPurposeRegister(const llvm::Value* val) +{ + uint32_t rid = getRegisterId(val); + return rid == X86_REG_EAX + || rid == X86_REG_EBX + || rid == X86_REG_ECX + || rid == X86_REG_EDX + || rid == X86_REG_ESP + || rid == X86_REG_EBP + || rid == X86_REG_ESI + || rid == X86_REG_EDI; +} + +bool AbiX86Pascal::isNopInstruction(cs_insn* insn) +{ + cs_x86& insn86 = insn->detail->x86; + + // True NOP variants. + // + if (insn->id == X86_INS_NOP + || insn->id == X86_INS_FNOP + || insn->id == X86_INS_FDISI8087_NOP + || insn->id == X86_INS_FENI8087_NOP + || insn->id == X86_INS_INT3) + { + return true; + } + // e.g. lea esi, [esi] + // + else if (insn->id == X86_INS_LEA + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_MEM + && insn86.operands[1].mem.segment == X86_REG_INVALID + && insn86.operands[1].mem.index == X86_REG_INVALID + && insn86.operands[1].mem.scale == 1 + && insn86.operands[1].mem.disp == 0 + && insn86.operands[1].mem.base == insn86.operands[0].reg) + { + return true; + } + // e.g. mov esi. esi + // + else if (insn->id == X86_INS_MOV + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_REG + && insn86.operands[0].reg == insn86.operands[1].reg) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec From 9f16ae2c22cbb43942e5c2e2894cad5acbd63dc3 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:14:13 +0100 Subject: [PATCH 065/159] abi: provide information about stack parameter order --- include/retdec/bin2llvmir/providers/abi/abi.h | 6 +++++- src/bin2llvmir/providers/abi/abi.cpp | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index aeaa56ef5..3918653c5 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -29,6 +29,8 @@ class Abi public: static const uint32_t REG_INVALID; static const unsigned DEFAULT_ADDR_SPACE; + static const bool RTL; + static const bool LTR; // Ctors, dtors. // @@ -55,6 +57,8 @@ class Abi llvm::GlobalVariable* getStackPointerRegister(); llvm::GlobalVariable* getZeroRegister(); + bool getStackParamOrder() const; + void addRegister(uint32_t id, llvm::GlobalVariable* reg); llvm::GlobalVariable* getSyscallIdRegister(); @@ -145,7 +149,7 @@ class Abi bool returnsOnStack = false; bool _fpRegsAsParams = false; bool _paramRegsOverlay = false; - + bool _stackParamOrder = RTL; }; class AbiProvider diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index b0ea99bd7..3014fdc82 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -26,6 +26,8 @@ namespace bin2llvmir { const uint32_t Abi::REG_INVALID = 0; const unsigned Abi::DEFAULT_ADDR_SPACE = 0; +const bool Abi::RTL = true; +const bool Abi::LTR = false; Abi::Abi(llvm::Module* m, Config* c) : _module(m), @@ -65,6 +67,12 @@ bool Abi::isZeroRegister(const llvm::Value* val) return getZeroRegister() == val; } + +bool Abi::getStackParamOrder() const +{ + return _stackParamOrder; +} + /** * \param r Register ID to get. * Warning! We are using Capstone register IDs which overlaps. From 35ef64e8e52b1950242233c65041b2f4a81b204c Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:14:52 +0100 Subject: [PATCH 066/159] param_return: use info about parameter stack order --- src/bin2llvmir/optimizations/param_return/param_return.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index e733cb909..9b80d9449 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1646,7 +1646,7 @@ ParamFilter::ParamFilter( orderRegistersBy(_fpRegValues, _abi->parameterFPRegisters()); orderRegistersBy(_regValues, _abi->parameterRegisters()); - orderStacks(_stackValues); + orderStacks(_stackValues, _abi->getStackParamOrder() == Abi::RTL); if (!paramTypes.empty() && call != nullptr) { From 4a0f407934208e135c3597e44e8f8c4f2892044b Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:41:34 +0100 Subject: [PATCH 067/159] param_return: get rid of unused methods --- .../optimizations/param_return/param_return.h | 1 - .../param_return/param_return.cpp | 44 ------------------- 2 files changed, 45 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index e43dabf05..eedb722bf 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -161,7 +161,6 @@ class DataFlowEntry void filterSortArgLoads(); void filterNegativeStacks(); - void sortValues(std::vector &args) const; void filterKnownParamPairs(); diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 9b80d9449..7c3d4aa3e 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -294,50 +294,6 @@ void CallEntry::extractSpecificArgTypes(Module* m, trueCall->getCalledFunction()); } -/** - * Stack with the lowest (highest negative) offset is the first call argument. - * - * Registers are sorted according to position got from abi. - */ -void DataFlowEntry::sortValues(std::vector &args) const -{ - auto regs = _abi->parameterRegisters(); - auto fpRegs = _abi->parameterFPRegisters(); - regs.insert(regs.end(), fpRegs.begin(), fpRegs.end()); - - std::stable_sort( - args.begin(), - args.end(), - [this, regs, args](Value* a, Value* b) -> bool - { - auto aOff = _config->getStackVariableOffset(a); - auto bOff = _config->getStackVariableOffset(b); - - if (aOff.isUndefined() && bOff.isUndefined()) - { - auto aId = _abi->getRegisterId(a); - auto bId = _abi->getRegisterId(b); - - auto it1 = std::find(regs.begin(), regs.end(), aId); - auto it2 = std::find(regs.begin(), regs.end(), bId); - - return std::distance(it1, it2) > 0; - } - else if (aOff.isUndefined() && bOff.isDefined()) - { - return true; - } - else if (aOff.isDefined() && bOff.isUndefined()) - { - return false; - } - else - { - return aOff < bOff; - } - }); -} - std::string CallEntry::extractFormatString(ReachingDefinitionsAnalysis& _RDA) const { std::string str; From 9d336f2e03721cd3e8a7c30ec603e9dcf4132064 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 29 Nov 2018 13:34:12 +0100 Subject: [PATCH 068/159] param_return: provides found arguments in definition if definition provides more arguments --- .../optimizations/param_return/param_return.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 7c3d4aa3e..916f70ffe 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1563,8 +1563,16 @@ void DataFlowEntry::setArgumentTypes() } else { - auto ce = calls.front(); - std::vector &a = args.empty() ? ce.possibleArgs : args; + CallEntry* ce = &calls.front(); + for (auto& c : calls) + { + if (!c.possibleArgs.empty()) + { + ce = &c; + break; + } + } + std::vector &a = args.size() < ce->possibleArgs.size() ? ce->possibleArgs : args; for (const auto& op: a) { From 73bb576f9715eecf8be183d028783f327d89ae3b Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:29:23 +0100 Subject: [PATCH 069/159] abi/arm: new unit tests --- .../param_return/param_return_tests.cpp | 464 ++++++++++++++++++ 1 file changed, 464 insertions(+) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 557a59bd3..c2512e905 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -4,6 +4,7 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ +#include "retdec/bin2llvmir/providers/abi/arm64.h" #include "retdec/bin2llvmir/providers/abi/x86_fastcall.h" #include "retdec/bin2llvmir/optimizations/param_return/param_return.h" @@ -2472,6 +2473,469 @@ TEST_F(ParamReturnTests, armExternalCallUseStacksIf4RegistersUsed) checkModuleAgainstExpectedIr(exp); } +TEST_F(ParamReturnTests, armExternalCallHasLargeSecondParameter) +{ + parseInput(R"( + @r0 = global i32 0 + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + declare void @print() + define void @fnc() { + store i32 1, i32* @r2 + store i32 1, i32* @r3 + store i32 1, i32* @r0 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "arm" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(ARM_REG_R0, getGlobalByName("r0")); + abi->addRegister(ARM_REG_R1, getGlobalByName("r1")); + abi->addRegister(ARM_REG_R2, getGlobalByName("r2")); + abi->addRegister(ARM_REG_R3, getGlobalByName("r3")); + abi->addRegister(ARM_REG_R4, getGlobalByName("r4")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r0 = global i32 0 + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + + declare i32 @print(i32, i32, i32) + + declare void @0() + + define i32 @fnc() { + store i32 1, i32* @r2 + store i32 1, i32* @r3 + store i32 1, i32* @r0 + %1 = load i32, i32* @r0 + %2 = load i32, i32* @r2 + %3 = load i32, i32* @r3 + %4 = call i32 @print(i32 %1, i32 %2, i32 %3) + store i32 %4, i32* @r0 + %5 = load i32, i32* @r0 + ret i32 %5 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, armExternalCallHasDouleParameter) +{ + parseInput(R"( + @r0 = global i32 0 + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + @d0 = global f64 0 + declare void @foo() + define void @fnc() { + store f64 0, f64* @d0 + call void @foo() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "arm" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(ARM_REG_R0, getGlobalByName("r0")); + abi->addRegister(ARM_REG_R1, getGlobalByName("r1")); + abi->addRegister(ARM_REG_R2, getGlobalByName("r2")); + abi->addRegister(ARM_REG_R3, getGlobalByName("r3")); + abi->addRegister(ARM_REG_R4, getGlobalByName("r4")); + abi->addRegister(ARM_REG_D0, getGlobalByName("d0")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r0 = global i32 0 + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + @d0 = global f64 0 + + declare i32 @print(f64) + + declare void @0() + + define i32 @fnc() { + store i32 1, i32* @d0 + %1 = load f64, i64* @d0 + %2 = call i32 @print(f64 %1) + store i32 %2, i32* @r0 + %3 = load i32, i32* @r0 + ret i32 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, arm64PtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i64 0 + @x0 = global i64 0 + @x1 = global i64 0 + define void @fnc() { + store i64 123, i64* @x0 + store i64 456, i64* @x1 + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "arm64" + } + })"); + AbiArm64 abi(module.get(), &config); + + abi.addRegister(ARM64_REG_X0, getGlobalByName("x0")); + abi.addRegister(ARM64_REG_X1, getGlobalByName("x1")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @r = global i32 0 + @x0 = global i64 0 + @x1 = global i64 0 + + define i32 @fnc() { + store i64 123, i64* @x0 + store i64 456, i64* @x1 + %a = bitcast i64* @r to void ()* + %1 = load i64, i64* @x0 + %2 = load i64, i64* @x1 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @x0 + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, arm64ExternalCallBasicFunctionality) +{ + parseInput(R"( + @x0 = global i64 0 + @x1 = global i64 0 + declare void @print() + define void @fnc() { + store i64 123, i64* @x0 + store i64 456, i64* @x1 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "arm64" + } + })"); + + AbiArm64 abi(module.get(), &config); + + abi.addRegister(ARM64_REG_X0, getGlobalByName("x0")); + abi.addRegister(ARM64_REG_X1, getGlobalByName("x1")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @x0 = global i64 0 + @x1 = global i64 0 + + declare i64 @print(i64, i64) + + declare void @0() + + define i64 @fnc() { + store i64 123, i64* @x0 + store i64 456, i64* @x1 + %1 = load i64, i64* @x0 + %2 = load i64, i64* @x1 + %3 = call i64 @print(i64 %1, i64 %2) + store i64 %3, i64* @x0 + %4 = load i64, i64* @x0 + ret i64 %4 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, arm64ExternalCallUseStacksIf8RegistersUsed) +{ + parseInput(R"( + @x0 = global i64 0 + @x1 = global i64 0 + @x2 = global i64 0 + @x3 = global i64 0 + @x4 = global i64 0 + @x5 = global i64 0 + @x6 = global i64 0 + @x7 = global i64 0 + @x8 = global i64 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i64 + %stack_-12 = alloca i64 + store i64 1, i64* @x2 + store i64 1, i64* @x1 + store i64 1, i64* @x5 + store i64 1, i64* @x6 + store i64 1, i64* @x8 + store i64 1, i64* @x7 + store i64 2, i64* %stack_-4 + store i64 1, i64* @x4 + store i64 1, i64* @x0 + store i64 2, i64* %stack_-12 + store i64 1, i64* @x3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "arm64" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-12", + "storage" : { "type" : "stack", "value" : -12 } + } + ] + } + ] + })"); + AbiArm64 abi(module.get(), &config); + + abi.addRegister(ARM64_REG_X0, getGlobalByName("x0")); + abi.addRegister(ARM64_REG_X1, getGlobalByName("x1")); + abi.addRegister(ARM64_REG_X2, getGlobalByName("x2")); + abi.addRegister(ARM64_REG_X3, getGlobalByName("x3")); + abi.addRegister(ARM64_REG_X4, getGlobalByName("x4")); + abi.addRegister(ARM64_REG_X5, getGlobalByName("x5")); + abi.addRegister(ARM64_REG_X6, getGlobalByName("x6")); + abi.addRegister(ARM64_REG_X7, getGlobalByName("x7")); + abi.addRegister(ARM64_REG_X8, getGlobalByName("x8")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @x0 = global i64 0 + @x1 = global i64 0 + @x2 = global i64 0 + @x3 = global i64 0 + @x4 = global i64 0 + @x5 = global i64 0 + @x6 = global i64 0 + @x7 = global i64 0 + @x8 = global i64 0 + + declare i64 @print(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) + + define i64 @fnc() { + %stack_-4 = alloca i64 + %stack_-12 = alloca i64 + store i64 1, i64* @x2 + store i64 1, i64* @x1 + store i64 1, i64* @x5 + store i64 1, i64* @x6 + store i64 1, i64* @x8 + store i64 1, i64* @x7 + store i64 2, i64* %stack_-4 + store i64 1, i64* @x4 + store i64 1, i64* @x0 + store i64 2, i64* %stack_-12 + store i64 1, i64* @x3 + + %1 = load i64, i64* @x0 + %2 = load i64, i64* @x1 + %3 = load i64, i64* @x2 + %4 = load i64, i64* @x3 + %5 = load i64, i64* @x4 + %6 = load i64, i64* @x5 + %7 = load i64, i64* @x6 + %8 = load i64, i64* @x7 + %9 = load i64, i64* %stack_-12 + %10 = load i64, i64* %stack_-4 + %11 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64, %7, i64, %8, i64 %9, i64 %10) + store i64 %11, i64* @x0 + %12 = load i64, i64* @x0 + ret i32 %12 + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, arm64ExternalCallHasLargeSecondParameter) +{ + parseInput(R"( + @x0 = global i64 0 + @x1 = global i64 0 + @x2 = global i64 0 + @x3 = global i64 0 + @x4 = global i64 0 + declare void @print() + define void @fnc() { + store i64 1, i64* @x2 + store i64 1, i64* @x3 + store i64 1, i64* @x0 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "arm64" + } + })"); + AbiArm64 abi(module.get(), &config); + + abi.addRegister(ARM64_REG_X0, getGlobalByName("x0")); + abi.addRegister(ARM64_REG_X1, getGlobalByName("x1")); + abi.addRegister(ARM64_REG_X2, getGlobalByName("x2")); + abi.addRegister(ARM64_REG_X3, getGlobalByName("x3")); + abi.addRegister(ARM64_REG_X4, getGlobalByName("x4")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @x0 = global i64 0 + @x1 = global i64 0 + @x2 = global i64 0 + @x3 = global i64 0 + @x4 = global i64 0 + + declare i64 @print(i64, i64, i64) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @r2 + store i64 1, i64* @r3 + store i64 1, i64* @r0 + %1 = load i64, i64* @r0 + %2 = load i64, i64* @r2 + %3 = load i64, i64* @r3 + %4 = call i64 @print(i64 %1, i64 %2, i64 %3) + store i64 %4, i64* @x0 + %5 = load i64, i64* @x0 + ret i64 %5 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, arm64ExternalCallHasDouleParameter) +{ + parseInput(R"( + @x0 = global i64 0 + @x1 = global i64 0 + @x2 = global i64 0 + @x3 = global i64 0 + @x4 = global i64 0 + @d0 = global f64 0 + declare void @foo() + define void @fnc() { + store f64 0, f64* @d0 + call void @foo() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "arm64" + } + })"); + AbiArm64 abi(module.get(), &config); + + abi.addRegister(ARM64_REG_X0, getGlobalByName("x0")); + abi.addRegister(ARM64_REG_X1, getGlobalByName("x1")); + abi.addRegister(ARM64_REG_X2, getGlobalByName("x2")); + abi.addRegister(ARM64_REG_X3, getGlobalByName("x3")); + abi.addRegister(ARM64_REG_X4, getGlobalByName("x4")); + abi.addRegister(ARM64_REG_D0, getGlobalByName("d0")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @x0 = global i64 0 + @x1 = global i64 0 + @x2 = global i64 0 + @x3 = global i64 0 + @x4 = global i64 0 + @d0 = global f64 0 + + declare i64 @print(f64) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @d0 + %1 = load f64, i64* @d0 + %2 = call i64 @print(f64 %1) + store i64 %2, i64* @x0 + %3 = load i64, i64* @x0 + ret i64 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + // //TEST_F(ParamReturnTests, ppcExternalCallUseStacksIf7RegistersUsed) //{ From 0a7e30a68d6156bb4a1570948e4a301f604e5e9e Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:32:43 +0100 Subject: [PATCH 070/159] abi/arm: provide option to pass parameters in float registers --- src/bin2llvmir/providers/abi/arm.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bin2llvmir/providers/abi/arm.cpp b/src/bin2llvmir/providers/abi/arm.cpp index 2a95c25bb..856d7448d 100644 --- a/src/bin2llvmir/providers/abi/arm.cpp +++ b/src/bin2llvmir/providers/abi/arm.cpp @@ -17,6 +17,7 @@ AbiArm::AbiArm(llvm::Module* m, Config* c) : _regs.reserve(ARM_REG_ENDING); _id2regs.resize(ARM_REG_ENDING, nullptr); _regStackPointerId = ARM_REG_SP; + _fpRegsAsParams = true; // system calls _regSyscallId = ARM_REG_R7; @@ -30,13 +31,19 @@ AbiArm::AbiArm(llvm::Module* m, Config* c) : ARM_REG_R5}; _regReturn = ARM_REG_R0; - _regFPReturn = ARM_REG_R0; + _regFPReturn = ARM_REG_D0; _paramRegs = { ARM_REG_R0, ARM_REG_R1, ARM_REG_R2, ARM_REG_R3}; + + _paramFPRegs = { + ARM_REG_D0, + ARM_REG_D1, + ARM_REG_D2, + ARM_REG_D3}; } AbiArm::~AbiArm() From f234314c67f3d5a9a883db7caa7af477de2539ee Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:39:25 +0100 Subject: [PATCH 071/159] abi: use watcom abi --- src/bin2llvmir/providers/abi/abi.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 3014fdc82..1ead869ee 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -10,6 +10,7 @@ #include "retdec/bin2llvmir/providers/abi/ms_x64.h" #include "retdec/bin2llvmir/providers/abi/powerpc.h" #include "retdec/bin2llvmir/providers/abi/x86.h" +#include "retdec/bin2llvmir/providers/abi/x86_watcom.h" #include "retdec/bin2llvmir/providers/abi/x64.h" #include "retdec/bin2llvmir/providers/abi/pic32.h" @@ -330,6 +331,12 @@ Abi* AbiProvider::addAbi( } else if (c->getConfig().architecture.isX86()) { + if (c->getConfig().tools.isWatcom()) { + auto p = _module2abi.emplace(m, std::make_unique(m, c)); + return p.first->second.get(); + + } + auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); } From 1348f52d632d5332037600881c40fecc15064ad3 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:39:44 +0100 Subject: [PATCH 072/159] abi: use pascal abi --- src/bin2llvmir/providers/abi/abi.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 1ead869ee..5c970d8f9 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -11,6 +11,7 @@ #include "retdec/bin2llvmir/providers/abi/powerpc.h" #include "retdec/bin2llvmir/providers/abi/x86.h" #include "retdec/bin2llvmir/providers/abi/x86_watcom.h" +#include "retdec/bin2llvmir/providers/abi/x86_pascal.h" #include "retdec/bin2llvmir/providers/abi/x64.h" #include "retdec/bin2llvmir/providers/abi/pic32.h" @@ -336,6 +337,10 @@ Abi* AbiProvider::addAbi( return p.first->second.get(); } + if (c->getConfig().tools.isBorland()) { + auto p = _module2abi.emplace(m, std::make_unique(m, c)); + return p.first->second.get(); + } auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); From 3e30df24805a80e2af958b91cbb640848e662077 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:41:32 +0100 Subject: [PATCH 073/159] param_return_tests: watcom unit tests --- .../param_return/param_return_tests.cpp | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index c2512e905..0cf42af7f 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -6,6 +6,7 @@ #include "retdec/bin2llvmir/providers/abi/arm64.h" #include "retdec/bin2llvmir/providers/abi/x86_fastcall.h" +#include "retdec/bin2llvmir/providers/abi/x86_watcom.h" #include "retdec/bin2llvmir/optimizations/param_return/param_return.h" #include "bin2llvmir/utils/llvmir_tests.h" @@ -3377,6 +3378,168 @@ TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) checkModuleAgainstExpectedIr(exp); } +TEST_F(ParamReturnTests, x86WatcomBasic) +{ + parseInput(R"( + @eax = global i32 0 + @ebx = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @ebx + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + + AbiX86Watcom abi(module.get(), &config); + abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi.addRegister(X86_REG_EBX, getGlobalByName("ebx")); + abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); + abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @eax = global i32 0 + @ebx = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @ebx + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* @eax + %2 = load i32, i32* @edx + %3 = load i32, i32* @ebx + %4 = load i32, i32* @ecx + %5 = load i32, i32* %stack_-8 + %6 = load i32, i32* %stack_-4 + %7 = bitcast void ()* %a to void (i32, i32, i32, i32, i32, i32)* + call void %7(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) + %8 = load i32, i32* @eax + ret i32 %8 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86WatcomPassDouble) +{ + parseInput(R"( + @eax = global i32 0 + @edx = global i32 0 + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @edx + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + + AbiX86Watcom abi(module.get(), &config); + abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @eax = global i32 0 + @edx = global i32 0 + @r = global i32 0 + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @edx + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* @eax + %2 = load i32, i32* @edx + %3 = load i32, i32* %stack_-8 + %4 = load i32, i32* %stack_-4 + %5 = bitcast void ()* %a to void (i32, i32, i32, i32)* + call void %5(i32 %1, i32 %2, i32 %3, i32 %4) + %6 = load i32, i32* @eax + ret i32 %6 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + } // namespace tests } // namespace bin2llvmir } // namespace retdec From adb8ee5332e9ca10eb73dbba2032d6edeee666c8 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:42:27 +0100 Subject: [PATCH 074/159] pascal: new unit tests --- .../param_return/param_return_tests.cpp | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 0cf42af7f..c54cffc2c 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -6,6 +6,7 @@ #include "retdec/bin2llvmir/providers/abi/arm64.h" #include "retdec/bin2llvmir/providers/abi/x86_fastcall.h" +#include "retdec/bin2llvmir/providers/abi/x86_pascal.h" #include "retdec/bin2llvmir/providers/abi/x86_watcom.h" #include "retdec/bin2llvmir/optimizations/param_return/param_return.h" @@ -3378,6 +3379,221 @@ TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) checkModuleAgainstExpectedIr(exp); } +TEST_F(ParamReturnTests, x86PascalBasic) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + AbiX86Pascal abi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-4 + %2 = load i32, i32* %stack_-8 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PascalFastcallBasic) +{ + parseInput(R"( + @eax = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + + AbiX86Pascal abi(module.get(), &config); + abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); + abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @eax = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* @eax + %2 = load i32, i32* @edx + %3 = load i32, i32* @ecx + %4 = load i32, i32* %stack_-4 + %5 = load i32, i32* %stack_-8 + %6 = bitcast void ()* %a to void (i32, i32, i32, i32, i32)* + call void %6(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5) + %7 = load i32, i32* @eax + ret i32 %7 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PascalFastcallLargeType) +{ + parseInput(R"( + @eax = global i32 0 + @edx = global i32 0 + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + store i32 1, i32* @edx + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + + AbiX86Pascal abi(module.get(), &config); + abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @eax = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + store i32 1, i32* @edx + %a = bitcast i32* @r to void()* + %1 = load i32, i32* @eax + %2 = load i32, i32* @edx + %3 = load i32, i32* %stack_-8 + %4 = load i32, i32* %stack_-4 + %5 = bitcast void ()* %a to void (i32, i32, i32, i32)* + call void %5(i32 %1, i32 %2, i32 %3, i32 %4) + %6 = load i32, i32* @eax + ret i32 %6 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + TEST_F(ParamReturnTests, x86WatcomBasic) { parseInput(R"( From 1909aa5e031798cd712485b70215dc6a209e6659 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:43:30 +0100 Subject: [PATCH 075/159] abi/mips: new unit tests --- .../param_return/param_return_tests.cpp | 375 ++++++++++++++++++ 1 file changed, 375 insertions(+) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index c54cffc2c..d4cc55a20 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -5,6 +5,7 @@ */ #include "retdec/bin2llvmir/providers/abi/arm64.h" +#include "retdec/bin2llvmir/providers/abi/mips64.h" #include "retdec/bin2llvmir/providers/abi/x86_fastcall.h" #include "retdec/bin2llvmir/providers/abi/x86_pascal.h" #include "retdec/bin2llvmir/providers/abi/x86_watcom.h" @@ -3211,6 +3212,380 @@ TEST_F(ParamReturnTests, mipsExternalCallUseStacksIf4RegistersUsed) checkModuleAgainstExpectedIr(exp); } +TEST_F(ParamReturnTests, mipsExternalCallHasFloatParameter) +{ + parseInput(R"( + @a0 = global i32 0 + @a1 = global i32 0 + @a2 = global i32 0 + @a3 = global i32 0 + @f12 = global f32 0 + @t0 = global i32 0 + declare void @foo() + define void @fnc() { + store i32 1, i32* @t0 + store i32 1, f32* @f12 + call void @foo() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "mips" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi->addRegister(MIPS_REG_A1, getGlobalByName("a1")); + abi->addRegister(MIPS_REG_A2, getGlobalByName("a2")); + abi->addRegister(MIPS_REG_A3, getGlobalByName("a3")); + abi->addRegister(MIPS_REG_F12, getGlobalByName("f12")); + abi->addRegister(MIPS_REG_T0, getGlobalByName("t0")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @a0 = global i32 0 + @a1 = global i32 0 + @a2 = global i32 0 + @a3 = global i32 0 + @f12 = gloabl f32 0 + @t0 = global i32 0 + declare void @foo(f32) + declare void @0() + define void @fnc() { + store i32 1, i32* @t0 + store i32 1, f32* @f12 + %1 = load f32, f32* @f12 + call void @foo(f32 %1) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mipsExternalCallHasFloatFirstParameter) +{ + parseInput(R"( + @a0 = global i32 0 + @a1 = global i32 0 + @a2 = global i32 0 + @a3 = global i32 0 + @f12 = global f32 0 + @t0 = global i32 0 + declare void @foo() + define void @fnc() { + store i32 1, i32* @t0 + store i32 1, i32* @a0 + store i32 1, f32* @f12 + call void @foo() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "mips" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi->addRegister(MIPS_REG_A1, getGlobalByName("a1")); + abi->addRegister(MIPS_REG_A2, getGlobalByName("a2")); + abi->addRegister(MIPS_REG_A3, getGlobalByName("a3")); + abi->addRegister(MIPS_REG_F12, getGlobalByName("f12")); + abi->addRegister(MIPS_REG_T0, getGlobalByName("t0")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @a0 = global i32 0 + @a1 = global i32 0 + @a2 = global i32 0 + @a3 = global i32 0 + @f12 = gloabl f32 0 + @t0 = global i32 0 + declare void @foo(f32, i32) + declare void @0() + define void @fnc() { + store i32 1, i32* @t0 + store i32 1, i32* @a0 + store i32 1, f32* @f12 + %1 = load f32, f32* @f12 + %2 = load i32, i32* @a + call void @foo(f32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mips64PtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i64 0 + @a0 = global i64 0 + @a1 = global i64 0 + define void @fnc() { + store i64 123, i64* @a0 + store i64 456, i64* @a1 + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "mips64" + } + })"); + + AbiMips64 abi(module.get(), &config); + + abi.addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi.addRegister(MIPS_REG_A1, getGlobalByName("a1")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @r = global i64 0 + @a0 = global i64 0 + @a1 = global i64 0 + define void @fnc() { + store i64 123, i64* @a0 + store i64 456, i64* @a1 + %a = bitcast i64* @r to void()* + %1 = load i64, i64* @a0 + %2 = load i64, i64* @a1 + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mips64ExternalCallBasicFunctionality) +{ + parseInput(R"( + @a0 = global i64 0 + @a1 = global i64 0 + declare void @print() + define void @fnc() { + store i64 123, i64* @a0 + store i64 456, i64* @a1 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "mips64" + } + })"); + + AbiMips64 abi(module.get(), &config); + + abi.addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi.addRegister(MIPS_REG_A1, getGlobalByName("a1")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @a0 = global i64 0 + @a1 = global i64 0 + declare void @print(i64, i64) + declare void @0() + define void @fnc() { + store i64 123, i64* @a0 + store i64 456, i64* @a1 + %1 = load i64, i64* @a0 + %2 = load i64, i64* @a1 + call void @print(i64 %1, i64 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mips64ExternalCallUseStacksIf8RegistersUsed) +{ + parseInput(R"( + @a0 = global i64 0 + @a1 = global i64 0 + @a2 = global i64 0 + @a3 = global i64 0 + @a4 = global i64 0 + @a5 = global i64 0 + @a6 = global i64 0 + @a7 = global i64 0 + @t4 = global i64 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i64 + %stack_-12 = alloca i64 + store i64 1, i64* @a2 + store i64 1, i64* @a1 + store i64 1, i64* @a7 + store i64 1, i64* @a4 + store i64 2, i64* %stack_-4 + store i64 1, i64* @t4 + store i64 1, i64* @a0 + store i64 2, i64* %stack_-12 + store i64 1, i64* @a6 + store i64 1, i64* @a5 + store i64 1, i64* @a3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "mips64" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-12", + "storage" : { "type" : "stack", "value" : -12 } + } + ] + } + ] + })"); + + AbiMips64 abi(module.get(), &config); + + abi.addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi.addRegister(MIPS_REG_A1, getGlobalByName("a1")); + abi.addRegister(MIPS_REG_A2, getGlobalByName("a2")); + abi.addRegister(MIPS_REG_A3, getGlobalByName("a3")); + abi.addRegister(MIPS_REG_T0, getGlobalByName("a1")); + abi.addRegister(MIPS_REG_T1, getGlobalByName("a2")); + abi.addRegister(MIPS_REG_T2, getGlobalByName("a3")); + abi.addRegister(MIPS_REG_T3, getGlobalByName("a4")); + abi.addRegister(MIPS_REG_T4, getGlobalByName("t4")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @a0 = global i64 0 + @a1 = global i64 0 + @a2 = global i64 0 + @a3 = global i64 0 + @a4 = global i64 0 + @a5 = global i64 0 + @a6 = global i64 0 + @a7 = global i64 0 + @t4 = global i64 0 + + declare void @0() + declare void @print(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) + define void @fnc() { + %stack_-4 = alloca i64 + %stack_-12 = alloca i64 + store i64 1, i64* @a2 + store i64 1, i64* @a1 + store i64 1, i64* @a7 + store i64 1, i64* @a4 + store i64 2, i64* %stack_-4 + store i64 1, i64* @t4 + store i64 1, i64* @a0 + store i64 2, i64* %stack_-12 + store i64 1, i64* @a6 + store i64 1, i64* @a5 + store i64 1, i64* @a3 + + %1 = load i64, i64* @a0 + %2 = load i64, i64* @a1 + %3 = load i64, i64* @a2 + %4 = load i64, i64* @a3 + %5 = load i64, i64* @a4 + %6 = load i64, i64* @a5 + %7 = load i64, i64* @a6 + %8 = load i64, i64* @a7 + %9 = load i64, i64* %stack_-12 + %10 = load i64, i64* %stack_-4 + call void @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i64 %8, i64 %9, i64 %10) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mips64ExternalCallHasFloatParameter) +{ + parseInput(R"( + @a0 = global i64 0 + @a1 = global i64 0 + @a2 = global i64 0 + @a3 = global i64 0 + @t4 = global i64 0 + @f12 = global f64 0 + declare void @foo() + define void @fnc() { + store i64 1, i64* @t4 + store i64 1, f64* @f12 + call void @foo() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "mips64" + } + })"); + + AbiMips64 abi(module.get(), &config); + + abi.addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi.addRegister(MIPS_REG_A1, getGlobalByName("a1")); + abi.addRegister(MIPS_REG_A2, getGlobalByName("a2")); + abi.addRegister(MIPS_REG_A3, getGlobalByName("a3")); + abi.addRegister(MIPS_REG_T4, getGlobalByName("t4")); + abi.addRegister(MIPS_REG_F12, getGlobalByName("f12")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @a0 = global i64 0 + @a1 = global i64 0 + @a2 = global i64 0 + @a3 = global i64 0 + @f12 = gloabl f64 0 + @t0 = global i64 0 + declare void @foo(f64) + declare void @0() + define void @fnc() { + store i64 1, i64* @t0 + store i64 1, f64* @f12 + %1 = load f64, f64* @f12 + call void @foo(f64 %1) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + /** * Tests basic parameter sequence of fascall * calling convention: From 7884faf76d9a7e0aff91317599116a169cb02711 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:44:45 +0100 Subject: [PATCH 076/159] config/architecture: provide test for mips64 --- include/retdec/config/architecture.h | 1 + src/config/architecture.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/retdec/config/architecture.h b/include/retdec/config/architecture.h index af6579194..cd2797ad3 100644 --- a/include/retdec/config/architecture.h +++ b/include/retdec/config/architecture.h @@ -25,6 +25,7 @@ class Architecture bool isUnknown() const; bool isKnown() const; bool isMips() const; + bool isMips64() const; bool isPic32() const; bool isMipsOrPic32() const; bool isArm() const; diff --git a/src/config/architecture.cpp b/src/config/architecture.cpp index 4a21b177a..c5a9ef238 100644 --- a/src/config/architecture.cpp +++ b/src/config/architecture.cpp @@ -13,6 +13,7 @@ namespace { const std::string ARCH_UNKNOWN = "unknown"; const std::string ARCH_MIPS = "mips"; +const std::string ARCH_MIPS64 = "mips64"; const std::string ARCH_PIC32 = "pic32"; const std::string ARCH_ARM = "arm"; const std::string ARCH_THUMB = "thumb"; @@ -43,6 +44,7 @@ bool Architecture::isPpc() const { return isArch(eArch::PPC); } bool Architecture::isKnown() const { return !isUnknown(); } bool Architecture::isUnknown() const { return isArch(eArch::UNKNOWN); } bool Architecture::isMips() const { return isArch(eArch::MIPS); } +bool Architecture::isMips64() const { return isMips() && getBitSize() == 64; } bool Architecture::isMipsOrPic32() const{ return isMips() || isPic32(); } /** From 195f49ae1902cbe38a26b38aea286418744e0b16 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:45:41 +0100 Subject: [PATCH 077/159] config/architecture: provide test for arm64 --- include/retdec/config/architecture.h | 1 + src/config/architecture.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/retdec/config/architecture.h b/include/retdec/config/architecture.h index cd2797ad3..e3a9d395c 100644 --- a/include/retdec/config/architecture.h +++ b/include/retdec/config/architecture.h @@ -29,6 +29,7 @@ class Architecture bool isPic32() const; bool isMipsOrPic32() const; bool isArm() const; + bool isArm64() const; bool isThumb() const; bool isArmOrThumb() const; bool isX86() const; diff --git a/src/config/architecture.cpp b/src/config/architecture.cpp index c5a9ef238..1ecada32a 100644 --- a/src/config/architecture.cpp +++ b/src/config/architecture.cpp @@ -16,6 +16,7 @@ const std::string ARCH_MIPS = "mips"; const std::string ARCH_MIPS64 = "mips64"; const std::string ARCH_PIC32 = "pic32"; const std::string ARCH_ARM = "arm"; +const std::string ARCH_ARM64 = "arm64"; const std::string ARCH_THUMB = "thumb"; const std::string ARCH_x86 = "x86"; const std::string ARCH_PPC = "powerpc"; @@ -35,6 +36,7 @@ namespace config { bool Architecture::isArmOrThumb() const { return isArm() || isThumb(); } bool Architecture::isPic32() const { return isArch(eArch::PIC32); } bool Architecture::isArm() const { return isArch(eArch::ARM); } +bool Architecture::isArm64() const { return isArm() && getBitSize() == 64; } bool Architecture::isThumb() const { return isArch(eArch::THUMB); } bool Architecture::isX86() const { return isArch(eArch::X86); } bool Architecture::isX86_16() const { return isX86() && getBitSize() == 16; } From fbe08108836b529df03289b273c084f561cb9f24 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 00:45:54 +0100 Subject: [PATCH 078/159] config/architecture: provide test for ppc64 --- include/retdec/config/architecture.h | 1 + src/config/architecture.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/retdec/config/architecture.h b/include/retdec/config/architecture.h index e3a9d395c..28470d953 100644 --- a/include/retdec/config/architecture.h +++ b/include/retdec/config/architecture.h @@ -37,6 +37,7 @@ class Architecture bool isX86_32() const; bool isX86_64() const; bool isPpc() const; + bool isPpc64() const; bool isEndianLittle() const; bool isEndianBig() const; bool isEndianKnown() const; diff --git a/src/config/architecture.cpp b/src/config/architecture.cpp index 1ecada32a..fffee32c0 100644 --- a/src/config/architecture.cpp +++ b/src/config/architecture.cpp @@ -20,6 +20,7 @@ const std::string ARCH_ARM64 = "arm64"; const std::string ARCH_THUMB = "thumb"; const std::string ARCH_x86 = "x86"; const std::string ARCH_PPC = "powerpc"; +const std::string ARCH_PPC64 = "powerpc64"; const std::string JSON_name = "name"; const std::string JSON_endian = "endian"; @@ -43,6 +44,7 @@ bool Architecture::isX86_16() const { return isX86() && getBitSize() == 16; bool Architecture::isX86_32() const { return isX86() && getBitSize() == 32; } bool Architecture::isX86_64() const { return isX86() && getBitSize() == 64; } bool Architecture::isPpc() const { return isArch(eArch::PPC); } +bool Architecture::isPpc64() const { return isPpc() && getBitSize() == 64; } bool Architecture::isKnown() const { return !isUnknown(); } bool Architecture::isUnknown() const { return isArch(eArch::UNKNOWN); } bool Architecture::isMips() const { return isArch(eArch::MIPS); } From 52eb101f8a4395531cb8bd0a103746e97d2e446f Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 10:39:03 +0100 Subject: [PATCH 079/159] ppc abi: new unit tests --- .../param_return/param_return_tests.cpp | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index d4cc55a20..7cbd3531a 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -1980,6 +1980,64 @@ TEST_F(ParamReturnTests, ppcExternalCallBasicFunctionality) checkModuleAgainstExpectedIr(exp); } +TEST_F(ParamReturnTests, ppcExternalCallBasicFPFunctionality) +{ + parseInput(R"( + @r3 = global i32 0 + @r4 = global i32 0 + @f1 = global f64 0 + @f2 = global f64 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + store f64 0, f64* @f1 + store f64 0, f64* @f2 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + abi->addRegister(PPC_REG_F1, getGlobalByName("f1")); + abi->addRegister(PPC_REG_F2, getGlobalByName("f2")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + @r4 = global i32 0 + + declare i32 @print(i32, i32, f64, f64) + declare void @0() + + define i32 @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + %1 = load i32, i32* @r3 + %2 = load i32, i32* @r4 + %3 = load i64, i64* @f1 + %4 = load i64, i64* @f2 + %5 = call i32 @print(i32 %1, i32 %2, f64 %3, f64 %4) + store i32 %5, i32* @r3 + %6 = load i32, i32* @r3 + ret i32 %6 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + TEST_F(ParamReturnTests, ppcExternalCallDoNotUseObjectsIfTheyAreNotRegisters) { parseInput(R"( From a470ad8bbd9a16ae903ec6daaa7457fb015e9df5 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 11 Feb 2019 10:45:02 +0100 Subject: [PATCH 080/159] abi/ppc: new unit tests --- .../param_return/param_return_tests.cpp | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 7cbd3531a..564f281b7 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -6,6 +6,7 @@ #include "retdec/bin2llvmir/providers/abi/arm64.h" #include "retdec/bin2llvmir/providers/abi/mips64.h" +#include "retdec/bin2llvmir/providers/abi/powerpc64.h" #include "retdec/bin2llvmir/providers/abi/x86_fastcall.h" #include "retdec/bin2llvmir/providers/abi/x86_pascal.h" #include "retdec/bin2llvmir/providers/abi/x86_watcom.h" @@ -2314,6 +2315,57 @@ TEST_F(ParamReturnTests, ppcExternalCallDoNotUseStacksIfLessThan7RegistersUsed) checkModuleAgainstExpectedIr(exp); } +TEST_F(ParamReturnTests, ppc64PtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i64 0 + @r3 = global i64 0 + @r4 = global i64 0 + define void @fnc() { + store i64 123, i64* @r3 + store i64 456, i64* @r4 + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "big", + "name" : "powerpc64" + } + })"); + + AbiPowerpc64 abi(module.get(), &config); + + abi.addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi.addRegister(PPC_REG_R4, getGlobalByName("r4")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @r = global i64 0 + @r3 = global i64 0 + @r4 = global i64 0 + + define i64 @fnc() { + store i32 123, i64* @r3 + store i32 456, i64* @r4 + %a = bitcast i32* @r to void ()* + %1 = load i32, i64* @r3 + %2 = load i32, i64* @r4 + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @r3 + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + // // std::string exp = R"( // @r = global i32 0 From 30f76b5a0cac95fc19a38279ccef015a2cd828a6 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:42:22 +0100 Subject: [PATCH 081/159] calling_convention: new interface This interface provides general information about calling conventions in general. Every new calling convention must implement this interface and provide calling convention specific information. --- .../calling_convention/calling_convention.h | 139 +++++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../calling_convention/calling_convention.cpp | 218 ++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h create mode 100644 src/bin2llvmir/providers/calling_convention/calling_convention.cpp diff --git a/include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h b/include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h new file mode 100644 index 000000000..1496c7058 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h @@ -0,0 +1,139 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h + * @brief Calling convention information. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_CALL_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_CALL_CONV_H + +#include + +#include + +#include "retdec/config/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class Abi; + +class CallingConvention +{ + // Typedefs. + // + public: + typedef std::unique_ptr Ptr; + typedef retdec::config::CallingConventionID ID; + + typedef Ptr (*ConstructorMethod)(const Abi*); + + // Constants. + // + public: + static const bool RTL; + static const bool LTR; + + // Ctors, dtors. + // + public: + CallingConvention(const Abi* abi); + virtual ~CallingConvention(); + + // Registers. + // + public: + std::vector getParamRegisters() const; + std::vector getParamFPRegisters() const; + std::vector getParamDoubleRegisters() const; + std::vector getParamVectorRegisters() const; + + std::vector getReturnRegisters() const; + std::vector getReturnFPRegisters() const; + std::vector getReturnDoubleRegisters() const; + std::vector getReturnVectorRegisters() const; + + bool usesFPRegistersForParameters() const; + bool parameterRegistersOverlay() const; + + std::size_t getRegsNumPerParam() const; + + // Stacks. + public: + bool getStackParamOrder() const; + bool usesStackForParameters() const; + bool passesStructsOnStack() const; + + virtual std::size_t getMaxBytesPerStackParam() const; + + // Values. + public: + virtual bool valueCanBeParameter(const llvm::Value* val) const; + virtual bool canHoldReturnValue(const llvm::Value* val) const; + + // Private data - misc. + // + protected: + const Abi* _abi; + CallingConvention::ID _ccType; + + // Private data - registers. + // + protected: + std::vector _paramRegs {}; + std::vector _paramFPRegs {}; + std::vector _paramDoubleRegs {}; + std::vector _paramVectorRegs {}; + + std::vector _returnRegs {}; + std::vector _returnFPRegs {}; + std::vector _returnDoubleRegs {}; + std::vector _returnVectorRegs {}; + + // Private data - registers informational. + // + protected: + bool _paramRegsOverlay = false; + size_t _regNumPerParam = 1; + + // Private data - stacks informational. + // + protected: + bool _paramStructsOnStack = false; + bool _stackParamOrder = RTL; + bool _passesOnStack = true; +}; + +class CallingConventionProvider +{ + // Private constructor. + // + private: + CallingConventionProvider(); + + // Destructor, singleton method. + public: + ~CallingConventionProvider(); + static CallingConventionProvider* getProvider(); + + // Factory methods. + public: + void registerCC( + const CallingConvention::ID& cc, + const CallingConvention::ConstructorMethod& con); + + CallingConvention::Ptr createCallingConvention( + const CallingConvention::ID& cc, + const Abi* a) const; + + // Private data - constrctor methods. + private: + std::vector _id2cc; + +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 22fd47a91..4c042b7e3 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -78,6 +78,7 @@ set(BIN2LLVMIR_SOURCES providers/abi/x86_fastcall.cpp providers/abi/x86_pascal.cpp providers/abi/x86_watcom.cpp + providers/calling_convention/calling_conventnion.cpp providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/providers/calling_convention/calling_convention.cpp b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp new file mode 100644 index 000000000..a79a42e96 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp @@ -0,0 +1,218 @@ +/** + * @file src/retdec/bin2llvmir/providers/calling_convention/calling_convention.cpp + * @brief Calling convention information. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" +#include "retdec/bin2llvmir/providers/calling_convention/arm.h" +#include "retdec/bin2llvmir/providers/calling_convention/arm64.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips64.h" +#include "retdec/bin2llvmir/providers/calling_convention/pic32.h" +#include "retdec/bin2llvmir/providers/calling_convention/powerpc.h" +#include "retdec/bin2llvmir/providers/calling_convention/powerpc64.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86.h" +#include "retdec/bin2llvmir/providers/calling_convention/x64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================== +// CallingConvention +//============================================================================== +// + +const bool CallingConvention::RTL = true; +const bool CallingConvention::LTR = false; + +CallingConvention::CallingConvention( + const Abi* abi) : + _abi(abi) +{ +} + +CallingConvention::~CallingConvention() +{ +} + +std::vector CallingConvention::getParamRegisters() const +{ + return _paramRegs; +} + +std::vector CallingConvention::getParamFPRegisters() const +{ + return _paramFPRegs; +} + +std::vector CallingConvention::getParamDoubleRegisters() const +{ + return _paramDoubleRegs; +} + +std::vector CallingConvention::getParamVectorRegisters() const +{ + return _paramVectorRegs; +} + +std::vector CallingConvention::getReturnRegisters() const +{ + return _returnRegs; +} + +std::vector CallingConvention::getReturnFPRegisters() const +{ + return _returnFPRegs; +} + +std::vector CallingConvention::getReturnDoubleRegisters() const +{ + return _returnDoubleRegs; +} + +std::vector CallingConvention::getReturnVectorRegisters() const +{ + return _returnVectorRegs; +} + +bool CallingConvention::usesFPRegistersForParameters() const +{ + return !(_paramFPRegs.empty() && _paramDoubleRegs.empty()); +} + +bool CallingConvention::parameterRegistersOverlay() const +{ + return _paramRegsOverlay; +} + +std::size_t CallingConvention::getRegsNumPerParam() const +{ + return _regNumPerParam; +} + +bool CallingConvention::getStackParamOrder() const +{ + return _stackParamOrder; +} + +bool CallingConvention::passesStructsOnStack() const +{ + return _paramStructsOnStack; +} + +std::size_t CallingConvention::getMaxBytesPerStackParam() const +{ + return _abi->getWordSize(); +} + +bool CallingConvention::valueCanBeParameter(const Value *val) const +{ + if (_abi->isStackVariable(val)) + { + return true; + } + + auto rId = _abi->getRegisterId(val); + + if (rId == Abi::REG_INVALID) + { + return false; + } + + return std::count(_paramRegs.begin(), _paramRegs.end(), rId) + || std::count(_paramFPRegs.begin(), _paramFPRegs.end(), rId) + || std::count(_paramDoubleRegs.begin(), _paramDoubleRegs.end(), rId) + || std::count(_paramVectorRegs.begin(), _paramVectorRegs.end(), rId); +} + +bool CallingConvention::canHoldReturnValue(const Value* val) const +{ + auto rId = _abi->getRegisterId(val); + + if (rId == Abi::REG_INVALID) + { + return false; + } + + return std::count(_returnRegs.begin(), _returnRegs.end(), rId) + || std::count(_returnFPRegs.begin(), _returnFPRegs.end(), rId) + || std::count(_returnDoubleRegs.begin(), _returnDoubleRegs.end(), rId) + || std::count(_returnVectorRegs.begin(), _returnVectorRegs.end(), rId); +} + +// +//============================================================================== +// CallingConventionProvider +//============================================================================== +// + +CallingConventionProvider::CallingConventionProvider() +{ + registerCC(CallingConvention::ID::CC_CDECL, &CdeclCallingConvention::create); + registerCC(CallingConvention::ID::CC_ELLIPSIS, &CdeclCallingConvention::create); + registerCC(CallingConvention::ID::CC_STDCALL, &CdeclCallingConvention::create); + registerCC(CallingConvention::ID::CC_THISCALL, &ThiscallCallingConvention::create); + registerCC(CallingConvention::ID::CC_PASCAL, &PascalCallingConvention::create); + registerCC(CallingConvention::ID::CC_FASTCALL, &FastcallCallingConvention::create); + registerCC(CallingConvention::ID::CC_PASCAL_FASTCALL, &PascalFastcallCallingConvention::create); + registerCC(CallingConvention::ID::CC_WATCOM, &WatcomCallingConvention::create); + registerCC(CallingConvention::ID::CC_SYSTEMVX64, &SystemVX64CallingConvention::create); + registerCC(CallingConvention::ID::CC_MICROSOFTX64, &MicrosoftX64CallingConvention::create); + registerCC(CallingConvention::ID::CC_ARM, &ArmCallingConvention::create); + registerCC(CallingConvention::ID::CC_ARM64, &Arm64CallingConvention::create); + registerCC(CallingConvention::ID::CC_POWERPC, &PowerPCCallingConvention::create); + registerCC(CallingConvention::ID::CC_POWERPC64, &PowerPC64CallingConvention::create); + registerCC(CallingConvention::ID::CC_MIPS, &MipsCallingConvention::create); + registerCC(CallingConvention::ID::CC_MIPSPSP, &MipsPSPCallingConvention::create); + registerCC(CallingConvention::ID::CC_MIPS64, &Mips64CallingConvention::create); + registerCC(CallingConvention::ID::CC_PIC32, &Pic32CallingConvention::create); +} + +CallingConventionProvider::~CallingConventionProvider() +{ + _id2cc.clear(); +} + +CallingConventionProvider* CallingConventionProvider::getProvider() +{ + static CallingConventionProvider instance; + + return &instance; +} + +void CallingConventionProvider::registerCC( + const CallingConvention::ID& cc, + const CallingConvention::ConstructorMethod& con) +{ + auto ccId = static_cast(cc); + + if (ccId >= _id2cc.size()) + { + _id2cc.resize(ccId+1, nullptr); + } + + _id2cc[ccId] = con; +} + +CallingConvention::Ptr CallingConventionProvider::createCallingConvention( + const CallingConvention::ID& cc, + const Abi* a) const +{ + auto ccId = static_cast(cc); + + if (ccId >= _id2cc.size() || _id2cc[ccId] == nullptr) + { + return nullptr; + } + + return _id2cc[ccId](a); +} + +} +} From e6514c892c1d8f415778c445974cf1bac4dff431 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:45:15 +0100 Subject: [PATCH 082/159] calling_convention/arm: arm cc definition Provides implementation of arm calling convention. --- .../providers/calling_convention/arm.h | 33 +++++++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../providers/calling_convention/arm.cpp | 49 +++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/arm.h create mode 100644 src/bin2llvmir/providers/calling_convention/arm.cpp diff --git a/include/retdec/bin2llvmir/providers/calling_convention/arm.h b/include/retdec/bin2llvmir/providers/calling_convention/arm.h new file mode 100644 index 000000000..4473f9c72 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/arm.h @@ -0,0 +1,33 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/arm.h + * @brief Calling conventions of ARM architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class ArmCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + ArmCallingConvention(const Abi* a); + virtual ~ArmCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 4c042b7e3..2087cec2b 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -79,6 +79,7 @@ set(BIN2LLVMIR_SOURCES providers/abi/x86_pascal.cpp providers/abi/x86_watcom.cpp providers/calling_convention/calling_conventnion.cpp + providers/calling_convention/arm.h providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/providers/calling_convention/arm.cpp b/src/bin2llvmir/providers/calling_convention/arm.cpp new file mode 100644 index 000000000..99aea1cfe --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/arm.cpp @@ -0,0 +1,49 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/arm.cpp + * @brief Calling conventions of ARM architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/arm.h" +#include "retdec/capstone2llvmir/arm/arm.h" + +namespace retdec { +namespace bin2llvmir { + +ArmCallingConvention::ArmCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + ARM_REG_R0, + ARM_REG_R1, + ARM_REG_R2, + ARM_REG_R3}; + + _paramFPRegs = { + ARM_REG_D0, + ARM_REG_D1, + ARM_REG_D2, + ARM_REG_D3}; + + _returnRegs = { + ARM_REG_R0, + ARM_REG_R1}; + + _returnFPRegs = { + ARM_REG_D0, + ARM_REG_D1}; + + _regNumPerParam = 2; +} + +ArmCallingConvention::~ArmCallingConvention() +{ +} + +CallingConvention::Ptr ArmCallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +} +} From 0490206e36435f94df2912eb1a87130cc9a9aed6 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:46:15 +0100 Subject: [PATCH 083/159] calling_convention/arm64: arm64 cc implementation Provides implementation of arm64 calling convention. --- .../providers/calling_convention/arm64.h | 33 +++++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../providers/calling_convention/arm64.cpp | 59 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/arm64.h create mode 100644 src/bin2llvmir/providers/calling_convention/arm64.cpp diff --git a/include/retdec/bin2llvmir/providers/calling_convention/arm64.h b/include/retdec/bin2llvmir/providers/calling_convention/arm64.h new file mode 100644 index 000000000..d5ee374aa --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/arm64.h @@ -0,0 +1,33 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/arm64.h + * @brief Calling conventions of ARM64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM64_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class Arm64CallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + Arm64CallingConvention(const Abi* a); + virtual ~Arm64CallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 2087cec2b..d72f300a1 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -80,6 +80,7 @@ set(BIN2LLVMIR_SOURCES providers/abi/x86_watcom.cpp providers/calling_convention/calling_conventnion.cpp providers/calling_convention/arm.h + providers/calling_convention/arm64.h providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/providers/calling_convention/arm64.cpp b/src/bin2llvmir/providers/calling_convention/arm64.cpp new file mode 100644 index 000000000..a44c3f24f --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/arm64.cpp @@ -0,0 +1,59 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/arm64.cpp + * @brief Calling conventions of ARM64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include + +#include "retdec/bin2llvmir/providers/calling_convention/arm64.h" + +namespace retdec { +namespace bin2llvmir { + +Arm64CallingConvention::Arm64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + ARM64_REG_X0, + ARM64_REG_X1, + ARM64_REG_X2, + ARM64_REG_X3, + ARM64_REG_X4, + ARM64_REG_X5, + ARM64_REG_X6, + ARM64_REG_X7 + }; + _paramFPRegs = { + ARM64_REG_V0, + ARM64_REG_V1, + ARM64_REG_V2, + ARM64_REG_V3, + ARM64_REG_V4, + ARM64_REG_V5, + ARM64_REG_V6, + ARM64_REG_V7 + }; + + _returnRegs = { + ARM64_REG_X0 + }; + + _returnFPRegs = { + ARM64_REG_V0 + }; + + _regNumPerParam = 2; +} + +Arm64CallingConvention::~Arm64CallingConvention() +{ +} + +CallingConvention::Ptr Arm64CallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +} +} From 83f5d226e030dcdc067c90797b31710c37eb2787 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:50:38 +0100 Subject: [PATCH 084/159] calling_convention/mips: implementation of mips cc Provides implementation of mips calling conventnion. --- .../providers/calling_convention/mips.h | 48 +++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../providers/calling_convention/mips.cpp | 98 +++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/mips.h create mode 100644 src/bin2llvmir/providers/calling_convention/mips.cpp diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips.h b/include/retdec/bin2llvmir/providers/calling_convention/mips.h new file mode 100644 index 000000000..7c71ff405 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips.h @@ -0,0 +1,48 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/mips.h + * @brief Calling conventions of MIPS architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class MipsCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + MipsCallingConvention(const Abi* a); + virtual ~MipsCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +class MipsPSPCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + MipsPSPCallingConvention(const Abi* a); + virtual ~MipsPSPCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index d72f300a1..d64c30579 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -81,6 +81,7 @@ set(BIN2LLVMIR_SOURCES providers/calling_convention/calling_conventnion.cpp providers/calling_convention/arm.h providers/calling_convention/arm64.h + providers/calling_convention/mips.h providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/providers/calling_convention/mips.cpp b/src/bin2llvmir/providers/calling_convention/mips.cpp new file mode 100644 index 000000000..113114fb7 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/mips.cpp @@ -0,0 +1,98 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/mips.cpp + * @brief Calling conventions of MIPS architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/mips.h" +#include "retdec/capstone2llvmir/mips/mips.h" + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================== +// MipsCallingConvention +//============================================================================== +// + +MipsCallingConvention::MipsCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3 + }; + _paramFPRegs = { + MIPS_REG_F12, + MIPS_REG_F14, + MIPS_REG_F16, + MIPS_REG_F18 + }; + _paramDoubleRegs = { + MIPS_REG_FD12, + MIPS_REG_FD14, + MIPS_REG_FD16, + }; + + _returnRegs = { + MIPS_REG_V0 + }; + _returnFPRegs = { + MIPS_REG_V0 + }; + _returnDoubleRegs = { + MIPS_REG_V0 + }; + + _regNumPerParam = 2; +} + +// +//============================================================================== +// MipsPSPCallingConvention +//============================================================================== +// + +MipsPSPCallingConvention::MipsPSPCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3, + MIPS_REG_T0, + MIPS_REG_T1, + MIPS_REG_T2, + MIPS_REG_T3 + }; + _paramFPRegs = { + MIPS_REG_F12, + MIPS_REG_F14, + MIPS_REG_F16, + MIPS_REG_F18 + }; + _paramDoubleRegs = { + MIPS_REG_FD12, + MIPS_REG_FD14, + MIPS_REG_FD16, + }; + + _returnRegs = { + MIPS_REG_V0 + }; + _returnFPRegs = { + MIPS_REG_V0 + }; + _returnDoubleRegs = { + MIPS_REG_V0 + }; + + _regNumPerParam = 2; +} + +} +} From c42d15b710cf3761185df029e056ce215a9a2d3d Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:51:12 +0100 Subject: [PATCH 085/159] calling_convention/mips64: implementation of mips64 cc Provides implementation of mips64 calling conventnion. --- .../providers/calling_convention/mips64.h | 33 +++++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../providers/calling_convention/mips64.cpp | 57 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/mips64.h create mode 100644 src/bin2llvmir/providers/calling_convention/mips64.cpp diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips64.h b/include/retdec/bin2llvmir/providers/calling_convention/mips64.h new file mode 100644 index 000000000..574de321a --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips64.h @@ -0,0 +1,33 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/mips64.h + * @brief Calling conventions of Mips64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS64_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class Mips64CallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + Mips64CallingConvention(const Abi* a); + virtual ~Mips64CallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index d64c30579..f13fdf3ac 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -82,6 +82,7 @@ set(BIN2LLVMIR_SOURCES providers/calling_convention/arm.h providers/calling_convention/arm64.h providers/calling_convention/mips.h + providers/calling_convention/mips64.h providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/providers/calling_convention/mips64.cpp b/src/bin2llvmir/providers/calling_convention/mips64.cpp new file mode 100644 index 000000000..38357488b --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/mips64.cpp @@ -0,0 +1,57 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/mips64.cpp + * @brief Calling conventions of Mips64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/mips64.h" +#include "retdec/capstone2llvmir/mips/mips.h" + +namespace retdec { +namespace bin2llvmir { + +Mips64CallingConvention::Mips64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3, + MIPS_REG_T0, + MIPS_REG_T1, + MIPS_REG_T2, + MIPS_REG_T3 + }; + _paramFPRegs = { + MIPS_REG_F12, + MIPS_REG_F13, + MIPS_REG_F14, + MIPS_REG_F15, + MIPS_REG_F16, + MIPS_REG_F17, + MIPS_REG_F18 + }; + + _returnRegs = { + MIPS_REG_V0 + }; + _returnFPRegs = { + MIPS_REG_F1 + }; + + _regNumPerParam = 2; + _paramStructsOnStack = false; +} + +Mips64CallingConvention::~Mips64CallingConvention() +{ +} + +CallingConvention::Ptr Mips64CallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +} +} From 480a11370515b9bcc2501e63220d0c51fe669726 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:47:07 +0100 Subject: [PATCH 086/159] calling_conventnion/x86: implementation of x86 ccs Provides implementation of basic x86 calling conventnions: - cdecl - fastcall - pascal - pascal fastcall - thiscall --- .../providers/calling_convention/x86.h | 102 ++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../providers/calling_convention/x86.cpp | 225 ++++++++++++++++++ 3 files changed, 328 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86.h create mode 100644 src/bin2llvmir/providers/calling_convention/x86.cpp diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86.h b/include/retdec/bin2llvmir/providers/calling_convention/x86.h new file mode 100644 index 000000000..30b33ca85 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86.h @@ -0,0 +1,102 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/cdecl.h + * @brief Calling convention information for cdecl. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class CdeclCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + CdeclCallingConvention(const Abi* a); + virtual ~CdeclCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +class FastcallCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + FastcallCallingConvention(const Abi* a); + virtual ~FastcallCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +class PascalCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + PascalCallingConvention(const Abi* a); + virtual ~PascalCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +class PascalFastcallCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + PascalFastcallCallingConvention(const Abi* a); + virtual ~PascalFastcallCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +class ThiscallCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + ThiscallCallingConvention(const Abi* a); + virtual ~ThiscallCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +class WatcomCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + WatcomCallingConvention(const Abi* a); + virtual ~WatcomCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index f13fdf3ac..dfa8fdcf9 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -83,6 +83,7 @@ set(BIN2LLVMIR_SOURCES providers/calling_convention/arm64.h providers/calling_convention/mips.h providers/calling_convention/mips64.h + providers/calling_convention/x86.h providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/providers/calling_convention/x86.cpp b/src/bin2llvmir/providers/calling_convention/x86.cpp new file mode 100644 index 000000000..be3797338 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86.cpp @@ -0,0 +1,225 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86.cpp + * @brief Calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/x86.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================== +// CdeclCallingConvention +//============================================================================== +// + +CdeclCallingConvention::CdeclCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; + + _regNumPerParam = 1; +} + +CdeclCallingConvention::~CdeclCallingConvention() +{ +} + +CallingConvention::Ptr CdeclCallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +// +//============================================================================== +// FastcallCallingConvention +//============================================================================== +// + +FastcallCallingConvention::FastcallCallingConvention(const Abi* a) : + CallingConvention(a) + +{ + _paramRegs = { + X86_REG_ECX, + X86_REG_EDX, + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; + + _regNumPerParam = 1; +} + +FastcallCallingConvention::~FastcallCallingConvention() +{ +} + +CallingConvention::Ptr FastcallCallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +// +//============================================================================== +// PascalCallingConvention +//============================================================================== +// + +PascalCallingConvention::PascalCallingConvention(const Abi* a) : + CallingConvention(a) + +{ + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; + + _regNumPerParam = 1; + _stackParamOrder = LTR; +} + +PascalCallingConvention::~PascalCallingConvention() +{ +} + +CallingConvention::Ptr PascalCallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +// +//============================================================================== +// PascalFastcallCallingConvention +//============================================================================== +// + +PascalFastcallCallingConvention::PascalFastcallCallingConvention(const Abi* a) : + CallingConvention(a) + +{ + _paramRegs = { + X86_REG_ECX, + X86_REG_EDX, + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; + + _regNumPerParam = 1; + _stackParamOrder = LTR; +} + +PascalFastcallCallingConvention::~PascalFastcallCallingConvention() +{ +} + +CallingConvention::Ptr PascalFastcallCallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +// +//============================================================================== +// ThiscallCallingConvention +//============================================================================== +// + +ThiscallCallingConvention::ThiscallCallingConvention(const Abi* a) : + CallingConvention(a) + +{ + _paramRegs = { + X86_REG_ECX + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; + + _regNumPerParam = 1; +} + +ThiscallCallingConvention::~ThiscallCallingConvention() +{ +} + +CallingConvention::Ptr ThiscallCallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +// +//============================================================================== +// WatcomCallingConvention +//============================================================================== +// + +WatcomCallingConvention::WatcomCallingConvention(const Abi* a) : + CallingConvention(a) + +{ + _paramRegs = { + X86_REG_ECX + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; + + _regNumPerParam = 1; +} + +WatcomCallingConvention::~WatcomCallingConvention() +{ +} + +CallingConvention::Ptr WatcomCallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +} +} From f03f20ba8c8f7d5adf0d9c6e684a386dc5286e61 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:48:31 +0100 Subject: [PATCH 087/159] calling_conventnon/x64: implementation of x64 ccs Provide implementation of main x64 calling conventnions: - System V x64 calling convention - Microsoft x64 calling convention --- .../providers/calling_convention/x64.h | 48 ++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../providers/calling_convention/x64.cpp | 106 ++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x64.h create mode 100644 src/bin2llvmir/providers/calling_convention/x64.cpp diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64.h b/include/retdec/bin2llvmir/providers/calling_convention/x64.h new file mode 100644 index 000000000..7dd0616df --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x64.h @@ -0,0 +1,48 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/x64.h + * @brief Calling conventions of X64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class SystemVX64CallingConvention : public CallingConvention +{ + // Ctors, dtors. + // + public: + SystemVX64CallingConvention(const Abi* a); + virtual ~SystemVX64CallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +class MicrosoftX64CallingConvention : public CallingConvention +{ + // Ctors, dtors. + // + public: + MicrosoftX64CallingConvention(const Abi* a); + virtual ~MicrosoftX64CallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index dfa8fdcf9..76de37b85 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -83,6 +83,7 @@ set(BIN2LLVMIR_SOURCES providers/calling_convention/arm64.h providers/calling_convention/mips.h providers/calling_convention/mips64.h + providers/calling_convention/x64.h providers/calling_convention/x86.h providers/asm_instruction.cpp providers/config.cpp diff --git a/src/bin2llvmir/providers/calling_convention/x64.cpp b/src/bin2llvmir/providers/calling_convention/x64.cpp new file mode 100644 index 000000000..238ad2e04 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x64.cpp @@ -0,0 +1,106 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x64.cpp + * @brief Calling conventions of X64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/x64.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================== +// SystemVX64CallingConvention +//============================================================================== +// + +SystemVX64CallingConvention::SystemVX64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + X86_REG_RDI, + X86_REG_RSI, + X86_REG_RDX, + X86_REG_RCX, + X86_REG_R8, + X86_REG_R9 + }; + _paramFPRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3, + X86_REG_XMM4, + X86_REG_XMM5, + X86_REG_XMM6, + X86_REG_XMM7 + }; + + _returnRegs = { + X86_REG_RAX, + X86_REG_RDX + }; + _returnFPRegs = { + X86_REG_XMM0 + }; + + _regNumPerParam = 2; +} + +SystemVX64CallingConvention::~SystemVX64CallingConvention() +{ +} + +CallingConvention::Ptr SystemVX64CallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +// +//============================================================================== +// MicrosoftX64CallingConvention +//============================================================================== +// + +MicrosoftX64CallingConvention::MicrosoftX64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + X86_REG_RCX, + X86_REG_RDX, + X86_REG_R8, + X86_REG_R9 + }; + _paramFPRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3 + }; + + _returnRegs = { + X86_REG_RAX + }; + _returnFPRegs = { + X86_REG_XMM0 + }; + + _paramRegsOverlay = true; + _regNumPerParam = 1; +} + +MicrosoftX64CallingConvention::~MicrosoftX64CallingConvention() +{ +} + +CallingConvention::Ptr MicrosoftX64CallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + + + +} +} From 5414792eea3d43366959fcd8aacd52440c0d138e Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:52:34 +0100 Subject: [PATCH 088/159] calling_convention/pic32: implementation of pic32 cc Provides implementation of pic32 calling convention. --- .../providers/calling_convention/pic32.h | 33 +++++++++++++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../providers/calling_convention/pic32.cpp | 31 +++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/pic32.h create mode 100644 src/bin2llvmir/providers/calling_convention/pic32.cpp diff --git a/include/retdec/bin2llvmir/providers/calling_convention/pic32.h b/include/retdec/bin2llvmir/providers/calling_convention/pic32.h new file mode 100644 index 000000000..b2ca42aba --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/pic32.h @@ -0,0 +1,33 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/pic32.h + * @brief Calling conventions of PIC32 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PIC32_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PIC32_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class Pic32CallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + Pic32CallingConvention(const Abi* a); + virtual ~Pic32CallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 76de37b85..565456f67 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -83,6 +83,7 @@ set(BIN2LLVMIR_SOURCES providers/calling_convention/arm64.h providers/calling_convention/mips.h providers/calling_convention/mips64.h + providers/calling_convention/pic32.h providers/calling_convention/x64.h providers/calling_convention/x86.h providers/asm_instruction.cpp diff --git a/src/bin2llvmir/providers/calling_convention/pic32.cpp b/src/bin2llvmir/providers/calling_convention/pic32.cpp new file mode 100644 index 000000000..c48cd264a --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/pic32.cpp @@ -0,0 +1,31 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/pic32.cpp + * @brief Calling conventions of PIC32 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/pic32.h" +#include "retdec/capstone2llvmir/mips/mips.h" + +namespace retdec { +namespace bin2llvmir { + +Pic32CallingConvention::Pic32CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3 + }; + + _returnRegs = { + MIPS_REG_V0 + }; + + _regNumPerParam = 2; +} + +} +} From 164c284d0e1b35b405a76774cc4ca14b01a3acfd Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:49:57 +0100 Subject: [PATCH 089/159] calling_convention/powerpc: implementation of powerpc cc Provides implementation of powerpc calling convention. --- .../providers/calling_convention/powerpc.h | 33 +++++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../providers/calling_convention/powerpc.cpp | 59 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/powerpc.h create mode 100644 src/bin2llvmir/providers/calling_convention/powerpc.cpp diff --git a/include/retdec/bin2llvmir/providers/calling_convention/powerpc.h b/include/retdec/bin2llvmir/providers/calling_convention/powerpc.h new file mode 100644 index 000000000..567c9d56a --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/powerpc.h @@ -0,0 +1,33 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/powerpc.h + * @brief Calling conventions of PowerPC architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class PowerPCCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + PowerPCCallingConvention(const Abi* a); + virtual ~PowerPCCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 565456f67..32b16e1ad 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -84,6 +84,7 @@ set(BIN2LLVMIR_SOURCES providers/calling_convention/mips.h providers/calling_convention/mips64.h providers/calling_convention/pic32.h + providers/calling_convention/powerpc.h providers/calling_convention/x64.h providers/calling_convention/x86.h providers/asm_instruction.cpp diff --git a/src/bin2llvmir/providers/calling_convention/powerpc.cpp b/src/bin2llvmir/providers/calling_convention/powerpc.cpp new file mode 100644 index 000000000..2adc45010 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/powerpc.cpp @@ -0,0 +1,59 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/powerpc.cpp + * @brief Calling conventions of PowerPC architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/powerpc.h" +#include "retdec/capstone2llvmir/powerpc/powerpc.h" + +namespace retdec { +namespace bin2llvmir { + +PowerPCCallingConvention::PowerPCCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + PPC_REG_R3, + PPC_REG_R4, + PPC_REG_R5, + PPC_REG_R6, + PPC_REG_R7, + PPC_REG_R8, + PPC_REG_R9, + PPC_REG_R10 + }; + _paramFPRegs = { + PPC_REG_F1, + PPC_REG_F2, + PPC_REG_F3, + PPC_REG_F4, + PPC_REG_F5, + PPC_REG_F6, + PPC_REG_F7, + PPC_REG_F8 + }; + + _returnRegs = { + PPC_REG_R3, + PPC_REG_R4 + }; + _returnFPRegs = { + PPC_REG_F1 + }; + + _regNumPerParam = 2; + _paramStructsOnStack = false; +} + +PowerPCCallingConvention::~PowerPCCallingConvention() +{ +} + +CallingConvention::Ptr PowerPCCallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +} +} From 5918d44fe706c7444ee8b1554c03744856ac3cb0 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:51:43 +0100 Subject: [PATCH 090/159] calling_convention/powerpc64: implementation of powerpc64 cc Provides implementation of PowerPC64 calling convention. --- .../providers/calling_convention/powerpc64.h | 33 ++++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../calling_convention/powerpc64.cpp | 61 +++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/powerpc64.h create mode 100644 src/bin2llvmir/providers/calling_convention/powerpc64.cpp diff --git a/include/retdec/bin2llvmir/providers/calling_convention/powerpc64.h b/include/retdec/bin2llvmir/providers/calling_convention/powerpc64.h new file mode 100644 index 000000000..211c629b4 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/powerpc64.h @@ -0,0 +1,33 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/powerpc64.h + * @brief Calling conventions of PowerPC64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC64_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class PowerPC64CallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + PowerPC64CallingConvention(const Abi* a); + virtual ~PowerPC64CallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 32b16e1ad..0e67d6db5 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -85,6 +85,7 @@ set(BIN2LLVMIR_SOURCES providers/calling_convention/mips64.h providers/calling_convention/pic32.h providers/calling_convention/powerpc.h + providers/calling_convention/powerpc64.h providers/calling_convention/x64.h providers/calling_convention/x86.h providers/asm_instruction.cpp diff --git a/src/bin2llvmir/providers/calling_convention/powerpc64.cpp b/src/bin2llvmir/providers/calling_convention/powerpc64.cpp new file mode 100644 index 000000000..e1801171f --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/powerpc64.cpp @@ -0,0 +1,61 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/powerpc64.cpp + * @brief Calling conventions of PowerPC64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/powerpc64.h" +#include "retdec/capstone2llvmir/powerpc/powerpc.h" + +namespace retdec { +namespace bin2llvmir { + +PowerPC64CallingConvention::PowerPC64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + PPC_REG_R3, + PPC_REG_R4, + PPC_REG_R5, + PPC_REG_R6, + PPC_REG_R7, + PPC_REG_R8, + PPC_REG_R9, + PPC_REG_R10 + }; + _paramFPRegs = { + PPC_REG_F1, + PPC_REG_F2, + PPC_REG_F3, + PPC_REG_F4, + PPC_REG_F5, + PPC_REG_F6, + PPC_REG_F7, + PPC_REG_F8, + PPC_REG_F10, + PPC_REG_F11 + }; + + _returnRegs = { + PPC_REG_R3, + PPC_REG_R4 + }; + _returnFPRegs = { + PPC_REG_F1 + }; + + _regNumPerParam = 2; + _paramStructsOnStack = false; +} + +PowerPC64CallingConvention::~PowerPC64CallingConvention() +{ +} + +CallingConvention::Ptr PowerPC64CallingConvention::create(const Abi* a) +{ + return std::make_unique(a); +} + +} +} From 3933fbbd2999c88d08a55b70d30759f0c48b4915 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:55:05 +0100 Subject: [PATCH 091/159] abi: provide architecture word size info Provides implementation of method getWordSize() returning number of bytes in word of the architecture. --- include/retdec/bin2llvmir/providers/abi/abi.h | 2 ++ src/bin2llvmir/providers/abi/abi.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 3918653c5..bfeafc442 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -89,12 +89,14 @@ class Abi std::size_t getTypeBitSize(llvm::Type* t) const; llvm::IntegerType* getDefaultType() const; llvm::PointerType* getDefaultPointerType() const; + std::size_t getWordSize() const; static std::size_t getTypeByteSize(llvm::Module* m, llvm::Type* t); static std::size_t getTypeBitSize(llvm::Module* m, llvm::Type* t); static llvm::IntegerType* getDefaultType(llvm::Module* m); static llvm::Type* getDefaultFPType(llvm::Module* m); static llvm::PointerType* getDefaultPointerType(llvm::Module* m); + static std::size_t getWordSize(llvm::Module* m); // Architectures. // diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 5c970d8f9..323d85c24 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -185,6 +185,11 @@ llvm::PointerType* Abi::getDefaultPointerType() const return Abi::getDefaultPointerType(_module); } +std::size_t Abi::getWordSize() const +{ + return getWordSize(_module); +} + std::size_t Abi::getTypeByteSize(llvm::Module* m, llvm::Type* t) { assert(m); @@ -216,6 +221,11 @@ llvm::PointerType* Abi::getDefaultPointerType(llvm::Module* m) return PointerType::get(Abi::getDefaultType(m), 0); } +std::size_t Abi::getWordSize(llvm::Module* m) +{ + return m->getDataLayout().getPointerSize(0); +} + bool Abi::isMips() const { return _config->getConfig().architecture.isMipsOrPic32(); From 0a8afa83974c23d92708dfb22216ef4599bb73b2 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 11:59:48 +0100 Subject: [PATCH 092/159] abi: this commit shall revert not needed info --- include/retdec/bin2llvmir/providers/abi/abi.h | 33 --------- src/bin2llvmir/providers/abi/abi.cpp | 68 ------------------- 2 files changed, 101 deletions(-) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index bfeafc442..b591b28ac 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -29,8 +29,6 @@ class Abi public: static const uint32_t REG_INVALID; static const unsigned DEFAULT_ADDR_SPACE; - static const bool RTL; - static const bool LTR; // Ctors, dtors. // @@ -43,9 +41,6 @@ class Abi public: bool isRegister(const llvm::Value* val) const; bool isRegister(const llvm::Value* val, uint32_t r) const; - std::vector parameterRegisters() const; - std::vector parameterFPRegisters() const; - std::vector doubleParameterRegisters() const; bool isFlagRegister(const llvm::Value* val); bool isStackPointerRegister(const llvm::Value* val); bool isZeroRegister(const llvm::Value* val); @@ -57,25 +52,12 @@ class Abi llvm::GlobalVariable* getStackPointerRegister(); llvm::GlobalVariable* getZeroRegister(); - bool getStackParamOrder() const; - void addRegister(uint32_t id, llvm::GlobalVariable* reg); llvm::GlobalVariable* getSyscallIdRegister(); llvm::GlobalVariable* getSyscallReturnRegister(); llvm::GlobalVariable* getSyscallArgumentRegister(unsigned n); - llvm::GlobalVariable* getReturnRegister() const; - llvm::GlobalVariable* getFPReturnRegister() const; - - bool usesFPRegistersForParameters() const; - bool parameterRegistersOverlay() const; - - // Values. - public: - bool valueCanBeParameter(const llvm::Value* val) const; - virtual bool canHoldReturnValue(const llvm::Value* val) const; - // Instructions. // public: @@ -137,21 +119,6 @@ class Abi uint32_t _regSyscallId = REG_INVALID; /// Register that is always equal to zero - not every arch have this. uint32_t _regZeroReg = REG_INVALID; - /// Register used for returning values from functions. - uint32_t _regReturn = REG_INVALID; - /// Register used for returning floating point values from functions. - uint32_t _regFPReturn = REG_INVALID; - /// Registers that can be used as parameter according to abi. - std::vector _paramRegs {}; - /// Floating Point registers that can be used as parameter according to abi. - std::vector _paramFPRegs {}; - std::vector _doubleParamRegs {}; - - /// Specifies if abi returns value on stack. - bool returnsOnStack = false; - bool _fpRegsAsParams = false; - bool _paramRegsOverlay = false; - bool _stackParamOrder = RTL; }; class AbiProvider diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 323d85c24..d1d810d85 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -28,8 +28,6 @@ namespace bin2llvmir { const uint32_t Abi::REG_INVALID = 0; const unsigned Abi::DEFAULT_ADDR_SPACE = 0; -const bool Abi::RTL = true; -const bool Abi::LTR = false; Abi::Abi(llvm::Module* m, Config* c) : _module(m), @@ -69,12 +67,6 @@ bool Abi::isZeroRegister(const llvm::Value* val) return getZeroRegister() == val; } - -bool Abi::getStackParamOrder() const -{ - return _stackParamOrder; -} - /** * \param r Register ID to get. * Warning! We are using Capstone register IDs which overlaps. @@ -140,25 +132,6 @@ llvm::GlobalVariable* Abi::getSyscallArgumentRegister(unsigned n) return n < _syscallRegs.size() ? getRegister(_syscallRegs[n]) : nullptr; } -llvm::GlobalVariable* Abi::getReturnRegister() const -{ - return getRegister(_regReturn); -} - -llvm::GlobalVariable* Abi::getFPReturnRegister() const -{ - return getRegister(_regFPReturn); -} - -bool Abi::usesFPRegistersForParameters() const -{ - return _fpRegsAsParams; -} - -bool Abi::parameterRegistersOverlay() const -{ - return _paramRegsOverlay; -} bool Abi::isNopInstruction(AsmInstruction ai) { @@ -246,48 +219,7 @@ bool Abi::isPowerPC() const return _config->getConfig().architecture.isPpc(); } -bool Abi::valueCanBeParameter(const llvm::Value *val) const -{ - if (_config->isStackVariable(val)) - { - return true; - } - - bool isParamReg = find(_paramRegs.begin(), _paramRegs.end(), getRegisterId(val)) != _paramRegs.end(); - bool isFpParamReg = find(_paramFPRegs.begin(), _paramFPRegs.end(), getRegisterId(val)) != _paramFPRegs.end(); - - return isParamReg || isFpParamReg; -} - -std::vector Abi::parameterRegisters() const -{ - return _paramRegs; -} - -std::vector Abi::doubleParameterRegisters() const -{ - return _doubleParamRegs; -} -std::vector Abi::parameterFPRegisters() const -{ - return _paramFPRegs; -} - -bool Abi::canHoldReturnValue(const llvm::Value* val) const -{ - if (returnsOnStack) - { - return _config->isStackVariable(val); - } - - if (!isRegister(val)) - { - return false; - } - - return getRegisterId(val) == _regReturn || getRegisterId(val) == _regFPReturn; -} // //============================================================================== From a19d2c6b4f9329f74303f6d5a09602e92a1c22f5 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:05:05 +0100 Subject: [PATCH 093/159] abi: provide test for stack variables --- include/retdec/bin2llvmir/providers/abi/abi.h | 5 +++++ src/bin2llvmir/providers/abi/abi.cpp | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index b591b28ac..abebe9fa5 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -57,6 +57,11 @@ class Abi llvm::GlobalVariable* getSyscallIdRegister(); llvm::GlobalVariable* getSyscallReturnRegister(); llvm::GlobalVariable* getSyscallArgumentRegister(unsigned n); + + // Stacks. + // + public: + bool isStackVariable(const llvm::Value* val) const; // Instructions. // diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index d1d810d85..4dec3dc10 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -132,6 +132,10 @@ llvm::GlobalVariable* Abi::getSyscallArgumentRegister(unsigned n) return n < _syscallRegs.size() ? getRegister(_syscallRegs[n]) : nullptr; } +bool Abi::isStackVariable(const Value* val) const +{ + return _config->isStackVariable(val); +} bool Abi::isNopInstruction(AsmInstruction ai) { From c6073776d4b61447ade40da76c4289627d3ef7ca Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:07:03 +0100 Subject: [PATCH 094/159] abi: provide test for pic32 --- include/retdec/bin2llvmir/providers/abi/abi.h | 1 + src/bin2llvmir/providers/abi/abi.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index abebe9fa5..8a99889b0 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -92,6 +92,7 @@ class Abi bool isArm() const; bool isX86() const; bool isPowerPC() const; + bool isPic32() const; // Private data - misc. // diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 4dec3dc10..30cda6f7f 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -223,6 +223,10 @@ bool Abi::isPowerPC() const return _config->getConfig().architecture.isPpc(); } +bool Abi::isPic32() const +{ + return _config->getConfig().architecture.isPic32(); +} // From ac4427fe59a887f3c844a228efae5d5e159f9551 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:07:32 +0100 Subject: [PATCH 095/159] abi: provide calling convention info --- include/retdec/bin2llvmir/providers/abi/abi.h | 17 +++++++ src/bin2llvmir/providers/abi/abi.cpp | 46 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 8a99889b0..364f34ce5 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -16,6 +16,7 @@ #include "retdec/bin2llvmir/providers/asm_instruction.h" #include "retdec/bin2llvmir/providers/config.h" +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" //#include "retdec/capstone2llvmir/x86/x86_defs.h" @@ -93,6 +94,15 @@ class Abi bool isX86() const; bool isPowerPC() const; bool isPic32() const; + + // Calling conventions. + // + public: + CallingConvention* getCallingConvention( + const CallingConvention::ID& cc); + CallingConvention* getDefaultCallingConvention(); + virtual bool supportsCallingConvention(CallingConvention::ID& cc) const; + bool isSpecialCallingConvention(const CallingConvention::ID& cc) const; // Private data - misc. // @@ -125,6 +135,13 @@ class Abi uint32_t _regSyscallId = REG_INVALID; /// Register that is always equal to zero - not every arch have this. uint32_t _regZeroReg = REG_INVALID; + + // Private data - calling convention + // + protected: + std::vector _id2cc; + CallingConvention::ID _defcc; + }; class AbiProvider diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 30cda6f7f..75a6e125a 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -228,6 +228,52 @@ bool Abi::isPic32() const return _config->getConfig().architecture.isPic32(); } +CallingConvention* Abi::getDefaultCallingConvention() +{ + return getCallingConvention(_defcc); +} + +CallingConvention* Abi::getCallingConvention( + const CallingConvention::ID& c) +{ + CallingConvention::ID cc = c; + if (!isSpecialCallingConvention(cc) && !supportsCallingConvention(cc)) + { + return nullptr; + } + + auto ccId = static_cast(cc); + + if (ccId >= _id2cc.size()) + { + _id2cc.resize(ccId+1, nullptr); + } + if (_id2cc[ccId] == nullptr) + { + auto provider = CallingConventionProvider::getProvider(); + _id2cc[ccId] = provider->createCallingConvention(cc, this); + } + + return _id2cc[ccId].get(); +} + +bool Abi::supportsCallingConvention(CallingConvention::ID& cc) const +{ + return cc == _defcc; +} + +bool Abi::isSpecialCallingConvention(const CallingConvention::ID& cc) const +{ + switch (cc) + { + case CallingConvention::ID::CC_VOIDARG: + case CallingConvention::ID::CC_SPECIAL: + return true; + + default: + return false; + } +} // //============================================================================== From 95d73d2b498b15758c03e5e39c02d3f9556a700c Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:09:27 +0100 Subject: [PATCH 096/159] abi/x86: restet added convention inf --- src/bin2llvmir/providers/abi/x86.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bin2llvmir/providers/abi/x86.cpp b/src/bin2llvmir/providers/abi/x86.cpp index 03d6afc44..db9515510 100644 --- a/src/bin2llvmir/providers/abi/x86.cpp +++ b/src/bin2llvmir/providers/abi/x86.cpp @@ -29,8 +29,6 @@ AbiX86::AbiX86(llvm::Module* m, Config* c) : X86_REG_EDI, X86_REG_EBP}; - _regReturn = X86_REG_EAX; - _regFPReturn = X86_REG_ST7; } AbiX86::~AbiX86() From f6e87a42f9731dba3c61a5968bcfe7b80f531ccf Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:22:08 +0100 Subject: [PATCH 097/159] abi/x64: revert info providing --- src/bin2llvmir/providers/abi/x64.cpp | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/bin2llvmir/providers/abi/x64.cpp b/src/bin2llvmir/providers/abi/x64.cpp index d00c38a58..e6d01c32d 100644 --- a/src/bin2llvmir/providers/abi/x64.cpp +++ b/src/bin2llvmir/providers/abi/x64.cpp @@ -14,7 +14,6 @@ namespace bin2llvmir { AbiX64::AbiX64(llvm::Module* m, Config* c) : Abi(m, c) { - _fpRegsAsParams = true; _regs.reserve(X86_REG_ENDING); _id2regs.resize(X86_REG_ENDING, nullptr); _regStackPointerId = X86_REG_RSP; @@ -29,29 +28,6 @@ AbiX64::AbiX64(llvm::Module* m, Config* c) : X86_REG_R10, X86_REG_R8, X86_REG_R9}; - - _paramRegs = { - X86_REG_RDI, - X86_REG_RSI, - X86_REG_RDX, - X86_REG_RCX, - X86_REG_R8, - X86_REG_R9}; - - _paramFPRegs = { - X86_REG_XMM0, - X86_REG_XMM1, - X86_REG_XMM2, - X86_REG_XMM3, - X86_REG_XMM4, - X86_REG_XMM5, - X86_REG_XMM6, - X86_REG_XMM7 - }; - - _regReturn = X86_REG_RAX; - - _regFPReturn = X86_REG_ST0; } AbiX64::~AbiX64() From 503d5ed84aa41346e26929d9aff20c7f1eeb1e54 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:23:20 +0100 Subject: [PATCH 098/159] abi/arm: revert cc info providing --- src/bin2llvmir/providers/abi/arm.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/bin2llvmir/providers/abi/arm.cpp b/src/bin2llvmir/providers/abi/arm.cpp index 856d7448d..1bd34b1e3 100644 --- a/src/bin2llvmir/providers/abi/arm.cpp +++ b/src/bin2llvmir/providers/abi/arm.cpp @@ -17,7 +17,6 @@ AbiArm::AbiArm(llvm::Module* m, Config* c) : _regs.reserve(ARM_REG_ENDING); _id2regs.resize(ARM_REG_ENDING, nullptr); _regStackPointerId = ARM_REG_SP; - _fpRegsAsParams = true; // system calls _regSyscallId = ARM_REG_R7; @@ -30,20 +29,6 @@ AbiArm::AbiArm(llvm::Module* m, Config* c) : ARM_REG_R4, ARM_REG_R5}; - _regReturn = ARM_REG_R0; - _regFPReturn = ARM_REG_D0; - - _paramRegs = { - ARM_REG_R0, - ARM_REG_R1, - ARM_REG_R2, - ARM_REG_R3}; - - _paramFPRegs = { - ARM_REG_D0, - ARM_REG_D1, - ARM_REG_D2, - ARM_REG_D3}; } AbiArm::~AbiArm() From a52468921718fef70705782492fc341ae5375102 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:24:46 +0100 Subject: [PATCH 099/159] abi/arm: revert cc providing --- src/bin2llvmir/providers/abi/mips.cpp | 38 --------------------------- 1 file changed, 38 deletions(-) diff --git a/src/bin2llvmir/providers/abi/mips.cpp b/src/bin2llvmir/providers/abi/mips.cpp index f6d684728..adb0f38d0 100644 --- a/src/bin2llvmir/providers/abi/mips.cpp +++ b/src/bin2llvmir/providers/abi/mips.cpp @@ -19,8 +19,6 @@ AbiMips::AbiMips(llvm::Module* m, Config* c) : _regStackPointerId = MIPS_REG_SP; _regZeroReg = MIPS_REG_ZERO; - _fpRegsAsParams = true; - // system calls _regSyscallId = MIPS_REG_V0; _regSyscallReturn = MIPS_REG_V0; @@ -30,42 +28,6 @@ AbiMips::AbiMips(llvm::Module* m, Config* c) : MIPS_REG_A2, MIPS_REG_A3}; - _regReturn = MIPS_REG_V0; - _regFPReturn = MIPS_REG_V0; - - if (_config->getConfig().tools.isPspGcc()) - { - _paramRegs = { - MIPS_REG_A0, - MIPS_REG_A1, - MIPS_REG_A2, - MIPS_REG_A3, - MIPS_REG_T0, - MIPS_REG_T1, - MIPS_REG_T2, - MIPS_REG_T3}; - } - else - { - _paramRegs = { - MIPS_REG_A0, - MIPS_REG_A1, - MIPS_REG_A2, - MIPS_REG_A3}; - } - - _paramFPRegs = { - MIPS_REG_F12, - MIPS_REG_F14, - MIPS_REG_F16, - MIPS_REG_F18 - }; - - _doubleParamRegs = { - MIPS_REG_FD12, - MIPS_REG_FD14, - MIPS_REG_FD16, - }; } AbiMips::~AbiMips() From dc9df6adcab7019e26d9b630234b361c91ebde55 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:30:26 +0100 Subject: [PATCH 100/159] abi/arm64: revert providing cc info --- src/bin2llvmir/providers/abi/arm64.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/bin2llvmir/providers/abi/arm64.cpp b/src/bin2llvmir/providers/abi/arm64.cpp index a84ab4e42..3e2f29f20 100644 --- a/src/bin2llvmir/providers/abi/arm64.cpp +++ b/src/bin2llvmir/providers/abi/arm64.cpp @@ -29,28 +29,6 @@ AbiArm64::AbiArm64(llvm::Module* m, Config* c) : ARM64_REG_X4, ARM64_REG_X5}; - _regReturn = ARM64_REG_X0; - _regFPReturn = ARM64_REG_X0; - - _paramRegs = { - ARM64_REG_X0, - ARM64_REG_X1, - ARM64_REG_X2, - ARM64_REG_X3, - ARM64_REG_X4, - ARM64_REG_X5, - ARM64_REG_X6, - ARM64_REG_X7}; - - _paramFPRegs = { - ARM64_REG_V0, - ARM64_REG_V1, - ARM64_REG_V2, - ARM64_REG_V3, - ARM64_REG_V4, - ARM64_REG_V5, - ARM64_REG_V6, - ARM64_REG_V7}; } AbiArm64::~AbiArm64() From 0dfbd7dcff85c6db912f523fb7a6ec36bcb1b763 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:31:19 +0100 Subject: [PATCH 101/159] abi/ms_x64: revert cc info providing --- src/bin2llvmir/providers/abi/ms_x64.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/bin2llvmir/providers/abi/ms_x64.cpp b/src/bin2llvmir/providers/abi/ms_x64.cpp index b7fcdaa6e..db35309f6 100644 --- a/src/bin2llvmir/providers/abi/ms_x64.cpp +++ b/src/bin2llvmir/providers/abi/ms_x64.cpp @@ -14,8 +14,6 @@ namespace bin2llvmir { AbiMS_X64::AbiMS_X64(llvm::Module* m, Config* c) : Abi(m, c) { - _paramRegsOverlay = true; - _fpRegsAsParams = true; _regs.reserve(X86_REG_ENDING); _id2regs.resize(X86_REG_ENDING, nullptr); _regStackPointerId = X86_REG_RSP; @@ -31,21 +29,6 @@ AbiMS_X64::AbiMS_X64(llvm::Module* m, Config* c) : X86_REG_R8, X86_REG_R9}; - _paramRegs = { - X86_REG_RCX, - X86_REG_RDX, - X86_REG_R8, - X86_REG_R9}; - - _paramFPRegs = { - X86_REG_XMM0, - X86_REG_XMM1, - X86_REG_XMM2, - X86_REG_XMM3}; - - _regReturn = X86_REG_RAX; - - _regFPReturn = X86_REG_ST0; } AbiMS_X64::~AbiMS_X64() From 362a3ebe88ef87d22b3d0c40557f8aeca6ef3ee2 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:32:38 +0100 Subject: [PATCH 102/159] abi/mips64: revert cc info providing --- src/bin2llvmir/providers/abi/mips64.cpp | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/bin2llvmir/providers/abi/mips64.cpp b/src/bin2llvmir/providers/abi/mips64.cpp index e1234e2f9..cfe194265 100644 --- a/src/bin2llvmir/providers/abi/mips64.cpp +++ b/src/bin2llvmir/providers/abi/mips64.cpp @@ -19,8 +19,6 @@ AbiMips64::AbiMips64(llvm::Module* m, Config* c) : _regStackPointerId = MIPS_REG_SP; _regZeroReg = MIPS_REG_ZERO; - _fpRegsAsParams = true; - // system calls _regSyscallId = MIPS_REG_V0; _regSyscallReturn = MIPS_REG_V0; @@ -33,29 +31,6 @@ AbiMips64::AbiMips64(llvm::Module* m, Config* c) : MIPS_REG_T1, MIPS_REG_T2, MIPS_REG_T3}; - - _regReturn = MIPS_REG_V0; - _regFPReturn = MIPS_REG_V0; - - _paramRegs = { - MIPS_REG_A0, - MIPS_REG_A1, - MIPS_REG_A2, - MIPS_REG_A3, - MIPS_REG_T0, - MIPS_REG_T1, - MIPS_REG_T2, - MIPS_REG_T3}; - - _paramFPRegs = { - MIPS_REG_F12, - MIPS_REG_F13, - MIPS_REG_F14, - MIPS_REG_F15, - MIPS_REG_F16, - MIPS_REG_F17, - MIPS_REG_F18 - }; } AbiMips64::~AbiMips64() From 9b173746ce12b65ba9aa630578e15b55079d6df9 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:36:44 +0100 Subject: [PATCH 103/159] abi/powerpc: revert default c cproviding --- src/bin2llvmir/providers/abi/powerpc.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/bin2llvmir/providers/abi/powerpc.cpp b/src/bin2llvmir/providers/abi/powerpc.cpp index 3cdaa6bb4..92cbae6d8 100644 --- a/src/bin2llvmir/providers/abi/powerpc.cpp +++ b/src/bin2llvmir/providers/abi/powerpc.cpp @@ -17,19 +17,6 @@ AbiPowerpc::AbiPowerpc(llvm::Module* m, Config* c) : _regs.reserve(PPC_REG_ENDING); _id2regs.resize(PPC_REG_ENDING, nullptr); _regStackPointerId = PPC_REG_R1; - - _paramRegs = { - PPC_REG_R3, - PPC_REG_R4, - PPC_REG_R5, - PPC_REG_R6, - PPC_REG_R7, - PPC_REG_R8, - PPC_REG_R9, - PPC_REG_R10}; - - _regReturn = PPC_REG_R3; - _regFPReturn = PPC_REG_R3; } AbiPowerpc::~AbiPowerpc() From 95c63b7fcd0211cff2743b40e04e2950fc799e72 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:38:06 +0100 Subject: [PATCH 104/159] abi/powerpc64: revert cc info --- src/bin2llvmir/providers/abi/powerpc64.cpp | 30 ---------------------- 1 file changed, 30 deletions(-) diff --git a/src/bin2llvmir/providers/abi/powerpc64.cpp b/src/bin2llvmir/providers/abi/powerpc64.cpp index daf9a23f4..4d387e499 100644 --- a/src/bin2llvmir/providers/abi/powerpc64.cpp +++ b/src/bin2llvmir/providers/abi/powerpc64.cpp @@ -17,36 +17,6 @@ AbiPowerpc64::AbiPowerpc64(llvm::Module* m, Config* c) : _regs.reserve(PPC_REG_ENDING); _id2regs.resize(PPC_REG_ENDING, nullptr); _regStackPointerId = PPC_REG_R1; - _fpRegsAsParams = true; - - _paramRegs = { - PPC_REG_R3, - PPC_REG_R4, - PPC_REG_R5, - PPC_REG_R6, - PPC_REG_R7, - PPC_REG_R8, - PPC_REG_R9, - PPC_REG_R10}; - - _paramFPRegs = { - PPC_REG_F1, - PPC_REG_F2, - PPC_REG_F3, - PPC_REG_F4, - PPC_REG_F5, - PPC_REG_F6, - PPC_REG_F7, - PPC_REG_F8, - PPC_REG_F9, - PPC_REG_F10, - PPC_REG_F11}; - - // TODO paramVectorRegs = - - - _regReturn = PPC_REG_R3; - _regFPReturn = PPC_REG_R3; } AbiPowerpc64::~AbiPowerpc64() From 0445a35482f304aa1c83bba3191ec8e1bb8c0664 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:40:04 +0100 Subject: [PATCH 105/159] abi/pic32: rever cc info providing --- src/bin2llvmir/providers/abi/pic32.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/bin2llvmir/providers/abi/pic32.cpp b/src/bin2llvmir/providers/abi/pic32.cpp index 66063dbd6..a5afc7909 100644 --- a/src/bin2llvmir/providers/abi/pic32.cpp +++ b/src/bin2llvmir/providers/abi/pic32.cpp @@ -28,29 +28,6 @@ AbiPic32::AbiPic32(llvm::Module* m, Config* c) : MIPS_REG_A2, MIPS_REG_A3}; - _regReturn = MIPS_REG_V0; - _regFPReturn = MIPS_REG_V0; - - if (_config->getConfig().tools.isPspGcc()) - { - _paramRegs = { - MIPS_REG_A0, - MIPS_REG_A1, - MIPS_REG_A2, - MIPS_REG_A3, - MIPS_REG_T0, - MIPS_REG_T1, - MIPS_REG_T2, - MIPS_REG_T3}; - } - else - { - _paramRegs = { - MIPS_REG_A0, - MIPS_REG_A1, - MIPS_REG_A2, - MIPS_REG_A3}; - } } AbiPic32::~AbiPic32() From ed2b9fec476c5d406b08846a3d3d07c6fe422f2f Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:20:03 +0100 Subject: [PATCH 106/159] abi/x86: provide x86 specific calling conventnions --- include/retdec/bin2llvmir/providers/abi/x86.h | 7 +++ src/bin2llvmir/providers/abi/x86.cpp | 52 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/x86.h b/include/retdec/bin2llvmir/providers/abi/x86.h index 2a135274a..488a8ccb8 100644 --- a/include/retdec/bin2llvmir/providers/abi/x86.h +++ b/include/retdec/bin2llvmir/providers/abi/x86.h @@ -29,6 +29,13 @@ class AbiX86 : public Abi // public: virtual bool isNopInstruction(cs_insn* insn) override; + + + // Calling conventions. + // + private: + virtual bool supportsCallingConvention(CallingConvention::ID& cc) const override; + CallingConvention::ID fetchDefaultCC() const; }; } // namespace bin2llvmir diff --git a/src/bin2llvmir/providers/abi/x86.cpp b/src/bin2llvmir/providers/abi/x86.cpp index db9515510..d11c2b64b 100644 --- a/src/bin2llvmir/providers/abi/x86.cpp +++ b/src/bin2llvmir/providers/abi/x86.cpp @@ -29,6 +29,7 @@ AbiX86::AbiX86(llvm::Module* m, Config* c) : X86_REG_EDI, X86_REG_EBP}; + _defcc = fetchDefaultCC(); } AbiX86::~AbiX86() @@ -93,5 +94,56 @@ bool AbiX86::isNopInstruction(cs_insn* insn) return false; } +CallingConvention::ID AbiX86::fetchDefaultCC() const +{ + if (_config->getConfig().tools.isWatcom()) + { + return CallingConvention::ID::CC_WATCOM; + } + if (_config->getConfig().tools.isBorland()) + { + return CallingConvention::ID::CC_PASCAL; + } + + return CallingConvention::ID::CC_CDECL; +} + +bool AbiX86::supportsCallingConvention(CallingConvention::ID& cc) const +{ + if (_config->getConfig().tools.isBorland()) + { + switch (cc) + { + case CallingConvention::ID::CC_CDECL: + case CallingConvention::ID::CC_PASCAL: + cc = CallingConvention::ID::CC_PASCAL; + return true; + + case CallingConvention::ID::CC_FASTCALL: + case CallingConvention::ID::CC_FASTCALL_PASCAL: + cc = CallingConvention::ID::CC_FASTCALL; + return true; + + default: + return false; + } + } + + switch (cc) + { + case CallingConvention::ID::CC_CDECL: + case CallingConvention::ID::CC_ELLIPSIS: + case CallingConvention::ID::CC_FASTCALL: + case CallingConvention::ID::CC_THISCALL: + case CallingConvention::ID::CC_STDCALL: + return true; + + default: + return false; + } + + return false; +} + } // namespace bin2llvmir } // namespace retdec From 18f3b486e2bbbaa04f64822bac8ecbecac357428 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:22:42 +0100 Subject: [PATCH 107/159] abi/x64: provide defualt calling convnention --- src/bin2llvmir/providers/abi/x64.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bin2llvmir/providers/abi/x64.cpp b/src/bin2llvmir/providers/abi/x64.cpp index e6d01c32d..6b74d9547 100644 --- a/src/bin2llvmir/providers/abi/x64.cpp +++ b/src/bin2llvmir/providers/abi/x64.cpp @@ -28,6 +28,8 @@ AbiX64::AbiX64(llvm::Module* m, Config* c) : X86_REG_R10, X86_REG_R8, X86_REG_R9}; + + _defcc = CallingConvention::ID::CC_SYSTEMVX64; } AbiX64::~AbiX64() From abc0a97f53450863c4dfd32688dc16390aca4977 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:23:37 +0100 Subject: [PATCH 108/159] abi/arm: provide default cc info --- src/bin2llvmir/providers/abi/arm.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin2llvmir/providers/abi/arm.cpp b/src/bin2llvmir/providers/abi/arm.cpp index 1bd34b1e3..423e9dfeb 100644 --- a/src/bin2llvmir/providers/abi/arm.cpp +++ b/src/bin2llvmir/providers/abi/arm.cpp @@ -29,6 +29,7 @@ AbiArm::AbiArm(llvm::Module* m, Config* c) : ARM_REG_R4, ARM_REG_R5}; + _defcc = CallingConvention::ID::CC_ARM; } AbiArm::~AbiArm() From 96b067d439b663c74db9a40700f4528a7d233983 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:25:27 +0100 Subject: [PATCH 109/159] abi/mips: provide default calling convention --- src/bin2llvmir/providers/abi/mips.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bin2llvmir/providers/abi/mips.cpp b/src/bin2llvmir/providers/abi/mips.cpp index adb0f38d0..02ffb4111 100644 --- a/src/bin2llvmir/providers/abi/mips.cpp +++ b/src/bin2llvmir/providers/abi/mips.cpp @@ -28,6 +28,14 @@ AbiMips::AbiMips(llvm::Module* m, Config* c) : MIPS_REG_A2, MIPS_REG_A3}; + if (c->getConfig().tools.isPspGcc()) + { + _defcc = CallingConvention::ID::CC_MIPSPSP; + } + else + { + _defcc = CallingConvention::ID::CC_MIPS; + } } AbiMips::~AbiMips() From 343e395046341db5ca1755dbacb3b401ec1bf48e Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:30:45 +0100 Subject: [PATCH 110/159] abi/arm64: provide default ar64 cc --- src/bin2llvmir/providers/abi/arm64.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin2llvmir/providers/abi/arm64.cpp b/src/bin2llvmir/providers/abi/arm64.cpp index 3e2f29f20..0e818f039 100644 --- a/src/bin2llvmir/providers/abi/arm64.cpp +++ b/src/bin2llvmir/providers/abi/arm64.cpp @@ -29,6 +29,7 @@ AbiArm64::AbiArm64(llvm::Module* m, Config* c) : ARM64_REG_X4, ARM64_REG_X5}; + _defcc = CallingConvention::ID::CC_ARM64; } AbiArm64::~AbiArm64() From a568e18244640e4dd007e682993104a451b6a9fe Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:32:00 +0100 Subject: [PATCH 111/159] abi/ms_x64: provide default microsoft x64 cc info --- src/bin2llvmir/providers/abi/ms_x64.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin2llvmir/providers/abi/ms_x64.cpp b/src/bin2llvmir/providers/abi/ms_x64.cpp index db35309f6..ff1ed3d74 100644 --- a/src/bin2llvmir/providers/abi/ms_x64.cpp +++ b/src/bin2llvmir/providers/abi/ms_x64.cpp @@ -29,6 +29,7 @@ AbiMS_X64::AbiMS_X64(llvm::Module* m, Config* c) : X86_REG_R8, X86_REG_R9}; + _defcc = CallingConvention::ID::CC_MICROSOFTX64; } AbiMS_X64::~AbiMS_X64() From fce7750628fa9081eaed9034486429a5496b4383 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:37:27 +0100 Subject: [PATCH 112/159] abi/powerpc: provide default cc info --- src/bin2llvmir/providers/abi/powerpc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bin2llvmir/providers/abi/powerpc.cpp b/src/bin2llvmir/providers/abi/powerpc.cpp index 92cbae6d8..7121eb6df 100644 --- a/src/bin2llvmir/providers/abi/powerpc.cpp +++ b/src/bin2llvmir/providers/abi/powerpc.cpp @@ -17,6 +17,8 @@ AbiPowerpc::AbiPowerpc(llvm::Module* m, Config* c) : _regs.reserve(PPC_REG_ENDING); _id2regs.resize(PPC_REG_ENDING, nullptr); _regStackPointerId = PPC_REG_R1; + + _defcc = CallingConvention::ID::CC_POWERPC; } AbiPowerpc::~AbiPowerpc() From 540415ebb0877f7a0c44ec4980d7aebf99d63593 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:39:10 +0100 Subject: [PATCH 113/159] abi/powerpc64: provide default cc --- src/bin2llvmir/providers/abi/powerpc64.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bin2llvmir/providers/abi/powerpc64.cpp b/src/bin2llvmir/providers/abi/powerpc64.cpp index 4d387e499..8f13db2e5 100644 --- a/src/bin2llvmir/providers/abi/powerpc64.cpp +++ b/src/bin2llvmir/providers/abi/powerpc64.cpp @@ -17,6 +17,8 @@ AbiPowerpc64::AbiPowerpc64(llvm::Module* m, Config* c) : _regs.reserve(PPC_REG_ENDING); _id2regs.resize(PPC_REG_ENDING, nullptr); _regStackPointerId = PPC_REG_R1; + + _defcc = CallingConvention::ID::CC_POWERPC64; } AbiPowerpc64::~AbiPowerpc64() From b524b7be3b2e75d80529848d4640e532b19d47e7 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:40:16 +0100 Subject: [PATCH 114/159] abi/pic32: provide default cc --- src/bin2llvmir/providers/abi/pic32.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin2llvmir/providers/abi/pic32.cpp b/src/bin2llvmir/providers/abi/pic32.cpp index a5afc7909..b141a4702 100644 --- a/src/bin2llvmir/providers/abi/pic32.cpp +++ b/src/bin2llvmir/providers/abi/pic32.cpp @@ -28,6 +28,7 @@ AbiPic32::AbiPic32(llvm::Module* m, Config* c) : MIPS_REG_A2, MIPS_REG_A3}; + _defcc = CallingConvention::ID::CC_PIC32; } AbiPic32::~AbiPic32() From ea606fb1f61cb7f1653a886a7194e1c59209a7ae Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:41:49 +0100 Subject: [PATCH 115/159] abi/misp64: provide default cc --- src/bin2llvmir/providers/abi/mips64.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bin2llvmir/providers/abi/mips64.cpp b/src/bin2llvmir/providers/abi/mips64.cpp index cfe194265..412dfccee 100644 --- a/src/bin2llvmir/providers/abi/mips64.cpp +++ b/src/bin2llvmir/providers/abi/mips64.cpp @@ -31,6 +31,8 @@ AbiMips64::AbiMips64(llvm::Module* m, Config* c) : MIPS_REG_T1, MIPS_REG_T2, MIPS_REG_T3}; + + _defcc = CallingConvention::ID::CC_MIPS64; } AbiMips64::~AbiMips64() From 63171b6fce9a00a7f7523828829fb2a6d9081466 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Thu, 21 Feb 2019 12:43:59 +0100 Subject: [PATCH 116/159] config/calling_conventnion: make enum pubic --- include/retdec/config/calling_convention.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/include/retdec/config/calling_convention.h b/include/retdec/config/calling_convention.h index af90e95f8..d46ea8379 100644 --- a/include/retdec/config/calling_convention.h +++ b/include/retdec/config/calling_convention.h @@ -81,7 +81,7 @@ class CallingConvention Json::Value getJsonValue() const; void readJsonValue(const Json::Value& val); - private: + public: enum class eCallingConvention { CC_UNKNOWN = 0, @@ -96,7 +96,20 @@ class CallingConvention CC_SPOILED, CC_SPECIALE, CC_SPECIALP, - CC_SPECIAL + CC_SPECIAL, + CC_PASCAL_FASTCALL, + CC_WATCOM, + CC_SYSTEMVX64, + CC_MICROSOFTX64, + CC_ARM, + CC_ARM64, + CC_MIPS, + CC_MIPSPSP, + CC_MIPS64, + CC_POWERPC, + CC_POWERPC64, + CC_PIC32, + CC_ENDING, }; eCallingConvention _callingConvention = eCallingConvention::CC_UNKNOWN; @@ -104,6 +117,8 @@ class CallingConvention CallingConvention(eCallingConvention cc); }; +typedef CallingConvention::eCallingConvention CallingConventionID; + } // namespace config } // namespace retdec From fdac82bb3009be9b3e7852750313a0edb31729c4 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 21:17:27 +0100 Subject: [PATCH 117/159] calling_convention: support for pascal fastcal id --- include/retdec/config/calling_convention.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/retdec/config/calling_convention.h b/include/retdec/config/calling_convention.h index d46ea8379..94ca1fded 100644 --- a/include/retdec/config/calling_convention.h +++ b/include/retdec/config/calling_convention.h @@ -97,7 +97,7 @@ class CallingConvention CC_SPECIALE, CC_SPECIALP, CC_SPECIAL, - CC_PASCAL_FASTCALL, + CC_FASTCALL_PASCAL, CC_WATCOM, CC_SYSTEMVX64, CC_MICROSOFTX64, From 2c484d2c87564168559516b442d404359ca3871c Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 21:18:13 +0100 Subject: [PATCH 118/159] calling_convention: make cc id serialization public --- include/retdec/config/calling_convention.h | 8 +++++++- src/config/calling_convention.cpp | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/include/retdec/config/calling_convention.h b/include/retdec/config/calling_convention.h index 94ca1fded..94f56b4b4 100644 --- a/include/retdec/config/calling_convention.h +++ b/include/retdec/config/calling_convention.h @@ -111,10 +111,16 @@ class CallingConvention CC_PIC32, CC_ENDING, }; - eCallingConvention _callingConvention = eCallingConvention::CC_UNKNOWN; + + eCallingConvention getID() const; + + friend std::ostream& operator<< (std::ostream &out, const eCallingConvention& cc); private: CallingConvention(eCallingConvention cc); + + private: + eCallingConvention _callingConvention = eCallingConvention::CC_UNKNOWN; }; typedef CallingConvention::eCallingConvention CallingConventionID; diff --git a/src/config/calling_convention.cpp b/src/config/calling_convention.cpp index 0f7de479a..60f98926c 100644 --- a/src/config/calling_convention.cpp +++ b/src/config/calling_convention.cpp @@ -46,6 +46,11 @@ CallingConvention::CallingConvention(eCallingConvention cc) : } +CallingConventionID CallingConvention::getID() const +{ + return _callingConvention; +} + CallingConvention CallingConvention::initVoidarg() { return CallingConvention(eCallingConvention::CC_VOIDARG); } CallingConvention CallingConvention::initCdecl() { return CallingConvention(eCallingConvention::CC_CDECL); } CallingConvention CallingConvention::initEllipsis() { return CallingConvention(eCallingConvention::CC_ELLIPSIS); } @@ -132,9 +137,9 @@ bool CallingConvention::operator<(const CallingConvention& cc) const return _callingConvention < cc._callingConvention; } -std::ostream& operator<<(std::ostream &out, const CallingConvention& cc) +std::ostream& operator<<(std::ostream &out, const CallingConventionID& cc) { - switch(cc._callingConvention) + switch(cc) { case CallingConvention::eCallingConvention::CC_UNKNOWN: out << "CC_UNKNOWN"; break; case CallingConvention::eCallingConvention::CC_VOIDARG: out << "CC_VOIDARG"; break; @@ -154,5 +159,12 @@ std::ostream& operator<<(std::ostream &out, const CallingConvention& cc) return out; } +std::ostream& operator<<(std::ostream &out, const CallingConvention& cc) +{ + out << cc._callingConvention; + + return out; +} + } // namespace config } // namespace retdec From c188ba9599e71cfdb1b41052fe5d48ad613c2d86 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 21:21:58 +0100 Subject: [PATCH 119/159] abi: make methods const --- include/retdec/bin2llvmir/providers/abi/abi.h | 8 ++++---- src/bin2llvmir/providers/abi/abi.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 364f34ce5..3f019c9e6 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -43,15 +43,15 @@ class Abi bool isRegister(const llvm::Value* val) const; bool isRegister(const llvm::Value* val, uint32_t r) const; bool isFlagRegister(const llvm::Value* val); - bool isStackPointerRegister(const llvm::Value* val); + bool isStackPointerRegister(const llvm::Value* val) const; bool isZeroRegister(const llvm::Value* val); - virtual bool isGeneralPurposeRegister(const llvm::Value* val) = 0; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const = 0; llvm::GlobalVariable* getRegister(uint32_t r, bool use = true) const; uint32_t getRegisterId(const llvm::Value* r) const; const std::vector& getRegisters() const; - llvm::GlobalVariable* getStackPointerRegister(); - llvm::GlobalVariable* getZeroRegister(); + llvm::GlobalVariable* getStackPointerRegister() const; + llvm::GlobalVariable* getZeroRegister() const; void addRegister(uint32_t id, llvm::GlobalVariable* reg); diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 75a6e125a..f478679a9 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -57,7 +57,7 @@ bool Abi::isFlagRegister(const llvm::Value* val) && val->getType()->getPointerElementType()->isIntegerTy(1); } -bool Abi::isStackPointerRegister(const llvm::Value* val) +bool Abi::isStackPointerRegister(const llvm::Value* val) const { return getStackPointerRegister() == val; } @@ -96,12 +96,12 @@ const std::vector& Abi::getRegisters() const return _regs; } -llvm::GlobalVariable* Abi::getStackPointerRegister() +llvm::GlobalVariable* Abi::getStackPointerRegister() const { return getRegister(_regStackPointerId); } -llvm::GlobalVariable* Abi::getZeroRegister() +llvm::GlobalVariable* Abi::getZeroRegister() const { return getRegister(_regZeroReg); } From 61cbb400f1e1bef556bfdc3a3dfcb5be2cc77b97 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 21:22:26 +0100 Subject: [PATCH 120/159] abi: provide method for register size --- include/retdec/bin2llvmir/providers/abi/abi.h | 2 ++ src/bin2llvmir/providers/abi/abi.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 3f019c9e6..8332cde39 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -53,6 +53,8 @@ class Abi llvm::GlobalVariable* getStackPointerRegister() const; llvm::GlobalVariable* getZeroRegister() const; + std::size_t getRegisterByteSize(uint32_t r) const; + void addRegister(uint32_t id, llvm::GlobalVariable* reg); llvm::GlobalVariable* getSyscallIdRegister(); diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index f478679a9..51108c00e 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -106,6 +106,19 @@ llvm::GlobalVariable* Abi::getZeroRegister() const return getRegister(_regZeroReg); } +std::size_t Abi::getRegisterByteSize(uint32_t reg) const +{ + auto r = getRegister(reg); + assert(r); + + if (auto* p = dyn_cast(r->getType())) + { + return getTypeByteSize(p->getElementType()); + } + + return getTypeByteSize(r->getType()); +} + void Abi::addRegister(uint32_t id, llvm::GlobalVariable* reg) { if (id >= _id2regs.size()) From b87f4e9807a38d5516ad6ae4ddd5221dadbfa650 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 21:25:37 +0100 Subject: [PATCH 121/159] abi: let children override getTypeByteSize method --- include/retdec/bin2llvmir/providers/abi/abi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 8332cde39..e595ff1ae 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -75,8 +75,8 @@ class Abi // Types. // public: - std::size_t getTypeByteSize(llvm::Type* t) const; - std::size_t getTypeBitSize(llvm::Type* t) const; + virtual std::size_t getTypeByteSize(llvm::Type* t) const; + virtual std::size_t getTypeBitSize(llvm::Type* t) const; llvm::IntegerType* getDefaultType() const; llvm::PointerType* getDefaultPointerType() const; std::size_t getWordSize() const; From ac65a65b1beb95e1356cd18534bdf4b941a698e7 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 21:25:56 +0100 Subject: [PATCH 122/159] abi: provide config --- include/retdec/bin2llvmir/providers/abi/abi.h | 5 +++++ src/bin2llvmir/providers/abi/abi.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index e595ff1ae..34449b7a3 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -106,6 +106,11 @@ class Abi virtual bool supportsCallingConvention(CallingConvention::ID& cc) const; bool isSpecialCallingConvention(const CallingConvention::ID& cc) const; + // Config. + // + public: + Config* getConfig() const; + // Private data - misc. // protected: diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 51108c00e..bba74bb52 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -288,6 +288,11 @@ bool Abi::isSpecialCallingConvention(const CallingConvention::ID& cc) const } } +Config* Abi::getConfig() const +{ + return _config; +} + // //============================================================================== // AbiProvider From bf1bada161c6548d5df8def81bbf040ed7a3047c Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 21:26:18 +0100 Subject: [PATCH 123/159] abi: save calling conventions in map --- include/retdec/bin2llvmir/providers/abi/abi.h | 2 +- src/bin2llvmir/providers/abi/abi.cpp | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 34449b7a3..cd4c040ba 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -146,7 +146,7 @@ class Abi // Private data - calling convention // protected: - std::vector _id2cc; + std::map _id2cc; CallingConvention::ID _defcc; }; diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index bba74bb52..8bed8878e 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -255,13 +255,9 @@ CallingConvention* Abi::getCallingConvention( return nullptr; } - auto ccId = static_cast(cc); + auto ccId = static_cast(cc); - if (ccId >= _id2cc.size()) - { - _id2cc.resize(ccId+1, nullptr); - } - if (_id2cc[ccId] == nullptr) + if (!_id2cc.count(ccId)) { auto provider = CallingConventionProvider::getProvider(); _id2cc[ccId] = provider->createCallingConvention(cc, this); From c1fc119ef4d0e70cef8f2febab1ea24335830dc0 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 21:27:20 +0100 Subject: [PATCH 124/159] abi: assure type is sized --- src/bin2llvmir/providers/abi/abi.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 8bed8878e..69522e451 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -183,12 +183,16 @@ std::size_t Abi::getWordSize() const std::size_t Abi::getTypeByteSize(llvm::Module* m, llvm::Type* t) { assert(m); + assert(t->isSized()); + return m->getDataLayout().getTypeStoreSize(t); } std::size_t Abi::getTypeBitSize(llvm::Module* m, llvm::Type* t) { assert(m); + assert(t->isSized()); + return m->getDataLayout().getTypeSizeInBits(t); } From 20dbab9f56ca1ba07318a43712bd4904c1d5c5cd Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 21:29:04 +0100 Subject: [PATCH 125/159] abi: provide word size info from config --- src/bin2llvmir/providers/abi/abi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 69522e451..a9495273c 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -177,7 +177,7 @@ llvm::PointerType* Abi::getDefaultPointerType() const std::size_t Abi::getWordSize() const { - return getWordSize(_module); + return _config->getConfig().architecture.getBitSize() / 8; } std::size_t Abi::getTypeByteSize(llvm::Module* m, llvm::Type* t) From 09bae700b48f7566289a11cad1d786f16e8f9d4f Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 21:30:09 +0100 Subject: [PATCH 126/159] abi: return compiler specific settings in calling convention --- .../bin2llvmir/providers/abi/x86_fastcall.h | 37 ------ .../bin2llvmir/providers/abi/x86_pascal.h | 37 ------ .../bin2llvmir/providers/abi/x86_watcom.h | 37 ------ src/bin2llvmir/providers/abi/abi.cpp | 12 -- src/bin2llvmir/providers/abi/x86_fastcall.cpp | 103 ----------------- src/bin2llvmir/providers/abi/x86_pascal.cpp | 106 ------------------ src/bin2llvmir/providers/abi/x86_watcom.cpp | 106 ------------------ 7 files changed, 438 deletions(-) delete mode 100644 include/retdec/bin2llvmir/providers/abi/x86_fastcall.h delete mode 100644 include/retdec/bin2llvmir/providers/abi/x86_pascal.h delete mode 100644 include/retdec/bin2llvmir/providers/abi/x86_watcom.h delete mode 100644 src/bin2llvmir/providers/abi/x86_fastcall.cpp delete mode 100644 src/bin2llvmir/providers/abi/x86_pascal.cpp delete mode 100644 src/bin2llvmir/providers/abi/x86_watcom.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/x86_fastcall.h b/include/retdec/bin2llvmir/providers/abi/x86_fastcall.h deleted file mode 100644 index d3cab4850..000000000 --- a/include/retdec/bin2llvmir/providers/abi/x86_fastcall.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file include/retdec/bin2llvmir/providers/abi/x86.h - * @brief ABI information for x86. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_FASTCALL_X86_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_FASTCALL_X86_H - -#include "retdec/bin2llvmir/providers/abi/abi.h" - -namespace retdec { -namespace bin2llvmir { - -class AbiX86Fastcall : public Abi -{ - // Ctors, dtors. - // - public: - AbiX86Fastcall(llvm::Module* m, Config* c); - virtual ~AbiX86Fastcall(); - - // Registers. - // - public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; - - // Instructions. - // - public: - virtual bool isNopInstruction(cs_insn* insn) override; -}; - -} // namespace bin2llvmir -} // namespace retdec - -#endif diff --git a/include/retdec/bin2llvmir/providers/abi/x86_pascal.h b/include/retdec/bin2llvmir/providers/abi/x86_pascal.h deleted file mode 100644 index c3a9a1658..000000000 --- a/include/retdec/bin2llvmir/providers/abi/x86_pascal.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file include/retdec/bin2llvmir/providers/abi/x86.h - * @brief ABI information for x86. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_PASCAL_X86_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_PASCAL_X86_H - -#include "retdec/bin2llvmir/providers/abi/abi.h" - -namespace retdec { -namespace bin2llvmir { - -class AbiX86Pascal : public Abi -{ - // Ctors, dtors. - // - public: - AbiX86Pascal(llvm::Module* m, Config* c); - virtual ~AbiX86Pascal(); - - // Registers. - // - public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; - - // Instructions. - // - public: - virtual bool isNopInstruction(cs_insn* insn) override; -}; - -} // namespace bin2llvmir -} // namespace retdec - -#endif diff --git a/include/retdec/bin2llvmir/providers/abi/x86_watcom.h b/include/retdec/bin2llvmir/providers/abi/x86_watcom.h deleted file mode 100644 index 13e774e28..000000000 --- a/include/retdec/bin2llvmir/providers/abi/x86_watcom.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file include/retdec/bin2llvmir/providers/abi/x86.h - * @brief ABI information for x86. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_X86_WATCOM_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_X86_WATCOM_H - -#include "retdec/bin2llvmir/providers/abi/abi.h" - -namespace retdec { -namespace bin2llvmir { - -class AbiX86Watcom : public Abi -{ - // Ctors, dtors. - // - public: - AbiX86Watcom(llvm::Module* m, Config* c); - virtual ~AbiX86Watcom(); - - // Registers. - // - public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; - - // Instructions. - // - public: - virtual bool isNopInstruction(cs_insn* insn) override; -}; - -} // namespace bin2llvmir -} // namespace retdec - -#endif diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index a9495273c..2be2bc52e 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -10,8 +10,6 @@ #include "retdec/bin2llvmir/providers/abi/ms_x64.h" #include "retdec/bin2llvmir/providers/abi/powerpc.h" #include "retdec/bin2llvmir/providers/abi/x86.h" -#include "retdec/bin2llvmir/providers/abi/x86_watcom.h" -#include "retdec/bin2llvmir/providers/abi/x86_pascal.h" #include "retdec/bin2llvmir/providers/abi/x64.h" #include "retdec/bin2llvmir/providers/abi/pic32.h" @@ -346,16 +344,6 @@ Abi* AbiProvider::addAbi( } else if (c->getConfig().architecture.isX86()) { - if (c->getConfig().tools.isWatcom()) { - auto p = _module2abi.emplace(m, std::make_unique(m, c)); - return p.first->second.get(); - - } - if (c->getConfig().tools.isBorland()) { - auto p = _module2abi.emplace(m, std::make_unique(m, c)); - return p.first->second.get(); - } - auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); } diff --git a/src/bin2llvmir/providers/abi/x86_fastcall.cpp b/src/bin2llvmir/providers/abi/x86_fastcall.cpp deleted file mode 100644 index b3a9da9a3..000000000 --- a/src/bin2llvmir/providers/abi/x86_fastcall.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/** - * @file src/bin2llvmir/providers/abi/x86.cpp - * @brief ABI information for x86. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#include "retdec/bin2llvmir/providers/abi/x86_fastcall.h" - -using namespace llvm; - -namespace retdec { -namespace bin2llvmir { - -AbiX86Fastcall::AbiX86Fastcall(llvm::Module* m, Config* c) : - Abi(m, c) -{ - _regs.reserve(X86_REG_ENDING); - _id2regs.resize(X86_REG_ENDING, nullptr); - _regStackPointerId = X86_REG_ESP; - - // system calls - _regSyscallId = X86_REG_EAX; - _regSyscallReturn = X86_REG_EAX; - _syscallRegs = { - X86_REG_EBX, - X86_REG_ECX, - X86_REG_EDX, - X86_REG_ESI, - X86_REG_EDI, - X86_REG_EBP}; - - _paramRegs = { - X86_REG_ECX, - X86_REG_EDX}; - - _regReturn = X86_REG_EAX; - _regFPReturn = X86_REG_ST7; -} - -AbiX86Fastcall::~AbiX86Fastcall() -{ - -} - -bool AbiX86Fastcall::isGeneralPurposeRegister(const llvm::Value* val) -{ - uint32_t rid = getRegisterId(val); - return rid == X86_REG_EAX - || rid == X86_REG_EBX - || rid == X86_REG_ECX - || rid == X86_REG_EDX - || rid == X86_REG_ESP - || rid == X86_REG_EBP - || rid == X86_REG_ESI - || rid == X86_REG_EDI; -} - -bool AbiX86Fastcall::isNopInstruction(cs_insn* insn) -{ - cs_x86& insn86 = insn->detail->x86; - - // True NOP variants. - // - if (insn->id == X86_INS_NOP - || insn->id == X86_INS_FNOP - || insn->id == X86_INS_FDISI8087_NOP - || insn->id == X86_INS_FENI8087_NOP - || insn->id == X86_INS_INT3) - { - return true; - } - // e.g. lea esi, [esi] - // - else if (insn->id == X86_INS_LEA - && insn86.disp == 0 - && insn86.op_count == 2 - && insn86.operands[0].type == X86_OP_REG - && insn86.operands[1].type == X86_OP_MEM - && insn86.operands[1].mem.segment == X86_REG_INVALID - && insn86.operands[1].mem.index == X86_REG_INVALID - && insn86.operands[1].mem.scale == 1 - && insn86.operands[1].mem.disp == 0 - && insn86.operands[1].mem.base == insn86.operands[0].reg) - { - return true; - } - // e.g. mov esi. esi - // - else if (insn->id == X86_INS_MOV - && insn86.disp == 0 - && insn86.op_count == 2 - && insn86.operands[0].type == X86_OP_REG - && insn86.operands[1].type == X86_OP_REG - && insn86.operands[0].reg == insn86.operands[1].reg) - { - return true; - } - - return false; -} - -} // namespace bin2llvmir -} // namespace retdec diff --git a/src/bin2llvmir/providers/abi/x86_pascal.cpp b/src/bin2llvmir/providers/abi/x86_pascal.cpp deleted file mode 100644 index c4ce85c85..000000000 --- a/src/bin2llvmir/providers/abi/x86_pascal.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @file src/bin2llvmir/providers/abi/x86.cpp - * @brief ABI information for x86. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#include "retdec/bin2llvmir/providers/abi/x86_pascal.h" - -using namespace llvm; - -namespace retdec { -namespace bin2llvmir { - -AbiX86Pascal::AbiX86Pascal(llvm::Module* m, Config* c) : - Abi(m, c) -{ - _regs.reserve(X86_REG_ENDING); - _id2regs.resize(X86_REG_ENDING, nullptr); - _regStackPointerId = X86_REG_ESP; - - // system calls - _regSyscallId = X86_REG_EAX; - _regSyscallReturn = X86_REG_EAX; - _syscallRegs = { - X86_REG_EBX, - X86_REG_ECX, - X86_REG_EDX, - X86_REG_ESI, - X86_REG_EDI, - X86_REG_EBP}; - - _stackParamOrder = LTR; - - _paramRegs = { - X86_REG_EAX, - X86_REG_EDX, - X86_REG_ECX}; - - _regReturn = X86_REG_EAX; - _regFPReturn = X86_REG_ST7; -} - -AbiX86Pascal::~AbiX86Pascal() -{ - -} - -bool AbiX86Pascal::isGeneralPurposeRegister(const llvm::Value* val) -{ - uint32_t rid = getRegisterId(val); - return rid == X86_REG_EAX - || rid == X86_REG_EBX - || rid == X86_REG_ECX - || rid == X86_REG_EDX - || rid == X86_REG_ESP - || rid == X86_REG_EBP - || rid == X86_REG_ESI - || rid == X86_REG_EDI; -} - -bool AbiX86Pascal::isNopInstruction(cs_insn* insn) -{ - cs_x86& insn86 = insn->detail->x86; - - // True NOP variants. - // - if (insn->id == X86_INS_NOP - || insn->id == X86_INS_FNOP - || insn->id == X86_INS_FDISI8087_NOP - || insn->id == X86_INS_FENI8087_NOP - || insn->id == X86_INS_INT3) - { - return true; - } - // e.g. lea esi, [esi] - // - else if (insn->id == X86_INS_LEA - && insn86.disp == 0 - && insn86.op_count == 2 - && insn86.operands[0].type == X86_OP_REG - && insn86.operands[1].type == X86_OP_MEM - && insn86.operands[1].mem.segment == X86_REG_INVALID - && insn86.operands[1].mem.index == X86_REG_INVALID - && insn86.operands[1].mem.scale == 1 - && insn86.operands[1].mem.disp == 0 - && insn86.operands[1].mem.base == insn86.operands[0].reg) - { - return true; - } - // e.g. mov esi. esi - // - else if (insn->id == X86_INS_MOV - && insn86.disp == 0 - && insn86.op_count == 2 - && insn86.operands[0].type == X86_OP_REG - && insn86.operands[1].type == X86_OP_REG - && insn86.operands[0].reg == insn86.operands[1].reg) - { - return true; - } - - return false; -} - -} // namespace bin2llvmir -} // namespace retdec diff --git a/src/bin2llvmir/providers/abi/x86_watcom.cpp b/src/bin2llvmir/providers/abi/x86_watcom.cpp deleted file mode 100644 index e417c92e7..000000000 --- a/src/bin2llvmir/providers/abi/x86_watcom.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @file src/bin2llvmir/providers/abi/x86.cpp - * @brief ABI information for x86. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#include "retdec/bin2llvmir/providers/abi/x86_watcom.h" - -using namespace llvm; - -namespace retdec { -namespace bin2llvmir { - -AbiX86Watcom::AbiX86Watcom(llvm::Module* m, Config* c) : - Abi(m, c) -{ - _regs.reserve(X86_REG_ENDING); - _id2regs.resize(X86_REG_ENDING, nullptr); - _regStackPointerId = X86_REG_ESP; - - // system calls - _regSyscallId = X86_REG_EAX; - _regSyscallReturn = X86_REG_EAX; - _syscallRegs = { - X86_REG_EBX, - X86_REG_ECX, - X86_REG_EDX, - X86_REG_ESI, - X86_REG_EDI, - X86_REG_EBP}; - - _paramRegs = { - X86_REG_EAX, - X86_REG_EDX, - X86_REG_EBX, - X86_REG_ECX, - }; - - _regReturn = X86_REG_EAX; - _regFPReturn = X86_REG_ST7; -} - -AbiX86Watcom::~AbiX86Watcom() -{ - -} - -bool AbiX86Watcom::isGeneralPurposeRegister(const llvm::Value* val) -{ - uint32_t rid = getRegisterId(val); - return rid == X86_REG_EAX - || rid == X86_REG_EBX - || rid == X86_REG_ECX - || rid == X86_REG_EDX - || rid == X86_REG_ESP - || rid == X86_REG_EBP - || rid == X86_REG_ESI - || rid == X86_REG_EDI; -} - -bool AbiX86Watcom::isNopInstruction(cs_insn* insn) -{ - cs_x86& insn86 = insn->detail->x86; - - // True NOP variants. - // - if (insn->id == X86_INS_NOP - || insn->id == X86_INS_FNOP - || insn->id == X86_INS_FDISI8087_NOP - || insn->id == X86_INS_FENI8087_NOP - || insn->id == X86_INS_INT3) - { - return true; - } - // e.g. lea esi, [esi] - // - else if (insn->id == X86_INS_LEA - && insn86.disp == 0 - && insn86.op_count == 2 - && insn86.operands[0].type == X86_OP_REG - && insn86.operands[1].type == X86_OP_MEM - && insn86.operands[1].mem.segment == X86_REG_INVALID - && insn86.operands[1].mem.index == X86_REG_INVALID - && insn86.operands[1].mem.scale == 1 - && insn86.operands[1].mem.disp == 0 - && insn86.operands[1].mem.base == insn86.operands[0].reg) - { - return true; - } - // e.g. mov esi. esi - // - else if (insn->id == X86_INS_MOV - && insn86.disp == 0 - && insn86.op_count == 2 - && insn86.operands[0].type == X86_OP_REG - && insn86.operands[1].type == X86_OP_REG - && insn86.operands[0].reg == insn86.operands[1].reg) - { - return true; - } - - return false; -} - -} // namespace bin2llvmir -} // namespace retdec From 89e3e709e75fe09e9f733255afbcf15336e487da Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 22:33:20 +0100 Subject: [PATCH 127/159] capstone2llvmir/arm: fix STRD instruction Provides fix for implementation of STRD instruction semantics. --- src/capstone2llvmir/arm/arm.cpp | 20 ++++++++---- tests/capstone2llvmir/arm_tests.cpp | 50 +++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/capstone2llvmir/arm/arm.cpp b/src/capstone2llvmir/arm/arm.cpp index 2ce2c57a9..c10395eb4 100644 --- a/src/capstone2llvmir/arm/arm.cpp +++ b/src/capstone2llvmir/arm/arm.cpp @@ -1659,11 +1659,6 @@ void Capstone2LlvmIrTranslatorArm_impl::translateStr(cs_insn* i, cs_arm* ai, llv op0 = irb.CreateZExtOrTrunc(op0, irb.getInt16Ty()); break; } - // TODO: The new commented code is better, but without special handling - // in bin2llvmirl, it screws up some tests: - // e.g. "many-params.c -a arm -f elf -c gcc -C -O0 -g" - // Therefore, at the moment, we generate the same code as original sem. - // case ARM_INS_STRD: case ARM_INS_STREXD: { @@ -1687,12 +1682,15 @@ void Capstone2LlvmIrTranslatorArm_impl::translateStr(cs_insn* i, cs_arm* ai, llv bool subtract = false; if (i->id == ARM_INS_STRD || i->id == ARM_INS_STREXD) { - // TODO: op1 is not stored at all at the moment. See comment above. - if (ai->op_count == 3 && ai->operands[2].type == ARM_OP_MEM) { storeOp(ai->operands[2], op0, irb); + + auto op3 = ai->operands[2]; + op3.mem.disp += 4; + storeOp(op3, op1, irb); + baseR = ai->operands[2].mem.base; if (auto disp = ai->operands[2].mem.disp) { @@ -1702,11 +1700,19 @@ void Capstone2LlvmIrTranslatorArm_impl::translateStr(cs_insn* i, cs_arm* ai, llv { idx = loadRegister(ai->operands[2].mem.index, irb); } + // Maybe we should add +4 to idx? } else if (ai->op_count == 4 && ai->operands[2].type == ARM_OP_MEM) { storeOp(ai->operands[2], op0, irb); + + // We don't use op4 here, post-index offset is applied to source + // address only after the transfers at writeback. + auto op3 = ai->operands[2]; + op3.mem.disp += 4; + storeOp(op3, op1, irb); + baseR = ai->operands[2].mem.base; idx = loadOp(ai->operands[3], irb); subtract = ai->operands[3].subtracted; diff --git a/tests/capstone2llvmir/arm_tests.cpp b/tests/capstone2llvmir/arm_tests.cpp index d7676177a..8ab432776 100644 --- a/tests/capstone2llvmir/arm_tests.cpp +++ b/tests/capstone2llvmir/arm_tests.cpp @@ -2908,8 +2908,54 @@ TEST_P(Capstone2LlvmIrTranslatorArmTests, ARM_INS_STRD) EXPECT_NO_REGISTERS_STORED(); EXPECT_NO_MEMORY_LOADED(); EXPECT_JUST_MEMORY_STORED({ -// {0x1000, 0x1234567890abcdef_qw} - {0x1000, 0x12345678_dw} + {0x1000, 0x12345678_dw}, + {0x1004, 0x90abcdef_dw} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArmTests, ARM_INS_STRD_sp_imm) +{ + ALL_MODES; + + setRegisters({ + {ARM_REG_R0, 0x12345678}, + {ARM_REG_R1, 0x90abcdef}, + {ARM_REG_SP, 0x1000}, + }); + + emulate("strd r0, r1, [sp, #0x18]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM_REG_R0, ARM_REG_R1, ARM_REG_SP}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1018, 0x12345678_dw}, + {0x101c, 0x90abcdef_dw} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArmTests, ARM_INS_STRD_sp_post_imm) +{ + ALL_MODES; + + setRegisters({ + {ARM_REG_R0, 0x12345678}, + {ARM_REG_R1, 0x90abcdef}, + {ARM_REG_SP, 0x1000}, + }); + + emulate("strd r0, r1, [sp], #0x18"); + + EXPECT_JUST_REGISTERS_LOADED({ARM_REG_R0, ARM_REG_R1, ARM_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM_REG_SP, ANY}, // Not an exact value because some strange behaviour. + }); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1000, 0x12345678_dw}, + {0x1004, 0x90abcdef_dw} }); EXPECT_NO_VALUE_CALLED(); } From 13b345b3dcb2969a4709a96fb0e334a009732fdb Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 22:40:20 +0100 Subject: [PATCH 128/159] abi: archs: provide const methods squish --- include/retdec/bin2llvmir/providers/abi/arm.h | 2 +- include/retdec/bin2llvmir/providers/abi/arm64.h | 2 +- include/retdec/bin2llvmir/providers/abi/mips.h | 2 +- include/retdec/bin2llvmir/providers/abi/mips64.h | 2 +- include/retdec/bin2llvmir/providers/abi/ms_x64.h | 2 +- include/retdec/bin2llvmir/providers/abi/pic32.h | 2 +- include/retdec/bin2llvmir/providers/abi/powerpc.h | 2 +- include/retdec/bin2llvmir/providers/abi/powerpc64.h | 2 +- include/retdec/bin2llvmir/providers/abi/x64.h | 2 +- include/retdec/bin2llvmir/providers/abi/x86.h | 2 +- src/bin2llvmir/providers/abi/arm.cpp | 2 +- src/bin2llvmir/providers/abi/arm64.cpp | 2 +- src/bin2llvmir/providers/abi/mips.cpp | 2 +- src/bin2llvmir/providers/abi/mips64.cpp | 2 +- src/bin2llvmir/providers/abi/ms_x64.cpp | 2 +- src/bin2llvmir/providers/abi/pic32.cpp | 2 +- src/bin2llvmir/providers/abi/powerpc.cpp | 2 +- src/bin2llvmir/providers/abi/powerpc64.cpp | 2 +- src/bin2llvmir/providers/abi/x64.cpp | 2 +- src/bin2llvmir/providers/abi/x86.cpp | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/retdec/bin2llvmir/providers/abi/arm.h b/include/retdec/bin2llvmir/providers/abi/arm.h index 33c58dd82..b4f9348c7 100644 --- a/include/retdec/bin2llvmir/providers/abi/arm.h +++ b/include/retdec/bin2llvmir/providers/abi/arm.h @@ -23,7 +23,7 @@ class AbiArm : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/arm64.h b/include/retdec/bin2llvmir/providers/abi/arm64.h index 671812e25..ea9078f96 100644 --- a/include/retdec/bin2llvmir/providers/abi/arm64.h +++ b/include/retdec/bin2llvmir/providers/abi/arm64.h @@ -23,7 +23,7 @@ class AbiArm64 : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/mips.h b/include/retdec/bin2llvmir/providers/abi/mips.h index af144ea6c..a573f6998 100644 --- a/include/retdec/bin2llvmir/providers/abi/mips.h +++ b/include/retdec/bin2llvmir/providers/abi/mips.h @@ -23,7 +23,7 @@ class AbiMips : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/mips64.h b/include/retdec/bin2llvmir/providers/abi/mips64.h index 86e3ca7c9..7239227b6 100644 --- a/include/retdec/bin2llvmir/providers/abi/mips64.h +++ b/include/retdec/bin2llvmir/providers/abi/mips64.h @@ -23,7 +23,7 @@ class AbiMips64 : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/ms_x64.h b/include/retdec/bin2llvmir/providers/abi/ms_x64.h index e3fb9f27c..3a8f7a325 100644 --- a/include/retdec/bin2llvmir/providers/abi/ms_x64.h +++ b/include/retdec/bin2llvmir/providers/abi/ms_x64.h @@ -23,7 +23,7 @@ class AbiMS_X64 : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/pic32.h b/include/retdec/bin2llvmir/providers/abi/pic32.h index e78b7bcaa..74af41a54 100644 --- a/include/retdec/bin2llvmir/providers/abi/pic32.h +++ b/include/retdec/bin2llvmir/providers/abi/pic32.h @@ -23,7 +23,7 @@ class AbiPic32 : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/powerpc.h b/include/retdec/bin2llvmir/providers/abi/powerpc.h index 655087d17..0cf1df36d 100644 --- a/include/retdec/bin2llvmir/providers/abi/powerpc.h +++ b/include/retdec/bin2llvmir/providers/abi/powerpc.h @@ -23,7 +23,7 @@ class AbiPowerpc : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/powerpc64.h b/include/retdec/bin2llvmir/providers/abi/powerpc64.h index 1ad5cb693..1ad5b49d1 100644 --- a/include/retdec/bin2llvmir/providers/abi/powerpc64.h +++ b/include/retdec/bin2llvmir/providers/abi/powerpc64.h @@ -23,7 +23,7 @@ class AbiPowerpc64 : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/x64.h b/include/retdec/bin2llvmir/providers/abi/x64.h index 529e300c3..ab07e8bd7 100644 --- a/include/retdec/bin2llvmir/providers/abi/x64.h +++ b/include/retdec/bin2llvmir/providers/abi/x64.h @@ -23,7 +23,7 @@ class AbiX64 : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/x86.h b/include/retdec/bin2llvmir/providers/abi/x86.h index 488a8ccb8..92c633bc9 100644 --- a/include/retdec/bin2llvmir/providers/abi/x86.h +++ b/include/retdec/bin2llvmir/providers/abi/x86.h @@ -23,7 +23,7 @@ class AbiX86 : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/src/bin2llvmir/providers/abi/arm.cpp b/src/bin2llvmir/providers/abi/arm.cpp index 423e9dfeb..eee6a7a5a 100644 --- a/src/bin2llvmir/providers/abi/arm.cpp +++ b/src/bin2llvmir/providers/abi/arm.cpp @@ -37,7 +37,7 @@ AbiArm::~AbiArm() } -bool AbiArm::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiArm::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return ARM_REG_R0 <= rid && rid <= ARM_REG_R12; diff --git a/src/bin2llvmir/providers/abi/arm64.cpp b/src/bin2llvmir/providers/abi/arm64.cpp index 0e818f039..d9be3ba84 100644 --- a/src/bin2llvmir/providers/abi/arm64.cpp +++ b/src/bin2llvmir/providers/abi/arm64.cpp @@ -37,7 +37,7 @@ AbiArm64::~AbiArm64() } -bool AbiArm64::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiArm64::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return ARM64_REG_X0 <= rid && rid <= ARM64_REG_X30; diff --git a/src/bin2llvmir/providers/abi/mips.cpp b/src/bin2llvmir/providers/abi/mips.cpp index 02ffb4111..5e1fe2605 100644 --- a/src/bin2llvmir/providers/abi/mips.cpp +++ b/src/bin2llvmir/providers/abi/mips.cpp @@ -43,7 +43,7 @@ AbiMips::~AbiMips() } -bool AbiMips::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiMips::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return MIPS_REG_0 <= rid && rid <= MIPS_REG_31; diff --git a/src/bin2llvmir/providers/abi/mips64.cpp b/src/bin2llvmir/providers/abi/mips64.cpp index 412dfccee..cc2edb2a7 100644 --- a/src/bin2llvmir/providers/abi/mips64.cpp +++ b/src/bin2llvmir/providers/abi/mips64.cpp @@ -40,7 +40,7 @@ AbiMips64::~AbiMips64() } -bool AbiMips64::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiMips64::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return MIPS_REG_0 <= rid && rid <= MIPS_REG_31; diff --git a/src/bin2llvmir/providers/abi/ms_x64.cpp b/src/bin2llvmir/providers/abi/ms_x64.cpp index ff1ed3d74..d96a2905a 100644 --- a/src/bin2llvmir/providers/abi/ms_x64.cpp +++ b/src/bin2llvmir/providers/abi/ms_x64.cpp @@ -36,7 +36,7 @@ AbiMS_X64::~AbiMS_X64() { } -bool AbiMS_X64::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiMS_X64::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return rid == X86_REG_RAX diff --git a/src/bin2llvmir/providers/abi/pic32.cpp b/src/bin2llvmir/providers/abi/pic32.cpp index b141a4702..af204ac62 100644 --- a/src/bin2llvmir/providers/abi/pic32.cpp +++ b/src/bin2llvmir/providers/abi/pic32.cpp @@ -36,7 +36,7 @@ AbiPic32::~AbiPic32() } -bool AbiPic32::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiPic32::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return MIPS_REG_0 <= rid && rid <= MIPS_REG_31; diff --git a/src/bin2llvmir/providers/abi/powerpc.cpp b/src/bin2llvmir/providers/abi/powerpc.cpp index 7121eb6df..e6983d27d 100644 --- a/src/bin2llvmir/providers/abi/powerpc.cpp +++ b/src/bin2llvmir/providers/abi/powerpc.cpp @@ -26,7 +26,7 @@ AbiPowerpc::~AbiPowerpc() } -bool AbiPowerpc::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiPowerpc::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return PPC_REG_R0 <= rid && rid <= PPC_REG_R31; diff --git a/src/bin2llvmir/providers/abi/powerpc64.cpp b/src/bin2llvmir/providers/abi/powerpc64.cpp index 8f13db2e5..662114db6 100644 --- a/src/bin2llvmir/providers/abi/powerpc64.cpp +++ b/src/bin2llvmir/providers/abi/powerpc64.cpp @@ -26,7 +26,7 @@ AbiPowerpc64::~AbiPowerpc64() } -bool AbiPowerpc64::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiPowerpc64::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return PPC_REG_R0 <= rid && rid <= PPC_REG_R31; diff --git a/src/bin2llvmir/providers/abi/x64.cpp b/src/bin2llvmir/providers/abi/x64.cpp index 6b74d9547..832e01280 100644 --- a/src/bin2llvmir/providers/abi/x64.cpp +++ b/src/bin2llvmir/providers/abi/x64.cpp @@ -36,7 +36,7 @@ AbiX64::~AbiX64() { } -bool AbiX64::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiX64::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return rid == X86_REG_RAX diff --git a/src/bin2llvmir/providers/abi/x86.cpp b/src/bin2llvmir/providers/abi/x86.cpp index d11c2b64b..8c0fb42d7 100644 --- a/src/bin2llvmir/providers/abi/x86.cpp +++ b/src/bin2llvmir/providers/abi/x86.cpp @@ -37,7 +37,7 @@ AbiX86::~AbiX86() } -bool AbiX86::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiX86::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return rid == X86_REG_EAX From f49be24851ed9fbc47a85d5ce76ad7a5a6c63463 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 22:48:06 +0100 Subject: [PATCH 129/159] abi: pic32: define special size for double arguments --- .../retdec/bin2llvmir/providers/abi/pic32.h | 6 ++++++ src/bin2llvmir/providers/abi/pic32.cpp | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/pic32.h b/include/retdec/bin2llvmir/providers/abi/pic32.h index 74af41a54..4f060455d 100644 --- a/include/retdec/bin2llvmir/providers/abi/pic32.h +++ b/include/retdec/bin2llvmir/providers/abi/pic32.h @@ -20,6 +20,12 @@ class AbiPic32 : public Abi AbiPic32(llvm::Module* m, Config* c); virtual ~AbiPic32(); + // Types + // + public: + virtual std::size_t getTypeByteSize(llvm::Type* t) const override; + virtual std::size_t getTypeBitSize(llvm::Type* t) const override; + // Registers. // public: diff --git a/src/bin2llvmir/providers/abi/pic32.cpp b/src/bin2llvmir/providers/abi/pic32.cpp index af204ac62..f035b2f1e 100644 --- a/src/bin2llvmir/providers/abi/pic32.cpp +++ b/src/bin2llvmir/providers/abi/pic32.cpp @@ -55,5 +55,25 @@ bool AbiPic32::isNopInstruction(cs_insn* insn) return false; } +std::size_t AbiPic32::getTypeByteSize(llvm::Type* t) const +{ + if (t->isDoubleTy()) + { + t = Type::getFloatTy(_module->getContext()); + } + + return Abi::getTypeByteSize(t); +} + +std::size_t AbiPic32::getTypeBitSize(llvm::Type* t) const +{ + if (t->isDoubleTy()) + { + t = Type::getFloatTy(_module->getContext()); + } + + return Abi::getTypeByteSize(t); +} + } // namespace bin2llvmir } // namespace retdec From ac3728b5629cf4dfd55f59f47df1f63d4ba8a20f Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:35:37 +0100 Subject: [PATCH 130/159] collector: new class --- .../param_return/collector/collector.h | 115 ++++ src/bin2llvmir/CMakeLists.txt | 1 + .../param_return/collector/collector.cpp | 646 ++++++++++++++++++ 3 files changed, 762 insertions(+) create mode 100644 include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h create mode 100644 src/bin2llvmir/optimizations/param_return/collector/collector.cpp diff --git a/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h b/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h new file mode 100644 index 000000000..7360442cf --- /dev/null +++ b/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h @@ -0,0 +1,115 @@ +/** +* @file include/retdec/bin2llvmir/optimizations/param_return/collector.h +* @brief Collects possible arguments and returns of functions. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_COLLECTOR_COLLECTOR_H +#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_COLLECTOR_COLLECTOR_H + +#include +#include + +#include +#include + +#include "retdec/bin2llvmir/analyses/reaching_definitions.h" +#include "retdec/bin2llvmir/optimizations/param_return/data_entries.h" +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class Collector +{ + public: + typedef std::unique_ptr Ptr; + + public: + Collector( + const Abi* abi, + llvm::Module* m, + const ReachingDefinitionsAnalysis* rda); + + virtual ~Collector(); + + public: + virtual void collectCallArgs(CallEntry* ce) const; + virtual void collectCallRets(CallEntry* ce) const; + + virtual void collectDefArgs(DataFlowEntry* de) const; + virtual void collectDefRets(DataFlowEntry* de) const; + + virtual void collectCallSpecificTypes(CallEntry* ce) const; + + protected: + + void collectRetStores(ReturnEntry* re) const; + + void collectStoresBeforeInstruction( + llvm::Instruction* i, + std::vector& stores) const; + + void collectLoadsAfterInstruction( + llvm::Instruction* i, + std::vector& loads) const; + + bool collectLoadsAfterInstruction( + llvm::Instruction* i, + std::vector& loads, + std::set& excluded) const; + + void collectStoresInSinglePredecessors( + llvm::Instruction* i, + std::vector& stores) const; + + void collectStoresRecursively( + llvm::Instruction* i, + std::vector& stores, + std::map>& seen) const; + + bool collectStoresInInstructionBlock( + llvm::Instruction* i, + std::set& values, + std::vector& stores) const; + + protected: + bool extractFormatString(CallEntry* ce) const; + + bool storesString(llvm::StoreInst* si, std::string& str) const; + llvm::Value* getRoot(llvm::Value* i, bool first = true) const; + + protected: + const Abi* _abi; + llvm::Module* _module; + const ReachingDefinitionsAnalysis* _rda; +}; + +class CollectorPic32 : public Collector +{ + public: + CollectorPic32( + const Abi* abi, + llvm::Module* m, + const ReachingDefinitionsAnalysis* rda); + + virtual ~CollectorPic32() override; + + public: + virtual void collectCallSpecificTypes(CallEntry* ce) const override; +}; + +class CollectorProvider +{ + public: + static Collector::Ptr createCollector( + const Abi* abi, + llvm::Module* m, + const ReachingDefinitionsAnalysis* rda); +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 0e67d6db5..f11e6fe03 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -48,6 +48,7 @@ set(BIN2LLVMIR_SOURCES optimizations/inst_opt/inst_opt.cpp optimizations/local_vars/local_vars.cpp optimizations/main_detection/main_detection.cpp + optimizations/param_return/collector/collector.cpp optimizations/param_return/param_return.cpp optimizations/phi2seq/phi2seq.cpp optimizations/provider_init/provider_init.cpp diff --git a/src/bin2llvmir/optimizations/param_return/collector/collector.cpp b/src/bin2llvmir/optimizations/param_return/collector/collector.cpp new file mode 100644 index 000000000..c8c427c6a --- /dev/null +++ b/src/bin2llvmir/optimizations/param_return/collector/collector.cpp @@ -0,0 +1,646 @@ +/** +* @file src/bin2llvmir/optimizations/param_return/collector.cpp +* @brief Collects possible arguments and returns of functions. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#include + +#include +#include + +#include "retdec/bin2llvmir/optimizations/param_return/collector/collector.h" + +using namespace retdec::utils; +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +Collector::Collector( + const Abi* abi, + Module* m, + const ReachingDefinitionsAnalysis* rda) : + _abi(abi), + _module(m), + _rda(rda) +{ +} + +Collector::~Collector() +{ +} + +void Collector::collectCallArgs(CallEntry* ce) const +{ + std::vector foundStores; + + collectStoresBeforeInstruction( + ce->getCallInstruction(), + foundStores); + + ce->setArgStores(std::move(foundStores)); +} + +void Collector::collectCallRets(CallEntry* ce) const +{ + std::vector foundLoads; + + collectLoadsAfterInstruction( + ce->getCallInstruction(), + foundLoads); + + ce->setRetLoads(std::move(foundLoads)); +} + +void Collector::collectDefArgs(DataFlowEntry* dataflow) const +{ + if (!dataflow->hasDefinition()) + { + return; + } + + auto* f = dataflow->getFunction(); + + std::set added; + for (auto it = inst_begin(f), end = inst_end(f); it != end; ++it) + { + if (auto* l = dyn_cast(&*it)) + { + auto* ptr = l->getPointerOperand(); + if (!_abi->isGeneralPurposeRegister(ptr) && !_abi->isStackVariable(ptr)) + { + continue; + } + + auto* use = _rda->getUse(l); + if (use == nullptr) + { + continue; + } + + if ((use->defs.empty() || use->isUndef()) + && added.find(ptr) == added.end()) + { + dataflow->addArg(ptr); + added.insert(ptr); + } + } + } +} + +void Collector::collectDefRets(DataFlowEntry* dataflow) const +{ + if (!dataflow->hasDefinition()) + { + return; + } + + auto* f = dataflow->getFunction(); + + for (auto it = inst_begin(f), end = inst_end(f); it != end; ++it) + { + if (auto* r = dyn_cast(&*it)) + { + ReturnEntry* re = dataflow->createRetEntry(r); + collectRetStores(re); + } + } +} + +void Collector::collectRetStores(ReturnEntry* re) const +{ + std::vector foundStores; + +// collectStoresBeforeInstruction( +// re->getRetInstruction(), +// foundStores); + + collectStoresInSinglePredecessors( + re->getRetInstruction(), + foundStores); + + re->setRetStores(std::move(foundStores)); +} + +void Collector::collectStoresBeforeInstruction( + llvm::Instruction* i, + std::vector& stores) const +{ + if (i == nullptr) + { + return; + } + + std::map> seenBlocks; + + auto* block = i->getParent(); + + // In case of recursive call of same basic block. + std::set afterValues; + std::vector afterStores; + collectStoresInInstructionBlock( + &block->back(), + afterValues, + afterStores); + + seenBlocks[block] = std::move(afterValues); + + collectStoresRecursively(i->getPrevNode(), stores, seenBlocks); + + auto& values = seenBlocks[block]; + + stores.insert( + stores.end(), + std::make_move_iterator(afterStores.begin()), + std::make_move_iterator(afterStores.end())); + + stores.erase( + std::remove_if( + stores.begin(), + stores.end(), + [values](StoreInst* s) + { + return values.find( + s->getPointerOperand()) == values.end(); + }), + stores.end()); +} + +void Collector::collectStoresInSinglePredecessors( + llvm::Instruction* i, + std::vector& stores) const +{ + if (i == nullptr) + { + return; + } + + std::set seenBbs; + std::set disqualifiedValues; + + auto* b = i->getParent(); + seenBbs.insert(b); + Instruction* prev = i; + + while (true) + { + if (prev == &b->front()) + { + auto* spb = b->getSinglePredecessor(); + if (spb && !spb->empty() + && seenBbs.find(spb) == seenBbs.end()) + { + b = spb; + prev = &b->back(); + seenBbs.insert(b); + } + else + { + break; + } + } + else + { + prev = prev->getPrevNode(); + } + if (prev == nullptr) + { + break; + } + + if (isa(prev) || isa(prev)) + { + break; + } + else if (auto* store = dyn_cast(prev)) + { + auto* ptr = store->getPointerOperand(); + + if (disqualifiedValues.find(ptr) == disqualifiedValues.end() + && (_abi->isRegister(ptr) || _abi->isStackVariable(ptr))) + { + stores.push_back(store); + disqualifiedValues.insert(ptr); + } + } + else if (auto* load = dyn_cast(prev)) + { + auto* ptr = load->getPointerOperand(); + disqualifiedValues.insert(ptr); + } + } +} + +void Collector::collectStoresRecursively( + Instruction* i, + std::vector& stores, + std::map>& seen) const +{ + if (i == nullptr) + { + return; + } + + auto* block = i->getParent(); + + std::set values; + if (!collectStoresInInstructionBlock(i, values, stores)) + { + seen[block] = std::move(values); + return; + } + + seen.emplace(std::make_pair(block, values)); + std::set commonValues; + + for (BasicBlock* pred : predecessors(block)) + { + if (seen.find(pred) == seen.end()) + { + collectStoresRecursively( + &pred->back(), + stores, + seen); + } + + auto& foundValues = seen[pred]; + if (foundValues.empty()) + { + // Shorcut -> intersection would be empty set. + commonValues.clear(); + break; + } + + if (commonValues.empty()) + { + commonValues = foundValues; + } + else + { + std::set intersection; + std::set_intersection( + commonValues.begin(), + commonValues.end(), + foundValues.begin(), + foundValues.end(), + std::inserter(intersection, intersection.begin())); + + commonValues = std::move(intersection); + } + } + + values.insert(commonValues.begin(), commonValues.end()); + seen[block] = values; +} + + +bool Collector::collectStoresInInstructionBlock( + Instruction* start, + std::set& values, + std::vector& stores) const +{ + if (start == nullptr) + { + return false; + } + + std::set excluded; + + auto* block = start->getParent(); + + for (auto* inst = start; true; inst = inst->getPrevNode()) + { + if (inst == nullptr) + { + return false; + } + if (auto* call = dyn_cast(inst)) + { + auto* calledFnc = call->getCalledFunction(); + if (calledFnc == nullptr || !calledFnc->isIntrinsic()) + { + return false; + } + } + else if (isa(inst)) + { + return false; + } + else if (auto* store = dyn_cast(inst)) + { + auto* val = store->getValueOperand(); + auto* ptr = store->getPointerOperand(); + + if (!_abi->isRegister(ptr) && !_abi->isStackVariable(ptr)) + { + excluded.insert(ptr); + } + if (auto* l = dyn_cast(val)) + { + if (l->getPointerOperand() != store->getPointerOperand()) + { + excluded.insert(l->getPointerOperand()); + } + } + + if (excluded.find(ptr) == excluded.end()) + { + stores.push_back(store); + values.insert(ptr); + excluded.insert(ptr); + excluded.insert(val); + } + } + if (inst == &block->front()) + { + return true; + } + } + + return true; +} + +void Collector::collectLoadsAfterInstruction( + llvm::Instruction* start, + std::vector& loads) const +{ + if (start == nullptr) + { + return; + } + + std::queue next; + std::set excludedValues; + std::set seen; + + BasicBlock* beginBB = start->getParent(); + next.push(start->getNextNode()); + + while (!next.empty()) + { + auto* i = next.front(); + next.pop(); + + auto* block = i->getParent(); + seen.insert(block); + + if (collectLoadsAfterInstruction(i, loads, excludedValues)) + { + for (auto suc : successors(block)) + { + if (seen.find(suc) == seen.end()) + { + next.push(&suc->front()); + } + else if (suc == beginBB) + { + next.push(&beginBB->front()); + beginBB = nullptr; + } + } + } + } +} + +bool Collector::collectLoadsAfterInstruction( + llvm::Instruction* start, + std::vector& loads, + std::set& excluded) const +{ + if (start == nullptr) + { + return false; + } + + auto* block = start->getParent(); + for (auto* inst = start; true; inst = inst->getNextNode()) + { + if (inst == nullptr) + { + return false; + } + if (auto* call = dyn_cast(inst)) + { + auto* calledFnc = call->getCalledFunction(); + if (calledFnc == nullptr || !calledFnc->isIntrinsic()) + { + return false; + } + } + else if (isa(inst)) + { + return false; + } + else if (auto* store = dyn_cast(inst)) + { + auto* ptr = store->getPointerOperand(); + excluded.insert(ptr); + } + else if (auto* load = dyn_cast(inst)) + { + auto* ptr = load->getPointerOperand(); + + if (excluded.find(ptr) == excluded.end() + && ( _abi->isGeneralPurposeRegister(ptr) || _abi->isStackVariable(ptr) )) + { + loads.push_back(load); + } + } + + if (inst == &block->back()) + { + return true; + } + } + + return true; +} + +void Collector::collectCallSpecificTypes(CallEntry* ce) const +{ + if (!ce->getBaseFunction()->isVariadic()) + { + return; + } + + + if (!extractFormatString(ce)) + { + return; + } + + auto wrappedCall = ce->getBaseFunction()->getWrappedCall(); + + auto trueCall = wrappedCall ? wrappedCall : ce->getCallInstruction(); + + ce->setArgTypes( + llvm_utils::parseFormatString( + _module, + ce->getFormatString(), + trueCall->getCalledFunction()) + ); +} + +bool Collector::extractFormatString(CallEntry* ce) const +{ + for (auto& i : ce->args()) + { + auto inst = std::find_if( + ce->argStores().begin(), + ce->argStores().end(), + [i](StoreInst *st) + { + return st->getPointerOperand() == i; + }); + + if (inst != ce->argStores().end()) + { + std::string str; + if (storesString(*inst, str)) + { + ce->setFormatString(str); + return true; + } + } + } + + return false; +} + +bool Collector::storesString(StoreInst* si, std::string& str) const +{ + auto* v = getRoot(si->getValueOperand()); + auto* gv = dyn_cast_or_null(v); + + if (gv == nullptr || !gv->hasInitializer()) + { + return false; + } + + auto* init = dyn_cast_or_null(gv->getInitializer()); + if (init == nullptr) + { + if (auto* i = dyn_cast(gv->getInitializer())) + { + if (auto* igv = dyn_cast(i->getOperand(0))) + { + init = dyn_cast_or_null(igv->getInitializer()); + } + } + } + + if (init == nullptr || !init->isString()) + { + return false; + } + + str = init->getAsString(); + return true; +} + +llvm::Value* Collector::getRoot(llvm::Value* i, bool first) const +{ + static std::set seen; + if (first) + { + seen.clear(); + } + if (seen.count(i)) + { + return i; + } + seen.insert(i); + + i = llvm_utils::skipCasts(i); + if (auto* ii = dyn_cast(i)) + { + if (auto* u = _rda->getUse(ii)) + { + if (u->defs.size() == 1) + { + auto* d = (*u->defs.begin())->def; + if (auto* s = dyn_cast(d)) + { + return getRoot(s->getValueOperand(), false); + } + else + { + return d; + } + } + else if (auto* l = dyn_cast(ii)) + { + return getRoot(l->getPointerOperand(), false); + } + else + { + return i; + } + } + else if (auto* l = dyn_cast(ii)) + { + return getRoot(l->getPointerOperand(), false); + } + else + { + return i; + } + } + + return i; +} + +CollectorPic32::CollectorPic32( + const Abi* abi, + llvm::Module* m, + const ReachingDefinitionsAnalysis* rda) : + Collector(abi, m, rda) +{ +} + +CollectorPic32::~CollectorPic32() +{ +} + +void CollectorPic32::collectCallSpecificTypes(CallEntry* ce) const +{ + Collector::collectCallSpecificTypes(ce); + + std::vector argTypes; + for (auto t : ce->argTypes()) + { + if (t->isDoubleTy()) + { + argTypes.push_back(Type::getFloatTy(_module->getContext())); + } + else + { + argTypes.push_back(t); + } + } + + ce->setArgTypes(std::move(argTypes)); +} + +// +//============================================================================= +// CollectorProvider +//============================================================================= +// + +Collector::Ptr CollectorProvider::createCollector( + const Abi* abi, + Module* m, + const ReachingDefinitionsAnalysis* rda) +{ + if (abi->isPic32()) + { + return std::make_unique(abi, m, rda); + } + + return std::make_unique(abi, m, rda); +} + +} +} From d3870341a71b4a3449ce112f97cd3d40f04765d1 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:36:27 +0100 Subject: [PATCH 131/159] data_entries: new class Provides important objects needed for parameter analysis. --- .../optimizations/param_return/data_entries.h | 185 ++++++++ src/bin2llvmir/CMakeLists.txt | 1 + .../param_return/data_entries.cpp | 449 ++++++++++++++++++ 3 files changed, 635 insertions(+) create mode 100644 include/retdec/bin2llvmir/optimizations/param_return/data_entries.h create mode 100644 src/bin2llvmir/optimizations/param_return/data_entries.cpp diff --git a/include/retdec/bin2llvmir/optimizations/param_return/data_entries.h b/include/retdec/bin2llvmir/optimizations/param_return/data_entries.h new file mode 100644 index 000000000..c59e93272 --- /dev/null +++ b/include/retdec/bin2llvmir/optimizations/param_return/data_entries.h @@ -0,0 +1,185 @@ +/** +* @file include/retdec/bin2llvmir/optimizations/param_return/data_entries.h +* @brief Data entries for parameter analysis. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_DATA_ENTRIES_H +#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_DATA_ENTRIES_H + +#include + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +#include +#include + +namespace retdec { +namespace bin2llvmir { + +class ReturnEntry +{ + public: + ReturnEntry(llvm::ReturnInst* r); + + public: + void addRetStore(llvm::StoreInst* st); + + void setRetStores(std::vector&& stores); + void setRetStores(const std::vector& stores); + void setRetValues(std::vector&& values); + + void setRetValues(const std::vector& values); + + public: + llvm::ReturnInst* getRetInstruction() const; + + const std::vector& retStores() const; + const std::vector& retValues() const; + + + protected: + llvm::ReturnInst* _retInst = nullptr; + + std::vector _retStores; + std::vector _retValues; +}; + +class CallableEntry +{ + public: + bool isVoidarg() const; + + void addArg(llvm::Value* arg); + + void setVoidarg(bool voidarg = true); + void setArgTypes( + std::vector&& types, + std::vector&& names = {}); + + public: + const std::vector& args() const; + const std::vector& argTypes() const; + const std::vector& argNames() const; + + protected: + std::vector _args; + std::vector _argTypes; + std::vector _argNames; + + protected: + bool _voidarg = false; +}; + +class FunctionEntry : public CallableEntry +{ + public: + bool isVariadic() const; + bool isWrapper() const; + + public: + void addRetEntry(const ReturnEntry& ret); + ReturnEntry* createRetEntry(llvm::ReturnInst* ret); + + void setArgs(std::vector&& args); + void setVariadic(bool variadic = true); + void setWrappedCall(llvm::CallInst* wrap); + void setRetType(llvm::Type* type); + void setRetValue(llvm::Value* val); + void setCallingConvention(const CallingConvention::ID& cc); + + public: + llvm::Value* getRetValue() const; + llvm::Type* getRetType() const; + llvm::CallInst* getWrappedCall() const; + CallingConvention::ID getCallingConvention() const; + + const std::vector& retEntries() const; + std::vector& retEntries(); + + private: + llvm::CallInst* _wrap = nullptr; + llvm::Type* _retType = nullptr; + llvm::Value* _retVal = nullptr; + bool _variadic = false; + CallingConvention::ID _callconv = CallingConvention::ID::CC_UNKNOWN; + + std::vector _retEntries; +}; + +class CallEntry : public CallableEntry +{ + // Constructor. + // + public: + CallEntry( + llvm::CallInst* call, + const FunctionEntry* base = nullptr); + + // Usage data. + // + public: + void addRetLoad(llvm::LoadInst* load); + + void setFormatString(const std::string& fmt); + void setArgStores(std::vector&& stores); + void setArgs(std::vector&& args); + void setRetLoads(std::vector&& loads); + void setRetValues(std::vector&& values); + + llvm::CallInst* getCallInstruction() const; + const FunctionEntry* getBaseFunction() const; + std::string getFormatString() const; + + public: + const std::vector& argStores() const; + const std::vector& retValues() const; + const std::vector& retLoads() const; + + private: + const FunctionEntry* _baseFunction; + + llvm::CallInst* _callInst = nullptr; + std::string _fmtStr = ""; + + std::vector _retLoads; + std::vector _retValues; + std::vector _argStores; +}; + +class DataFlowEntry : public FunctionEntry +{ + // Constructor + // + public: + DataFlowEntry(llvm::Value* called); + + // Type information + // + public: + bool isFunction() const; + bool isValue() const; + bool hasDefinition() const; + + llvm::Function* getFunction() const; + llvm::Value* getValue() const; + + void setCalledValue(llvm::Value* called); + + // Usage data. + // + public: + CallEntry* createCallEntry(llvm::CallInst *call); + const std::vector& callEntries() const; + std::vector& callEntries(); + + private: + llvm::Value* _calledValue = nullptr; + + std::vector _calls; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index f11e6fe03..48d7d8c37 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -50,6 +50,7 @@ set(BIN2LLVMIR_SOURCES optimizations/main_detection/main_detection.cpp optimizations/param_return/collector/collector.cpp optimizations/param_return/param_return.cpp + optimizations/param_return/data_entries.cpp optimizations/phi2seq/phi2seq.cpp optimizations/provider_init/provider_init.cpp optimizations/x86_addr_spaces/x86_addr_spaces_pass.cpp diff --git a/src/bin2llvmir/optimizations/param_return/data_entries.cpp b/src/bin2llvmir/optimizations/param_return/data_entries.cpp new file mode 100644 index 000000000..c64a8b076 --- /dev/null +++ b/src/bin2llvmir/optimizations/param_return/data_entries.cpp @@ -0,0 +1,449 @@ +/** +* @file src/bin2llvmir/optimizations/param_return/data_entries.cpp +* @brief Data entries for parameter analysis. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#include + +#include "retdec/bin2llvmir/optimizations/param_return/data_entries.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================= +// ReturnEntry +//============================================================================= +// + +ReturnEntry::ReturnEntry(ReturnInst* r) : + _retInst(r) +{ +} + +void ReturnEntry::addRetStore(StoreInst* st) +{ + _retStores.push_back(st); + + if (std::find( + _retValues.begin(), + _retValues.end(), + st->getPointerOperand()) != _retValues.end()) + { + _retValues.push_back(st->getPointerOperand()); + } +} + +void ReturnEntry::setRetStores(std::vector&& stores) +{ + _retStores = std::move(stores); + + std::set vals; + for (auto& i: _retStores) + { + vals.insert(i->getPointerOperand()); + } + + _retValues = std::vector( + std::make_move_iterator(vals.begin()), + std::make_move_iterator(vals.end())); +} + +void ReturnEntry::setRetStores(const std::vector& stores) +{ + _retStores = stores; + + std::set vals; + for (auto& i: _retStores) + { + vals.insert(i->getPointerOperand()); + } + + _retValues = std::vector( + std::make_move_iterator(vals.begin()), + std::make_move_iterator(vals.end())); +} + +void ReturnEntry::setRetValues(std::vector&& values) +{ + _retStores.erase(std::remove_if( + _retStores.begin(), + _retStores.end(), + [values](llvm::StoreInst* st) + { + auto* op = st->getPointerOperand(); + return std::find( + values.begin(), + values.end(), op) == values.end(); + }), + _retStores.end()); + + _retValues = std::move(values); +} + +void ReturnEntry::setRetValues(const std::vector& values) +{ + _retStores.erase(std::remove_if( + _retStores.begin(), + _retStores.end(), + [values](llvm::StoreInst* st) + { + auto* op = st->getPointerOperand(); + return std::find( + values.begin(), + values.end(), op) == values.end(); + }), + _retStores.end()); + + _retValues = values; +} + +ReturnInst* ReturnEntry::getRetInstruction() const +{ + return _retInst; +} + +const std::vector& ReturnEntry::retStores() const +{ + return _retStores; +} + +const std::vector& ReturnEntry::retValues() const +{ + return _retValues; +} + +// +//============================================================================= +// CallableEntry +//============================================================================= +// + +bool CallableEntry::isVoidarg() const +{ + return _voidarg; +} + +void CallableEntry::addArg(Value* arg) +{ + _args.push_back(arg); +} + +void CallableEntry::setVoidarg(bool voidarg) +{ + _voidarg = voidarg; +} + +void CallableEntry::setArgTypes( + std::vector&& types, + std::vector&& names) +{ + _argTypes = std::move(types); + _argNames = std::move(names); + + if (_argTypes.size() > _argNames.size()) + { + _argNames.resize(_argTypes.size(), ""); + } + else if (_argTypes.size() < _argNames.size()) + { + _argTypes.resize(_argNames.size(), nullptr); + } + + if (_argTypes.empty()) + { + setVoidarg(); + } +} + +const std::vector& CallableEntry::args() const +{ + return _args; +} + +const std::vector& CallableEntry::argTypes() const +{ + return _argTypes; +} + +const std::vector& CallableEntry::argNames() const +{ + return _argNames; +} + +// +//============================================================================= +// FunctionEntry +//============================================================================= +// + +bool FunctionEntry::isVariadic() const +{ + return _variadic; +} + +bool FunctionEntry::isWrapper() const +{ + return _wrap != nullptr; +} + +void FunctionEntry::addRetEntry(const ReturnEntry& ret) +{ + _retEntries.push_back(ret); +} + +ReturnEntry* FunctionEntry::createRetEntry(llvm::ReturnInst* ret) +{ + _retEntries.push_back(ReturnEntry(ret)); + + return &(_retEntries.back()); +} + +void FunctionEntry::setVariadic(bool variadic) +{ + _variadic = variadic; +} + +void FunctionEntry::setArgs(std::vector&& args) +{ + _args = std::move(args); +} + +void FunctionEntry::setWrappedCall(llvm::CallInst* wrap) +{ + _wrap = wrap; +} + +void FunctionEntry::setRetType(llvm::Type* type) +{ + _retType = type; +} + +void FunctionEntry::setRetValue(llvm::Value* val) +{ + _retVal = val; +} + +void FunctionEntry::setCallingConvention(const CallingConvention::ID& cc) +{ + if (cc == CallingConvention::ID::CC_VOIDARG) + { + setVoidarg(); + } + else + { + _callconv = cc; + } +} + +llvm::Type* FunctionEntry::getRetType() const +{ + return _retType; +} + +llvm::Value* FunctionEntry::getRetValue() const +{ + return _retVal; +} + +llvm::CallInst* FunctionEntry::getWrappedCall() const +{ + return _wrap; +} + +CallingConvention::ID FunctionEntry::getCallingConvention() const +{ + return _callconv; +} + +const std::vector& FunctionEntry::retEntries() const +{ + return _retEntries; +} + +std::vector& FunctionEntry::retEntries() +{ + return _retEntries; +} + +// +//============================================================================= +// CallEntry +//============================================================================= +// + +CallEntry::CallEntry(CallInst* call, const FunctionEntry* base) : + _baseFunction(base), + _callInst(call) +{ +} + +void CallEntry::addRetLoad(LoadInst* load) +{ + _retLoads.push_back(load); + _retValues.push_back(load->getPointerOperand()); + + // TODO duplicity and pointer operand? +} + +void CallEntry::setFormatString(const std::string &fmt) +{ + _fmtStr = fmt; +} + +void CallEntry::setArgStores(std::vector&& stores) +{ + _argStores = std::move(stores); + + std::set vals; + for (auto& i : _argStores) + { + vals.insert(i->getPointerOperand()); + } + + _args.assign( + std::make_move_iterator(vals.begin()), + std::make_move_iterator(vals.end())); +} + +void CallEntry::setArgs(std::vector&& args) +{ + _argStores.erase( + std::remove_if( + _argStores.begin(), + _argStores.end(), + [args](llvm::StoreInst* st) + { + auto* op = st->getPointerOperand(); + return std::find( + args.begin(), + args.end(), op) == args.end(); + }), + _argStores.end()); + + _args = std::move(args); +} + +void CallEntry::setRetLoads(std::vector&& loads) +{ + _retLoads = std::move(loads); + + std::set vals; + for (auto& i: _retLoads) + { + vals.insert(i->getPointerOperand()); + } + _retValues = std::vector( + std::make_move_iterator(vals.begin()), + std::make_move_iterator(vals.end())); +} + +void CallEntry::setRetValues(std::vector&& values) +{ + _retLoads.erase(std::remove_if( + _retLoads.begin(), + _retLoads.end(), + [values](llvm::LoadInst* st) + { + auto* op = st->getPointerOperand(); + return std::find( + values.begin(), + values.end(), op) == values.end(); + }), + _retLoads.end()); + + _retValues = std::move(values); +} + +CallInst* CallEntry::getCallInstruction() const +{ + return _callInst; +} + +const FunctionEntry* CallEntry::getBaseFunction() const +{ + return _baseFunction; +} + +std::string CallEntry::getFormatString() const +{ + return _fmtStr; +} + +const std::vector& CallEntry::argStores() const +{ + return _argStores; +} + +const std::vector& CallEntry::retValues() const +{ + return _retValues; +} + +const std::vector& CallEntry::retLoads() const +{ + return _retLoads; +} + +// +//============================================================================= +// DataFlowEntry +//============================================================================= +// + +DataFlowEntry::DataFlowEntry(Value* called): + _calledValue(called) +{ +} + +bool DataFlowEntry::isFunction() const +{ + return getFunction() != nullptr; +} + +bool DataFlowEntry::isValue() const +{ + return _calledValue && !isFunction(); +} + +bool DataFlowEntry::hasDefinition() const +{ + return isFunction() && !getFunction()->empty(); +} + +Function* DataFlowEntry::getFunction() const +{ + return dyn_cast_or_null(_calledValue); +} + +Value* DataFlowEntry::getValue() const +{ + return _calledValue; +} + +void DataFlowEntry::setCalledValue(llvm::Value* called) +{ + _calledValue = called; +} + +CallEntry* DataFlowEntry::createCallEntry(CallInst* call) +{ + _calls.push_back(CallEntry(call, this)); + return &(_calls.back()); +} + +const std::vector& DataFlowEntry::callEntries() const +{ + return _calls; +} + +std::vector& DataFlowEntry::callEntries() +{ + return _calls; +} + +} +} From cae1ee1919839c9856f3e2f67a6a7222c8515307 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:37:51 +0100 Subject: [PATCH 132/159] filter: new class --- .../param_return/filter/filter.h | 199 +++ src/bin2llvmir/CMakeLists.txt | 1 + .../param_return/filter/filter.cpp | 1323 +++++++++++++++++ 3 files changed, 1523 insertions(+) create mode 100644 include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h create mode 100644 src/bin2llvmir/optimizations/param_return/filter/filter.cpp diff --git a/include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h b/include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h new file mode 100644 index 000000000..3dc28ab1c --- /dev/null +++ b/include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h @@ -0,0 +1,199 @@ +/** +* @file include/retdec/bin2llvmir/optimizations/param_return/filter.h +* @brief Filters potentail values according to calling convention. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_FILTER_FILTER_H +#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_FILTER_FILTER_H + +#include + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" +#include "retdec/bin2llvmir/optimizations/param_return/collector/collector.h" +#include "retdec/bin2llvmir/optimizations/param_return/data_entries.h" + +namespace retdec { +namespace bin2llvmir { + +class FilterableLayout +{ + public: + enum class Order { + ORD_GPR, + ORD_GPR_GROUP, + ORD_FPR, + ORD_FPR_GROUP, + ORD_DOUBR, + ORD_DOUBR_GROUP, + ORD_VECR, + ORD_VECR_GROUP, + ORD_STACK, + ORD_STACK_GROUP + }; + + public: + std::vector gpRegisters; + std::vector fpRegisters; + std::vector doubleRegisters; + std::vector vectorRegisters; + std::vector stacks; + std::vector knownTypes; + std::vector knownOrder; +}; + +typedef FilterableLayout::Order OrderID; + +class Filter +{ + public: + typedef std::unique_ptr Ptr; + + public: + Filter(const Abi* _abi, const CallingConvention* _cc); + virtual ~Filter(); + + void filterDefinition(DataFlowEntry* de) const; + void filterCalls(DataFlowEntry* de) const; + void filterCallsVariadic( + DataFlowEntry* de, + const Collector* collector) const; + + void estimateRetValue(DataFlowEntry* de) const; + + protected: + virtual void filterDefinitionArgs( + FilterableLayout& args, + bool isVoidarg) const; + + virtual void filterCallArgs( + FilterableLayout& args, + bool isVoidarg) const; + + virtual void filterCallArgsByDefLayout( + FilterableLayout& args, + const FilterableLayout& def) const; + + virtual void filterRets( + FilterableLayout& rets) const; + + virtual void filterRetsByDefLayout( + FilterableLayout& args, + const FilterableLayout& def) const; + + virtual void filterArgsByKnownTypes(FilterableLayout& lay) const; + virtual void filterRetsByKnownTypes(FilterableLayout& lay) const; + + protected: + void leaveCommonArgs( + std::vector& allArgs) const; + + void leaveCommonRets( + std::vector& allRets) const; + + void leaveCommon( + std::vector& allRets) const; + + void orderFiterableLayout(FilterableLayout& lay) const; + + void orderStacks( + std::vector& stacks, + bool asc = true) const; + + void orderRegistersBy( + std::vector& regs, + const std::vector& orderedVector) const; + + protected: + FilterableLayout createArgsFilterableLayout( + const std::vector& group, + const std::vector& knownTypes) const; + + FilterableLayout createRetsFilterableLayout( + const std::vector& group, + llvm::Type* knownType) const; + + FilterableLayout createRetsFilterableLayout( + const std::vector& group, + const std::vector& knownTypes) const; + + virtual FilterableLayout separateArgValues( + const std::vector& paramValues) const; + + virtual FilterableLayout separateRetValues( + const std::vector& paramValues) const; + + virtual std::vector createGroupedArgValues( + const FilterableLayout& lay) const; + + virtual std::vector createGroupedRetValues( + const FilterableLayout& lay) const; + + FilterableLayout separateValues( + const std::vector& paramValues, + const std::vector& gpRegs, + const std::vector& fpRegs, + const std::vector& doubleRegs, + const std::vector& vecRegs) const; + + std::vector createGroupedValues( + const FilterableLayout& lay) const; + + std::vector expandTypes( + const std::vector& types) const; + + protected: + std::size_t fetchGPRegsForType( + llvm::Type* type, + FilterableLayout& lay) const; + + std::size_t fetchFPRegsForType( + llvm::Type* type, + FilterableLayout& lay) const; + + std::size_t fetchDoubleRegsForType( + llvm::Type* type, + FilterableLayout& lay) const; + + std::size_t fetchVecRegsForType( + llvm::Type* type, + FilterableLayout& lay) const; + + std::size_t fetchRegsForType( + llvm::Type* type, + std::vector& store, + const std::vector& regs, + std::size_t maxRegsPerObject) const; + + protected: + std::size_t getNumberOfStacksForType(llvm::Type* type) const; + + protected: + void leaveOnlyPositiveStacks(FilterableLayout& lay) const; + void leaveOnlyContinuousStack(FilterableLayout& lay) const; + void leaveOnlyContinuousArgRegisters(FilterableLayout& lay) const; + void leaveOnlyContinuousRetRegisters(FilterableLayout& lay) const; + void leaveSameStacks(FilterableLayout& lay, const FilterableLayout& fig) const; + + void leaveOnlyContinuousRegisters( + std::vector& regs, + const std::vector& templRegs) const; + + void createContinuousArgRegisters(FilterableLayout& lay) const; + + protected: + const Abi* _abi; + const CallingConvention* _cc; +}; + +class FilterProvider +{ + public: + static Filter::Ptr createFilter(Abi* abi, const CallingConvention::ID& id); +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 48d7d8c37..0c363b156 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -49,6 +49,7 @@ set(BIN2LLVMIR_SOURCES optimizations/local_vars/local_vars.cpp optimizations/main_detection/main_detection.cpp optimizations/param_return/collector/collector.cpp + optimizations/param_return/filter/filter.cpp optimizations/param_return/param_return.cpp optimizations/param_return/data_entries.cpp optimizations/phi2seq/phi2seq.cpp diff --git a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp new file mode 100644 index 000000000..fcadb20a0 --- /dev/null +++ b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp @@ -0,0 +1,1323 @@ +/** +* @file src/bin2llvmir/optimizations/param_return/filter.cpp +* @brief Filters potentail values according to calling convention. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#include + +#include "retdec/bin2llvmir/optimizations/param_return/filter/filter.h" + +using namespace retdec::utils; +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================= +// Filter +//============================================================================= +// + +Filter::Filter( + const Abi* abi, + const CallingConvention* cc) : + _abi(abi), + _cc(cc) +{ +} + +Filter::~Filter() +{ +} + +void Filter::estimateRetValue(DataFlowEntry* de) const +{ + auto retValue = de->getRetValue(); + auto retType = de->getRetType(); + + if (retType == nullptr) + { + if (!de->retEntries().empty() + && !de->retEntries().front().retValues().empty()) + { + retType = de->retEntries().front().retValues().front()->getType(); + if (auto* p = dyn_cast(retType)) + { + retType = p->getElementType(); + } + retValue = de->retEntries().front().retValues().front(); + } + else + { + // This is hack -> retdec expects generation of + // implicit return for every funtion definition + // but not external calls. + // + // In fact this should return void type here. + // This is why retType is not set to any type. + if (!_cc->getReturnRegisters().empty()) + { + retValue = _abi->getRegister(_cc->getReturnRegisters().front()); + } + } + } + else + { +// TODO: double-read-modf.x86.clang-3.2.O0.g.elf +// if (!de->retEntries().empty() +// && !de->retEntries().front().retValues().empty()) +// { +// retValue = de->retEntries().front().retValues().front(); +// } +// else + { + if (!_cc->getReturnRegisters().empty()) + { + retValue = _abi->getRegister(_cc->getReturnRegisters().front()); + } + + if (retType->isFloatingPointTy() && !_cc->getReturnFPRegisters().empty()) + { + retValue = _abi->getRegister(_cc->getReturnFPRegisters().front()); + } + + if (retType->isDoubleTy() && !_cc->getReturnDoubleRegisters().empty()) + { + retValue = _abi->getRegister(_cc->getReturnDoubleRegisters().front()); + } + } + } + + de->setRetType(retType); + de->setRetValue(retValue); +} + +void Filter::filterDefinition(DataFlowEntry* de) const +{ + if (!de->hasDefinition()) + { + return; + } + + FilterableLayout defArgs = createArgsFilterableLayout(de->args(), de->argTypes()); + filterDefinitionArgs(defArgs, de->isVoidarg()); + + de->setArgs(createGroupedArgValues(defArgs)); + + if (de->retEntries().empty()) + { + return; + } + + std::vector defRets; + for (auto& ret : de->retEntries()) + { + defRets.push_back( + createRetsFilterableLayout(ret.retValues(), de->getRetType())); + } + + leaveCommonRets(defRets); + filterRets(defRets.front()); + + FilterableLayout retTempl = defRets.front(); + + for (auto& ret : de->retEntries()) + { + filterRetsByDefLayout(defRets.front(), retTempl); + ret.setRetValues(createGroupedValues(defRets.front())); + + defRets.erase(defRets.begin()); + } +} + +void Filter::filterCalls(DataFlowEntry* de) const +{ + if (de->callEntries().empty()) + { + return; + } + + std::vector callArgs, callArgsCopy; + std::vector callRets; + + for (auto& call : de->callEntries()) + { + callArgs.push_back( + createArgsFilterableLayout(call.args(), de->argTypes())); + callRets.push_back( + createRetsFilterableLayout( + call.retValues(), + de->getRetType())); + } + + callArgsCopy = callArgs; + + FilterableLayout retTempl, argTempl; + + if (!callArgs.empty()) + { + if (!de->isVoidarg() && de->argTypes().empty()) + { + leaveCommonArgs(callArgs); + } + filterCallArgs(callArgs.front(), de->isVoidarg()); + argTempl = callArgs.front(); + } + + if (!callRets.empty()) + { + leaveCommonRets(callRets); + filterRets(callRets.front()); + retTempl = callRets.front(); + } + + if (de->hasDefinition()) + { + FilterableLayout defArgs; + defArgs = createArgsFilterableLayout( + de->args(), + de->argTypes()); + if (!de->isVoidarg() && !de->argTypes().empty()) + { + // We need order + filterArgsByKnownTypes(defArgs); + } + else if (de->args().empty()) + { + filterCallArgsByDefLayout(defArgs, argTempl); + de->setArgs(createGroupedArgValues(defArgs)); + } + else if (argTempl.stacks.size() > defArgs.stacks.size()) + { + if (argTempl.gpRegisters.size() == defArgs.gpRegisters.size() + && argTempl.fpRegisters.size() == defArgs.fpRegisters.size() + && argTempl.doubleRegisters.size() == defArgs.doubleRegisters.size() + && argTempl.vectorRegisters.size() == defArgs.vectorRegisters.size()) + { + leaveSameStacks(defArgs, argTempl); + de->setArgs(createGroupedArgValues(defArgs)); + } + } + + if (!de->retEntries().empty()) + { + retTempl = createRetsFilterableLayout( + de->retEntries().front().retValues(), + de->getRetType()); + } + + argTempl = std::move(defArgs); + } + + for (auto& call : de->callEntries()) + { + filterCallArgsByDefLayout(callArgsCopy.front(), argTempl); + filterRetsByDefLayout(callRets.front(), retTempl); + + call.setArgs(createGroupedArgValues(callArgsCopy.front())); + call.setRetValues(createGroupedRetValues(callRets.front())); + + callArgsCopy.erase(callArgsCopy.begin()); + callRets.erase(callRets.begin()); + } +} + +void Filter::filterCallsVariadic(DataFlowEntry* de, const Collector* collector) const +{ + if (de->callEntries().empty()) + { + return; + } + + std::vector callArgs; + std::vector callRets; + + for (auto& call : de->callEntries()) + { + auto argTypes = de->argTypes(); + + FilterableLayout argLayout = createArgsFilterableLayout(call.args(), {}); + + // To collect specific types, we need ordered values. + // Collector will find first occourence of string and parse it. + call.setArgs(createGroupedArgValues(argLayout)); + collector->collectCallSpecificTypes(&call); + + argTypes.insert( + argTypes.end(), + call.argTypes().begin(), + call.argTypes().end()); + + argLayout.knownTypes = std::move(argTypes); + + callArgs.push_back(argLayout); + callRets.push_back( + createRetsFilterableLayout( + call.retValues(), + call.getBaseFunction()->getRetType())); + } + + FilterableLayout retTempl; + + if (de->hasDefinition() && !de->retEntries().empty()) + { + retTempl = createRetsFilterableLayout( + de->retEntries().front().retValues(), + de->getRetType()); + } + else if (!callRets.empty()) + { + leaveCommonRets(callRets); + filterRets(callRets.front()); + retTempl = callRets.front(); + } + + for (auto& call : de->callEntries()) + { + filterCallArgs(callArgs.front(), de->isVoidarg() && !call.argTypes().empty()); + filterRetsByDefLayout(callRets.front(), retTempl); + + call.setArgs(createGroupedArgValues(callArgs.front())); + call.setRetValues(createGroupedRetValues(callRets.front())); + + callArgs.erase(callArgs.begin()); + callRets.erase(callRets.begin()); + } +} + +void Filter::filterDefinitionArgs(FilterableLayout& args, bool isVoidarg) const +{ + leaveOnlyPositiveStacks(args); + + if (isVoidarg) + { + args.gpRegisters.clear(); + args.fpRegisters.clear(); + args.doubleRegisters.clear(); + args.vectorRegisters.clear(); + args.stacks.clear(); + } + else if (!args.knownTypes.empty()) + { + filterArgsByKnownTypes(args); + } + else + { + createContinuousArgRegisters(args); + } + + leaveOnlyContinuousStack(args); +} + +void Filter::filterCallArgs(FilterableLayout& args, bool isVoidarg) const +{ + if (isVoidarg) + { + args.gpRegisters.clear(); + args.fpRegisters.clear(); + args.doubleRegisters.clear(); + args.vectorRegisters.clear(); + args.stacks.clear(); + } + else if (!args.knownTypes.empty()) + { + filterArgsByKnownTypes(args); + } + else + { + leaveOnlyContinuousArgRegisters(args); + } + + leaveOnlyContinuousStack(args); +} + +void Filter::filterCallArgsByDefLayout( + FilterableLayout& args, + const FilterableLayout& defArgs) const +{ + args.gpRegisters = std::vector(defArgs.gpRegisters); + args.fpRegisters = std::vector(defArgs.fpRegisters); + args.doubleRegisters = std::vector(defArgs.doubleRegisters); + args.vectorRegisters = std::vector(defArgs.vectorRegisters); + args.knownOrder = defArgs.knownOrder; + + leaveOnlyContinuousStack(args); + leaveSameStacks(args, defArgs); +} + +void Filter::filterRets(FilterableLayout& rets) const +{ + if (!rets.knownTypes.empty() && rets.knownTypes.front()) + { + filterRetsByKnownTypes(rets); + } + else + { + leaveOnlyContinuousRetRegisters(rets); + } +} + +void Filter::filterRetsByDefLayout( + FilterableLayout& rets, + const FilterableLayout& defRets) const +{ + rets.gpRegisters = std::vector(defRets.gpRegisters); + rets.fpRegisters = std::vector(defRets.fpRegisters); + rets.doubleRegisters = std::vector(defRets.doubleRegisters); + rets.vectorRegisters = std::vector(defRets.vectorRegisters); + rets.knownOrder = defRets.knownOrder; + + leaveOnlyContinuousStack(rets); + leaveSameStacks(rets, defRets); +} + +void Filter::filterArgsByKnownTypes(FilterableLayout& lay) const +{ + FilterableLayout newLayout; + auto& gpRegs = _cc->getParamRegisters(); + auto& fpRegs = _cc->getParamFPRegisters(); + auto& doubleRegs = _cc->getParamDoubleRegisters(); + auto& vecRegs = _cc->getParamVectorRegisters(); + + // Indexes of registers to be used next as particular parameter. + auto sIt = lay.stacks.begin(); + + std::size_t gpEnd = gpRegs.size(); + std::size_t fpEnd = fpRegs.size(); + std::size_t doubleEnd = doubleRegs.size(); + std::size_t vecEnd = vecRegs.size(); + + std::vector types = expandTypes(lay.knownTypes); + + for (auto t: types) + { + std::size_t requiredStacks = 0; + OrderID stackOrd = OrderID::ORD_STACK; + + if (!doubleRegs.empty() && t->isDoubleTy()) + { + if (newLayout.doubleRegisters.size() < doubleEnd) + { + requiredStacks = fetchDoubleRegsForType(t, newLayout); + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + else if (!fpRegs.empty() && t->isFloatingPointTy()) + { + if (newLayout.fpRegisters.size() < fpEnd) + { + requiredStacks = fetchFPRegsForType(t, newLayout); + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + else if (!vecRegs.empty() && t->isVectorTy()) + { + if (newLayout.vectorRegisters.size() < vecEnd) + { + requiredStacks = fetchVecRegsForType(t, newLayout); + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + else if (!gpRegs.empty()) + { + if (newLayout.gpRegisters.size() < gpEnd) + { + requiredStacks = fetchGPRegsForType(t, newLayout); + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + + + if (!requiredStacks && stackOrd == OrderID::ORD_STACK) + { + requiredStacks = getNumberOfStacksForType(t); + } + + for (std::size_t i = 0; i < requiredStacks; i++) + { + if (sIt != lay.stacks.end()) + { + newLayout.stacks.push_back(*sIt); + sIt++; + } + else + { + newLayout.stacks.push_back(nullptr); + } + + newLayout.knownOrder.push_back( + i == 0 ? stackOrd : + OrderID::ORD_STACK_GROUP); + } + } + + lay = newLayout; +} + +std::vector Filter::expandTypes(const std::vector& types) const +{ + if (_cc->passesLargeObjectsByReference()) + { + return types; + } + else + { + std::vector expanded; + + std::deque toExpand( + types.begin(), + types.end()); + + while (!toExpand.empty()) + { + auto t = toExpand.front(); + toExpand.pop_front(); + + if (auto* st = dyn_cast(t)) + { + for (auto& e : st->elements()) + { + toExpand.push_back(e); + } + } + else + { + expanded.push_back(t); + } + } + + return expanded; + } +} + +size_t Filter::fetchGPRegsForType(Type* type, FilterableLayout& lay) const +{ + std::size_t sizeBefore = lay.gpRegisters.size(); + std::size_t reqStacks = fetchRegsForType( + type, + lay.gpRegisters, + _cc->getParamRegisters(), + _cc->getMaxNumOfRegsPerParam()); + + std::size_t change = lay.gpRegisters.size() - sizeBefore; + if (change) + { + lay.knownOrder.push_back(OrderID::ORD_GPR); + lay.knownOrder.resize( + lay.knownOrder.size() + change - 1, OrderID::ORD_GPR_GROUP); + } + + return reqStacks; +} + +size_t Filter::fetchFPRegsForType(Type* type, FilterableLayout& lay) const +{ + std::size_t sizeBefore = lay.fpRegisters.size(); + std::size_t reqStacks = fetchRegsForType( + type, + lay.fpRegisters, + _cc->getParamFPRegisters(), + _cc->getMaxNumOfFPRegsPerParam()); + + std::size_t change = lay.fpRegisters.size() - sizeBefore; + if (change) + { + lay.knownOrder.push_back(OrderID::ORD_FPR); + lay.knownOrder.resize( + lay.knownOrder.size() + change - 1, OrderID::ORD_FPR_GROUP); + } + + return reqStacks; +} + +size_t Filter::fetchDoubleRegsForType(Type* type, FilterableLayout& lay) const +{ + std::size_t sizeBefore = lay.doubleRegisters.size(); + std::size_t reqStacks = fetchRegsForType( + type, + lay.doubleRegisters, + _cc->getParamDoubleRegisters(), + _cc->getMaxNumOfDoubleRegsPerParam()); + + std::size_t change = lay.doubleRegisters.size() - sizeBefore; + if (change) + { + lay.knownOrder.push_back(OrderID::ORD_DOUBR); + lay.knownOrder.resize( + lay.knownOrder.size() + change - 1, OrderID::ORD_DOUBR_GROUP); + } + + return reqStacks; +} + +size_t Filter::fetchVecRegsForType(Type* type, FilterableLayout& lay) const +{ + std::size_t sizeBefore = lay.vectorRegisters.size(); + std::size_t reqStacks = fetchRegsForType( + type, + lay.vectorRegisters, + _cc->getParamVectorRegisters(), + _cc->getMaxNumOfVectorRegsPerParam()); + + std::size_t change = lay.vectorRegisters.size() - sizeBefore; + if (change) + { + lay.knownOrder.push_back(OrderID::ORD_VECR); + lay.knownOrder.resize( + lay.knownOrder.size() + change - 1, OrderID::ORD_VECR_GROUP); + } + + return reqStacks; +} + +size_t Filter::fetchRegsForType( + Type* type, + std::vector& store, + const std::vector& regs, + std::size_t maxRegsPerObject) const +{ + if (regs.empty()) + { + return getNumberOfStacksForType(type); + } + + Type* registerType = _abi->getRegister(regs.front())->getType(); + std::size_t registerSize = _abi->getTypeByteSize(registerType); + std::size_t typeSize = type->isVoidTy() ? + _abi->getWordSize() : _abi->getTypeByteSize(type); + + if (typeSize <= registerSize) + { + if (regs.size() <= store.size()) + { + return getNumberOfStacksForType(registerType); + } + + auto reg = regs[store.size()]; + store.push_back(reg); + + return 0; + } + + if ((typeSize > registerSize) + && (typeSize <= registerSize*maxRegsPerObject)) + { + std::size_t numberOfRegs = typeSize / registerSize; + auto regIt = store.size(); + + if (_cc->respectsRegisterCouples()) + { + if ((regIt+1)%2 == 0) + { + regIt++; + } + } + + for (std::size_t i = 0; i < numberOfRegs; i++) + { + if (regs.size() <= regIt) + { + return getNumberOfStacksForType(registerType)*(numberOfRegs-i); + } + + auto reg = regs[regIt]; + store.push_back(reg); + regIt++; + } + + return 0; + } + + if (_cc->passesLargeObjectsByReference()) + { + if (regs.size() <= store.size()) + { + return getNumberOfStacksForType(registerType); + } + + auto reg = regs[store.size()]; + store.push_back(reg); + + return 0; + } + + return getNumberOfStacksForType(type); +} + +size_t Filter::getNumberOfStacksForType(Type* type) const +{ + auto maxBytesPerParam = _cc->getMaxBytesPerStackParam(); + + if (maxBytesPerParam == 0) + { + return 0; + } + + std::size_t num = _abi->getTypeByteSize(type) / maxBytesPerParam; + + return num < 1 ? 1 : num; +} + +void Filter::filterRetsByKnownTypes(FilterableLayout& lay) const +{ + std::vector regGPValues, regFPValues, regDoubleValues, regVecValues; + + auto& gpRegs = _cc->getReturnRegisters(); + auto& fpRegs = _cc->getReturnFPRegisters(); + auto& doubleRegs = _cc->getReturnDoubleRegisters(); + auto& vecRegs = _cc->getReturnVectorRegisters(); + + Type* retType = lay.knownTypes.empty() ? nullptr + : lay.knownTypes.front(); + + if (retType == nullptr) + { + return; + } + + if (retType->isVectorTy() && !vecRegs.empty()) + { + std::size_t typeSize = _abi->getTypeByteSize(retType); + Type* registerType = _abi->getRegister(vecRegs.front())->getType(); + std::size_t registerSize = _abi->getTypeByteSize(registerType); + + if (typeSize <= registerSize || + (typeSize > registerSize*vecRegs.size())) + { + regVecValues.push_back(vecRegs.front()); + } + + std::size_t numOfRegs = typeSize/registerSize; + for (std::size_t i = 0; i < numOfRegs && i < vecRegs.size(); i++) + { + regVecValues.push_back(vecRegs[i]); + } + } + else if (retType->isDoubleTy() && !doubleRegs.empty()) + { + std::size_t typeSize = _abi->getTypeByteSize(retType); + Type* registerType = _abi->getRegister(doubleRegs.front())->getType(); + std::size_t registerSize = _abi->getTypeByteSize(registerType); + + if (typeSize <= registerSize || + (typeSize > registerSize*doubleRegs.size())) + { + regDoubleValues.push_back(doubleRegs.front()); + } + + std::size_t numOfRegs = typeSize/registerSize; + for (std::size_t i = 0; i < numOfRegs && i < doubleRegs.size(); i++) + { + regDoubleValues.push_back(doubleRegs[i]); + } + } + else if (retType->isFloatingPointTy() && !fpRegs.empty()) + { + std::size_t typeSize = _abi->getTypeByteSize(retType); + Type* registerType = _abi->getRegister(fpRegs.front())->getType(); + std::size_t registerSize = _abi->getTypeByteSize(registerType); + + if (typeSize <= registerSize || + (typeSize > registerSize*fpRegs.size())) + { + regFPValues.push_back(fpRegs.front()); + } + + std::size_t numOfRegs = typeSize/registerSize; + for (std::size_t i = 0; i < numOfRegs && i < fpRegs.size(); i++) + { + regFPValues.push_back(fpRegs[i]); + } + } + else if (!retType->isVoidTy()) + { + assert(!gpRegs.empty()); + + std::size_t typeSize = _abi->getTypeByteSize(retType); + Type* registerType = _abi->getRegister(gpRegs.front())->getType(); + std::size_t registerSize = _abi->getTypeByteSize(registerType); + + if (typeSize <= registerSize || + (typeSize > registerSize*gpRegs.size())) + { + regGPValues.push_back(gpRegs.front()); + } + + std::size_t numOfRegs = typeSize/registerSize; + for (std::size_t i = 0; i < numOfRegs && i < gpRegs.size(); i++) + { + regGPValues.push_back(gpRegs[i]); + } + } + + lay.gpRegisters = std::move(regGPValues); + lay.fpRegisters = std::move(regFPValues); + lay.doubleRegisters = std::move(regDoubleValues); + lay.vectorRegisters = std::move(regVecValues); + lay.knownTypes = {retType}; +} + + +void Filter::leaveCommonArgs(std::vector& allArgs) const +{ + leaveCommon(allArgs); +} + +void Filter::leaveCommonRets(std::vector& allRets) const +{ + leaveCommon(allRets); +} + +void Filter::leaveCommon(std::vector& lays) const +{ + if (lays.empty()) + { + return; + } + + auto& firstGPR = lays.front().gpRegisters; + auto& firstFPR = lays.front().fpRegisters; + auto& firstDR = lays.front().doubleRegisters; + auto& firstVR = lays.front().vectorRegisters; + + std::set commonGPR(firstGPR.begin(), firstGPR.end()); + std::set commonFPR(firstFPR.begin(), firstFPR.end()); + std::set commonDR(firstDR.begin(), firstDR.end()); + std::set commonVR(firstVR.begin(), firstVR.end()); + + std::size_t minStacks = lays.front().stacks.size(); + + for (auto& lay : lays) + { + + auto& gpr = lay.gpRegisters; + auto& fpr = lay.fpRegisters; + auto& dr = lay.doubleRegisters; + auto& vr = lay.vectorRegisters; + + commonGPR.insert(gpr.begin(), gpr.end()); + commonFPR.insert(fpr.begin(), fpr.end()); + commonDR.insert(dr.begin(), dr.end()); + commonVR.insert(vr.begin(), vr.end()); + + // if (lay.stacks.empty()) + // { + // continue; + // } + // else if (!minStacks || (minStacks > lay.stacks.size())) + if (minStacks > lay.stacks.size()) + { + minStacks = lay.stacks.size(); + } + } + + for (auto& lay : lays) + { + lay.gpRegisters.assign(commonGPR.begin(), commonGPR.end()); + lay.fpRegisters.assign(commonFPR.begin(), commonFPR.end()); + lay.doubleRegisters.assign(commonDR.begin(), commonDR.end()); + lay.vectorRegisters.assign(commonVR.begin(), commonVR.end()); + lay.stacks.resize(minStacks, nullptr); + + // TODO: move commons to layout and order just it. + orderFiterableLayout(lay); + } +} + +void Filter::orderFiterableLayout(FilterableLayout& lay) const +{ + orderStacks(lay.stacks, _cc->getStackParamOrder()); + orderRegistersBy(lay.gpRegisters, _cc->getParamRegisters()); + orderRegistersBy(lay.fpRegisters, _cc->getParamFPRegisters()); + orderRegistersBy(lay.doubleRegisters, _cc->getParamDoubleRegisters()); + orderRegistersBy(lay.vectorRegisters, _cc->getParamVectorRegisters()); +} + +void Filter::orderStacks(std::vector& stacks, bool asc) const +{ + auto config = _abi->getConfig(); + + std::stable_sort( + stacks.begin(), + stacks.end(), + [config, asc](Value* a, Value* b) -> bool + { + auto aOff = config->getStackVariableOffset(a); + auto bOff = config->getStackVariableOffset(b); + + bool ascOrd = aOff < bOff; + + return asc ? ascOrd : !ascOrd; + }); +} + +void Filter::orderRegistersBy( + std::vector& regs, + const std::vector& orderedVector) const +{ + std::stable_sort( + regs.begin(), + regs.end(), + [orderedVector](uint32_t a, uint32_t b) -> bool + { + auto it1 = std::find(orderedVector.begin(), orderedVector.end(), a); + auto it2 = std::find(orderedVector.begin(), orderedVector.end(), b); + + return std::distance(it1, it2) > 0; + }); +} + +FilterableLayout Filter::createArgsFilterableLayout( + const std::vector& group, + const std::vector& knownTypes) const +{ + FilterableLayout layout = separateArgValues(group); + layout.knownTypes = knownTypes; + + orderFiterableLayout(layout); + + return layout; +} + +FilterableLayout Filter::createRetsFilterableLayout( + const std::vector& group, + Type* knownType) const +{ + std::vector knownTypes = {knownType}; + return createRetsFilterableLayout(group, knownTypes); +} + +FilterableLayout Filter::createRetsFilterableLayout( + const std::vector& group, + const std::vector& knownTypes) const +{ + FilterableLayout layout = separateRetValues(group); + layout.knownTypes = knownTypes; + + orderFiterableLayout(layout); + + return layout; +} + +FilterableLayout Filter::separateArgValues(const std::vector& paramValues) const +{ + auto& regs = _cc->getParamRegisters(); + auto& fpRegs = _cc->getParamFPRegisters(); + auto& doubleRegs = _cc->getParamDoubleRegisters(); + auto& vecRegs = _cc->getParamVectorRegisters(); + + return separateValues(paramValues, regs, fpRegs, doubleRegs, vecRegs); +} + +FilterableLayout Filter::separateRetValues(const std::vector& paramValues) const +{ + auto& regs = _cc->getReturnRegisters(); + auto& fpRegs = _cc->getReturnFPRegisters(); + auto& doubleRegs = _cc->getReturnDoubleRegisters(); + auto& vecRegs = _cc->getReturnVectorRegisters(); + + FilterableLayout lay = separateValues(paramValues, regs, fpRegs, doubleRegs, vecRegs); + lay.stacks.clear(); + + return lay; +} + +FilterableLayout Filter::separateValues( + const std::vector& paramValues, + const std::vector& gpRegs, + const std::vector& fpRegs, + const std::vector& doubleRegs, + const std::vector& vecRegs) const +{ + FilterableLayout layout; + + for (auto pv: paramValues) + { + if (_abi->isStackVariable(pv)) + { + layout.stacks.push_back(pv); + } + if (std::find(gpRegs.begin(), gpRegs.end(), + _abi->getRegisterId(pv)) != gpRegs.end()) + { + layout.gpRegisters.push_back(_abi->getRegisterId(pv)); + } + else if (std::find(doubleRegs.begin(), doubleRegs.end(), + _abi->getRegisterId(pv)) != doubleRegs.end()) + { + layout.doubleRegisters.push_back(_abi->getRegisterId(pv)); + } + else if (std::find(fpRegs.begin(), fpRegs.end(), + _abi->getRegisterId(pv)) != fpRegs.end()) + { + layout.fpRegisters.push_back(_abi->getRegisterId(pv)); + } + else if (std::find(vecRegs.begin(), vecRegs.end(), + _abi->getRegisterId(pv)) != vecRegs.end()) + { + layout.vectorRegisters.push_back(_abi->getRegisterId(pv)); + } + } + + return layout; +} + +std::vector Filter::createGroupedArgValues(const FilterableLayout& lay) const +{ + return createGroupedValues(lay); +} + +std::vector Filter::createGroupedRetValues(const FilterableLayout& lay) const +{ + return createGroupedValues(lay); +} + +std::vector Filter::createGroupedValues(const FilterableLayout& lay) const +{ + std::vector paramValues; + + auto ri = lay.gpRegisters.begin(); + auto fi = lay.fpRegisters.begin(); + auto di = lay.doubleRegisters.begin(); + auto vi = lay.vectorRegisters.begin(); + auto si = lay.stacks.begin(); + + if (!lay.knownOrder.empty()) + { + for (auto ord : lay.knownOrder) + { + switch (ord) + { + case OrderID::ORD_GPR: + if (ri != lay.gpRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*ri)); + ri++; + } + break; + + case OrderID::ORD_FPR: + if (fi != lay.fpRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*fi)); + fi++; + } + break; + + case OrderID::ORD_DOUBR: + if (di != lay.doubleRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*di)); + di++; + } + break; + + case OrderID::ORD_VECR: + if (vi != lay.vectorRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*vi)); + vi++; + } + break; + + case OrderID::ORD_STACK: + if (si != lay.stacks.end()) + { + paramValues.push_back(*si); + si++; + } + break; + + case OrderID::ORD_GPR_GROUP: + if (ri != lay.gpRegisters.end()) + { + ri++; + } + break; + + case OrderID::ORD_FPR_GROUP: + if (fi != lay.fpRegisters.end()) + { + fi++; + } + break; + + case OrderID::ORD_DOUBR_GROUP: + if (di != lay.doubleRegisters.end()) + { + di++; + } + break; + + case OrderID::ORD_VECR_GROUP: + + if (vi != lay.vectorRegisters.end()) + { + vi++; + } + break; + + case OrderID::ORD_STACK_GROUP: + if (si != lay.stacks.end()) + { + si++; + } + break; + + + default: + continue; + } + } + + return paramValues; + } + + while (ri != lay.gpRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*ri)); + ri++; + } + + while (fi != lay.fpRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*fi)); + fi++; + } + + while (di != lay.doubleRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*di)); + di++; + } + + while (vi != lay.vectorRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*vi)); + vi++; + } + + paramValues.insert(paramValues.end(), si, lay.stacks.end()); + + return paramValues; +} + +void Filter::leaveOnlyPositiveStacks(FilterableLayout& lay) const +{ + auto* config = _abi->getConfig(); + + lay.stacks.erase( + std::remove_if(lay.stacks.begin(), lay.stacks.end(), + [config](const Value* li) + { + auto aOff = config->getStackVariableOffset(li); + return aOff.isDefined() && aOff < 0; + }), + lay.stacks.end()); +} + +void Filter::leaveOnlyContinuousStack(FilterableLayout& lay) const +{ + retdec::utils::Maybe prevOff; + int gap = _cc->getMaxBytesPerStackParam(); + auto* config = _abi->getConfig(); + + auto it = lay.stacks.begin(); + while (it != lay.stacks.end()) + { + auto off = config->getStackVariableOffset(*it); + + if (prevOff.isUndefined()) + { + prevOff = off; + } + else if (std::abs(prevOff - off) > gap) + { + it = lay.stacks.erase(it); + continue; + } + else + { + prevOff = off; + } + + ++it; + } +} + +void Filter::leaveOnlyContinuousArgRegisters(FilterableLayout& lay) const +{ + leaveOnlyContinuousRegisters(lay.gpRegisters, _cc->getParamRegisters()); + leaveOnlyContinuousRegisters(lay.fpRegisters, _cc->getParamFPRegisters()); + leaveOnlyContinuousRegisters(lay.doubleRegisters, _cc->getParamDoubleRegisters()); + leaveOnlyContinuousRegisters(lay.vectorRegisters, _cc->getParamVectorRegisters()); + + bool usingGPR = !_cc->getParamRegisters().empty(); + bool usingFPR = !_cc->getParamFPRegisters().empty(); + bool usingDR = !_cc->getParamDoubleRegisters().empty(); + bool usingVR = !_cc->getParamVectorRegisters().empty(); + + bool missingGPR = lay.gpRegisters.size() < _cc->getParamRegisters().size(); + bool missingFPR = lay.fpRegisters.size() < _cc->getParamFPRegisters().size(); + bool missingDR = lay.doubleRegisters.size() < _cc->getParamDoubleRegisters().size(); + bool missingVR = lay.vectorRegisters.size() < _cc->getParamVectorRegisters().size(); + + // If calling convention passes large objects on stacks (not by refetence) + // usage of another registers will be omitted. + // + // Stacks can be erased only if all types of registers that a cc + // uses are missing some register usage. + + bool eraseStacks = false; + if (_cc->passesLargeObjectsByReference()) + { + if (usingGPR) + { + eraseStacks = missingGPR; + } + + if (usingFPR) + { + eraseStacks = eraseStacks && missingFPR; + } + + if (usingDR) + { + eraseStacks = eraseStacks && missingDR; + } + + if (usingVR) + { + eraseStacks = eraseStacks && missingVR; + } + } + + if (eraseStacks) + { + lay.stacks.clear(); + } +} + +void Filter::createContinuousArgRegisters(FilterableLayout& lay) const +{ + std::vector gpRegs, fpRegs, dbRegs, veRegs; + + if (!lay.gpRegisters.empty()) + { + uint32_t regId = lay.gpRegisters.back(); + + for (auto ccR : _cc->getParamRegisters()) + { + gpRegs.push_back(ccR); + if (regId == ccR) + { + break; + } + } + } + + if (!lay.fpRegisters.empty()) + { + uint32_t regId = lay.fpRegisters.back(); + + for (auto ccR : _cc->getParamFPRegisters()) + { + fpRegs.push_back(ccR); + if (regId == ccR) + { + break; + } + } + } + + if (!lay.doubleRegisters.empty()) + { + uint32_t regId = lay.doubleRegisters.back(); + + for (auto ccR : _cc->getParamDoubleRegisters()) + { + dbRegs.push_back(ccR); + if (regId == ccR) + { + break; + } + } + } + + if (!lay.vectorRegisters.empty()) + { + uint32_t regId = lay.vectorRegisters.back(); + + for (auto ccR : _cc->getParamRegisters()) + { + veRegs.push_back(ccR); + if (regId == ccR) + { + break; + } + } + } + + lay.gpRegisters = std::move(gpRegs); + lay.fpRegisters = std::move(fpRegs); + lay.doubleRegisters = std::move(dbRegs); + lay.vectorRegisters = std::move(veRegs); +} + +void Filter::leaveOnlyContinuousRetRegisters(FilterableLayout& lay) const +{ + leaveOnlyContinuousRegisters(lay.gpRegisters, _cc->getReturnRegisters()); + leaveOnlyContinuousRegisters(lay.fpRegisters, _cc->getReturnFPRegisters()); + leaveOnlyContinuousRegisters(lay.doubleRegisters, _cc->getReturnDoubleRegisters()); + leaveOnlyContinuousRegisters(lay.vectorRegisters, _cc->getReturnVectorRegisters()); +} + +void Filter::leaveOnlyContinuousRegisters( + std::vector& regs, + const std::vector& templRegs) const +{ + auto itEnd = regs.end(); + auto it = regs.begin(); + for (auto regId : templRegs) + { + if (it == itEnd) + { + break; + } + + if (regId != *it) + { + regs.erase(it, itEnd); + break; + } + + it++; + } +} + +void Filter::leaveSameStacks(FilterableLayout& lay, const FilterableLayout& fig) const +{ + lay.stacks.resize(fig.stacks.size(), nullptr); +} + +// +//============================================================================= +// FilterProvider +//============================================================================= +// + +Filter::Ptr FilterProvider::createFilter(Abi* abi, const CallingConvention::ID& id) +{ + auto* cc = abi->getCallingConvention(id); + if (cc == nullptr) + { + cc = abi->getDefaultCallingConvention(); + } + + return std::make_unique(abi, cc); +} + +} +} From 04eef0b957b5afb3f4806c3d19e1ff6475406029 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:38:15 +0100 Subject: [PATCH 133/159] param_return: refactor design --- .../optimizations/param_return/param_return.h | 227 +- .../param_return/param_return.cpp | 2041 ++++------------- 2 files changed, 550 insertions(+), 1718 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index eedb722bf..abda626a5 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -1,7 +1,7 @@ /** * @file include/retdec/bin2llvmir/optimizations/param_return/param_return.h * @brief Detect functions' parameters and returns. -* @copyright (c) 2017 Avast Software, licensed under the MIT license +* @copyright (c) 2019 Avast Software, licensed under the MIT license */ #ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_PARAM_RETURN_H @@ -16,197 +16,17 @@ #include #include "retdec/bin2llvmir/analyses/reaching_definitions.h" +#include "retdec/bin2llvmir/optimizations/param_return/collector/collector.h" +#include "retdec/bin2llvmir/optimizations/param_return/data_entries.h" #include "retdec/bin2llvmir/providers/abi/abi.h" #include "retdec/bin2llvmir/providers/config.h" #include "retdec/bin2llvmir/providers/debugformat.h" #include "retdec/bin2llvmir/providers/fileimage.h" #include "retdec/bin2llvmir/providers/lti.h" -#include "retdec/utils/container.h" namespace retdec { namespace bin2llvmir { -class CallEntry -{ - public: - CallEntry(llvm::CallInst* c); - - public: - bool instructionStoresString( - llvm::StoreInst* si, - std::string& str, - ReachingDefinitionsAnalysis& _RDA) const; - - void extractSpecificArgTypes( - llvm::Module* m, - ReachingDefinitionsAnalysis& _RDA, - llvm::CallInst* wrappedCall = nullptr); - - private: - std::string extractFormatString(ReachingDefinitionsAnalysis& _RDA) const; - - public: - llvm::CallInst* call = nullptr; - std::vector possibleArgs; - std::vector possibleArgStores; - std::vector possibleRetLoads; - std::vector specTypes; -}; - -class ReturnEntry -{ - public: - ReturnEntry(llvm::ReturnInst* r); - - public: - llvm::ReturnInst* ret = nullptr; - std::vector possibleRetStores; -}; - -class ParamFilter -{ - public: - ParamFilter( - llvm::CallInst* call, - const std::vector& paramValues, - const std::vector &types, - const Abi* abi, - Config* config); - - void orderStacks(std::vector& stacks, bool asc = true) const; - void orderRegistersBy( - std::vector& regs, - const std::vector& orderedVector) const; - - void leaveOnlyContinuousSequence(); - void leaveOnlyContinuousStackOffsets(); - void leaveOnlyPositiveStacks(); - - void adjustValuesByKnownTypes( - llvm::CallInst* call, - std::vector &types); - - std::vector getParamValues() const; - - private: - void separateParamValues(const std::vector& paramValues); - void applyAlternatingRegistersFilter(); - void applySequentialRegistersFilter(); - llvm::Value* stackVariableForType(llvm::CallInst* call, llvm::Type* type) const; - - bool moveRegsByTypeSizeAtIdx(std::vector &destinastion, - const std::vector &sourceTemplate, - llvm::Type* type, - uint32_t* idx); - - private: - const Abi* _abi; - Config* _config; - - llvm::CallInst* _call; - - std::vector _regValues; - std::vector _fpRegValues; - std::vector _stackValues; - - std::vector _paramTypes; -}; - -class DataFlowEntry -{ - public: - DataFlowEntry( - llvm::Module* m, - ReachingDefinitionsAnalysis& rda, - Config* c, - Abi* abi, - FileImage* img, - DebugFormat* dbg, - Lti* lti, - llvm::Value* v); - - bool isFunctionEntry() const; - bool isValueEntry() const; - llvm::Value* getValue() const; - llvm::Function* getFunction() const; - void dump() const; - - void addCall(llvm::CallInst* call); - - void filter(); - - void applyToIr(); - void connectWrappers(); - - private: - void addArgLoads(); - void addRetStores(); - void addCallArgs(llvm::CallInst* call, CallEntry& ce); - void addCallReturns(llvm::CallInst* call, CallEntry& ce); - - std::set collectArgsFromInstruction( - llvm::Instruction* startInst, - std::map> &seenBlocks, - std::vector *possibleArgStores = nullptr); - - void callsFilterCommonRegisters(); - void callsFilterSameNumberOfStacks(); - - void setTypeFromExtraInfo(); - void setTypeFromUseContext(); - void setReturnType(); - void setArgumentTypes(); - - llvm::CallInst* isSimpleWrapper(llvm::Function* fnc) const; - - void filterSortArgLoads(); - void filterNegativeStacks(); - - void filterKnownParamPairs(); - - void replaceCalls(); - std::map> - fetchLoadsOfCalls() const; - - llvm::Value* joinParamPair(llvm::Value* low, llvm::Value* high, - llvm::Type *type, llvm::Instruction *before) const; - void splitIntoParamPair( - llvm::AllocaInst* blob, - std::pair ¶mPair) const; - - public: - llvm::Module* _module = nullptr; - ReachingDefinitionsAnalysis& _RDA; - Config* _config = nullptr; - Abi* _abi = nullptr; - FileImage* _image = nullptr; - Lti* _lti = nullptr; - - llvm::Value* called = nullptr; - retdec::config::Function* configFnc = nullptr; - retdec::config::Function* dbgFnc = nullptr; - - // In caller. - // - std::vector calls; - - // In called function. - // - std::vector regArgs; - std::vector args; - std::vector retStores; - - // Result. - // - bool typeSet = false; - llvm::Type* retType = nullptr; - std::vector argTypes; - std::map specialArgStorage; - bool isVarArg = false; - llvm::CallInst* wrappedCall = nullptr; - std::vector argNames; -}; - class ParamReturn : public llvm::ModulePass { public: @@ -223,14 +43,50 @@ class ParamReturn : public llvm::ModulePass private: bool run(); - void dumpInfo(); + void dumpInfo() const; + void dumpInfo(const DataFlowEntry& de) const; + void dumpInfo(const CallEntry& ce) const; + void dumpInfo(const ReturnEntry& de) const; + // Collection of functions. + // + private: void collectAllCalls(); + DataFlowEntry createDataFlowEntry(llvm::Value* calledValue) const; + + private: + void collectExtraData(DataFlowEntry* de) const; + void collectExtraData(CallEntry* ce) const; + + void collectCallSpecificTypes(CallEntry* ce) const; + + // Collection of functions usage data. + // + private: + void addDataFromCall(DataFlowEntry* dataflow, llvm::CallInst* call) const; + + // Optimizations. + // + private: + llvm::CallInst* getWrapper(llvm::Function* fnc) const; + llvm::Type* extractType(llvm::Value* from) const; + + // Filtration of collected functions arguments. + // + private: void filterCalls(); - void filterSort(CallEntry& ce); + void modifyType(DataFlowEntry& de) const; + // Modification of functions in IR. + // + private: void applyToIr(); + void applyToIr(DataFlowEntry& de); + void connectWrappers(const DataFlowEntry& de); + + std::map> fetchLoadsOfCalls( + const std::vector& calls) const; private: llvm::Module* _module = nullptr; @@ -242,6 +98,7 @@ class ParamReturn : public llvm::ModulePass std::map _fnc2calls; ReachingDefinitionsAnalysis _RDA; + Collector::Ptr _collector; }; } // namespace bin2llvmir diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 916f70ffe..28bfeae46 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1,21 +1,7 @@ /** * @file src/bin2llvmir/optimizations/param_return/param_return.cpp * @brief Detect functions' parameters and returns. -* @copyright (c) 2017 Avast Software, licensed under the MIT license -* -* Original implementation: -* name -- position of format string, position of variadic arg start -* printf/scanf -- 0, 1 -* __printf_chk -- 1, 2 -* __fprintf_chk -- 2, 3 -* fprintf/fscanf/wsprintfA/wsprintf/sprintf/sscanf -- 1, 2 -* snprintf -- 2, 3 -* __snprintf_chk -- 4, 5 -* ioctl/open/FmtStr -- not handled -- erase arguments -* wprintf/wscanf -- 0, 1 -* error -- 2, 3 -* error_at_line -- 4, 5 -* other -- not handled -- copy arguments +* @copyright (c) 2019 Avast Software, licensed under the MIT license */ #include @@ -31,8 +17,9 @@ #include "retdec/utils/container.h" #include "retdec/utils/string.h" +#include "retdec/bin2llvmir/optimizations/param_return/filter/filter.h" #include "retdec/bin2llvmir/optimizations/param_return/param_return.h" -#define debug_enabled true +#define debug_enabled false #include "retdec/bin2llvmir/utils/llvm.h" #include "retdec/bin2llvmir/providers/asm_instruction.h" #include "retdec/bin2llvmir/utils/ir_modifier.h" @@ -43,58 +30,6 @@ using namespace llvm; namespace retdec { namespace bin2llvmir { -llvm::Value* getRoot(ReachingDefinitionsAnalysis& RDA, llvm::Value* i, bool first = true) -{ - static std::set seen; - if (first) - { - seen.clear(); - } - if (seen.count(i)) - { - return i; - } - seen.insert(i); - - i = llvm_utils::skipCasts(i); - if (auto* ii = dyn_cast(i)) - { - if (auto* u = RDA.getUse(ii)) - { - if (u->defs.size() == 1) - { - auto* d = (*u->defs.begin())->def; - if (auto* s = dyn_cast(d)) - { - return getRoot(RDA, s->getValueOperand(), false); - } - else - { - return d; - } - } - else if (auto* l = dyn_cast(ii)) - { - return getRoot(RDA, l->getPointerOperand(), false); - } - else - { - return i; - } - } - else if (auto* l = dyn_cast(ii)) - { - return getRoot(RDA, l->getPointerOperand(), false); - } - else - { - return i; - } - } - - return i; -} - // //============================================================================= // ParamReturn @@ -124,12 +59,13 @@ bool ParamReturn::runOnModule(Module& m) _image = FileImageProvider::getFileImage(_module); _dbgf = DebugFormatProvider::getDebugFormat(_module); _lti = LtiProvider::getLti(_module); + _collector = CollectorProvider::createCollector(_abi, _module, &_RDA); return run(); } bool ParamReturn::runOnModuleCustom( - llvm::Module& m, + Module& m, Config* c, Abi* abi, FileImage* img, @@ -142,6 +78,8 @@ bool ParamReturn::runOnModuleCustom( _image = img; _dbgf = dbgf; _lti = lti; + _collector = CollectorProvider::createCollector(_abi, _module, &_RDA); + return run(); } @@ -153,12 +91,12 @@ bool ParamReturn::run() return false; } - _RDA.runOnModule(*_module, AbiProvider::getAbi(_module)); + _RDA.runOnModule(*_module, _abi); collectAllCalls(); - dumpInfo(); +// dumpInfo(); filterCalls(); - dumpInfo(); +// dumpInfo(); applyToIr(); _RDA.clear(); @@ -180,18 +118,9 @@ void ParamReturn::collectAllCalls() continue; } - _fnc2calls.emplace( - std::make_pair( - &f, - DataFlowEntry( - _module, - _RDA, - _config, - _abi, - _image, - _dbgf, - _lti, - &f))); + _fnc2calls.emplace(std::make_pair( + &f, + createDataFlowEntry(&f))); } for (auto& f : _module->getFunctionList()) @@ -215,983 +144,689 @@ void ParamReturn::collectAllCalls() auto fIt = _fnc2calls.find(calledVal); if (fIt == _fnc2calls.end()) { - fIt = _fnc2calls.emplace(std::make_pair( + fIt = _fnc2calls.emplace( + std::make_pair( calledVal, - DataFlowEntry( - _module, - _RDA, - _config, - _abi, - _image, - _dbgf, - _lti, - calledVal))).first; + createDataFlowEntry(calledVal))).first; } - fIt->second.addCall(call); + addDataFromCall(&fIt->second, call); } } -void ParamReturn::filterCalls() +DataFlowEntry ParamReturn::createDataFlowEntry(Value* calledValue) const { - for (auto& p : _fnc2calls) - { - p.second.filter(); - } -} + DataFlowEntry dataflow(calledValue); -void ParamReturn::applyToIr() -{ - for (auto& p : _fnc2calls) - { - p.second.applyToIr(); - } + _collector->collectDefArgs(&dataflow); + _collector->collectDefRets(&dataflow); - for (auto& p : _fnc2calls) - { - p.second.connectWrappers(); - } + collectExtraData(&dataflow); + + return dataflow; } -/** - * Dump all the info collected and processed so far. - */ -void ParamReturn::dumpInfo() +void ParamReturn::collectExtraData(DataFlowEntry* dataflow) const { - LOG << std::endl << "_fnc2calls:" << std::endl; - for (auto& p : _fnc2calls) + auto* fnc = dataflow->getFunction(); + if (fnc == nullptr) { - p.second.dump(); + return; } -} - -// -//============================================================================= -// CallEntry -//============================================================================= -// - -CallEntry::CallEntry(llvm::CallInst* c) : - call(c) -{ -} + // Main + // + if (fnc->getName() == "main") + { + auto charPointer = PointerType::get( + Type::getInt8Ty(_module->getContext()), 0); -void CallEntry::extractSpecificArgTypes(Module* m, - ReachingDefinitionsAnalysis& _RDA, - CallInst *wrappedCall) -{ - std::string formatStr = extractFormatString(_RDA); + dataflow->setArgTypes( + { + _abi->getDefaultType(), + PointerType::get(charPointer, 0) + }, + { + "argc", + "argv" + }); - if (formatStr.empty()) + dataflow->setRetType(_abi->getDefaultType()); return; + } - auto trueCall = wrappedCall ? wrappedCall : call; - - specTypes = llvm_utils::parseFormatString( - m, - formatStr, - trueCall->getCalledFunction()); -} - -std::string CallEntry::extractFormatString(ReachingDefinitionsAnalysis& _RDA) const -{ - std::string str; - - for (auto i : possibleArgs) + // LTI info. + // + auto* cf = _config->getConfigFunction(fnc); + if (cf && (cf->isDynamicallyLinked() || cf->isStaticallyLinked())) { - auto inst = std::find_if(possibleArgStores.begin(), - possibleArgStores.end(), - [i](StoreInst *st) - { - return st->getPointerOperand() == i; - }); - - if (inst != possibleArgStores.end()) + auto fp = _lti->getPairFunctionFree(cf->getName()); + if (fp.first) { - if (instructionStoresString(*inst, str, _RDA)) + std::vector argTypes; + std::vector argNames; + for (auto& a : fp.first->args()) { - break; + if (!a.getType()->isSized()) + { + continue; + } + argTypes.push_back(a.getType()); + argNames.push_back(a.getName()); } - } - } - - return str; -} - -// -//============================================================================= -// ReturnEntry -//============================================================================= -// + dataflow->setArgTypes( + std::move(argTypes), + std::move(argNames)); -ReturnEntry::ReturnEntry(llvm::ReturnInst* r) : - ret(r) -{ + if (fp.first->isVarArg()) + { + dataflow->setVariadic(); + } + dataflow->setRetType(fp.first->getReturnType()); -} + std::string declr = fp.second->getDeclaration(); + if (!declr.empty()) + { + cf->setDeclarationString(declr); + } + return; + } + } -// -//============================================================================= -// DataFlowEntry -//============================================================================= -// + auto dbgFnc = _dbgf ? _dbgf->getFunction( + _config->getFunctionAddress(fnc)) : nullptr; -DataFlowEntry::DataFlowEntry( - llvm::Module* m, - ReachingDefinitionsAnalysis& rda, - Config* c, - Abi* abi, - FileImage* img, - DebugFormat* dbg, - Lti* lti, - llvm::Value* v) - : - _module(m), - _RDA(rda), - _config(c), - _abi(abi), - _image(img), - _lti(lti), - called(v) -{ - if (auto* f = getFunction()) + // Debug info. + // + if (dbgFnc) { - configFnc = c->getConfigFunction(f); - if (dbg) + std::vector argTypes; + std::vector argNames; + for (auto& a : dbgFnc->parameters) { - dbgFnc = dbg->getFunction(c->getFunctionAddress(f)); + auto* t = llvm_utils::stringToLlvmTypeDefault( + _module, a.type.getLlvmIr()); + if (!t->isSized()) + { + continue; + } + argTypes.push_back(t); + argNames.push_back(a.getName()); } + dataflow->setArgTypes( + std::move(argTypes), + std::move(argNames)); - if (!f->empty()) + if (dbgFnc->isVariadic()) { - addArgLoads(); - addRetStores(); + dataflow->setVariadic(); } - } - - setTypeFromExtraInfo(); -} - -bool DataFlowEntry::isFunctionEntry() const -{ - return getFunction() != nullptr; -} - -bool DataFlowEntry::isValueEntry() const -{ - return called && !isFunctionEntry(); -} - -llvm::Value* DataFlowEntry::getValue() const -{ - return called; -} - -llvm::Function* DataFlowEntry::getFunction() const -{ - return dyn_cast_or_null(called); -} + dataflow->setRetType( + llvm_utils::stringToLlvmTypeDefault( + _module, + dbgFnc->returnType.getLlvmIr())); -void DataFlowEntry::dump() const -{ - LOG << "\n\t>|" << called->getName().str() << std::endl; - LOG << "\t>|fnc call : " << isFunctionEntry() << std::endl; - LOG << "\t>|val call : " << isValueEntry() << std::endl; - LOG << "\t>|variadic : " << isVarArg << std::endl; - LOG << "\t>|config f : " << (configFnc != nullptr) << std::endl; - LOG << "\t>|debug f : " << (dbgFnc != nullptr) << std::endl; - LOG << "\t>|wrapp c : " << llvmObjToString(wrappedCall) << std::endl; - LOG << "\t>|type set : " << typeSet << std::endl; - LOG << "\t>|ret type : " << llvmObjToString(retType) << std::endl; - LOG << "\t>|arg types:" << std::endl; - for (auto* t : argTypes) - { - LOG << "\t\t>|" << llvmObjToString(t) << std::endl; - } - LOG << "\t>|arg names:" << std::endl; - for (auto& n : argNames) - { - LOG << "\t\t>|" << n << std::endl; + return; } - LOG << "\t>|calls:" << std::endl; - for (auto& e : calls) + auto configFnc = _config->getConfigFunction(fnc); + if (_config->getConfig().isIda() && configFnc) { - LOG << "\t\t>|" << llvmObjToString(e.call) << std::endl; - LOG << "\t\t\targ stores:" << std::endl; - for (auto* s : e.possibleArgs) - { - LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; - } - LOG << "\t\t\tret loads:" << std::endl; - for (auto* l : e.possibleRetLoads) - { - LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; - } - LOG << "\t\t\targ types:" << std::endl; - for (auto* t : e.specTypes) + std::vector argTypes; + std::vector argNames; + for (auto& a : configFnc->parameters) { - LOG << "\t\t\t>|" << llvmObjToString(t) << std::endl; + auto* t = llvm_utils::stringToLlvmTypeDefault( + _module, + a.type.getLlvmIr()); + if (!t->isSized()) + { + continue; + } + argTypes.push_back(t); + argNames.push_back(a.getName()); } - } - - LOG << "\t>|arg loads:" << std::endl; - for (auto* l : args) - { - LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; - } + dataflow->setArgTypes( + std::move(argTypes), + std::move(argNames)); - LOG << "\t>|return stores:" << std::endl; - for (auto& e : retStores) - { - LOG << "\t\t>|" << llvmObjToString(e.ret) << std::endl; - for (auto* s : e.possibleRetStores) + if (configFnc->isVariadic()) { - LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; + dataflow->setVariadic(); } + dataflow->setRetType( + llvm_utils::stringToLlvmTypeDefault( + _module, + configFnc->returnType.getLlvmIr())); + return; } -} -void DataFlowEntry::addArgLoads() -{ - auto* f = getFunction(); - if (f == nullptr) + // Calling convention. + if (configFnc) { - return; + dataflow->setCallingConvention(configFnc->callingConvention.getID()); } - std::set added; - for (auto it = inst_begin(f), end = inst_end(f); it != end; ++it) + // Wrappers. + // + if (CallInst* wrappedCall = getWrapper(fnc)) { - if (auto* l = dyn_cast(&*it)) + auto* wf = wrappedCall->getCalledFunction(); + auto* ltiFnc = _lti->getLlvmFunctionFree(wf->getName()); + if (ltiFnc) { - auto* ptr = l->getPointerOperand(); - if (!_abi->valueCanBeParameter(ptr)) + std::vector argTypes; + std::vector argNames; + for (auto& a : ltiFnc->args()) { - continue; + if (!a.getType()->isSized()) + { + continue; + } + argTypes.push_back(a.getType()); + argNames.push_back(a.getName()); } + dataflow->setArgTypes( + std::move(argTypes), + std::move(argNames)); - auto* use = _RDA.getUse(l); - if (use == nullptr) + if (ltiFnc->isVarArg()) { - continue; + dataflow->setVariadic(); } + dataflow->setRetType(ltiFnc->getReturnType()); + dataflow->setWrappedCall(wrappedCall); - if ((use->defs.empty() || use->isUndef()) - && added.find(ptr) == added.end()) - { - args.push_back(ptr); - if (_abi->isRegister(ptr)) - regArgs.push_back(ptr); - - added.insert(ptr); - } + return; } } } -void DataFlowEntry::addRetStores() +CallInst* ParamReturn::getWrapper(Function* fnc) const { - auto* f = getFunction(); - if (f == nullptr) + auto ai = AsmInstruction(fnc); + if (ai.isInvalid()) { - return; + return nullptr; } - for (auto it = inst_begin(f), end = inst_end(f); it != end; ++it) + bool single = true; + auto next = ai.getNext(); + while (next.isValid()) { - if (auto* r = dyn_cast(&*it)) + if (!next.empty() && !isa(next.front())) { - ReturnEntry re(r); - - NonIterableSet seenBbs; - NonIterableSet disqualifiedValues; - auto* b = r->getParent(); - seenBbs.insert(b); - Instruction* prev = r; - while (true) - { - if (prev == &b->front()) - { - auto* spb = b->getSinglePredecessor(); - if (spb && !spb->empty() && seenBbs.hasNot(spb)) - { - b = spb; - prev = &b->back(); - seenBbs.insert(b); - } - else - { - break; - } - } - else - { - prev = prev->getPrevNode(); - } - if (prev == nullptr) - { - break; - } - - if (isa(prev) || isa(prev)) - { - break; - } - else if (auto* store = dyn_cast(prev)) - { - auto* ptr = store->getPointerOperand(); + single = false; + break; + } + next = next.getNext(); + } - if (disqualifiedValues.hasNot(ptr) - && _abi->canHoldReturnValue(ptr)) - { - re.possibleRetStores.push_back(store); - disqualifiedValues.insert(ptr); - } - } - else if (auto* load = dyn_cast(prev)) + // Pattern + // .text:00008A38 LDR R0, =aCCc ; "C::cc()" + // .text:00008A3C B puts + // .text:00008A40 off_8A40 DCD aCCc + // TODO: make better wrapper detection. In wrapper, wrapped function params + // should not be set like in this example. + // + if (ai && next) + { + if (_image->getConstantDefault(next.getEndAddress())) + { + auto* l = ai.getInstructionFirst(); + auto* s = ai.getInstructionFirst(); + auto* c = next.getInstructionFirst(); + if (l && s && c && isa(l->getPointerOperand()) + && s->getPointerOperand()->getName() == "r0") + { + auto gvA = _config->getGlobalAddress(cast(l->getPointerOperand())); + if (gvA == next.getEndAddress()) { - auto* ptr = load->getPointerOperand(); - disqualifiedValues.insert(ptr); + return nullptr; } } - - retStores.push_back(re); } } -} - -void DataFlowEntry::addCall(llvm::CallInst* call) -{ - CallEntry ce(call); - - addCallArgs(call, ce); - addCallReturns(call, ce); - - calls.push_back(ce); -} - -// std::vector? -std::set DataFlowEntry::collectArgsFromInstruction( - Instruction* startInst, - std::map> &seenBlocks, - std::vector *possibleArgStores) -{ - NonIterableSet excludedValues; - auto* block = startInst->getParent(); - std::set argStores; - - bool canContinue = true; - for (auto* inst = startInst; canContinue; inst = inst->getPrevNode()) + if (single) { - if (inst == nullptr) + for (auto& i : ai) { - return argStores; + if (auto* c = dyn_cast(&i)) + { + auto* cf = c->getCalledFunction(); + if (cf && !cf->isIntrinsic()) // && cf->isDeclaration()) + { + return c; + } + } } + } - if (auto* call = dyn_cast(inst)) + unsigned aiNum = 0; + bool isSmall = true; + next = ai; + while (next.isValid()) + { + ++aiNum; + next = next.getNext(); + if (aiNum > 4) { - auto* calledFnc = call->getCalledFunction(); - if (calledFnc == nullptr || !calledFnc->isIntrinsic()) - { - return argStores; - } + isSmall = false; + break; } - else if (auto* store = dyn_cast(inst)) + } + auto* s = _image->getImage()->getSegmentFromAddress(ai.getAddress()); + if ((s && s->getName() == ".plt") || isSmall) + { + for (inst_iterator it = inst_begin(fnc), rIt = inst_end(fnc); + it != rIt; ++it) { - auto* val = store->getValueOperand(); - auto* ptr = store->getPointerOperand(); - - if (!_abi->valueCanBeParameter(ptr)) - { - excludedValues.insert(ptr); - } - - if (auto* l = dyn_cast(val)) + if (auto* l = dyn_cast(&*it)) { - if (_abi->isX86()) + std::string n = l->getPointerOperand()->getName(); + if (n == "lr" || n == "sp") { - if (_abi->getRegisterId(l->getPointerOperand()) == X86_REG_EBP - || _abi->getRegisterId(l->getPointerOperand()) == X86_REG_RBP) - { - excludedValues.insert(ptr); - } + return nullptr; } - - if (l->getPointerOperand() != store->getPointerOperand()) + } + else if (auto* s = dyn_cast(&*it)) + { + std::string n = s->getPointerOperand()->getName(); + if (n == "lr" || n == "sp") { - excludedValues.insert(l->getPointerOperand()); + return nullptr; } } - - if (excludedValues.hasNot(ptr)) + else if (auto* c = dyn_cast(&*it)) { - argStores.insert(ptr); - excludedValues.insert(ptr); - excludedValues.insert(val); - - if (possibleArgStores != nullptr) + auto* cf = c->getCalledFunction(); + if (cf && !cf->isIntrinsic() && cf->isDeclaration()) { - possibleArgStores->push_back(store); + return c; } } } - - if (inst == &block->front()) - { - canContinue = false; - } } - std::set commonArgStores; - // recursive? - seenBlocks[block] = argStores; - - for (auto pred: predecessors(block)) - { - std::set foundArgs; - if (seenBlocks.find(pred) == seenBlocks.end()) - { - foundArgs = collectArgsFromInstruction(&pred->back(), seenBlocks, possibleArgStores); - } - else - { - foundArgs = seenBlocks[pred]; - } + return nullptr; +} - if (foundArgs.empty()) - { - return argStores; - } +void ParamReturn::addDataFromCall(DataFlowEntry* dataflow, CallInst* call) const +{ + CallEntry* ce = dataflow->createCallEntry(call); - if (commonArgStores.empty()) - { - commonArgStores = std::move(foundArgs); - } - else - { - std::set intersection; - std::set_intersection( - commonArgStores.begin(), - commonArgStores.end(), - foundArgs.begin(), - foundArgs.end(), - std::inserter(intersection, intersection.begin())); - - commonArgStores = std::move(intersection); - } - } + _collector->collectCallArgs(ce); + _collector->collectCallRets(ce); - argStores.insert(commonArgStores.begin(), commonArgStores.end()); + collectExtraData(ce); +} - seenBlocks[block] = argStores; - return argStores; +void ParamReturn::collectExtraData(CallEntry* ce) const +{ } -bool CallEntry::instructionStoresString( - StoreInst *si, - std::string& str, - ReachingDefinitionsAnalysis &_RDA) const +void ParamReturn::dumpInfo() const { - auto* v = getRoot(_RDA, si->getValueOperand()); - auto* gv = dyn_cast_or_null(v); + LOG << std::endl << "_fnc2calls:" << std::endl; - if (gv == nullptr || !gv->hasInitializer()) + for (auto& p : _fnc2calls) { - return false; + dumpInfo(p.second); } +} - auto* init = dyn_cast_or_null(gv->getInitializer()); - if (init == nullptr) +void ParamReturn::dumpInfo(const DataFlowEntry& de) const +{ + auto called = de.getValue(); + auto fnc = de.getFunction(); + auto configFnc = _config->getConfigFunction(fnc); + auto dbgFnc = _dbgf ? _dbgf->getFunction( + _config->getFunctionAddress(fnc)) : nullptr; + auto wrappedCall = de.getWrappedCall(); + + LOG << "\n\t>|" << called->getName().str() << std::endl; + LOG << "\t>|fnc call : " << de.isFunction() << std::endl; + LOG << "\t>|val call : " << de.isValue() << std::endl; + LOG << "\t>|variadic : " << de.isVariadic() << std::endl; + LOG << "\t>|voidarg : " << de.isVoidarg() << std::endl; + LOG << "\t>|call conv: " << de.getCallingConvention() << std::endl; + LOG << "\t>|config f : " << (configFnc != nullptr) << std::endl; + LOG << "\t>|debug f : " << (dbgFnc != nullptr) << std::endl; + LOG << "\t>|wrapp c : " << llvmObjToString(wrappedCall) << std::endl; + LOG << "\t>|type set : " << !de.argTypes().empty() << std::endl; + LOG << "\t>|ret type : " << llvmObjToString(de.getRetType()) << std::endl; + LOG << "\t>|ret value: " << llvmObjToString(de.getRetValue()) << std::endl; + LOG << "\t>|arg types:" << std::endl; + for (auto* t : de.argTypes()) { - if (auto* i = dyn_cast(gv->getInitializer())) - { - if (auto* igv = dyn_cast(i->getOperand(0))) - { - init = dyn_cast_or_null(igv->getInitializer()); - } - } + LOG << "\t\t>|" << llvmObjToString(t) << std::endl; } - - if (init == nullptr || !init->isString()) + LOG << "\t>|arg names:" << std::endl; + for (auto& n : de.argNames()) { - return false; + LOG << "\t\t>|" << n << std::endl; } - str = init->getAsString(); - return true; -} - -void DataFlowEntry::addCallArgs(llvm::CallInst* call, CallEntry& ce) -{ - std::map> seenBlocks; - - auto fromInst = call->getPrevNode(); - if (fromInst == nullptr) + LOG << "\t>|calls:" << std::endl; + for (auto& e : de.callEntries()) { - return; + dumpInfo(e); } - auto wantedStores = isVarArg ? &ce.possibleArgStores : nullptr; - - auto possibleArgs = collectArgsFromInstruction(fromInst, seenBlocks, wantedStores); - - ce.possibleArgs.assign(possibleArgs.begin(), possibleArgs.end()); -} - -void DataFlowEntry::addCallReturns(llvm::CallInst* call, CallEntry& ce) -{ - NonIterableSet disqualifiedValues; - auto* b = call->getParent(); - Instruction* next = call; - std::set seen; - seen.insert(b); - while (true) + LOG << "\t>|arg loads:" << std::endl; + for (auto* l : de.args()) { - if (next == &b->back()) - { - auto* ssb = b->getSingleSuccessor(); - if (ssb && !ssb->empty() && ssb != b && seen.count(ssb) == 0) - { - b = ssb; - next = &b->front(); - seen.insert(b); - } - else - { - break; - } - } - else - { - next = next->getNextNode(); - } - if (next == nullptr) - { - break; - } - - if (auto* call = dyn_cast(next)) - { - auto* calledFnc = call->getCalledFunction(); - if (calledFnc == nullptr || !calledFnc->isIntrinsic()) - { - break; - } - } - else if (auto* store = dyn_cast(next)) - { - auto* ptr = store->getPointerOperand(); - disqualifiedValues.insert(ptr); - } - else if (auto* load = dyn_cast(next)) - { - auto* ptr = load->getPointerOperand(); + LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; + } - if (disqualifiedValues.hasNot(ptr) - && _abi->canHoldReturnValue(ptr)) - { - ce.possibleRetLoads.push_back(load); - disqualifiedValues.insert(ptr); - } - } + LOG << "\t>|return stores:" << std::endl; + for (auto& e : de.retEntries()) + { + dumpInfo(e); } } -void DataFlowEntry::filter() +void ParamReturn::dumpInfo(const CallEntry& ce) const { - if (!args.empty()) + LOG << "\t\t>|" << llvmObjToString(ce.getCallInstruction()) + << std::endl; + LOG << "\t\t\tvoidarg :" << ce.isVoidarg() << std::endl; + LOG << "\t\t\targ values:" << std::endl; + for (auto* s : ce.args()) { - ParamFilter filter(nullptr, args, argTypes, _abi, _config); - filter.leaveOnlyPositiveStacks(); - args = filter.getParamValues(); + LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; } - - for (CallEntry& e : calls) + LOG << "\t\t\targ stores:" << std::endl; + for (auto* s : ce.argStores()) { - if (isVarArg) - { - e.extractSpecificArgTypes( - _module, - _RDA, - isSimpleWrapper( - e.call->getCalledFunction())); - } - - auto types = argTypes; - types.insert(types.end(), e.specTypes.begin(), e.specTypes.end()); - - ParamFilter filter(e.call, e.possibleArgs, types, - _abi, _config); - - filter.leaveOnlyContinuousStackOffsets(); - filter.leaveOnlyContinuousSequence(); - - e.possibleArgs = filter.getParamValues(); + LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; } - - if (!isVarArg) + LOG << "\t\t\tret values:" << std::endl; + for (auto* l : ce.retValues()) { - callsFilterCommonRegisters(); - callsFilterSameNumberOfStacks(); + LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; } - - if (!typeSet) + LOG << "\t\t\tret loads:" << std::endl; + for (auto* l : ce.retLoads()) + { + LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; + } + LOG << "\t\t\targ types:" << std::endl; + for (auto* t : ce.getBaseFunction()->argTypes()) + { + LOG << "\t\t\t>|" << llvmObjToString(t); + LOG << " (size : " << _abi->getTypeByteSize(t) << "B)" << std::endl; + } + for (auto* t : ce.argTypes()) { - setTypeFromUseContext(); + LOG << "\t\t\t>|" << llvmObjToString(t); + LOG << " (size : " << _abi->getTypeByteSize(t) << "B)" << std::endl; } + LOG << "\t\t\tformat string: " << ce.getFormatString() << std::endl; } -void DataFlowEntry::callsFilterCommonRegisters() +void ParamReturn::dumpInfo(const ReturnEntry& re) const { - if (calls.empty()) + LOG << "\t\t>|" << llvmObjToString(re.getRetInstruction()) + << std::endl; + + LOG << "\t\t\tret stores:" << std::endl; + for (auto* s : re.retStores()) { - return; + LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; } - std::set commonRegs; + LOG << "\t\t\tret values:" << std::endl; + for (auto* s : re.retValues()) + { + LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; + } +} - for (auto& e : calls) +void ParamReturn::filterCalls() +{ + std::map filters; + + for (auto& p : _fnc2calls) { - // TODO: sometimes, we do not find all arg stores. - // this is a hack, we should manufacture loads even if we do not have - // stores but know there are some arguments (debug, ...). - if (e.possibleArgs.empty()) + DataFlowEntry& de = p.second; + auto cc = de.getCallingConvention(); + if (filters.find(cc) == filters.end()) { - continue; + filters[cc] = FilterProvider::createFilter(_abi, cc); } - std::set regs; - for (auto r : e.possibleArgs) + if (de.hasDefinition()) { - if (_abi->isRegister(r)) - { - regs.insert(r); - } + filters[cc]->filterDefinition(&de); } - if (regs.empty()) - { - commonRegs.erase(commonRegs.begin(), commonRegs.end()); - break; - } - else if (commonRegs.empty()) + if (de.isVariadic()) { - commonRegs = std::move(regs); + filters[cc]->filterCallsVariadic(&de, _collector.get()); } else { - std::set intersect; - std::set_intersection( - commonRegs.begin(), - commonRegs.end(), - regs.begin(), - regs.end(), - std::inserter(intersect, intersect.begin())); - - commonRegs = std::move(intersect); + filters[cc]->filterCalls(&de); } - } - for (auto& e : calls) - { - e.possibleArgs.erase( - std::remove_if( - e.possibleArgs.begin(), - e.possibleArgs.end(), - [this, commonRegs](Value* arg) - { - return _abi->isRegister(arg) - && !commonRegs.count(arg); - }), - e.possibleArgs.end()); + filters[cc]->estimateRetValue(&de); + + modifyType(de); } } -void DataFlowEntry::callsFilterSameNumberOfStacks() +Type* ParamReturn::extractType(Value* from) const { - if (calls.empty()) + from = llvm_utils::skipCasts(from); + + if (from == nullptr) { - return; + return _abi->getDefaultType(); } - std::size_t loads = 0; - for (auto* l : args) + if (auto* p = dyn_cast(from->getType())) { - if (_config->isStackVariable(l)) + return p->getElementType(); + } + + if (auto* p = dyn_cast(from->getType())) + { + if (auto* a = dyn_cast(p->getElementType())) { - ++loads; + return PointerType::get(a->getElementType(), 0); } } - std::size_t stacks = std::numeric_limits::max(); - for (auto& ce : calls) + return from->getType(); +} + +void ParamReturn::modifyType(DataFlowEntry& de) const +{ + // TODO + // Based on large type we should do: + // + // If large type is encountered + // and if cc passes large type by reference + // just cast the reference + // + // else separate as much values as possible + // and call function that will create new structure + // and put this values in the elements of + // the structure set this structure as parameter + + if (de.argTypes().empty()) { - std::size_t ss = 0; - for (auto* s : ce.possibleArgs) + for (auto& call : de.callEntries()) { - if (_config->isStackVariable(s)) + std::vector types; + for (auto& arg : call.args()) { - ++ss; + if (arg == nullptr) + { + types.push_back(_abi->getDefaultType()); + continue; + } + + auto usage = std::find_if( + call.argStores().begin(), + call.argStores().end(), + [arg](StoreInst* s) + { + return s->getPointerOperand() + == arg; + }); + + if (usage == call.argStores().end()) + { + + if (auto* p = dyn_cast(arg->getType())) + { + types.push_back(p->getElementType()); + } + else + { + types.push_back(arg->getType()); + } + } + else + { + types.push_back(extractType((*usage)->getValueOperand())); + } } - } - // TODO: all but one have 2 params, receiving have 2 params, one has zero. - // - if (ss < stacks && ss != 0 && ss >= loads) - { - stacks = ss; + de.setArgTypes(std::move(types)); + break; } } - if (typeSet && stacks < argTypes.size()) - { - stacks = argTypes.size(); - } - for (auto& ce : calls) + if (de.argTypes().empty()) { - std::size_t cntr = 0; - auto it = ce.possibleArgs.begin(); - while (it != ce.possibleArgs.end()) + std::vector types; + std::vector args; + + for (auto i : de.args()) { - auto* s = *it; - if (!_config->isStackVariable(s)) + if (i == nullptr) { - ++it; - continue; + types.push_back(_abi->getDefaultType()); } - - ++cntr; - if (cntr > stacks) + else if (auto* p = dyn_cast(i->getType())) { - it = ce.possibleArgs.erase(it); + types.push_back(p->getElementType()); } else { - ++it; + types.push_back(i->getType()); } } + + de.setArgTypes(std::move(types)); } + + auto args = de.args(); + args.erase( + std::remove_if( + args.begin(), + args.end(), + [](Value* v){return v == nullptr;}), + args.end()); + de.setArgs(std::move(args)); } -Value* DataFlowEntry::joinParamPair(Value* low, Value* high, Type *type, Instruction *before) const +void ParamReturn::applyToIr() { - auto ib = _abi->getTypeBitSize(type); - auto intType = IntegerType::get(_module->getContext(), ib); - auto wordSize = _abi->getTypeBitSize( - _abi->getDefaultPointerType()); - - high = IrModifier::convertValueToType(high, intType, before); - low = IrModifier::convertValueToType(low, intType, before); - - high = BinaryOperator::Create(Instruction::Shl, high, llvm::ConstantInt::get(intType, wordSize), "", before); - auto join = BinaryOperator::Create(Instruction::Or, low, high, "", before); + for (auto& p : _fnc2calls) + { + applyToIr(p.second); + } - return IrModifier::convertValueToType(join, type, before); + for (auto& p : _fnc2calls) + { + + connectWrappers(p.second); + } } -void DataFlowEntry::splitIntoParamPair(AllocaInst* blob, std::pair ¶mPair) const +void ParamReturn::applyToIr(DataFlowEntry& de) { - auto param1 = paramPair.first; - auto param2 = paramPair.second; - - auto wordSize = _abi->getTypeBitSize( - _abi->getDefaultPointerType()); - - auto halfInt = IntegerType::get(_module->getContext(), wordSize); - auto intType = IntegerType::get(_module->getContext(), wordSize*2); - - auto before = blob->getNextNode(); + Function* fnc = de.getFunction(); - auto load = new LoadInst(blob, "", before); - - auto val = IrModifier::convertValueToType(load, intType, before); - - auto trunc = new TruncInst(val, halfInt, "", before); - new StoreInst(trunc, param1, before); + if (fnc == nullptr) + { + auto loadsOfCalls = fetchLoadsOfCalls(de.callEntries()); - auto shift = BinaryOperator::Create(Instruction::LShr, val, llvm::ConstantInt::get(intType, wordSize), "", before); - trunc = new TruncInst(shift, halfInt, "", before); - new StoreInst(trunc, param2, before); -} + for (auto l : loadsOfCalls) + { + IrModifier::modifyCallInst(l.first, de.getRetType(), l.second); + } -std::map> DataFlowEntry::fetchLoadsOfCalls() const -{ - std::map> loadsOfCalls; + return; + } - for (auto& e : calls) + if (fnc->arg_size() > 0) { - std::vector loads; - auto* call = e.call; - auto paramRegs = _abi->parameterRegisters(); + return; + } + + auto loadsOfCalls = fetchLoadsOfCalls(de.callEntries()); - auto types = argTypes; - types.insert(types.end(), - e.specTypes.begin(), e.specTypes.end()); - auto tIt = types.begin(); + std::map rets2vals; - auto aIt = e.possibleArgs.begin(); - while (aIt != e.possibleArgs.end()) + if (de.getRetValue()) + { + if (de.getRetType() == nullptr) { - if (*aIt == nullptr) + if (auto* p = dyn_cast(de.getRetValue()->getType())) { - aIt++; - continue; + de.setRetType(p->getElementType()); } - - auto fIt = specialArgStorage.find(loads.size()); - while (fIt != specialArgStorage.end()) + else { - auto* sl = new LoadInst(fIt->second, "", call); - loads.push_back(sl); - fIt = specialArgStorage.find(loads.size()); + de.setRetType(de.getRetValue()->getType()); } - - Value* l = new LoadInst(*aIt, "", call); - aIt++; - - if (tIt != types.end()) - { - auto wordSize = _abi->getTypeByteSize( - _abi->getDefaultPointerType()); - if (wordSize < _abi->getTypeByteSize(*tIt) - && aIt != e.possibleArgs.end()) - { - Value* lp = new LoadInst(*aIt, "", call); - aIt++; - - l = joinParamPair(l, lp, *tIt, call); - } - else - { - l = IrModifier::convertValueToType(l, *tIt, call); - } - - tIt++; - } - else - { - l = IrModifier::convertValueToType(l, _abi->getDefaultType(), call); - } - - loads.push_back(l); } - loadsOfCalls[call] = loads; - } - - return loadsOfCalls; -} - -void DataFlowEntry::replaceCalls() -{ - auto loadsOfCalls = fetchLoadsOfCalls(); - - for (auto l : loadsOfCalls) - IrModifier::modifyCallInst(l.first, l.first->getType(), l.second); -} - -void DataFlowEntry::applyToIr() -{ - Function* analysedFunction = getFunction(); - - if (analysedFunction == nullptr) - { - replaceCalls(); - - return; - } - - if (analysedFunction->arg_size() > 0) - { - return; - } - - auto loadsOfCalls = fetchLoadsOfCalls(); - - llvm::Value* retVal = retType->isFloatingPointTy() ? - _abi->getFPReturnRegister() : _abi->getReturnRegister(); - - std::map rets2vals; - - if (retVal) - { - for (auto& e : retStores) + for (auto& e : de.retEntries()) { - auto* l = new LoadInst(retVal, "", e.ret); - rets2vals[e.ret] = l; + auto* l = new LoadInst(de.getRetValue(), "", e.getRetInstruction()); + rets2vals[e.getRetInstruction()] = l; } } - - auto paramRegs = _abi->parameterRegisters(); - - std::vector argStores; - - auto aIt = args.begin(); - auto tIt = argTypes.begin(); - - std::map> createdPairs; - - while (aIt != args.end()) + else { - if (*aIt == nullptr) { - aIt++; - continue; - } - - Value *l = *aIt; - aIt++; - - auto fIt = specialArgStorage.find(argStores.size()); - while (fIt != specialArgStorage.end()) - { - argStores.push_back(fIt->second); - fIt = specialArgStorage.find(argStores.size()); - } - auto wordSize = _abi->getTypeByteSize( - _abi->getDefaultPointerType()); + de.setRetType(Type::getVoidTy(_module->getContext())); + } - if (aIt != args.end() && tIt != argTypes.end() - && _abi->getTypeByteSize(*tIt) > wordSize) + std::vector definitionArgs; + for (auto& a : de.args()) + { + if (a != nullptr) { - auto p1 = l; - auto p2 = *aIt; - aIt++; - - auto ai = IrModifier::createAlloca(analysedFunction, *tIt); - createdPairs[ai] = std::make_pair(p1, p2); - splitIntoParamPair(ai, createdPairs[ai]); - l = ai; + definitionArgs.push_back(a); } - - argStores.push_back(l); } - auto* oldType = analysedFunction->getType(); IrModifier irm(_module, _config); auto* newFnc = irm.modifyFunction( - analysedFunction, - retType, - argTypes, - isVarArg, + fnc, + de.getRetType(), + de.argTypes(), + de.isVariadic(), rets2vals, loadsOfCalls, - retVal, - argStores, - argNames).first; + de.getRetValue(), + definitionArgs, + de.argNames()).first; - LOG << "modify fnc: " << newFnc->getName().str() << " = " - << llvmObjToString(oldType) << " -> " - << llvmObjToString(newFnc->getType()) << std::endl; - - called = newFnc; + de.setCalledValue(newFnc); } -void DataFlowEntry::connectWrappers() +void ParamReturn::connectWrappers(const DataFlowEntry& de) { - auto* fnc = getFunction(); + auto* fnc = de.getFunction(); + auto* wrappedCall = de.getWrappedCall(); if (fnc == nullptr || wrappedCall == nullptr) { return; @@ -1279,714 +914,54 @@ void DataFlowEntry::connectWrappers() } } -llvm::CallInst* DataFlowEntry::isSimpleWrapper(llvm::Function* fnc) const +std::map> ParamReturn::fetchLoadsOfCalls( + const std::vector& calls) const { - auto ai = AsmInstruction(fnc); - if (ai.isInvalid()) - { - return nullptr; - } - - bool single = true; - auto next = ai.getNext(); - while (next.isValid()) - { - if (!next.empty() && !isa(next.front())) - { - single = false; - break; - } - next = next.getNext(); - } - - // Pattern - // .text:00008A38 LDR R0, =aCCc ; "C::cc()" - // .text:00008A3C B puts - // .text:00008A40 off_8A40 DCD aCCc - // TODO: make better wrapper detection. In wrapper, wrapped function params - // should not be set like in this example. - // - if (ai && next) - { - if (_image->getConstantDefault(next.getEndAddress())) - { - auto* l = ai.getInstructionFirst(); - auto* s = ai.getInstructionFirst(); - auto* c = next.getInstructionFirst(); - if (l && s && c && isa(l->getPointerOperand()) - && s->getPointerOperand()->getName() == "r0") - { - auto gvA = _config->getGlobalAddress(cast(l->getPointerOperand())); - if (gvA == next.getEndAddress()) - { - return nullptr; - } - } - } - } - - if (single) - { - for (auto& i : ai) - { - if (auto* c = dyn_cast(&i)) - { - auto* cf = c->getCalledFunction(); - if (cf && !cf->isIntrinsic()) // && cf->isDeclaration()) - { - return c; - } - } - } - } - - unsigned aiNum = 0; - bool isSmall = true; - next = ai; - while (next.isValid()) - { - ++aiNum; - next = next.getNext(); - if (aiNum > 4) - { - isSmall = false; - break; - } - } - auto* s = _image->getImage()->getSegmentFromAddress(ai.getAddress()); - if ((s && s->getName() == ".plt") || isSmall) - { - for (inst_iterator it = inst_begin(fnc), rIt = inst_end(fnc); - it != rIt; ++it) - { - if (auto* l = dyn_cast(&*it)) - { - std::string n = l->getPointerOperand()->getName(); - if (n == "lr" || n == "sp") - { - return nullptr; - } - } - else if (auto* s = dyn_cast(&*it)) - { - std::string n = s->getPointerOperand()->getName(); - if (n == "lr" || n == "sp") - { - return nullptr; - } - } - else if (auto* c = dyn_cast(&*it)) - { - auto* cf = c->getCalledFunction(); - if (cf && !cf->isIntrinsic() && cf->isDeclaration()) - { - return c; - } - } - } - } - - return nullptr; -} - -void DataFlowEntry::setTypeFromExtraInfo() -{ - auto* fnc = getFunction(); - if (fnc == nullptr) - { - return; - } - - // Main - // - if (fnc->getName() == "main") - { - argTypes.push_back(Type::getInt32Ty(_module->getContext())); - argTypes.push_back(PointerType::get( - PointerType::get( - Type::getInt8Ty(_module->getContext()), - 0), - 0)); - argNames.push_back("argc"); - argNames.push_back("argv"); - retType = Type::getInt32Ty(_module->getContext()); - typeSet = true; - return; - } - - // LTI info. - // - auto* cf = _config->getConfigFunction(fnc); - if (cf && (cf->isDynamicallyLinked() || cf->isStaticallyLinked())) - { - auto fp = _lti->getPairFunctionFree(cf->getName()); - if (fp.first) - { - for (auto& a : fp.first->args()) - { - argTypes.push_back(a.getType()); - argNames.push_back(a.getName()); - } - if (fp.first->isVarArg()) - { - isVarArg = true; - } - retType = fp.first->getReturnType(); - typeSet = true; - - std::string declr = fp.second->getDeclaration(); - if (!declr.empty()) - { - cf->setDeclarationString(declr); - } - - // TODO: we could rename function if LTI name differs. - // e.g. scanf vs _scanf. - // -// if (fp.first->getName() != fnc->getName()) -// { -// IrModifier irmodif(_module, _config); -// irmodif.renameFunction(fnc, fp.first->getName()); -// } - - return; - } - } - - // Debug info. - // - if (dbgFnc) - { - for (auto& a : dbgFnc->parameters) - { - auto* t = llvm_utils::stringToLlvmTypeDefault(_module, a.type.getLlvmIr()); - argTypes.push_back(t); - argNames.push_back(a.getName()); - } - if (dbgFnc->isVariadic()) - { - isVarArg = true; - } - retType = llvm_utils::stringToLlvmTypeDefault( - _module, - dbgFnc->returnType.getLlvmIr()); - typeSet = true; - return; - } - - if (_config->getConfig().isIda() && configFnc) - { - for (auto& a : configFnc->parameters) - { - auto* t = llvm_utils::stringToLlvmTypeDefault(_module, a.type.getLlvmIr()); - argTypes.push_back(t); - argNames.push_back(a.getName()); - - if (_config->getConfig().architecture.isX86()) - { - std::string regName; - if (a.getStorage().isRegister(regName)) - { - if (auto* reg = _config->getLlvmRegister(regName)) - { - specialArgStorage[argTypes.size()-1] = reg; - } - } - } - } - if (configFnc->isVariadic()) - { - isVarArg = true; - } - retType = llvm_utils::stringToLlvmTypeDefault( - _module, - configFnc->returnType.getLlvmIr()); - if (!argTypes.empty()) - { - typeSet = true; - } - return; - } + std::map> loadsOfCalls; - // Wrappers. - // - if ((wrappedCall = isSimpleWrapper(fnc))) + for (auto& e : calls) { - auto* wf = wrappedCall->getCalledFunction(); - auto* ltiFnc = _lti->getLlvmFunctionFree(wf->getName()); - if (ltiFnc) - { - for (auto& a : ltiFnc->args()) - { - argTypes.push_back(a.getType()); - argNames.push_back(a.getName()); - } - if (ltiFnc->isVarArg()) - { - isVarArg = true; - } - retType = ltiFnc->getReturnType(); - typeSet = true; - return; - } - else - { - wrappedCall = nullptr; - } - } -} - -void DataFlowEntry::setTypeFromUseContext() -{ - setReturnType(); - setArgumentTypes(); - typeSet = true; -} - -void DataFlowEntry::setReturnType() -{ - llvm::Value* retVal = _abi->getReturnRegister(); + std::vector loads; + auto* call = e.getCallInstruction(); - retType = retVal ? - retVal->getType()->getPointerElementType() : - Type::getVoidTy(_module->getContext()); -} + auto types = e.getBaseFunction()->argTypes(); + types.insert( + types.end(), + e.argTypes().begin(), + e.argTypes().end()); -void DataFlowEntry::setArgumentTypes() -{ - if (calls.empty()) - { - argTypes.insert( - argTypes.end(), - args.size(), - Abi::getDefaultType(_module)); - } - else - { - CallEntry* ce = &calls.front(); - for (auto& c : calls) - { - if (!c.possibleArgs.empty()) - { - ce = &c; - break; - } - } - std::vector &a = args.size() < ce->possibleArgs.size() ? ce->possibleArgs : args; + auto tIt = types.begin(); + auto aIt = e.args().begin(); - for (const auto& op: a) + while (aIt != e.args().end()) { - if (_abi->isRegister(op) && !_abi->isGeneralPurposeRegister(op)) - { - argTypes.push_back(Abi::getDefaultFPType(_module)); - } - else + if (*aIt == nullptr) { - argTypes.push_back(Abi::getDefaultType(_module)); + aIt++; + continue; } - } - } -} - -// -//============================================================================= -// ParamFilter -//============================================================================= -// - -ParamFilter::ParamFilter( - CallInst* call, - const std::vector& paramValues, - const std::vector& paramTypes, - const Abi* abi, - Config* config) - : - _abi(abi), - _config(config), - _call(call), - _paramTypes(paramTypes) -{ - separateParamValues(paramValues); - - orderRegistersBy(_fpRegValues, _abi->parameterFPRegisters()); - orderRegistersBy(_regValues, _abi->parameterRegisters()); - orderStacks(_stackValues, _abi->getStackParamOrder() == Abi::RTL); - - if (!paramTypes.empty() && call != nullptr) - { - adjustValuesByKnownTypes(call, _paramTypes); - } -} - -void ParamFilter::separateParamValues(const std::vector& paramValues) -{ - auto regs = _abi->parameterRegisters(); - - for (auto pv: paramValues) - { - if (_config->isStackVariable(pv)) - { - _stackValues.push_back(pv); - } - else if (std::find(regs.begin(), regs.end(), - _abi->getRegisterId(pv)) != regs.end()) - { - _regValues.push_back(_abi->getRegisterId(pv)); - } - else - { - _fpRegValues.push_back(_abi->getRegisterId(pv)); - } - } -} - -void ParamFilter::orderStacks(std::vector& stacks, bool asc) const -{ - std::stable_sort( - stacks.begin(), - stacks.end(), - [this, asc](Value* a, Value* b) -> bool - { - auto aOff = _config->getStackVariableOffset(a); - auto bOff = _config->getStackVariableOffset(b); - - bool ascOrd = aOff < bOff; - - return asc ? ascOrd : !ascOrd; - }); -} - -void ParamFilter::orderRegistersBy( - std::vector& regs, - const std::vector& orderedVector) const -{ - std::stable_sort( - regs.begin(), - regs.end(), - [this, orderedVector](uint32_t a, uint32_t b) -> bool - { - auto it1 = std::find(orderedVector.begin(), orderedVector.end(), a); - auto it2 = std::find(orderedVector.begin(), orderedVector.end(), b); - - return std::distance(it1, it2) > 0; - }); -} - -void ParamFilter::leaveOnlyContinuousStackOffsets() -{ - retdec::utils::Maybe prevOff; - int gap = _abi->getTypeByteSize(_abi->getDefaultPointerType()) * 2; - - auto it = _stackValues.begin(); - while (it != _stackValues.end()) - { - auto off = _config->getStackVariableOffset(*it); - - if (prevOff.isUndefined()) - { - prevOff = off; - } - else if (std::abs(prevOff - off) > gap) - { - it = _stackValues.erase(it); - continue; - } - else - { - prevOff = off; - } - - ++it; - } -} - -void ParamFilter::leaveOnlyContinuousSequence() -{ - if (_abi->parameterRegistersOverlay()) - { - applyAlternatingRegistersFilter(); - } - else - { - applySequentialRegistersFilter(); - } -} - -void ParamFilter::applyAlternatingRegistersFilter() -{ - auto templRegs = _abi->parameterRegisters(); - auto fpTemplRegs = _abi->parameterFPRegisters(); - - size_t idx = 0; - auto it = _regValues.begin(); - auto fIt = _fpRegValues.begin(); - - while (idx < fpTemplRegs.size() && idx < templRegs.size()) - { - if (it == _regValues.end() && fIt == _fpRegValues.end()) - { - _stackValues.clear(); - return; - } - - if (it != _regValues.end() && *it == templRegs[idx]) - { - it++; - } - else if (fIt != _fpRegValues.end() && *fIt == fpTemplRegs[idx]) - { - fIt++; - } - else - { - _regValues.erase(it, _regValues.end()); - _fpRegValues.erase(fIt, _fpRegValues.end()); - _stackValues.clear(); - - return; - } - - idx++; - } -} - -void ParamFilter::applySequentialRegistersFilter() -{ - auto it = _regValues.begin(); - for (auto regId : _abi->parameterRegisters()) - { - if (it == _regValues.end()) - { - _stackValues.clear(); - break; - } - - if (regId != *it) - { - _regValues.erase(it, _regValues.end()); - _stackValues.clear(); - break; - } - - it++; - } - - auto fIt = _fpRegValues.begin(); - for (auto regId : _abi->parameterFPRegisters()) - { - if (fIt == _fpRegValues.end()) - { - break; - } - - if (regId != *fIt) - { - _fpRegValues.erase(fIt, _fpRegValues.end()); - break; - } - - fIt++; - } -} - -std::vector ParamFilter::getParamValues() const -{ - std::vector paramValues; - auto ri = _regValues.begin(); - auto fi = _fpRegValues.begin(); - auto si = _stackValues.begin(); - for (auto t: _paramTypes) - { - bool shouldGetFromStack = false; - - if (t->isFloatingPointTy() && _abi->usesFPRegistersForParameters()) - { - if (fi != _fpRegValues.end()) - { - auto reg = _abi->getRegister(*fi); - paramValues.push_back(reg); - ++fi; - } - else - { - shouldGetFromStack = true; - } - } - else if (ri != _regValues.end()) - { - auto reg = _abi->getRegister(*ri); - paramValues.push_back(reg); - ++ri; - } - else - { - shouldGetFromStack = true; - } + Value* l = new LoadInst(*aIt, "", call); - if (shouldGetFromStack) - { - if (si != _stackValues.end()) + if (tIt != types.end()) { - paramValues.push_back(*si); - ++si; + l = IrModifier::convertValueToType(l, *tIt, call); + tIt++; } else { - paramValues.push_back(nullptr); + l = IrModifier::convertValueToType(l, _abi->getDefaultType(), call); } - } - } - - while (ri != _regValues.end()) - { - paramValues.push_back(_abi->getRegister(*ri)); - ri++; - } - - while (fi != _fpRegValues.end()) - { - paramValues.push_back(_abi->getRegister(*fi)); - fi++; - } - - paramValues.insert(paramValues.end(), si, _stackValues.end()); - - return paramValues; -} - -Value* ParamFilter::stackVariableForType(CallInst* call, Type* type) const -{ - uint32_t wordSize = _abi->getTypeByteSize(_abi->getDefaultPointerType()); - - uint32_t off = _abi->getTypeByteSize(type); - off = off > wordSize ? wordSize*2:wordSize; - - if (!_stackValues.empty()) - { - off += _config->getStackVariableOffset(_stackValues.back()); - } - - return _config->getLlvmStackVariable(call->getFunction(), off); -} - -bool ParamFilter::moveRegsByTypeSizeAtIdx(std::vector &destinastion, - const std::vector &sourceTemplate, - Type* type, - uint32_t* idx) -{ - if (idx == nullptr || *idx >= sourceTemplate.size()) - { - return false; - } - - /* - // Register pairs must start with register with even number - if (*idx % reqRegs != 0) - { - (*idx)++; - }*/ - destinastion.push_back(sourceTemplate[*idx]); - auto templateReg = _abi->getRegister(sourceTemplate[*idx]); - - *idx += 1; - - if (_abi->getTypeByteSize(type) - > _abi->getTypeByteSize(templateReg->getType())) - { - if (*idx >= sourceTemplate.size()) - { - return false; + loads.push_back(l); + aIt++; } - - destinastion.push_back(sourceTemplate[*idx]); - *idx += 1; + loadsOfCalls[call] = std::move(loads); } - return true; + return loadsOfCalls; } -void ParamFilter::adjustValuesByKnownTypes(CallInst* call, std::vector& types) -{ - std::vector regValues, fpRegValues; - - auto paramRegs = _abi->parameterRegisters(); - auto fpParamRegs = _abi->parameterFPRegisters(); - - // Indexes of registers to be used next as particular parameter. - uint32_t pI = 0; - uint32_t fI = 0; - - auto sI = _stackValues.begin(); - - std::vector paramValues; - for (auto t: types) - { - if (_abi->usesFPRegistersForParameters() - && t->isFloatingPointTy()) - { - // if cannot move to fp regs push on stack - if (!moveRegsByTypeSizeAtIdx(fpRegValues, fpParamRegs, t, &fI)) - { - if (sI != _stackValues.end()) - { - sI++; - } - else - { - auto s = stackVariableForType(call, t); - if (s != nullptr) - { - _stackValues.push_back(s); - sI = _stackValues.end(); - } - } - } - } - else - { - // if cannot move to regs push on stack - if (!moveRegsByTypeSizeAtIdx(regValues, paramRegs, t, &pI)) - { - if (sI != _stackValues.end()) - { - sI++; - } - else - { - auto s = stackVariableForType(call, t); - if (s != nullptr) - { - _stackValues.push_back(s); - sI = _stackValues.end(); - } - } - } - } - } - - _fpRegValues = fpRegValues; - _regValues = regValues; - - if (sI != _stackValues.end()) - { - _stackValues.erase(sI, _stackValues.end()); - } } - -void ParamFilter::leaveOnlyPositiveStacks() -{ - _stackValues.erase( - std::remove_if(_stackValues.begin(), _stackValues.end(), - [this](const Value* li) - { - auto aOff = _config->getStackVariableOffset(li); - return aOff.isDefined() && aOff < 0; - }), - _stackValues.end()); } - -} // namespace bin2llvmir -} // namespace retdec From f15ef96123ed01af12459157f98add0b1832ee9d Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:41:03 +0100 Subject: [PATCH 134/159] calling_convention: refactor methods --- .../calling_convention/calling_convention.h | 45 ++++++++++++------- .../calling_convention/calling_convention.cpp | 43 ++++++++++++------ 2 files changed, 59 insertions(+), 29 deletions(-) diff --git a/include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h b/include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h index 1496c7058..a4b7e9f30 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h @@ -44,26 +44,34 @@ class CallingConvention // Registers. // public: - std::vector getParamRegisters() const; - std::vector getParamFPRegisters() const; - std::vector getParamDoubleRegisters() const; - std::vector getParamVectorRegisters() const; + const std::vector& getParamRegisters() const; + const std::vector& getParamFPRegisters() const; + const std::vector& getParamDoubleRegisters() const; + const std::vector& getParamVectorRegisters() const; - std::vector getReturnRegisters() const; - std::vector getReturnFPRegisters() const; - std::vector getReturnDoubleRegisters() const; - std::vector getReturnVectorRegisters() const; + const std::vector& getReturnRegisters() const; + const std::vector& getReturnFPRegisters() const; + const std::vector& getReturnDoubleRegisters() const; + const std::vector& getReturnVectorRegisters() const; bool usesFPRegistersForParameters() const; - bool parameterRegistersOverlay() const; - std::size_t getRegsNumPerParam() const; + std::size_t getMaxNumOfRegsPerParam() const; + std::size_t getMaxNumOfFPRegsPerParam() const; + std::size_t getMaxNumOfDoubleRegsPerParam() const; + std::size_t getMaxNumOfVectorRegsPerParam() const; + + std::size_t getMaxNumOfRegsPerReturn() const; + std::size_t getMaxNumOfFPRegsPerReturn() const; + std::size_t getMaxNumOfDoubleRegsPerReturn() const; + std::size_t getMaxNumOfVectorRegsPerReturn() const; // Stacks. public: bool getStackParamOrder() const; bool usesStackForParameters() const; - bool passesStructsOnStack() const; + bool passesLargeObjectsByReference() const; + bool respectsRegisterCouples() const; virtual std::size_t getMaxBytesPerStackParam() const; @@ -94,15 +102,22 @@ class CallingConvention // Private data - registers informational. // protected: - bool _paramRegsOverlay = false; - size_t _regNumPerParam = 1; + size_t _numOfRegsPerParam = 1; + size_t _numOfFPRegsPerParam = 1; + size_t _numOfDoubleRegsPerParam = 1; + size_t _numOfVectorRegsPerParam = 1; + + size_t _numOfRegsPerReturn = 1; + size_t _numOfFPRegsPerReturn = 1; + size_t _numOfDoubleRegsPerReturn = 1; + size_t _numOfVectorRegsPerReturn = 1; // Private data - stacks informational. // protected: - bool _paramStructsOnStack = false; bool _stackParamOrder = RTL; - bool _passesOnStack = true; + bool _largeObjectsPassedByReference = false; + bool _respectsRegCouples = false; }; class CallingConventionProvider diff --git a/src/bin2llvmir/providers/calling_convention/calling_convention.cpp b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp index a79a42e96..70dbdcc62 100644 --- a/src/bin2llvmir/providers/calling_convention/calling_convention.cpp +++ b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp @@ -41,42 +41,42 @@ CallingConvention::~CallingConvention() { } -std::vector CallingConvention::getParamRegisters() const +const std::vector& CallingConvention::getParamRegisters() const { return _paramRegs; } -std::vector CallingConvention::getParamFPRegisters() const +const std::vector& CallingConvention::getParamFPRegisters() const { return _paramFPRegs; } -std::vector CallingConvention::getParamDoubleRegisters() const +const std::vector& CallingConvention::getParamDoubleRegisters() const { return _paramDoubleRegs; } -std::vector CallingConvention::getParamVectorRegisters() const +const std::vector& CallingConvention::getParamVectorRegisters() const { return _paramVectorRegs; } -std::vector CallingConvention::getReturnRegisters() const +const std::vector& CallingConvention::getReturnRegisters() const { return _returnRegs; } -std::vector CallingConvention::getReturnFPRegisters() const +const std::vector& CallingConvention::getReturnFPRegisters() const { return _returnFPRegs; } -std::vector CallingConvention::getReturnDoubleRegisters() const +const std::vector& CallingConvention::getReturnDoubleRegisters() const { return _returnDoubleRegs; } -std::vector CallingConvention::getReturnVectorRegisters() const +const std::vector& CallingConvention::getReturnVectorRegisters() const { return _returnVectorRegs; } @@ -86,14 +86,24 @@ bool CallingConvention::usesFPRegistersForParameters() const return !(_paramFPRegs.empty() && _paramDoubleRegs.empty()); } -bool CallingConvention::parameterRegistersOverlay() const +std::size_t CallingConvention::getMaxNumOfRegsPerParam() const { - return _paramRegsOverlay; + return _numOfRegsPerParam; } -std::size_t CallingConvention::getRegsNumPerParam() const +std::size_t CallingConvention::getMaxNumOfFPRegsPerParam() const { - return _regNumPerParam; + return _numOfFPRegsPerParam; +} + +std::size_t CallingConvention::getMaxNumOfDoubleRegsPerParam() const +{ + return _numOfDoubleRegsPerParam; +} + +std::size_t CallingConvention::getMaxNumOfVectorRegsPerParam() const +{ + return _numOfVectorRegsPerParam; } bool CallingConvention::getStackParamOrder() const @@ -101,9 +111,14 @@ bool CallingConvention::getStackParamOrder() const return _stackParamOrder; } -bool CallingConvention::passesStructsOnStack() const +bool CallingConvention::passesLargeObjectsByReference() const +{ + return _largeObjectsPassedByReference; +} + +bool CallingConvention::respectsRegisterCouples() const { - return _paramStructsOnStack; + return _respectsRegCouples; } std::size_t CallingConvention::getMaxBytesPerStackParam() const From 8ee78d8eb19e544f67648f2cb4b561f9c427ca04 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:42:25 +0100 Subject: [PATCH 135/159] calling_convention: x86: provide larger stack offset --- .../providers/calling_convention/x86.h | 30 +++++++++++++++++++ src/bin2llvmir/CMakeLists.txt | 23 +++++++------- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86.h b/include/retdec/bin2llvmir/providers/calling_convention/x86.h index 30b33ca85..c57989c94 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/x86.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86.h @@ -20,6 +20,11 @@ class CdeclCallingConvention: public CallingConvention CdeclCallingConvention(const Abi* a); virtual ~CdeclCallingConvention(); + // Stacks. + // + public: + virtual std::size_t getMaxBytesPerStackParam() const override; + // Construcor method. // public: @@ -34,6 +39,11 @@ class FastcallCallingConvention: public CallingConvention FastcallCallingConvention(const Abi* a); virtual ~FastcallCallingConvention(); + // Stacks. + // + public: + virtual std::size_t getMaxBytesPerStackParam() const override; + // Construcor method. // public: @@ -48,6 +58,11 @@ class PascalCallingConvention: public CallingConvention PascalCallingConvention(const Abi* a); virtual ~PascalCallingConvention(); + // Stacks. + // + public: + virtual std::size_t getMaxBytesPerStackParam() const override; + // Construcor method. // public: @@ -62,6 +77,11 @@ class PascalFastcallCallingConvention: public CallingConvention PascalFastcallCallingConvention(const Abi* a); virtual ~PascalFastcallCallingConvention(); + // Stacks. + // + public: + virtual std::size_t getMaxBytesPerStackParam() const override; + // Construcor method. // public: @@ -76,6 +96,11 @@ class ThiscallCallingConvention: public CallingConvention ThiscallCallingConvention(const Abi* a); virtual ~ThiscallCallingConvention(); + // Stacks. + // + public: + virtual std::size_t getMaxBytesPerStackParam() const override; + // Construcor method. // public: @@ -90,6 +115,11 @@ class WatcomCallingConvention: public CallingConvention WatcomCallingConvention(const Abi* a); virtual ~WatcomCallingConvention(); + // Stacks. + // + public: + virtual std::size_t getMaxBytesPerStackParam() const override; + // Construcor method. // public: diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 0c363b156..b104adb5a 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -78,19 +78,16 @@ set(BIN2LLVMIR_SOURCES providers/abi/powerpc64.cpp providers/abi/x64.cpp providers/abi/x86.cpp - providers/abi/x86_fastcall.cpp - providers/abi/x86_pascal.cpp - providers/abi/x86_watcom.cpp - providers/calling_convention/calling_conventnion.cpp - providers/calling_convention/arm.h - providers/calling_convention/arm64.h - providers/calling_convention/mips.h - providers/calling_convention/mips64.h - providers/calling_convention/pic32.h - providers/calling_convention/powerpc.h - providers/calling_convention/powerpc64.h - providers/calling_convention/x64.h - providers/calling_convention/x86.h + providers/calling_convention/calling_convention.cpp + providers/calling_convention/arm.cpp + providers/calling_convention/arm64.cpp + providers/calling_convention/mips.cpp + providers/calling_convention/mips64.cpp + providers/calling_convention/pic32.cpp + providers/calling_convention/powerpc.cpp + providers/calling_convention/powerpc64.cpp + providers/calling_convention/x64.cpp + providers/calling_convention/x86.cpp providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp From a8c6d2838ee94a4f9a6cb1e2bdcbe9e38e5d34eb Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:43:14 +0100 Subject: [PATCH 136/159] calling_convention: arm: correct info about cc --- .../providers/calling_convention/arm.cpp | 16 +++++----------- .../providers/calling_convention/arm64.cpp | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/bin2llvmir/providers/calling_convention/arm.cpp b/src/bin2llvmir/providers/calling_convention/arm.cpp index 99aea1cfe..3cd2994d6 100644 --- a/src/bin2llvmir/providers/calling_convention/arm.cpp +++ b/src/bin2llvmir/providers/calling_convention/arm.cpp @@ -19,21 +19,15 @@ ArmCallingConvention::ArmCallingConvention(const Abi* a) : ARM_REG_R2, ARM_REG_R3}; - _paramFPRegs = { - ARM_REG_D0, - ARM_REG_D1, - ARM_REG_D2, - ARM_REG_D3}; - _returnRegs = { ARM_REG_R0, ARM_REG_R1}; - _returnFPRegs = { - ARM_REG_D0, - ARM_REG_D1}; - - _regNumPerParam = 2; + _largeObjectsPassedByReference = true; +// _respectsRegCouples = true; + _numOfRegsPerParam = 2; + _numOfFPRegsPerParam = 2; + _numOfVectorRegsPerParam = 4; } ArmCallingConvention::~ArmCallingConvention() diff --git a/src/bin2llvmir/providers/calling_convention/arm64.cpp b/src/bin2llvmir/providers/calling_convention/arm64.cpp index a44c3f24f..34352780c 100644 --- a/src/bin2llvmir/providers/calling_convention/arm64.cpp +++ b/src/bin2llvmir/providers/calling_convention/arm64.cpp @@ -35,6 +35,17 @@ Arm64CallingConvention::Arm64CallingConvention(const Abi* a) : ARM64_REG_V7 }; + _paramVectorRegs = { + ARM64_REG_V0, + ARM64_REG_V1, + ARM64_REG_V2, + ARM64_REG_V3, + ARM64_REG_V4, + ARM64_REG_V5, + ARM64_REG_V6, + ARM64_REG_V7 + }; + _returnRegs = { ARM64_REG_X0 }; @@ -43,7 +54,9 @@ Arm64CallingConvention::Arm64CallingConvention(const Abi* a) : ARM64_REG_V0 }; - _regNumPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; + _numOfRegsPerParam = 2; } Arm64CallingConvention::~Arm64CallingConvention() From bc2618691671d444faf97a34bc8fe0c1f65683c3 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:43:45 +0100 Subject: [PATCH 137/159] calling_convention: mips: correct info about cc --- .../providers/calling_convention/mips.cpp | 32 ++++++++++++++----- .../providers/calling_convention/mips64.cpp | 5 +-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/bin2llvmir/providers/calling_convention/mips.cpp b/src/bin2llvmir/providers/calling_convention/mips.cpp index 113114fb7..71a47c6fe 100644 --- a/src/bin2llvmir/providers/calling_convention/mips.cpp +++ b/src/bin2llvmir/providers/calling_convention/mips.cpp @@ -40,14 +40,19 @@ MipsCallingConvention::MipsCallingConvention(const Abi* a) : _returnRegs = { MIPS_REG_V0 }; - _returnFPRegs = { - MIPS_REG_V0 - }; - _returnDoubleRegs = { - MIPS_REG_V0 - }; - _regNumPerParam = 2; + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +MipsCallingConvention::~MipsCallingConvention() +{ +} + +CallingConvention::Ptr MipsCallingConvention::create(const Abi* a) +{ + return std::make_unique(a); } // @@ -91,7 +96,18 @@ MipsPSPCallingConvention::MipsPSPCallingConvention(const Abi* a) : MIPS_REG_V0 }; - _regNumPerParam = 2; + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +MipsPSPCallingConvention::~MipsPSPCallingConvention() +{ +} + +CallingConvention::Ptr MipsPSPCallingConvention::create(const Abi* a) +{ + return std::make_unique(a); } } diff --git a/src/bin2llvmir/providers/calling_convention/mips64.cpp b/src/bin2llvmir/providers/calling_convention/mips64.cpp index 38357488b..ab6573866 100644 --- a/src/bin2llvmir/providers/calling_convention/mips64.cpp +++ b/src/bin2llvmir/providers/calling_convention/mips64.cpp @@ -40,8 +40,9 @@ Mips64CallingConvention::Mips64CallingConvention(const Abi* a) : MIPS_REG_F1 }; - _regNumPerParam = 2; - _paramStructsOnStack = false; + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; } Mips64CallingConvention::~Mips64CallingConvention() From 242bb26aef3a33eec1aa8babd65cd6a254e080ab Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:44:06 +0100 Subject: [PATCH 138/159] pic32: correct info about cc --- .../providers/calling_convention/pic32.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/bin2llvmir/providers/calling_convention/pic32.cpp b/src/bin2llvmir/providers/calling_convention/pic32.cpp index c48cd264a..699afce7a 100644 --- a/src/bin2llvmir/providers/calling_convention/pic32.cpp +++ b/src/bin2llvmir/providers/calling_convention/pic32.cpp @@ -24,7 +24,18 @@ Pic32CallingConvention::Pic32CallingConvention(const Abi* a) : MIPS_REG_V0 }; - _regNumPerParam = 2; + _numOfRegsPerParam = 1; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +Pic32CallingConvention::~Pic32CallingConvention() +{ +} + +CallingConvention::Ptr Pic32CallingConvention::create(const Abi* a) +{ + return std::make_unique(a); } } From f96312b1cf33ea7299d89bc035c7d5aa62052f1f Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:44:36 +0100 Subject: [PATCH 139/159] calling_convention: fix pascal_fastcall id --- .../providers/calling_convention/calling_convention.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin2llvmir/providers/calling_convention/calling_convention.cpp b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp index 70dbdcc62..897e86e91 100644 --- a/src/bin2llvmir/providers/calling_convention/calling_convention.cpp +++ b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp @@ -175,7 +175,7 @@ CallingConventionProvider::CallingConventionProvider() registerCC(CallingConvention::ID::CC_THISCALL, &ThiscallCallingConvention::create); registerCC(CallingConvention::ID::CC_PASCAL, &PascalCallingConvention::create); registerCC(CallingConvention::ID::CC_FASTCALL, &FastcallCallingConvention::create); - registerCC(CallingConvention::ID::CC_PASCAL_FASTCALL, &PascalFastcallCallingConvention::create); + registerCC(CallingConvention::ID::CC_FASTCALL_PASCAL, &PascalFastcallCallingConvention::create); registerCC(CallingConvention::ID::CC_WATCOM, &WatcomCallingConvention::create); registerCC(CallingConvention::ID::CC_SYSTEMVX64, &SystemVX64CallingConvention::create); registerCC(CallingConvention::ID::CC_MICROSOFTX64, &MicrosoftX64CallingConvention::create); From bf2c54c0ac1390102ba7b37fee3f051702192360 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:45:09 +0100 Subject: [PATCH 140/159] powerpc: correct cc info --- src/bin2llvmir/providers/calling_convention/powerpc.cpp | 5 +++-- src/bin2llvmir/providers/calling_convention/powerpc64.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/bin2llvmir/providers/calling_convention/powerpc.cpp b/src/bin2llvmir/providers/calling_convention/powerpc.cpp index 2adc45010..888f4b143 100644 --- a/src/bin2llvmir/providers/calling_convention/powerpc.cpp +++ b/src/bin2llvmir/providers/calling_convention/powerpc.cpp @@ -42,8 +42,9 @@ PowerPCCallingConvention::PowerPCCallingConvention(const Abi* a) : PPC_REG_F1 }; - _regNumPerParam = 2; - _paramStructsOnStack = false; + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; } PowerPCCallingConvention::~PowerPCCallingConvention() diff --git a/src/bin2llvmir/providers/calling_convention/powerpc64.cpp b/src/bin2llvmir/providers/calling_convention/powerpc64.cpp index e1801171f..3a5b47635 100644 --- a/src/bin2llvmir/providers/calling_convention/powerpc64.cpp +++ b/src/bin2llvmir/providers/calling_convention/powerpc64.cpp @@ -44,8 +44,9 @@ PowerPC64CallingConvention::PowerPC64CallingConvention(const Abi* a) : PPC_REG_F1 }; - _regNumPerParam = 2; - _paramStructsOnStack = false; + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; } PowerPC64CallingConvention::~PowerPC64CallingConvention() From e16715d86244a905ee362562d63f25a89ec82d91 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:45:31 +0100 Subject: [PATCH 141/159] calling_convention: x64: x86: fix cc info --- .../providers/calling_convention/x64.cpp | 25 +++++++++-- .../providers/calling_convention/x86.cpp | 41 ++++++++++++++----- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/bin2llvmir/providers/calling_convention/x64.cpp b/src/bin2llvmir/providers/calling_convention/x64.cpp index 238ad2e04..148e1b399 100644 --- a/src/bin2llvmir/providers/calling_convention/x64.cpp +++ b/src/bin2llvmir/providers/calling_convention/x64.cpp @@ -37,16 +37,34 @@ SystemVX64CallingConvention::SystemVX64CallingConvention(const Abi* a) : X86_REG_XMM6, X86_REG_XMM7 }; + _paramVectorRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3, + X86_REG_XMM4, + X86_REG_XMM5, + X86_REG_XMM6, + X86_REG_XMM7 + }; _returnRegs = { X86_REG_RAX, X86_REG_RDX }; _returnFPRegs = { - X86_REG_XMM0 + X86_REG_XMM0, + X86_REG_XMM1 + }; + _returnVectorRegs = { + X86_REG_XMM0, + X86_REG_XMM1 }; - _regNumPerParam = 2; + _largeObjectsPassedByReference = true; + _numOfRegsPerParam = 2; + _numOfFPRegsPerParam = 2; + _numOfVectorRegsPerParam = 2; } SystemVX64CallingConvention::~SystemVX64CallingConvention() @@ -87,8 +105,7 @@ MicrosoftX64CallingConvention::MicrosoftX64CallingConvention(const Abi* a) : X86_REG_XMM0 }; - _paramRegsOverlay = true; - _regNumPerParam = 1; + _largeObjectsPassedByReference = true; } MicrosoftX64CallingConvention::~MicrosoftX64CallingConvention() diff --git a/src/bin2llvmir/providers/calling_convention/x86.cpp b/src/bin2llvmir/providers/calling_convention/x86.cpp index be3797338..dbea14c06 100644 --- a/src/bin2llvmir/providers/calling_convention/x86.cpp +++ b/src/bin2llvmir/providers/calling_convention/x86.cpp @@ -4,6 +4,7 @@ * @copyright (c) 2019 Avast Software, licensed under the MIT license */ +#include "retdec/bin2llvmir/providers/abi/abi.h" #include "retdec/bin2llvmir/providers/calling_convention/x86.h" #include "retdec/capstone2llvmir/x86/x86.h" @@ -28,14 +29,17 @@ CdeclCallingConvention::CdeclCallingConvention(const Abi* a) : X86_REG_ST7, X86_REG_ST0 }; - - _regNumPerParam = 1; } CdeclCallingConvention::~CdeclCallingConvention() { } +std::size_t CdeclCallingConvention::getMaxBytesPerStackParam() const +{ + return _abi->getWordSize()*2; +} + CallingConvention::Ptr CdeclCallingConvention::create(const Abi* a) { return std::make_unique(a); @@ -65,14 +69,17 @@ FastcallCallingConvention::FastcallCallingConvention(const Abi* a) : X86_REG_ST7, X86_REG_ST0 }; - - _regNumPerParam = 1; } FastcallCallingConvention::~FastcallCallingConvention() { } +std::size_t FastcallCallingConvention::getMaxBytesPerStackParam() const +{ + return _abi->getWordSize()*2; +} + CallingConvention::Ptr FastcallCallingConvention::create(const Abi* a) { return std::make_unique(a); @@ -98,7 +105,6 @@ PascalCallingConvention::PascalCallingConvention(const Abi* a) : X86_REG_ST0 }; - _regNumPerParam = 1; _stackParamOrder = LTR; } @@ -106,6 +112,11 @@ PascalCallingConvention::~PascalCallingConvention() { } +std::size_t PascalCallingConvention::getMaxBytesPerStackParam() const +{ + return _abi->getWordSize()*2; +} + CallingConvention::Ptr PascalCallingConvention::create(const Abi* a) { return std::make_unique(a); @@ -136,7 +147,6 @@ PascalFastcallCallingConvention::PascalFastcallCallingConvention(const Abi* a) : X86_REG_ST0 }; - _regNumPerParam = 1; _stackParamOrder = LTR; } @@ -144,6 +154,11 @@ PascalFastcallCallingConvention::~PascalFastcallCallingConvention() { } +std::size_t PascalFastcallCallingConvention::getMaxBytesPerStackParam() const +{ + return _abi->getWordSize()*2; +} + CallingConvention::Ptr PascalFastcallCallingConvention::create(const Abi* a) { return std::make_unique(a); @@ -172,14 +187,17 @@ ThiscallCallingConvention::ThiscallCallingConvention(const Abi* a) : X86_REG_ST7, X86_REG_ST0 }; - - _regNumPerParam = 1; } ThiscallCallingConvention::~ThiscallCallingConvention() { } +std::size_t ThiscallCallingConvention::getMaxBytesPerStackParam() const +{ + return _abi->getWordSize()*2; +} + CallingConvention::Ptr ThiscallCallingConvention::create(const Abi* a) { return std::make_unique(a); @@ -208,14 +226,17 @@ WatcomCallingConvention::WatcomCallingConvention(const Abi* a) : X86_REG_ST7, X86_REG_ST0 }; - - _regNumPerParam = 1; } WatcomCallingConvention::~WatcomCallingConvention() { } +std::size_t WatcomCallingConvention::getMaxBytesPerStackParam() const +{ + return _abi->getWordSize()*2; +} + CallingConvention::Ptr WatcomCallingConvention::create(const Abi* a) { return std::make_unique(a); From a86918efa62a9ecb0d338734655f6bb894cb8d81 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:46:34 +0100 Subject: [PATCH 142/159] param_return_tests: fix tests --- .../param_return/param_return_tests.cpp | 526 +++--------------- 1 file changed, 91 insertions(+), 435 deletions(-) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 564f281b7..96b3eb8db 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -7,9 +7,6 @@ #include "retdec/bin2llvmir/providers/abi/arm64.h" #include "retdec/bin2llvmir/providers/abi/mips64.h" #include "retdec/bin2llvmir/providers/abi/powerpc64.h" -#include "retdec/bin2llvmir/providers/abi/x86_fastcall.h" -#include "retdec/bin2llvmir/providers/abi/x86_pascal.h" -#include "retdec/bin2llvmir/providers/abi/x86_watcom.h" #include "retdec/bin2llvmir/optimizations/param_return/param_return.h" #include "bin2llvmir/utils/llvmir_tests.h" @@ -1162,7 +1159,7 @@ TEST_F(ParamReturnTests, x86_64ExternalCallUsesFPRegistersBasic) @xmm0 = global double 0.000000e+00 @xmm1 = global double 0.000000e+00 - declare i64 @print(float, float) + declare i64 @print(double, double) declare void @0() @@ -1171,12 +1168,10 @@ TEST_F(ParamReturnTests, x86_64ExternalCallUsesFPRegistersBasic) store double 2.000000e+00, double* @xmm0 %1 = load double, double* @xmm0 %2 = load double, double* @xmm1 - %3 = fptrunc double %1 to float - %4 = fptrunc double %2 to float - %5 = call i64 @print(float %3, float %4) - store i64 %5, i64* @rax - %6 = load i64, i64* @rax - ret i64 %6 + %3 = call i64 @print(double %1, double %2) + store i64 %3, i64* @rax + %4 = load i64, i64* @rax + ret i64 %4 } declare void @1() @@ -1253,7 +1248,7 @@ TEST_F(ParamReturnTests, x86_64ExternalCallUsesFPRegisters) @xmm0 = global double 0.000000e+00 @xmm1 = global double 0.000000e+00 - declare i64 @print(i64, i64, i64, i64, i64, i64, float, float) + declare i64 @print(i64, i64, i64, i64, i64, i64, double, double) declare void @0() @@ -1275,12 +1270,10 @@ TEST_F(ParamReturnTests, x86_64ExternalCallUsesFPRegisters) %6 = load i64, i64* @r9 %7 = load double, double* @xmm0 %8 = load double, double* @xmm1 - %9 = fptrunc double %7 to float - %10 = fptrunc double %8 to float - %11 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, float %9, float %10) - store i64 %11, i64* @rax - %12 = load i64, i64* @rax - ret i64 %12 + %9 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, double %7, double %8) + store i64 %9, i64* @rax + %10 = load i64, i64* @rax + ret i64 %10 } declare void @1() @@ -1355,6 +1348,7 @@ TEST_F(ParamReturnTests, x86_64UsesJustContinuousSequenceOfRegisters) checkModuleAgainstExpectedIr(exp); } +/* TEST_F(ParamReturnTests, ms_x64PtrCallBasicFunctionality) { parseInput(R"( @@ -1663,10 +1657,10 @@ TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegisters) %1 = load i64, i64* @r8 %2 = load i64, i64* @r9 %3 = load double, double* @xmm0 - %4 = load double, double* @xmm1 - %5 = fptrunc double %3 to float - %6 = fptrunc double %4 to float - %7 = call i64 @print(i64 %1, i64 %2, float %5, float %6) + %4 = fptrunc double %3 to float + %5 = load double, double* @xmm1 + %6 = fptrunc double %5 to float + %7 = call i64 @print(i64 %1, i64 %2, float %4, float %6) store i64 %7, i64* @rax %8 = load i64, i64* @rax ret i64 %8 @@ -1743,10 +1737,10 @@ TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegistersAdvanced) %1 = load i64, i64* @rcx %2 = load i64, i64* @rdx %3 = load double, double* @xmm2 - %4 = load double, double* @xmm3 - %5 = fptrunc double %3 to float - %6 = fptrunc double %4 to float - %7 = call i64 @print(i64 %1, i64 %2, float %5, float %6) + %4 = fptrunc double %3 to float + %5 = load double, double* @xmm3 + %6 = fptrunc double %5 to float + %7 = call i64 @print(i64 %1, i64 %2, float %4, float %6) store i64 %7, i64* @rax %8 = load i64, i64* @rax ret i64 %8 @@ -1827,7 +1821,7 @@ TEST_F(ParamReturnTests, ms_x64UsesJustContinuousSequenceOfRegisters) declare void @1() )"; checkModuleAgainstExpectedIr(exp); -} +}*/ // //TEST_F(ParamReturnTests, x86PtrCallOnlyContinuousStackOffsetsAreUsed) @@ -1986,14 +1980,14 @@ TEST_F(ParamReturnTests, ppcExternalCallBasicFPFunctionality) parseInput(R"( @r3 = global i32 0 @r4 = global i32 0 - @f1 = global f64 0 - @f2 = global f64 0 + @f1 = global double 0.0 + @f2 = global double 0.0 declare void @print() define void @fnc() { store i32 123, i32* @r3 store i32 456, i32* @r4 - store f64 0, f64* @f1 - store f64 0, f64* @f2 + store double 0.0, double* @f1 + store double 0.0, double* @f2 call void @print() ret void } @@ -2017,18 +2011,22 @@ TEST_F(ParamReturnTests, ppcExternalCallBasicFPFunctionality) std::string exp = R"( @r3 = global i32 0 @r4 = global i32 0 + @f1 = global double 0.0 + @f2 = global double 0.0 - declare i32 @print(i32, i32, f64, f64) + declare i32 @print(i32, i32, double, double) declare void @0() define i32 @fnc() { store i32 123, i32* @r3 store i32 456, i32* @r4 + store double 0.0, double* @f1 + store double 0.0, double* @f2 %1 = load i32, i32* @r3 %2 = load i32, i32* @r4 - %3 = load i64, i64* @f1 - %4 = load i64, i64* @f2 - %5 = call i32 @print(i32 %1, i32 %2, f64 %3, f64 %4) + %3 = load double, double* @f1 + %4 = load double, double* @f2 + %5 = call i32 @print(i32 %1, i32 %2, double %3, double %4) store i32 %5, i32* @r3 %6 = load i32, i32* @r3 ret i32 %6 @@ -2072,7 +2070,7 @@ TEST_F(ParamReturnTests, ppcExternalCallDoNotUseObjectsIfTheyAreNotRegisters) )"; checkModuleAgainstExpectedIr(exp); } - +/* TEST_F(ParamReturnTests, ppcExternalCallFilterRegistersOnMultiplePlaces) { parseInput(R"( @@ -2197,6 +2195,7 @@ TEST_F(ParamReturnTests, ppcExternalCallDoNotUseAllRegisters) )"; checkModuleAgainstExpectedIr(exp); } +*/ TEST_F(ParamReturnTests, ppcExternalCallSortRegistersIntoCorrectOrder) { @@ -2318,6 +2317,7 @@ TEST_F(ParamReturnTests, ppcExternalCallDoNotUseStacksIfLessThan7RegistersUsed) TEST_F(ParamReturnTests, ppc64PtrCallBasicFunctionality) { parseInput(R"( + target datalayout = "E-m:e-p:64:64-i64:64-n32" @r = global i64 0 @r3 = global i64 0 @r4 = global i64 0 @@ -2345,16 +2345,18 @@ TEST_F(ParamReturnTests, ppc64PtrCallBasicFunctionality) pass.runOnModuleCustom(*module, &config, &abi); std::string exp = R"( + target datalayout = "E-m:e-p:64:64-i64:64-n32" + @r = global i64 0 @r3 = global i64 0 @r4 = global i64 0 define i64 @fnc() { - store i32 123, i64* @r3 - store i32 456, i64* @r4 - %a = bitcast i32* @r to void ()* - %1 = load i32, i64* @r3 - %2 = load i32, i64* @r4 + store i64 123, i64* @r3 + store i64 456, i64* @r4 + %a = bitcast i64* @r to void ()* + %1 = load i64, i64* @r3 + %2 = load i64, i64* @r4 %3 = bitcast void ()* %a to void (i64, i64)* call void %3(i64 %1, i64 %2) %4 = load i64, i64* @r3 @@ -2586,132 +2588,11 @@ TEST_F(ParamReturnTests, armExternalCallUseStacksIf4RegistersUsed) checkModuleAgainstExpectedIr(exp); } -TEST_F(ParamReturnTests, armExternalCallHasLargeSecondParameter) -{ - parseInput(R"( - @r0 = global i32 0 - @r1 = global i32 0 - @r2 = global i32 0 - @r3 = global i32 0 - @r4 = global i32 0 - declare void @print() - define void @fnc() { - store i32 1, i32* @r2 - store i32 1, i32* @r3 - store i32 1, i32* @r0 - call void @print() - ret void - } - )"); - auto config = Config::fromJsonString(module.get(), R"({ - "architecture" : { - "bitSize" : 32, - "endian" : "little", - "name" : "arm" - } - })"); - auto abi = AbiProvider::addAbi(module.get(), &config); - - abi->addRegister(ARM_REG_R0, getGlobalByName("r0")); - abi->addRegister(ARM_REG_R1, getGlobalByName("r1")); - abi->addRegister(ARM_REG_R2, getGlobalByName("r2")); - abi->addRegister(ARM_REG_R3, getGlobalByName("r3")); - abi->addRegister(ARM_REG_R4, getGlobalByName("r4")); - - pass.runOnModuleCustom(*module, &config, abi); - - std::string exp = R"( - @r0 = global i32 0 - @r1 = global i32 0 - @r2 = global i32 0 - @r3 = global i32 0 - @r4 = global i32 0 - - declare i32 @print(i32, i32, i32) - - declare void @0() - - define i32 @fnc() { - store i32 1, i32* @r2 - store i32 1, i32* @r3 - store i32 1, i32* @r0 - %1 = load i32, i32* @r0 - %2 = load i32, i32* @r2 - %3 = load i32, i32* @r3 - %4 = call i32 @print(i32 %1, i32 %2, i32 %3) - store i32 %4, i32* @r0 - %5 = load i32, i32* @r0 - ret i32 %5 - } - - declare void @1() - )"; - checkModuleAgainstExpectedIr(exp); -} - -TEST_F(ParamReturnTests, armExternalCallHasDouleParameter) -{ - parseInput(R"( - @r0 = global i32 0 - @r1 = global i32 0 - @r2 = global i32 0 - @r3 = global i32 0 - @r4 = global i32 0 - @d0 = global f64 0 - declare void @foo() - define void @fnc() { - store f64 0, f64* @d0 - call void @foo() - ret void - } - )"); - auto config = Config::fromJsonString(module.get(), R"({ - "architecture" : { - "bitSize" : 32, - "endian" : "little", - "name" : "arm" - } - })"); - auto abi = AbiProvider::addAbi(module.get(), &config); - - abi->addRegister(ARM_REG_R0, getGlobalByName("r0")); - abi->addRegister(ARM_REG_R1, getGlobalByName("r1")); - abi->addRegister(ARM_REG_R2, getGlobalByName("r2")); - abi->addRegister(ARM_REG_R3, getGlobalByName("r3")); - abi->addRegister(ARM_REG_R4, getGlobalByName("r4")); - abi->addRegister(ARM_REG_D0, getGlobalByName("d0")); - - pass.runOnModuleCustom(*module, &config, abi); - - std::string exp = R"( - @r0 = global i32 0 - @r1 = global i32 0 - @r2 = global i32 0 - @r3 = global i32 0 - @r4 = global i32 0 - @d0 = global f64 0 - - declare i32 @print(f64) - - declare void @0() - - define i32 @fnc() { - store i32 1, i32* @d0 - %1 = load f64, i64* @d0 - %2 = call i32 @print(f64 %1) - store i32 %2, i32* @r0 - %3 = load i32, i32* @r0 - ret i32 %3 - } - - declare void @1() - )"; - checkModuleAgainstExpectedIr(exp); -} - TEST_F(ParamReturnTests, arm64PtrCallBasicFunctionality) { parseInput(R"( + target datalayout = "E-m:e-p:64:64-i64:64-n32" + @r = global i64 0 @x0 = global i64 0 @x1 = global i64 0 @@ -2738,17 +2619,19 @@ TEST_F(ParamReturnTests, arm64PtrCallBasicFunctionality) pass.runOnModuleCustom(*module, &config, &abi); std::string exp = R"( - @r = global i32 0 + target datalayout = "E-m:e-p:64:64-i64:64-n32" + + @r = global i64 0 @x0 = global i64 0 @x1 = global i64 0 - define i32 @fnc() { + define i64 @fnc() { store i64 123, i64* @x0 store i64 456, i64* @x1 %a = bitcast i64* @r to void ()* %1 = load i64, i64* @x0 %2 = load i64, i64* @x1 - %3 = bitcast void ()* %a to void (i32, i32)* + %3 = bitcast void ()* %a to void (i64, i64)* call void %3(i64 %1, i64 %2) %4 = load i64, i64* @x0 ret i64 %4 @@ -2891,6 +2774,8 @@ TEST_F(ParamReturnTests, arm64ExternalCallUseStacksIf8RegistersUsed) @x8 = global i64 0 declare i64 @print(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) + + declare void @0() define i64 @fnc() { %stack_-4 = alloca i64 @@ -2917,71 +2802,10 @@ TEST_F(ParamReturnTests, arm64ExternalCallUseStacksIf8RegistersUsed) %8 = load i64, i64* @x7 %9 = load i64, i64* %stack_-12 %10 = load i64, i64* %stack_-4 - %11 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64, %7, i64, %8, i64 %9, i64 %10) + %11 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i64 %8, i64 %9, i64 %10) store i64 %11, i64* @x0 %12 = load i64, i64* @x0 - ret i32 %12 - } - )"; - checkModuleAgainstExpectedIr(exp); -} - -TEST_F(ParamReturnTests, arm64ExternalCallHasLargeSecondParameter) -{ - parseInput(R"( - @x0 = global i64 0 - @x1 = global i64 0 - @x2 = global i64 0 - @x3 = global i64 0 - @x4 = global i64 0 - declare void @print() - define void @fnc() { - store i64 1, i64* @x2 - store i64 1, i64* @x3 - store i64 1, i64* @x0 - call void @print() - ret void - } - )"); - auto config = Config::fromJsonString(module.get(), R"({ - "architecture" : { - "bitSize" : 64, - "endian" : "little", - "name" : "arm64" - } - })"); - AbiArm64 abi(module.get(), &config); - - abi.addRegister(ARM64_REG_X0, getGlobalByName("x0")); - abi.addRegister(ARM64_REG_X1, getGlobalByName("x1")); - abi.addRegister(ARM64_REG_X2, getGlobalByName("x2")); - abi.addRegister(ARM64_REG_X3, getGlobalByName("x3")); - abi.addRegister(ARM64_REG_X4, getGlobalByName("x4")); - - pass.runOnModuleCustom(*module, &config, &abi); - - std::string exp = R"( - @x0 = global i64 0 - @x1 = global i64 0 - @x2 = global i64 0 - @x3 = global i64 0 - @x4 = global i64 0 - - declare i64 @print(i64, i64, i64) - - declare void @0() - - define i64 @fnc() { - store i64 1, i64* @r2 - store i64 1, i64* @r3 - store i64 1, i64* @r0 - %1 = load i64, i64* @r0 - %2 = load i64, i64* @r2 - %3 = load i64, i64* @r3 - %4 = call i64 @print(i64 %1, i64 %2, i64 %3) - store i64 %4, i64* @x0 - %5 = load i64, i64* @x0 - ret i64 %5 + ret i64 %12 } declare void @1() @@ -2997,10 +2821,10 @@ TEST_F(ParamReturnTests, arm64ExternalCallHasDouleParameter) @x2 = global i64 0 @x3 = global i64 0 @x4 = global i64 0 - @d0 = global f64 0 + @v0 = global double 0.0 declare void @foo() define void @fnc() { - store f64 0, f64* @d0 + store double 0.0, double* @v0 call void @foo() ret void } @@ -3019,7 +2843,7 @@ TEST_F(ParamReturnTests, arm64ExternalCallHasDouleParameter) abi.addRegister(ARM64_REG_X2, getGlobalByName("x2")); abi.addRegister(ARM64_REG_X3, getGlobalByName("x3")); abi.addRegister(ARM64_REG_X4, getGlobalByName("x4")); - abi.addRegister(ARM64_REG_D0, getGlobalByName("d0")); + abi.addRegister(ARM64_REG_V0, getGlobalByName("v0")); pass.runOnModuleCustom(*module, &config, &abi); @@ -3029,16 +2853,16 @@ TEST_F(ParamReturnTests, arm64ExternalCallHasDouleParameter) @x2 = global i64 0 @x3 = global i64 0 @x4 = global i64 0 - @d0 = global f64 0 + @v0 = global double 0.0 - declare i64 @print(f64) + declare i64 @foo(double) declare void @0() define i64 @fnc() { - store i64 1, i64* @d0 - %1 = load f64, i64* @d0 - %2 = call i64 @print(f64 %1) + store double 0.0, double* @v0 + %1 = load double, double* @v0 + %2 = call i64 @foo(double %1) store i64 %2, i64* @x0 %3 = load i64, i64* @x0 ret i64 %3 @@ -3322,122 +3146,11 @@ TEST_F(ParamReturnTests, mipsExternalCallUseStacksIf4RegistersUsed) checkModuleAgainstExpectedIr(exp); } -TEST_F(ParamReturnTests, mipsExternalCallHasFloatParameter) -{ - parseInput(R"( - @a0 = global i32 0 - @a1 = global i32 0 - @a2 = global i32 0 - @a3 = global i32 0 - @f12 = global f32 0 - @t0 = global i32 0 - declare void @foo() - define void @fnc() { - store i32 1, i32* @t0 - store i32 1, f32* @f12 - call void @foo() - ret void - } - )"); - auto config = Config::fromJsonString(module.get(), R"({ - "architecture" : { - "bitSize" : 32, - "endian" : "little", - "name" : "mips" - } - })"); - auto abi = AbiProvider::addAbi(module.get(), &config); - - abi->addRegister(MIPS_REG_A0, getGlobalByName("a0")); - abi->addRegister(MIPS_REG_A1, getGlobalByName("a1")); - abi->addRegister(MIPS_REG_A2, getGlobalByName("a2")); - abi->addRegister(MIPS_REG_A3, getGlobalByName("a3")); - abi->addRegister(MIPS_REG_F12, getGlobalByName("f12")); - abi->addRegister(MIPS_REG_T0, getGlobalByName("t0")); - - pass.runOnModuleCustom(*module, &config, abi); - - std::string exp = R"( - @a0 = global i32 0 - @a1 = global i32 0 - @a2 = global i32 0 - @a3 = global i32 0 - @f12 = gloabl f32 0 - @t0 = global i32 0 - declare void @foo(f32) - declare void @0() - define void @fnc() { - store i32 1, i32* @t0 - store i32 1, f32* @f12 - %1 = load f32, f32* @f12 - call void @foo(f32 %1) - ret void - } - )"; - checkModuleAgainstExpectedIr(exp); -} - -TEST_F(ParamReturnTests, mipsExternalCallHasFloatFirstParameter) -{ - parseInput(R"( - @a0 = global i32 0 - @a1 = global i32 0 - @a2 = global i32 0 - @a3 = global i32 0 - @f12 = global f32 0 - @t0 = global i32 0 - declare void @foo() - define void @fnc() { - store i32 1, i32* @t0 - store i32 1, i32* @a0 - store i32 1, f32* @f12 - call void @foo() - ret void - } - )"); - auto config = Config::fromJsonString(module.get(), R"({ - "architecture" : { - "bitSize" : 32, - "endian" : "little", - "name" : "mips" - } - })"); - auto abi = AbiProvider::addAbi(module.get(), &config); - - abi->addRegister(MIPS_REG_A0, getGlobalByName("a0")); - abi->addRegister(MIPS_REG_A1, getGlobalByName("a1")); - abi->addRegister(MIPS_REG_A2, getGlobalByName("a2")); - abi->addRegister(MIPS_REG_A3, getGlobalByName("a3")); - abi->addRegister(MIPS_REG_F12, getGlobalByName("f12")); - abi->addRegister(MIPS_REG_T0, getGlobalByName("t0")); - - pass.runOnModuleCustom(*module, &config, abi); - - std::string exp = R"( - @a0 = global i32 0 - @a1 = global i32 0 - @a2 = global i32 0 - @a3 = global i32 0 - @f12 = gloabl f32 0 - @t0 = global i32 0 - declare void @foo(f32, i32) - declare void @0() - define void @fnc() { - store i32 1, i32* @t0 - store i32 1, i32* @a0 - store i32 1, f32* @f12 - %1 = load f32, f32* @f12 - %2 = load i32, i32* @a - call void @foo(f32 %1, i32 %2) - ret void - } - )"; - checkModuleAgainstExpectedIr(exp); -} - TEST_F(ParamReturnTests, mips64PtrCallBasicFunctionality) { parseInput(R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + @r = global i64 0 @a0 = global i64 0 @a1 = global i64 0 @@ -3465,6 +3178,8 @@ TEST_F(ParamReturnTests, mips64PtrCallBasicFunctionality) pass.runOnModuleCustom(*module, &config, &abi); std::string exp = R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + @r = global i64 0 @a0 = global i64 0 @a1 = global i64 0 @@ -3485,6 +3200,8 @@ TEST_F(ParamReturnTests, mips64PtrCallBasicFunctionality) TEST_F(ParamReturnTests, mips64ExternalCallBasicFunctionality) { parseInput(R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + @a0 = global i64 0 @a1 = global i64 0 declare void @print() @@ -3511,6 +3228,8 @@ TEST_F(ParamReturnTests, mips64ExternalCallBasicFunctionality) pass.runOnModuleCustom(*module, &config, &abi); std::string exp = R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + @a0 = global i64 0 @a1 = global i64 0 declare void @print(i64, i64) @@ -3530,6 +3249,8 @@ TEST_F(ParamReturnTests, mips64ExternalCallBasicFunctionality) TEST_F(ParamReturnTests, mips64ExternalCallUseStacksIf8RegistersUsed) { parseInput(R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + @a0 = global i64 0 @a1 = global i64 0 @a2 = global i64 0 @@ -3587,15 +3308,17 @@ TEST_F(ParamReturnTests, mips64ExternalCallUseStacksIf8RegistersUsed) abi.addRegister(MIPS_REG_A1, getGlobalByName("a1")); abi.addRegister(MIPS_REG_A2, getGlobalByName("a2")); abi.addRegister(MIPS_REG_A3, getGlobalByName("a3")); - abi.addRegister(MIPS_REG_T0, getGlobalByName("a1")); - abi.addRegister(MIPS_REG_T1, getGlobalByName("a2")); - abi.addRegister(MIPS_REG_T2, getGlobalByName("a3")); - abi.addRegister(MIPS_REG_T3, getGlobalByName("a4")); + abi.addRegister(MIPS_REG_T0, getGlobalByName("a4")); + abi.addRegister(MIPS_REG_T1, getGlobalByName("a5")); + abi.addRegister(MIPS_REG_T2, getGlobalByName("a6")); + abi.addRegister(MIPS_REG_T3, getGlobalByName("a7")); abi.addRegister(MIPS_REG_T4, getGlobalByName("t4")); pass.runOnModuleCustom(*module, &config, &abi); std::string exp = R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + @a0 = global i64 0 @a1 = global i64 0 @a2 = global i64 0 @@ -3606,8 +3329,9 @@ TEST_F(ParamReturnTests, mips64ExternalCallUseStacksIf8RegistersUsed) @a7 = global i64 0 @t4 = global i64 0 - declare void @0() declare void @print(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) + declare void @0() + define void @fnc() { %stack_-4 = alloca i64 %stack_-12 = alloca i64 @@ -3640,69 +3364,7 @@ TEST_F(ParamReturnTests, mips64ExternalCallUseStacksIf8RegistersUsed) checkModuleAgainstExpectedIr(exp); } -TEST_F(ParamReturnTests, mips64ExternalCallHasFloatParameter) -{ - parseInput(R"( - @a0 = global i64 0 - @a1 = global i64 0 - @a2 = global i64 0 - @a3 = global i64 0 - @t4 = global i64 0 - @f12 = global f64 0 - declare void @foo() - define void @fnc() { - store i64 1, i64* @t4 - store i64 1, f64* @f12 - call void @foo() - ret void - } - )"); - auto config = Config::fromJsonString(module.get(), R"({ - "architecture" : { - "bitSize" : 64, - "endian" : "little", - "name" : "mips64" - } - })"); - - AbiMips64 abi(module.get(), &config); - - abi.addRegister(MIPS_REG_A0, getGlobalByName("a0")); - abi.addRegister(MIPS_REG_A1, getGlobalByName("a1")); - abi.addRegister(MIPS_REG_A2, getGlobalByName("a2")); - abi.addRegister(MIPS_REG_A3, getGlobalByName("a3")); - abi.addRegister(MIPS_REG_T4, getGlobalByName("t4")); - abi.addRegister(MIPS_REG_F12, getGlobalByName("f12")); - - pass.runOnModuleCustom(*module, &config, &abi); - - std::string exp = R"( - @a0 = global i64 0 - @a1 = global i64 0 - @a2 = global i64 0 - @a3 = global i64 0 - @f12 = gloabl f64 0 - @t0 = global i64 0 - declare void @foo(f64) - declare void @0() - define void @fnc() { - store i64 1, i64* @t0 - store i64 1, f64* @f12 - %1 = load f64, f64* @f12 - call void @foo(f64 %1) - ret void - } - )"; - checkModuleAgainstExpectedIr(exp); -} - -/** - * Tests basic parameter sequence of fascall - * calling convention: - * - * - ecx and edx are used for first two parameters - * - other parameters are passed on the stack - */ +/* TEST_F(ParamReturnTests, x86FastcallBasic) { parseInput(R"( @@ -3745,7 +3407,8 @@ TEST_F(ParamReturnTests, x86FastcallBasic) ] })"); - AbiX86Fastcall abi(module.get(), &config); + + AbiMips64 abi(module.get(), &config); abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); @@ -3782,13 +3445,6 @@ TEST_F(ParamReturnTests, x86FastcallBasic) } -/** - * Tests more complex parameter passing. - * When type larger than a size of a 32 bit register - * is passed to the funcion then: - * - this type is split to the more 32 bit parts, - * - each part is passed on the stack separately. - */ TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) { parseInput(R"( @@ -3830,7 +3486,7 @@ TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) ] })"); - AbiX86Fastcall abi(module.get(), &config); + AbiMips64 abi(module.get(), &config); abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); @@ -3900,7 +3556,7 @@ TEST_F(ParamReturnTests, x86PascalBasic) } ] })"); - AbiX86Pascal abi(module.get(), &config); + AbiMips64 abi(module.get(), &config); pass.runOnModuleCustom(*module, &config, &abi); @@ -3965,7 +3621,7 @@ TEST_F(ParamReturnTests, x86PascalFastcallBasic) ] })"); - AbiX86Pascal abi(module.get(), &config); + AbiMips64 abi(module.get(), &config); abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); @@ -4044,7 +3700,7 @@ TEST_F(ParamReturnTests, x86PascalFastcallLargeType) ] })"); - AbiX86Pascal abi(module.get(), &config); + AbiMips64 abi(module.get(), &config); abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); @@ -4053,7 +3709,6 @@ TEST_F(ParamReturnTests, x86PascalFastcallLargeType) std::string exp = R"( @eax = global i32 0 @edx = global i32 0 - @ecx = global i32 0 @r = global i32 0 define i32 @fnc() { @@ -4066,8 +3721,8 @@ TEST_F(ParamReturnTests, x86PascalFastcallLargeType) %a = bitcast i32* @r to void()* %1 = load i32, i32* @eax %2 = load i32, i32* @edx - %3 = load i32, i32* %stack_-8 - %4 = load i32, i32* %stack_-4 + %3 = load i32, i32* %stack_-4 + %4 = load i32, i32* %stack_-8 %5 = bitcast void ()* %a to void (i32, i32, i32, i32)* call void %5(i32 %1, i32 %2, i32 %3, i32 %4) %6 = load i32, i32* @eax @@ -4124,7 +3779,7 @@ TEST_F(ParamReturnTests, x86WatcomBasic) ] })"); - AbiX86Watcom abi(module.get(), &config); + AbiMips64 abi(module.get(), &config); abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); abi.addRegister(X86_REG_EBX, getGlobalByName("ebx")); abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); @@ -4207,7 +3862,7 @@ TEST_F(ParamReturnTests, x86WatcomPassDouble) ] })"); - AbiX86Watcom abi(module.get(), &config); + AbiMips64 abi(module.get(), &config); abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); @@ -4240,6 +3895,7 @@ TEST_F(ParamReturnTests, x86WatcomPassDouble) )"; checkModuleAgainstExpectedIr(exp); } +*/ } // namespace tests } // namespace bin2llvmir From 200f1ce49fa1a84b0223dd7921ea596d65a8a77e Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Mon, 4 Mar 2019 23:42:28 +0100 Subject: [PATCH 143/159] watcom fix --- .../optimizations/param_return/filter/filter.cpp | 10 ++++++++++ src/bin2llvmir/providers/abi/abi.cpp | 3 ++- src/bin2llvmir/providers/abi/x86.cpp | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp index fcadb20a0..7a911884e 100644 --- a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp +++ b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp @@ -837,6 +837,11 @@ void Filter::orderFiterableLayout(FilterableLayout& lay) const void Filter::orderStacks(std::vector& stacks, bool asc) const { + if (stacks.empty()) + { + return; + } + auto config = _abi->getConfig(); std::stable_sort( @@ -939,6 +944,10 @@ FilterableLayout Filter::separateValues( { layout.stacks.push_back(pv); } + else if (!_abi->isRegister(pv)) + { + continue; + } if (std::find(gpRegs.begin(), gpRegs.end(), _abi->getRegisterId(pv)) != gpRegs.end()) { @@ -1316,6 +1325,7 @@ Filter::Ptr FilterProvider::createFilter(Abi* abi, const CallingConvention::ID& cc = abi->getDefaultCallingConvention(); } + assert(cc); return std::make_unique(abi, cc); } diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 2be2bc52e..2742b67b1 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -252,7 +252,8 @@ CallingConvention* Abi::getCallingConvention( const CallingConvention::ID& c) { CallingConvention::ID cc = c; - if (!isSpecialCallingConvention(cc) && !supportsCallingConvention(cc)) + if (!isSpecialCallingConvention(cc) + && !supportsCallingConvention(cc)) { return nullptr; } diff --git a/src/bin2llvmir/providers/abi/x86.cpp b/src/bin2llvmir/providers/abi/x86.cpp index 8c0fb42d7..6db10ccab 100644 --- a/src/bin2llvmir/providers/abi/x86.cpp +++ b/src/bin2llvmir/providers/abi/x86.cpp @@ -132,6 +132,7 @@ bool AbiX86::supportsCallingConvention(CallingConvention::ID& cc) const switch (cc) { case CallingConvention::ID::CC_CDECL: + case CallingConvention::ID::CC_WATCOM: case CallingConvention::ID::CC_ELLIPSIS: case CallingConvention::ID::CC_FASTCALL: case CallingConvention::ID::CC_THISCALL: From b07272f7cc89326b4206494d564a460dced47e05 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:29:51 +0100 Subject: [PATCH 144/159] abi: provide shortcuts to test if abi is for 64 bit arch --- include/retdec/bin2llvmir/providers/abi/abi.h | 4 ++++ src/bin2llvmir/providers/abi/abi.cpp | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index cd4c040ba..0b435db41 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -92,9 +92,13 @@ class Abi // public: bool isMips() const; + bool isMips64() const; bool isArm() const; + bool isArm64() const; bool isX86() const; + bool isX64() const; bool isPowerPC() const; + bool isPowerPC64() const; bool isPic32() const; // Calling conventions. diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 2742b67b1..12c339b68 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -223,21 +223,41 @@ bool Abi::isMips() const return _config->getConfig().architecture.isMipsOrPic32(); } +bool Abi::isMips64() const +{ + return _config->getConfig().architecture.isMips64(); +} + bool Abi::isArm() const { return _config->getConfig().architecture.isArmOrThumb(); } +bool Abi::isArm64() const +{ + return _config->getConfig().architecture.isArm64(); +} + bool Abi::isX86() const { return _config->getConfig().architecture.isX86(); } +bool Abi::isX64() const +{ + return _config->getConfig().architecture.isX86_64(); +} + bool Abi::isPowerPC() const { return _config->getConfig().architecture.isPpc(); } +bool Abi::isPowerPC64() const +{ + return _config->getConfig().architecture.isPpc64(); +} + bool Abi::isPic32() const { return _config->getConfig().architecture.isPic32(); From 0bd8d05070c6821f382b4e7c53a8cd9b13e7ae2d Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 12:30:44 +0100 Subject: [PATCH 145/159] calling_convention: refactor repository structure --- include/retdec/bin2llvmir/providers/abi/abi.h | 4 +- include/retdec/bin2llvmir/providers/abi/x86.h | 1 - .../{arm.h => arm/arm_conv.h} | 6 +- .../{arm64.h => arm64/arm64_conv.h} | 6 +- .../providers/calling_convention/mips.h | 48 ---- .../calling_convention/mips/mips_conv.h | 33 +++ .../calling_convention/mips/mips_psp.h | 28 ++ .../{mips64.h => mips64/mips64_conv.h} | 8 +- .../{pic32.h => pic32/pic32_conv.h} | 6 +- .../{powerpc.h => powerpc/powerpc_conv.h} | 6 +- .../powerpc64_conv.h} | 6 +- .../providers/calling_convention/x64.h | 48 ---- .../calling_convention/x64/x64_conv.h | 26 ++ .../calling_convention/x64/x64_microsoft.h | 27 ++ .../calling_convention/x64/x64_systemv.h | 27 ++ .../providers/calling_convention/x86.h | 132 ---------- .../calling_convention/x86/x86_cdecl.h | 32 +++ .../calling_convention/x86/x86_conv.h | 31 +++ .../calling_convention/x86/x86_fastcall.h | 41 +++ .../calling_convention/x86/x86_pascal.h | 32 +++ .../calling_convention/x86/x86_thiscall.h | 32 +++ .../calling_convention/x86/x86_watcom.h | 32 +++ include/retdec/config/calling_convention.h | 5 +- src/bin2llvmir/CMakeLists.txt | 26 +- src/bin2llvmir/providers/abi/abi.cpp | 35 +-- src/bin2llvmir/providers/abi/mips.cpp | 9 +- src/bin2llvmir/providers/abi/ms_x64.cpp | 2 +- src/bin2llvmir/providers/abi/x64.cpp | 2 +- src/bin2llvmir/providers/abi/x86.cpp | 38 --- .../{arm.cpp => arm/arm_conv.cpp} | 12 +- .../{arm64.cpp => arm64/arm64_conv.cpp} | 10 +- .../calling_convention/calling_convention.cpp | 27 +- .../providers/calling_convention/mips.cpp | 114 -------- .../calling_convention/mips/mips_conv.cpp | 65 +++++ .../calling_convention/mips/mips_psp.cpp | 58 +++++ .../{mips64.cpp => mips64/mips64_conv.cpp} | 12 +- .../{pic32.cpp => pic32/pic32_conv.cpp} | 10 +- .../{powerpc.cpp => powerpc/powerpc_conv.cpp} | 10 +- .../powerpc64_conv.cpp} | 10 +- .../providers/calling_convention/x64.cpp | 123 --------- .../calling_convention/x64/x64_conv.cpp | 36 +++ .../calling_convention/x64/x64_microsoft.cpp | 44 ++++ .../calling_convention/x64/x64_systemv.cpp | 69 +++++ .../providers/calling_convention/x86.cpp | 246 ------------------ .../calling_convention/x86/x86_cdecl.cpp | 43 +++ .../calling_convention/x86/x86_conv.cpp | 26 ++ .../calling_convention/x86/x86_fastcall.cpp | 92 +++++++ .../calling_convention/x86/x86_pascal.cpp | 46 ++++ .../calling_convention/x86/x86_thiscall.cpp | 48 ++++ .../calling_convention/x86/x86_watcom.cpp | 48 ++++ 50 files changed, 1025 insertions(+), 853 deletions(-) rename include/retdec/bin2llvmir/providers/calling_convention/{arm.h => arm/arm_conv.h} (81%) rename include/retdec/bin2llvmir/providers/calling_convention/{arm64.h => arm64/arm64_conv.h} (81%) delete mode 100644 include/retdec/bin2llvmir/providers/calling_convention/mips.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h rename include/retdec/bin2llvmir/providers/calling_convention/{mips64.h => mips64/mips64_conv.h} (72%) rename include/retdec/bin2llvmir/providers/calling_convention/{pic32.h => pic32/pic32_conv.h} (71%) rename include/retdec/bin2llvmir/providers/calling_convention/{powerpc.h => powerpc/powerpc_conv.h} (78%) rename include/retdec/bin2llvmir/providers/calling_convention/{powerpc64.h => powerpc64/powerpc64_conv.h} (79%) delete mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x64.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h delete mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h rename src/bin2llvmir/providers/calling_convention/{arm.cpp => arm/arm_conv.cpp} (71%) rename src/bin2llvmir/providers/calling_convention/{arm64.cpp => arm64/arm64_conv.cpp} (81%) delete mode 100644 src/bin2llvmir/providers/calling_convention/mips.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/mips/mips_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/mips/mips_psp.cpp rename src/bin2llvmir/providers/calling_convention/{mips64.cpp => mips64/mips64_conv.cpp} (74%) rename src/bin2llvmir/providers/calling_convention/{pic32.cpp => pic32/pic32_conv.cpp} (74%) rename src/bin2llvmir/providers/calling_convention/{powerpc.cpp => powerpc/powerpc_conv.cpp} (84%) rename src/bin2llvmir/providers/calling_convention/{powerpc64.cpp => powerpc64/powerpc64_conv.cpp} (84%) delete mode 100644 src/bin2llvmir/providers/calling_convention/x64.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp delete mode 100644 src/bin2llvmir/providers/calling_convention/x86.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_cdecl.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_pascal.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_thiscall.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 0b435db41..eca8192cf 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -107,8 +107,6 @@ class Abi CallingConvention* getCallingConvention( const CallingConvention::ID& cc); CallingConvention* getDefaultCallingConvention(); - virtual bool supportsCallingConvention(CallingConvention::ID& cc) const; - bool isSpecialCallingConvention(const CallingConvention::ID& cc) const; // Config. // @@ -150,7 +148,7 @@ class Abi // Private data - calling convention // protected: - std::map _id2cc; + std::map _id2cc; CallingConvention::ID _defcc; }; diff --git a/include/retdec/bin2llvmir/providers/abi/x86.h b/include/retdec/bin2llvmir/providers/abi/x86.h index 92c633bc9..d9cd25bf1 100644 --- a/include/retdec/bin2llvmir/providers/abi/x86.h +++ b/include/retdec/bin2llvmir/providers/abi/x86.h @@ -34,7 +34,6 @@ class AbiX86 : public Abi // Calling conventions. // private: - virtual bool supportsCallingConvention(CallingConvention::ID& cc) const override; CallingConvention::ID fetchDefaultCC() const; }; diff --git a/include/retdec/bin2llvmir/providers/calling_convention/arm.h b/include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h similarity index 81% rename from include/retdec/bin2llvmir/providers/calling_convention/arm.h rename to include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h index 4473f9c72..b70b3fe97 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/arm.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h @@ -1,11 +1,11 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/arm.h + * @file retdec/include/bin2llvmir/providers/calling_convention/arm/arm_conv.h * @brief Calling conventions of ARM architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM_H +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM_CONV_H #include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" diff --git a/include/retdec/bin2llvmir/providers/calling_convention/arm64.h b/include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h similarity index 81% rename from include/retdec/bin2llvmir/providers/calling_convention/arm64.h rename to include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h index d5ee374aa..54001d0c0 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/arm64.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h @@ -1,11 +1,11 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/arm64.h + * @file retdec/include/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h * @brief Calling conventions of ARM64 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM64_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM64_H +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM64_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM64_CONV_H #include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips.h b/include/retdec/bin2llvmir/providers/calling_convention/mips.h deleted file mode 100644 index 7c71ff405..000000000 --- a/include/retdec/bin2llvmir/providers/calling_convention/mips.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file retdec/include/bin2llvmir/providers/calling_convention/mips.h - * @brief Calling conventions of MIPS architecture. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_H - -#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" - -namespace retdec { -namespace bin2llvmir { - -class MipsCallingConvention: public CallingConvention -{ - // Ctors, dtors. - // - public: - MipsCallingConvention(const Abi* a); - virtual ~MipsCallingConvention(); - - // Construcor method. - // - public: - static CallingConvention::Ptr create(const Abi* a); - -}; - -class MipsPSPCallingConvention: public CallingConvention -{ - // Ctors, dtors. - // - public: - MipsPSPCallingConvention(const Abi* a); - virtual ~MipsPSPCallingConvention(); - - // Construcor method. - // - public: - static CallingConvention::Ptr create(const Abi* a); - -}; - -} -} - -#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h new file mode 100644 index 000000000..ad626ff36 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h @@ -0,0 +1,33 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/mips/mips_conv.h + * @brief Calling convention of MIPS architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_CONV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class MipsCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + MipsCallingConvention(const Abi* a); + virtual ~MipsCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h new file mode 100644 index 000000000..d5a9dec1c --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h @@ -0,0 +1,28 @@ + +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/mips/mips_psp.h + * @brief Calling convention of MIPS architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_MIPS_PSP_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_MIPS_PSP_CONV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class MipsPSPCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + MipsPSPCallingConvention(const Abi* a); + virtual ~MipsPSPCallingConvention(); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips64.h b/include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h similarity index 72% rename from include/retdec/bin2llvmir/providers/calling_convention/mips64.h rename to include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h index 574de321a..27ed87fc3 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/mips64.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h @@ -1,11 +1,11 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/mips64.h - * @brief Calling conventions of Mips64 architecture. + * @file retdec/include/bin2llvmir/providers/calling_convention/mips64/mips64_convention.h + * @brief Calling convention of Mips64 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS64_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS64_H +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS64_MIPS64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS64_MIPS64_H #include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" diff --git a/include/retdec/bin2llvmir/providers/calling_convention/pic32.h b/include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h similarity index 71% rename from include/retdec/bin2llvmir/providers/calling_convention/pic32.h rename to include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h index b2ca42aba..34a986c76 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/pic32.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h @@ -1,11 +1,11 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/pic32.h + * @file retdec/include/bin3llvmir/providers/calling_convention/pic32/pic32_conv.h * @brief Calling conventions of PIC32 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PIC32_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PIC32_H +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PIC32_PIC32_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PIC32_PIC32_CONV_H #include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" diff --git a/include/retdec/bin2llvmir/providers/calling_convention/powerpc.h b/include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h similarity index 78% rename from include/retdec/bin2llvmir/providers/calling_convention/powerpc.h rename to include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h index 567c9d56a..b9808d049 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/powerpc.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h @@ -1,11 +1,11 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/powerpc.h + * @file retdec/include/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h * @brief Calling conventions of PowerPC architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC_H +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC_POWERPC_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC_POWERPC_CONV_H #include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" diff --git a/include/retdec/bin2llvmir/providers/calling_convention/powerpc64.h b/include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h similarity index 79% rename from include/retdec/bin2llvmir/providers/calling_convention/powerpc64.h rename to include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h index 211c629b4..fdca77deb 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/powerpc64.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h @@ -1,11 +1,11 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/powerpc64.h + * @file retdec/include/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h * @brief Calling conventions of PowerPC64 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC64_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC64_H +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PPC64_PPC64_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PPC64_PPC64_CONV_H #include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64.h b/include/retdec/bin2llvmir/providers/calling_convention/x64.h deleted file mode 100644 index 7dd0616df..000000000 --- a/include/retdec/bin2llvmir/providers/calling_convention/x64.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file retdec/include/bin2llvmir/providers/calling_convention/x64.h - * @brief Calling conventions of X64 architecture. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_H - -#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" - -namespace retdec { -namespace bin2llvmir { - -class SystemVX64CallingConvention : public CallingConvention -{ - // Ctors, dtors. - // - public: - SystemVX64CallingConvention(const Abi* a); - virtual ~SystemVX64CallingConvention(); - - // Construcor method. - // - public: - static CallingConvention::Ptr create(const Abi* a); - -}; - -class MicrosoftX64CallingConvention : public CallingConvention -{ - // Ctors, dtors. - // - public: - MicrosoftX64CallingConvention(const Abi* a); - virtual ~MicrosoftX64CallingConvention(); - - // Construcor method. - // - public: - static CallingConvention::Ptr create(const Abi* a); - -}; - -} -} - -#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h new file mode 100644 index 000000000..2aa209797 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h @@ -0,0 +1,26 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/x64/x64_conv.h + * @brief Calling convention of X64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class X64CallingConvention : public CallingConvention +{ + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h new file mode 100644 index 000000000..063933316 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h @@ -0,0 +1,27 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h + * @brief MS Windows calling convention of X64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_MICROSOFT_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_MICROSOFT_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class MicrosoftX64CallingConvention : public CallingConvention +{ + // Ctors, dtors. + // + public: + MicrosoftX64CallingConvention(const Abi* a); + virtual ~MicrosoftX64CallingConvention(); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h new file mode 100644 index 000000000..7dd896e37 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h @@ -0,0 +1,27 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/x64/x64_systemv.h + * @brief System V calling convention of X64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_SYSV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_SYSV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class SystemVX64CallingConvention : public CallingConvention +{ + // Ctors, dtors. + // + public: + SystemVX64CallingConvention(const Abi* a); + virtual ~SystemVX64CallingConvention(); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86.h b/include/retdec/bin2llvmir/providers/calling_convention/x86.h deleted file mode 100644 index c57989c94..000000000 --- a/include/retdec/bin2llvmir/providers/calling_convention/x86.h +++ /dev/null @@ -1,132 +0,0 @@ -/** - * @file retdec/include/bin2llvmir/providers/calling_convention/cdecl.h - * @brief Calling convention information for cdecl. - * @copyright (c) 2017 Avast Software, licensed under the MIT license - */ - -#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_H -#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_H - -#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" - -namespace retdec { -namespace bin2llvmir { - -class CdeclCallingConvention: public CallingConvention -{ - // Ctors, dtors. - // - public: - CdeclCallingConvention(const Abi* a); - virtual ~CdeclCallingConvention(); - - // Stacks. - // - public: - virtual std::size_t getMaxBytesPerStackParam() const override; - - // Construcor method. - // - public: - static CallingConvention::Ptr create(const Abi* a); -}; - -class FastcallCallingConvention: public CallingConvention -{ - // Ctors, dtors. - // - public: - FastcallCallingConvention(const Abi* a); - virtual ~FastcallCallingConvention(); - - // Stacks. - // - public: - virtual std::size_t getMaxBytesPerStackParam() const override; - - // Construcor method. - // - public: - static CallingConvention::Ptr create(const Abi* a); -}; - -class PascalCallingConvention: public CallingConvention -{ - // Ctors, dtors. - // - public: - PascalCallingConvention(const Abi* a); - virtual ~PascalCallingConvention(); - - // Stacks. - // - public: - virtual std::size_t getMaxBytesPerStackParam() const override; - - // Construcor method. - // - public: - static CallingConvention::Ptr create(const Abi* a); -}; - -class PascalFastcallCallingConvention: public CallingConvention -{ - // Ctors, dtors. - // - public: - PascalFastcallCallingConvention(const Abi* a); - virtual ~PascalFastcallCallingConvention(); - - // Stacks. - // - public: - virtual std::size_t getMaxBytesPerStackParam() const override; - - // Construcor method. - // - public: - static CallingConvention::Ptr create(const Abi* a); -}; - -class ThiscallCallingConvention: public CallingConvention -{ - // Ctors, dtors. - // - public: - ThiscallCallingConvention(const Abi* a); - virtual ~ThiscallCallingConvention(); - - // Stacks. - // - public: - virtual std::size_t getMaxBytesPerStackParam() const override; - - // Construcor method. - // - public: - static CallingConvention::Ptr create(const Abi* a); -}; - -class WatcomCallingConvention: public CallingConvention -{ - // Ctors, dtors. - // - public: - WatcomCallingConvention(const Abi* a); - virtual ~WatcomCallingConvention(); - - // Stacks. - // - public: - virtual std::size_t getMaxBytesPerStackParam() const override; - - // Construcor method. - // - public: - static CallingConvention::Ptr create(const Abi* a); -}; - -} -} - -#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h new file mode 100644 index 000000000..a29cfe219 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h @@ -0,0 +1,32 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h + * @brief Cdecl calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_CDECL_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_CDECL_H + +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" + +namespace retdec { +namespace bin2llvmir { + +class CdeclCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + CdeclCallingConvention(const Abi* a); + virtual ~CdeclCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h new file mode 100644 index 000000000..bdcab88f7 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h @@ -0,0 +1,31 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_conv.h + * @brief Common calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_CONV_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class X86CallingConvention: public CallingConvention +{ + // Ctors. + public: + X86CallingConvention(const Abi* a); + + // Stacks. + // + public: + virtual std::size_t getMaxBytesPerStackParam() const override; +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h new file mode 100644 index 000000000..1202f17b5 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h @@ -0,0 +1,41 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h + * @brief Fastcall calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_FASTCALL_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_FASTCALL_H + +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" + +namespace retdec { +namespace bin2llvmir { + +class FastcallCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + FastcallCallingConvention(const Abi* a); + virtual ~FastcallCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +class PascalFastcallCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + PascalFastcallCallingConvention(const Abi* a); + virtual ~PascalFastcallCallingConvention(); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h new file mode 100644 index 000000000..ba617468b --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h @@ -0,0 +1,32 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_pascal.h + * @brief Pascal calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_PASCAL_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_PASCAL_H + +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" + +namespace retdec { +namespace bin2llvmir { + +class PascalCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + PascalCallingConvention(const Abi* a); + virtual ~PascalCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h new file mode 100644 index 000000000..0a69a6607 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h @@ -0,0 +1,32 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h + * @brief Thiscall calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_THISCALL_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_THISCALL_H + +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" + +namespace retdec { +namespace bin2llvmir { + +class ThiscallCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + ThiscallCallingConvention(const Abi* a); + virtual ~ThiscallCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h new file mode 100644 index 000000000..cf2c90552 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h @@ -0,0 +1,32 @@ +/** + * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_watcom.h + * @brief Common calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_WATCOM_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_WATCOM_H + +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" + +namespace retdec { +namespace bin2llvmir { + +class WatcomCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + WatcomCallingConvention(const Abi* a); + virtual ~WatcomCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/include/retdec/config/calling_convention.h b/include/retdec/config/calling_convention.h index 94f56b4b4..9743a9826 100644 --- a/include/retdec/config/calling_convention.h +++ b/include/retdec/config/calling_convention.h @@ -97,14 +97,11 @@ class CallingConvention CC_SPECIALE, CC_SPECIALP, CC_SPECIAL, - CC_FASTCALL_PASCAL, CC_WATCOM, - CC_SYSTEMVX64, - CC_MICROSOFTX64, + CC_X64, CC_ARM, CC_ARM64, CC_MIPS, - CC_MIPSPSP, CC_MIPS64, CC_POWERPC, CC_POWERPC64, diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index b104adb5a..1d698f7c8 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -79,15 +79,23 @@ set(BIN2LLVMIR_SOURCES providers/abi/x64.cpp providers/abi/x86.cpp providers/calling_convention/calling_convention.cpp - providers/calling_convention/arm.cpp - providers/calling_convention/arm64.cpp - providers/calling_convention/mips.cpp - providers/calling_convention/mips64.cpp - providers/calling_convention/pic32.cpp - providers/calling_convention/powerpc.cpp - providers/calling_convention/powerpc64.cpp - providers/calling_convention/x64.cpp - providers/calling_convention/x86.cpp + providers/calling_convention/arm/arm_conv.cpp + providers/calling_convention/arm64/arm64_conv.cpp + providers/calling_convention/mips/mips_conv.cpp + providers/calling_convention/mips/mips_psp.cpp + providers/calling_convention/mips64/mips64_conv.cpp + providers/calling_convention/pic32/pic32_conv.cpp + providers/calling_convention/powerpc/powerpc_conv.cpp + providers/calling_convention/powerpc64/powerpc64_conv.cpp + providers/calling_convention/x64/x64_conv.cpp + providers/calling_convention/x64/x64_microsoft.cpp + providers/calling_convention/x64/x64_systemv.cpp + providers/calling_convention/x86/x86_cdecl.cpp + providers/calling_convention/x86/x86_conv.cpp + providers/calling_convention/x86/x86_fastcall.cpp + providers/calling_convention/x86/x86_pascal.cpp + providers/calling_convention/x86/x86_thiscall.cpp + providers/calling_convention/x86/x86_watcom.cpp providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 12c339b68..84f84e93f 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -269,42 +269,15 @@ CallingConvention* Abi::getDefaultCallingConvention() } CallingConvention* Abi::getCallingConvention( - const CallingConvention::ID& c) + const CallingConvention::ID& cc) { - CallingConvention::ID cc = c; - if (!isSpecialCallingConvention(cc) - && !supportsCallingConvention(cc)) - { - return nullptr; - } - - auto ccId = static_cast(cc); - - if (!_id2cc.count(ccId)) + if (_id2cc.find(cc) == _id2cc.end()) { auto provider = CallingConventionProvider::getProvider(); - _id2cc[ccId] = provider->createCallingConvention(cc, this); + _id2cc[cc] = provider->createCallingConvention(cc, this); } - return _id2cc[ccId].get(); -} - -bool Abi::supportsCallingConvention(CallingConvention::ID& cc) const -{ - return cc == _defcc; -} - -bool Abi::isSpecialCallingConvention(const CallingConvention::ID& cc) const -{ - switch (cc) - { - case CallingConvention::ID::CC_VOIDARG: - case CallingConvention::ID::CC_SPECIAL: - return true; - - default: - return false; - } + return _id2cc[cc].get(); } Config* Abi::getConfig() const diff --git a/src/bin2llvmir/providers/abi/mips.cpp b/src/bin2llvmir/providers/abi/mips.cpp index 5e1fe2605..c29fc3184 100644 --- a/src/bin2llvmir/providers/abi/mips.cpp +++ b/src/bin2llvmir/providers/abi/mips.cpp @@ -28,14 +28,7 @@ AbiMips::AbiMips(llvm::Module* m, Config* c) : MIPS_REG_A2, MIPS_REG_A3}; - if (c->getConfig().tools.isPspGcc()) - { - _defcc = CallingConvention::ID::CC_MIPSPSP; - } - else - { - _defcc = CallingConvention::ID::CC_MIPS; - } + _defcc = CallingConvention::ID::CC_MIPS; } AbiMips::~AbiMips() diff --git a/src/bin2llvmir/providers/abi/ms_x64.cpp b/src/bin2llvmir/providers/abi/ms_x64.cpp index d96a2905a..4a8a53e75 100644 --- a/src/bin2llvmir/providers/abi/ms_x64.cpp +++ b/src/bin2llvmir/providers/abi/ms_x64.cpp @@ -29,7 +29,7 @@ AbiMS_X64::AbiMS_X64(llvm::Module* m, Config* c) : X86_REG_R8, X86_REG_R9}; - _defcc = CallingConvention::ID::CC_MICROSOFTX64; + _defcc = CallingConvention::ID::CC_X64; } AbiMS_X64::~AbiMS_X64() diff --git a/src/bin2llvmir/providers/abi/x64.cpp b/src/bin2llvmir/providers/abi/x64.cpp index 832e01280..5ec5246f9 100644 --- a/src/bin2llvmir/providers/abi/x64.cpp +++ b/src/bin2llvmir/providers/abi/x64.cpp @@ -29,7 +29,7 @@ AbiX64::AbiX64(llvm::Module* m, Config* c) : X86_REG_R8, X86_REG_R9}; - _defcc = CallingConvention::ID::CC_SYSTEMVX64; + _defcc = CallingConvention::ID::CC_X64; } AbiX64::~AbiX64() diff --git a/src/bin2llvmir/providers/abi/x86.cpp b/src/bin2llvmir/providers/abi/x86.cpp index 6db10ccab..361137b63 100644 --- a/src/bin2llvmir/providers/abi/x86.cpp +++ b/src/bin2llvmir/providers/abi/x86.cpp @@ -108,43 +108,5 @@ CallingConvention::ID AbiX86::fetchDefaultCC() const return CallingConvention::ID::CC_CDECL; } -bool AbiX86::supportsCallingConvention(CallingConvention::ID& cc) const -{ - if (_config->getConfig().tools.isBorland()) - { - switch (cc) - { - case CallingConvention::ID::CC_CDECL: - case CallingConvention::ID::CC_PASCAL: - cc = CallingConvention::ID::CC_PASCAL; - return true; - - case CallingConvention::ID::CC_FASTCALL: - case CallingConvention::ID::CC_FASTCALL_PASCAL: - cc = CallingConvention::ID::CC_FASTCALL; - return true; - - default: - return false; - } - } - - switch (cc) - { - case CallingConvention::ID::CC_CDECL: - case CallingConvention::ID::CC_WATCOM: - case CallingConvention::ID::CC_ELLIPSIS: - case CallingConvention::ID::CC_FASTCALL: - case CallingConvention::ID::CC_THISCALL: - case CallingConvention::ID::CC_STDCALL: - return true; - - default: - return false; - } - - return false; -} - } // namespace bin2llvmir } // namespace retdec diff --git a/src/bin2llvmir/providers/calling_convention/arm.cpp b/src/bin2llvmir/providers/calling_convention/arm/arm_conv.cpp similarity index 71% rename from src/bin2llvmir/providers/calling_convention/arm.cpp rename to src/bin2llvmir/providers/calling_convention/arm/arm_conv.cpp index 3cd2994d6..4e1ce53dc 100644 --- a/src/bin2llvmir/providers/calling_convention/arm.cpp +++ b/src/bin2llvmir/providers/calling_convention/arm/arm_conv.cpp @@ -1,10 +1,11 @@ /** - * @file src/bin2llvmir/providers/calling_convention/arm.cpp - * @brief Calling conventions of ARM architecture. + * @file src/bin2llvmir/providers/calling_convention/arm/arm_conv.cpp + * @brief Calling convention of ARM architecture. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ -#include "retdec/bin2llvmir/providers/calling_convention/arm.h" +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h" #include "retdec/capstone2llvmir/arm/arm.h" namespace retdec { @@ -36,6 +37,11 @@ ArmCallingConvention::~ArmCallingConvention() CallingConvention::Ptr ArmCallingConvention::create(const Abi* a) { + if (!a->isArm()) + { + return nullptr; + } + return std::make_unique(a); } diff --git a/src/bin2llvmir/providers/calling_convention/arm64.cpp b/src/bin2llvmir/providers/calling_convention/arm64/arm64_conv.cpp similarity index 81% rename from src/bin2llvmir/providers/calling_convention/arm64.cpp rename to src/bin2llvmir/providers/calling_convention/arm64/arm64_conv.cpp index 34352780c..79a5af180 100644 --- a/src/bin2llvmir/providers/calling_convention/arm64.cpp +++ b/src/bin2llvmir/providers/calling_convention/arm64/arm64_conv.cpp @@ -1,12 +1,13 @@ /** - * @file src/bin2llvmir/providers/calling_convention/arm64.cpp + * @file src/bin2llvmir/providers/calling_convention/arm64/arm64_conv.cpp * @brief Calling conventions of ARM64 architecture. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ #include -#include "retdec/bin2llvmir/providers/calling_convention/arm64.h" +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h" namespace retdec { namespace bin2llvmir { @@ -65,6 +66,11 @@ Arm64CallingConvention::~Arm64CallingConvention() CallingConvention::Ptr Arm64CallingConvention::create(const Abi* a) { + if (!a->isArm64()) + { + return nullptr; + } + return std::make_unique(a); } diff --git a/src/bin2llvmir/providers/calling_convention/calling_convention.cpp b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp index 897e86e91..02ec90c57 100644 --- a/src/bin2llvmir/providers/calling_convention/calling_convention.cpp +++ b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp @@ -7,15 +7,19 @@ #include "retdec/bin2llvmir/providers/abi/abi.h" #include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" -#include "retdec/bin2llvmir/providers/calling_convention/arm.h" -#include "retdec/bin2llvmir/providers/calling_convention/arm64.h" -#include "retdec/bin2llvmir/providers/calling_convention/mips.h" -#include "retdec/bin2llvmir/providers/calling_convention/mips64.h" -#include "retdec/bin2llvmir/providers/calling_convention/pic32.h" -#include "retdec/bin2llvmir/providers/calling_convention/powerpc.h" -#include "retdec/bin2llvmir/providers/calling_convention/powerpc64.h" -#include "retdec/bin2llvmir/providers/calling_convention/x86.h" -#include "retdec/bin2llvmir/providers/calling_convention/x64.h" +#include "retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h" +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h" using namespace llvm; @@ -175,16 +179,13 @@ CallingConventionProvider::CallingConventionProvider() registerCC(CallingConvention::ID::CC_THISCALL, &ThiscallCallingConvention::create); registerCC(CallingConvention::ID::CC_PASCAL, &PascalCallingConvention::create); registerCC(CallingConvention::ID::CC_FASTCALL, &FastcallCallingConvention::create); - registerCC(CallingConvention::ID::CC_FASTCALL_PASCAL, &PascalFastcallCallingConvention::create); registerCC(CallingConvention::ID::CC_WATCOM, &WatcomCallingConvention::create); - registerCC(CallingConvention::ID::CC_SYSTEMVX64, &SystemVX64CallingConvention::create); - registerCC(CallingConvention::ID::CC_MICROSOFTX64, &MicrosoftX64CallingConvention::create); + registerCC(CallingConvention::ID::CC_X64, &X64CallingConvention::create); registerCC(CallingConvention::ID::CC_ARM, &ArmCallingConvention::create); registerCC(CallingConvention::ID::CC_ARM64, &Arm64CallingConvention::create); registerCC(CallingConvention::ID::CC_POWERPC, &PowerPCCallingConvention::create); registerCC(CallingConvention::ID::CC_POWERPC64, &PowerPC64CallingConvention::create); registerCC(CallingConvention::ID::CC_MIPS, &MipsCallingConvention::create); - registerCC(CallingConvention::ID::CC_MIPSPSP, &MipsPSPCallingConvention::create); registerCC(CallingConvention::ID::CC_MIPS64, &Mips64CallingConvention::create); registerCC(CallingConvention::ID::CC_PIC32, &Pic32CallingConvention::create); } diff --git a/src/bin2llvmir/providers/calling_convention/mips.cpp b/src/bin2llvmir/providers/calling_convention/mips.cpp deleted file mode 100644 index 71a47c6fe..000000000 --- a/src/bin2llvmir/providers/calling_convention/mips.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/** - * @file src/bin2llvmir/providers/calling_convention/mips.cpp - * @brief Calling conventions of MIPS architecture. - * @copyright (c) 2019 Avast Software, licensed under the MIT license - */ - -#include "retdec/bin2llvmir/providers/calling_convention/mips.h" -#include "retdec/capstone2llvmir/mips/mips.h" - -namespace retdec { -namespace bin2llvmir { - -// -//============================================================================== -// MipsCallingConvention -//============================================================================== -// - -MipsCallingConvention::MipsCallingConvention(const Abi* a) : - CallingConvention(a) -{ - _paramRegs = { - MIPS_REG_A0, - MIPS_REG_A1, - MIPS_REG_A2, - MIPS_REG_A3 - }; - _paramFPRegs = { - MIPS_REG_F12, - MIPS_REG_F14, - MIPS_REG_F16, - MIPS_REG_F18 - }; - _paramDoubleRegs = { - MIPS_REG_FD12, - MIPS_REG_FD14, - MIPS_REG_FD16, - }; - - _returnRegs = { - MIPS_REG_V0 - }; - - _numOfRegsPerParam = 2; - _largeObjectsPassedByReference = true; - _respectsRegCouples = true; -} - -MipsCallingConvention::~MipsCallingConvention() -{ -} - -CallingConvention::Ptr MipsCallingConvention::create(const Abi* a) -{ - return std::make_unique(a); -} - -// -//============================================================================== -// MipsPSPCallingConvention -//============================================================================== -// - -MipsPSPCallingConvention::MipsPSPCallingConvention(const Abi* a) : - CallingConvention(a) -{ - _paramRegs = { - MIPS_REG_A0, - MIPS_REG_A1, - MIPS_REG_A2, - MIPS_REG_A3, - MIPS_REG_T0, - MIPS_REG_T1, - MIPS_REG_T2, - MIPS_REG_T3 - }; - _paramFPRegs = { - MIPS_REG_F12, - MIPS_REG_F14, - MIPS_REG_F16, - MIPS_REG_F18 - }; - _paramDoubleRegs = { - MIPS_REG_FD12, - MIPS_REG_FD14, - MIPS_REG_FD16, - }; - - _returnRegs = { - MIPS_REG_V0 - }; - _returnFPRegs = { - MIPS_REG_V0 - }; - _returnDoubleRegs = { - MIPS_REG_V0 - }; - - _numOfRegsPerParam = 2; - _largeObjectsPassedByReference = true; - _respectsRegCouples = true; -} - -MipsPSPCallingConvention::~MipsPSPCallingConvention() -{ -} - -CallingConvention::Ptr MipsPSPCallingConvention::create(const Abi* a) -{ - return std::make_unique(a); -} - -} -} diff --git a/src/bin2llvmir/providers/calling_convention/mips/mips_conv.cpp b/src/bin2llvmir/providers/calling_convention/mips/mips_conv.cpp new file mode 100644 index 000000000..015b667c0 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/mips/mips_conv.cpp @@ -0,0 +1,65 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/mips/mips_conv.cpp + * @brief Calling conventions of MIPS architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h" +#include "retdec/capstone2llvmir/mips/mips.h" + +namespace retdec { +namespace bin2llvmir { + +MipsCallingConvention::MipsCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3 + }; + _paramFPRegs = { + MIPS_REG_F12, + MIPS_REG_F14, + MIPS_REG_F16, + MIPS_REG_F18 + }; + _paramDoubleRegs = { + MIPS_REG_FD12, + MIPS_REG_FD14, + MIPS_REG_FD16, + }; + + _returnRegs = { + MIPS_REG_V0 + }; + + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +MipsCallingConvention::~MipsCallingConvention() +{ +} + +CallingConvention::Ptr MipsCallingConvention::create(const Abi* a) +{ + if (!a->isMips()) + { + return nullptr; + } + + if (a->getConfig()->getConfig().tools.isPspGcc()) + { + return std::make_unique(a); + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/mips/mips_psp.cpp b/src/bin2llvmir/providers/calling_convention/mips/mips_psp.cpp new file mode 100644 index 000000000..28dc6a970 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/mips/mips_psp.cpp @@ -0,0 +1,58 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/mips/mips_psp.cpp + * @brief Calling conventions of MIPS architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h" +#include "retdec/capstone2llvmir/mips/mips.h" + +namespace retdec { +namespace bin2llvmir { + +MipsPSPCallingConvention::MipsPSPCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3, + MIPS_REG_T0, + MIPS_REG_T1, + MIPS_REG_T2, + MIPS_REG_T3 + }; + _paramFPRegs = { + MIPS_REG_F12, + MIPS_REG_F14, + MIPS_REG_F16, + MIPS_REG_F18 + }; + _paramDoubleRegs = { + MIPS_REG_FD12, + MIPS_REG_FD14, + MIPS_REG_FD16, + }; + + _returnRegs = { + MIPS_REG_V0 + }; + _returnFPRegs = { + MIPS_REG_V0 + }; + _returnDoubleRegs = { + MIPS_REG_V0 + }; + + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +MipsPSPCallingConvention::~MipsPSPCallingConvention() +{ +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/mips64.cpp b/src/bin2llvmir/providers/calling_convention/mips64/mips64_conv.cpp similarity index 74% rename from src/bin2llvmir/providers/calling_convention/mips64.cpp rename to src/bin2llvmir/providers/calling_convention/mips64/mips64_conv.cpp index ab6573866..c29bcdf9e 100644 --- a/src/bin2llvmir/providers/calling_convention/mips64.cpp +++ b/src/bin2llvmir/providers/calling_convention/mips64/mips64_conv.cpp @@ -1,10 +1,11 @@ /** - * @file src/bin2llvmir/providers/calling_convention/mips64.cpp - * @brief Calling conventions of Mips64 architecture. + * @file src/bin2llvmir/providers/calling_convention/mips64/mips64_conv.cpp + * @brief Calling convention of Mips64 architecture. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ -#include "retdec/bin2llvmir/providers/calling_convention/mips64.h" +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h" #include "retdec/capstone2llvmir/mips/mips.h" namespace retdec { @@ -51,6 +52,11 @@ Mips64CallingConvention::~Mips64CallingConvention() CallingConvention::Ptr Mips64CallingConvention::create(const Abi* a) { + if (!a->isMips64()) + { + return nullptr; + } + return std::make_unique(a); } diff --git a/src/bin2llvmir/providers/calling_convention/pic32.cpp b/src/bin2llvmir/providers/calling_convention/pic32/pic32_conv.cpp similarity index 74% rename from src/bin2llvmir/providers/calling_convention/pic32.cpp rename to src/bin2llvmir/providers/calling_convention/pic32/pic32_conv.cpp index 699afce7a..46f0bc03a 100644 --- a/src/bin2llvmir/providers/calling_convention/pic32.cpp +++ b/src/bin2llvmir/providers/calling_convention/pic32/pic32_conv.cpp @@ -1,10 +1,11 @@ /** - * @file src/bin2llvmir/providers/calling_convention/pic32.cpp + * @file src/bin2llvmir/providers/calling_convention/pic32/pic32_conv.cpp * @brief Calling conventions of PIC32 architecture. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ -#include "retdec/bin2llvmir/providers/calling_convention/pic32.h" +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h" #include "retdec/capstone2llvmir/mips/mips.h" namespace retdec { @@ -35,6 +36,11 @@ Pic32CallingConvention::~Pic32CallingConvention() CallingConvention::Ptr Pic32CallingConvention::create(const Abi* a) { + if (!a->isPic32()) + { + return nullptr; + } + return std::make_unique(a); } diff --git a/src/bin2llvmir/providers/calling_convention/powerpc.cpp b/src/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.cpp similarity index 84% rename from src/bin2llvmir/providers/calling_convention/powerpc.cpp rename to src/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.cpp index 888f4b143..fcd9589c7 100644 --- a/src/bin2llvmir/providers/calling_convention/powerpc.cpp +++ b/src/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.cpp @@ -1,10 +1,11 @@ /** - * @file src/bin2llvmir/providers/calling_convention/powerpc.cpp + * @file src/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.cpp * @brief Calling conventions of PowerPC architecture. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ -#include "retdec/bin2llvmir/providers/calling_convention/powerpc.h" +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h" #include "retdec/capstone2llvmir/powerpc/powerpc.h" namespace retdec { @@ -53,6 +54,11 @@ PowerPCCallingConvention::~PowerPCCallingConvention() CallingConvention::Ptr PowerPCCallingConvention::create(const Abi* a) { + if (!a->isPowerPC()) + { + return nullptr; + } + return std::make_unique(a); } diff --git a/src/bin2llvmir/providers/calling_convention/powerpc64.cpp b/src/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.cpp similarity index 84% rename from src/bin2llvmir/providers/calling_convention/powerpc64.cpp rename to src/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.cpp index 3a5b47635..c15373711 100644 --- a/src/bin2llvmir/providers/calling_convention/powerpc64.cpp +++ b/src/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.cpp @@ -1,10 +1,11 @@ /** - * @file src/bin2llvmir/providers/calling_convention/powerpc64.cpp + * @file src/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.cpp * @brief Calling conventions of PowerPC64 architecture. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ -#include "retdec/bin2llvmir/providers/calling_convention/powerpc64.h" +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h" #include "retdec/capstone2llvmir/powerpc/powerpc.h" namespace retdec { @@ -55,6 +56,11 @@ PowerPC64CallingConvention::~PowerPC64CallingConvention() CallingConvention::Ptr PowerPC64CallingConvention::create(const Abi* a) { + if (!a->isPowerPC64()) + { + return nullptr; + } + return std::make_unique(a); } diff --git a/src/bin2llvmir/providers/calling_convention/x64.cpp b/src/bin2llvmir/providers/calling_convention/x64.cpp deleted file mode 100644 index 148e1b399..000000000 --- a/src/bin2llvmir/providers/calling_convention/x64.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/** - * @file src/bin2llvmir/providers/calling_convention/x64.cpp - * @brief Calling conventions of X64 architecture. - * @copyright (c) 2019 Avast Software, licensed under the MIT license - */ - -#include "retdec/bin2llvmir/providers/calling_convention/x64.h" -#include "retdec/capstone2llvmir/x86/x86.h" - -namespace retdec { -namespace bin2llvmir { - -// -//============================================================================== -// SystemVX64CallingConvention -//============================================================================== -// - -SystemVX64CallingConvention::SystemVX64CallingConvention(const Abi* a) : - CallingConvention(a) -{ - _paramRegs = { - X86_REG_RDI, - X86_REG_RSI, - X86_REG_RDX, - X86_REG_RCX, - X86_REG_R8, - X86_REG_R9 - }; - _paramFPRegs = { - X86_REG_XMM0, - X86_REG_XMM1, - X86_REG_XMM2, - X86_REG_XMM3, - X86_REG_XMM4, - X86_REG_XMM5, - X86_REG_XMM6, - X86_REG_XMM7 - }; - _paramVectorRegs = { - X86_REG_XMM0, - X86_REG_XMM1, - X86_REG_XMM2, - X86_REG_XMM3, - X86_REG_XMM4, - X86_REG_XMM5, - X86_REG_XMM6, - X86_REG_XMM7 - }; - - _returnRegs = { - X86_REG_RAX, - X86_REG_RDX - }; - _returnFPRegs = { - X86_REG_XMM0, - X86_REG_XMM1 - }; - _returnVectorRegs = { - X86_REG_XMM0, - X86_REG_XMM1 - }; - - _largeObjectsPassedByReference = true; - _numOfRegsPerParam = 2; - _numOfFPRegsPerParam = 2; - _numOfVectorRegsPerParam = 2; -} - -SystemVX64CallingConvention::~SystemVX64CallingConvention() -{ -} - -CallingConvention::Ptr SystemVX64CallingConvention::create(const Abi* a) -{ - return std::make_unique(a); -} - -// -//============================================================================== -// MicrosoftX64CallingConvention -//============================================================================== -// - -MicrosoftX64CallingConvention::MicrosoftX64CallingConvention(const Abi* a) : - CallingConvention(a) -{ - _paramRegs = { - X86_REG_RCX, - X86_REG_RDX, - X86_REG_R8, - X86_REG_R9 - }; - _paramFPRegs = { - X86_REG_XMM0, - X86_REG_XMM1, - X86_REG_XMM2, - X86_REG_XMM3 - }; - - _returnRegs = { - X86_REG_RAX - }; - _returnFPRegs = { - X86_REG_XMM0 - }; - - _largeObjectsPassedByReference = true; -} - -MicrosoftX64CallingConvention::~MicrosoftX64CallingConvention() -{ -} - -CallingConvention::Ptr MicrosoftX64CallingConvention::create(const Abi* a) -{ - return std::make_unique(a); -} - - - -} -} diff --git a/src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp b/src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp new file mode 100644 index 000000000..c2b5ae8db --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp @@ -0,0 +1,36 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x64.cpp + * @brief Calling conventions of X64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h" +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +CallingConvention::Ptr X64CallingConvention::create(const Abi* a) +{ + if (!a->isX64()) + { + return nullptr; + } + + auto c = a->getConfig(); + bool isMinGW = c->getConfig().tools.isGcc() + && c->getConfig().fileFormat.isPe(); + + if (isMinGW || c->getConfig().tools.isMsvc()) + { + return std::make_unique(a); + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp b/src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp new file mode 100644 index 000000000..df90e42ba --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp @@ -0,0 +1,44 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x64.cpp + * @brief Microsoft calling convention of X64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +MicrosoftX64CallingConvention::MicrosoftX64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + X86_REG_RCX, + X86_REG_RDX, + X86_REG_R8, + X86_REG_R9 + }; + _paramFPRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3 + }; + + _returnRegs = { + X86_REG_RAX + }; + _returnFPRegs = { + X86_REG_XMM0 + }; + + _largeObjectsPassedByReference = true; +} + +MicrosoftX64CallingConvention::~MicrosoftX64CallingConvention() +{ +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp b/src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp new file mode 100644 index 000000000..6e6062e4b --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp @@ -0,0 +1,69 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x64.cpp + * @brief System V Calling convention of X64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +SystemVX64CallingConvention::SystemVX64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + X86_REG_RDI, + X86_REG_RSI, + X86_REG_RDX, + X86_REG_RCX, + X86_REG_R8, + X86_REG_R9 + }; + _paramFPRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3, + X86_REG_XMM4, + X86_REG_XMM5, + X86_REG_XMM6, + X86_REG_XMM7 + }; + _paramVectorRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3, + X86_REG_XMM4, + X86_REG_XMM5, + X86_REG_XMM6, + X86_REG_XMM7 + }; + + _returnRegs = { + X86_REG_RAX, + X86_REG_RDX + }; + _returnFPRegs = { + X86_REG_XMM0, + X86_REG_XMM1 + }; + _returnVectorRegs = { + X86_REG_XMM0, + X86_REG_XMM1 + }; + + _largeObjectsPassedByReference = true; + _numOfRegsPerParam = 2; + _numOfFPRegsPerParam = 2; + _numOfVectorRegsPerParam = 2; +} + +SystemVX64CallingConvention::~SystemVX64CallingConvention() +{ +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86.cpp b/src/bin2llvmir/providers/calling_convention/x86.cpp deleted file mode 100644 index dbea14c06..000000000 --- a/src/bin2llvmir/providers/calling_convention/x86.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/** - * @file src/bin2llvmir/providers/calling_convention/x86.cpp - * @brief Calling convention of architecture x86. - * @copyright (c) 2019 Avast Software, licensed under the MIT license - */ - -#include "retdec/bin2llvmir/providers/abi/abi.h" -#include "retdec/bin2llvmir/providers/calling_convention/x86.h" -#include "retdec/capstone2llvmir/x86/x86.h" - -namespace retdec { -namespace bin2llvmir { - -// -//============================================================================== -// CdeclCallingConvention -//============================================================================== -// - -CdeclCallingConvention::CdeclCallingConvention(const Abi* a) : - CallingConvention(a) -{ - _returnRegs = { - X86_REG_EAX, - X86_REG_EDX - }; - - _returnFPRegs = { - X86_REG_ST7, - X86_REG_ST0 - }; -} - -CdeclCallingConvention::~CdeclCallingConvention() -{ -} - -std::size_t CdeclCallingConvention::getMaxBytesPerStackParam() const -{ - return _abi->getWordSize()*2; -} - -CallingConvention::Ptr CdeclCallingConvention::create(const Abi* a) -{ - return std::make_unique(a); -} - -// -//============================================================================== -// FastcallCallingConvention -//============================================================================== -// - -FastcallCallingConvention::FastcallCallingConvention(const Abi* a) : - CallingConvention(a) - -{ - _paramRegs = { - X86_REG_ECX, - X86_REG_EDX, - }; - - _returnRegs = { - X86_REG_EAX, - X86_REG_EDX - }; - - _returnFPRegs = { - X86_REG_ST7, - X86_REG_ST0 - }; -} - -FastcallCallingConvention::~FastcallCallingConvention() -{ -} - -std::size_t FastcallCallingConvention::getMaxBytesPerStackParam() const -{ - return _abi->getWordSize()*2; -} - -CallingConvention::Ptr FastcallCallingConvention::create(const Abi* a) -{ - return std::make_unique(a); -} - -// -//============================================================================== -// PascalCallingConvention -//============================================================================== -// - -PascalCallingConvention::PascalCallingConvention(const Abi* a) : - CallingConvention(a) - -{ - _returnRegs = { - X86_REG_EAX, - X86_REG_EDX - }; - - _returnFPRegs = { - X86_REG_ST7, - X86_REG_ST0 - }; - - _stackParamOrder = LTR; -} - -PascalCallingConvention::~PascalCallingConvention() -{ -} - -std::size_t PascalCallingConvention::getMaxBytesPerStackParam() const -{ - return _abi->getWordSize()*2; -} - -CallingConvention::Ptr PascalCallingConvention::create(const Abi* a) -{ - return std::make_unique(a); -} - -// -//============================================================================== -// PascalFastcallCallingConvention -//============================================================================== -// - -PascalFastcallCallingConvention::PascalFastcallCallingConvention(const Abi* a) : - CallingConvention(a) - -{ - _paramRegs = { - X86_REG_ECX, - X86_REG_EDX, - }; - - _returnRegs = { - X86_REG_EAX, - X86_REG_EDX - }; - - _returnFPRegs = { - X86_REG_ST7, - X86_REG_ST0 - }; - - _stackParamOrder = LTR; -} - -PascalFastcallCallingConvention::~PascalFastcallCallingConvention() -{ -} - -std::size_t PascalFastcallCallingConvention::getMaxBytesPerStackParam() const -{ - return _abi->getWordSize()*2; -} - -CallingConvention::Ptr PascalFastcallCallingConvention::create(const Abi* a) -{ - return std::make_unique(a); -} - -// -//============================================================================== -// ThiscallCallingConvention -//============================================================================== -// - -ThiscallCallingConvention::ThiscallCallingConvention(const Abi* a) : - CallingConvention(a) - -{ - _paramRegs = { - X86_REG_ECX - }; - - _returnRegs = { - X86_REG_EAX, - X86_REG_EDX - }; - - _returnFPRegs = { - X86_REG_ST7, - X86_REG_ST0 - }; -} - -ThiscallCallingConvention::~ThiscallCallingConvention() -{ -} - -std::size_t ThiscallCallingConvention::getMaxBytesPerStackParam() const -{ - return _abi->getWordSize()*2; -} - -CallingConvention::Ptr ThiscallCallingConvention::create(const Abi* a) -{ - return std::make_unique(a); -} - -// -//============================================================================== -// WatcomCallingConvention -//============================================================================== -// - -WatcomCallingConvention::WatcomCallingConvention(const Abi* a) : - CallingConvention(a) - -{ - _paramRegs = { - X86_REG_ECX - }; - - _returnRegs = { - X86_REG_EAX, - X86_REG_EDX - }; - - _returnFPRegs = { - X86_REG_ST7, - X86_REG_ST0 - }; -} - -WatcomCallingConvention::~WatcomCallingConvention() -{ -} - -std::size_t WatcomCallingConvention::getMaxBytesPerStackParam() const -{ - return _abi->getWordSize()*2; -} - -CallingConvention::Ptr WatcomCallingConvention::create(const Abi* a) -{ - return std::make_unique(a); -} - -} -} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_cdecl.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_cdecl.cpp new file mode 100644 index 000000000..87ef9a78e --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_cdecl.cpp @@ -0,0 +1,43 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_cdecl.cpp + * @brief Cdecl calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +CdeclCallingConvention::CdeclCallingConvention(const Abi* a) : + X86CallingConvention(a) +{ + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; +} + +CdeclCallingConvention::~CdeclCallingConvention() +{ +} + +CallingConvention::Ptr CdeclCallingConvention::create(const Abi* a) +{ + if (!a->isX86()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_conv.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_conv.cpp new file mode 100644 index 000000000..3c50f2983 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_conv.cpp @@ -0,0 +1,26 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_conv.cpp + * @brief Calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +X86CallingConvention::X86CallingConvention(const Abi* a) : + CallingConvention(a) + +{ +} + +std::size_t X86CallingConvention::getMaxBytesPerStackParam() const +{ + return _abi->getWordSize()*2; +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp new file mode 100644 index 000000000..95430b948 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp @@ -0,0 +1,92 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp + * @brief Fastcall calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================== +// PascalFastcallCallingConvention +//============================================================================== +// + +PascalFastcallCallingConvention::PascalFastcallCallingConvention(const Abi* a) : + X86CallingConvention(a) + +{ + _paramRegs = { + X86_REG_ECX, + X86_REG_EDX, + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; + + _stackParamOrder = LTR; +} + +PascalFastcallCallingConvention::~PascalFastcallCallingConvention() +{ +} + +// +//============================================================================== +// FastcallCallingConvention +//============================================================================== +// + +FastcallCallingConvention::FastcallCallingConvention(const Abi* a) : + X86CallingConvention(a) + +{ + _paramRegs = { + X86_REG_ECX, + X86_REG_EDX, + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; +} + +FastcallCallingConvention::~FastcallCallingConvention() +{ +} + +CallingConvention::Ptr FastcallCallingConvention::create(const Abi* a) +{ + if (!a->isX86()) + { + return nullptr; + } + + if (a->getConfig()->getConfig().tools.isBorland()) + { + return std::make_unique(a); + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_pascal.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_pascal.cpp new file mode 100644 index 000000000..66fa1b155 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_pascal.cpp @@ -0,0 +1,46 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_pascal.cpp + * @brief Pascal calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +PascalCallingConvention::PascalCallingConvention(const Abi* a) : + X86CallingConvention(a) + +{ + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; + + _stackParamOrder = LTR; +} + +PascalCallingConvention::~PascalCallingConvention() +{ +} + +CallingConvention::Ptr PascalCallingConvention::create(const Abi* a) +{ + if (!a->isX86()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_thiscall.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_thiscall.cpp new file mode 100644 index 000000000..b5f9dd247 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_thiscall.cpp @@ -0,0 +1,48 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_thiscall.cpp + * @brief Thiscall calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +ThiscallCallingConvention::ThiscallCallingConvention(const Abi* a) : + X86CallingConvention(a) + +{ + _paramRegs = { + X86_REG_ECX + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; +} + +ThiscallCallingConvention::~ThiscallCallingConvention() +{ +} + +CallingConvention::Ptr ThiscallCallingConvention::create(const Abi* a) +{ + if (!a->isX86()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp new file mode 100644 index 000000000..0cfe72b69 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp @@ -0,0 +1,48 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp + * @brief Watcom calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +WatcomCallingConvention::WatcomCallingConvention(const Abi* a) : + X86CallingConvention(a) + +{ + _paramRegs = { + X86_REG_ECX + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; +} + +WatcomCallingConvention::~WatcomCallingConvention() +{ +} + +CallingConvention::Ptr WatcomCallingConvention::create(const Abi* a) +{ + if (!a->isX86()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} From 50f26551c1747cc7fbf30722278b35e43784dc9b Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 13:11:07 +0100 Subject: [PATCH 146/159] collector/pic32: separate special collector --- .../param_return/collector/collector.h | 14 ------ .../param_return/collector/pic32.h | 32 +++++++++++++ .../param_return/collector/collector.cpp | 33 +------------ .../param_return/collector/pic32.cpp | 48 +++++++++++++++++++ 4 files changed, 81 insertions(+), 46 deletions(-) create mode 100644 include/retdec/bin2llvmir/optimizations/param_return/collector/pic32.h create mode 100644 src/bin2llvmir/optimizations/param_return/collector/pic32.cpp diff --git a/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h b/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h index 7360442cf..9a4daf199 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h @@ -86,20 +86,6 @@ class Collector const ReachingDefinitionsAnalysis* _rda; }; -class CollectorPic32 : public Collector -{ - public: - CollectorPic32( - const Abi* abi, - llvm::Module* m, - const ReachingDefinitionsAnalysis* rda); - - virtual ~CollectorPic32() override; - - public: - virtual void collectCallSpecificTypes(CallEntry* ce) const override; -}; - class CollectorProvider { public: diff --git a/include/retdec/bin2llvmir/optimizations/param_return/collector/pic32.h b/include/retdec/bin2llvmir/optimizations/param_return/collector/pic32.h new file mode 100644 index 000000000..e69ae762b --- /dev/null +++ b/include/retdec/bin2llvmir/optimizations/param_return/collector/pic32.h @@ -0,0 +1,32 @@ +/** +* @file include/retdec/bin2llvmir/optimizations/param_return/collector/pic32.h +* @brief Pic32 specific collection algorithms. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_COLLECTOR_PIC32_H +#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_COLLECTOR_PIC32_H + +#include "retdec/bin2llvmir/optimizations/param_return/collector/collector.h" + +namespace retdec { +namespace bin2llvmir { + +class CollectorPic32 : public Collector +{ + public: + CollectorPic32( + const Abi* abi, + llvm::Module* m, + const ReachingDefinitionsAnalysis* rda); + + virtual ~CollectorPic32() override; + + public: + virtual void collectCallSpecificTypes(CallEntry* ce) const override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/optimizations/param_return/collector/collector.cpp b/src/bin2llvmir/optimizations/param_return/collector/collector.cpp index c8c427c6a..5179d6686 100644 --- a/src/bin2llvmir/optimizations/param_return/collector/collector.cpp +++ b/src/bin2llvmir/optimizations/param_return/collector/collector.cpp @@ -10,6 +10,7 @@ #include #include "retdec/bin2llvmir/optimizations/param_return/collector/collector.h" +#include "retdec/bin2llvmir/optimizations/param_return/collector/pic32.h" using namespace retdec::utils; using namespace llvm; @@ -591,38 +592,6 @@ llvm::Value* Collector::getRoot(llvm::Value* i, bool first) const return i; } -CollectorPic32::CollectorPic32( - const Abi* abi, - llvm::Module* m, - const ReachingDefinitionsAnalysis* rda) : - Collector(abi, m, rda) -{ -} - -CollectorPic32::~CollectorPic32() -{ -} - -void CollectorPic32::collectCallSpecificTypes(CallEntry* ce) const -{ - Collector::collectCallSpecificTypes(ce); - - std::vector argTypes; - for (auto t : ce->argTypes()) - { - if (t->isDoubleTy()) - { - argTypes.push_back(Type::getFloatTy(_module->getContext())); - } - else - { - argTypes.push_back(t); - } - } - - ce->setArgTypes(std::move(argTypes)); -} - // //============================================================================= // CollectorProvider diff --git a/src/bin2llvmir/optimizations/param_return/collector/pic32.cpp b/src/bin2llvmir/optimizations/param_return/collector/pic32.cpp new file mode 100644 index 000000000..1a0f368c6 --- /dev/null +++ b/src/bin2llvmir/optimizations/param_return/collector/pic32.cpp @@ -0,0 +1,48 @@ +/** +* @file src/bin2llvmir/optimizations/param_return/collector.cpp +* @brief Pic32 specific collection algorithms. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#include "retdec/bin2llvmir/optimizations/param_return/collector/pic32.h" + +using namespace retdec::utils; +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +CollectorPic32::CollectorPic32( + const Abi* abi, + llvm::Module* m, + const ReachingDefinitionsAnalysis* rda) : + Collector(abi, m, rda) +{ +} + +CollectorPic32::~CollectorPic32() +{ +} + +void CollectorPic32::collectCallSpecificTypes(CallEntry* ce) const +{ + Collector::collectCallSpecificTypes(ce); + + std::vector argTypes; + for (auto t : ce->argTypes()) + { + if (t->isDoubleTy()) + { + argTypes.push_back(Type::getFloatTy(_module->getContext())); + } + else + { + argTypes.push_back(t); + } + } + + ce->setArgTypes(std::move(argTypes)); +} + +} +} From e42ed24139901de8b777b84638d7d9a14464465a Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 00:11:15 +0100 Subject: [PATCH 147/159] param_return: disabling find of arg loads At this moment retdec does not use info from argument loads as this info is not reliable for parameter and return value analysis. --- .../optimizations/param_return/param_return.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index 28bfeae46..5d763c5c5 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -457,7 +457,16 @@ void ParamReturn::addDataFromCall(DataFlowEntry* dataflow, CallInst* call) const CallEntry* ce = dataflow->createCallEntry(call); _collector->collectCallArgs(ce); - _collector->collectCallRets(ce); + + // TODO: Use info from collecting return loads. + // + // At this moment info return loads is not used + // as it is not reliable source of info + // about return value. To enable this + // collector must have redesigned and reimplemented + // collection algorithm. + // + //_collector->collectCallRets(ce); collectExtraData(ce); } From e4aa80423be872d93b3089807ff76ffea98ea439 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 13:23:51 +0100 Subject: [PATCH 148/159] collector/pic32: update cmakelist --- src/bin2llvmir/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 1d698f7c8..bd310f736 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -49,6 +49,7 @@ set(BIN2LLVMIR_SOURCES optimizations/local_vars/local_vars.cpp optimizations/main_detection/main_detection.cpp optimizations/param_return/collector/collector.cpp + optimizations/param_return/collector/pic32.cpp optimizations/param_return/filter/filter.cpp optimizations/param_return/param_return.cpp optimizations/param_return/data_entries.cpp From 212e94f0df631ab4fcaf80daca49e98b0803816b Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 14:19:21 +0100 Subject: [PATCH 149/159] param_return_tests: enable calling convention unit tests --- .../param_return/param_return_tests.cpp | 43 ++++++++++++++++--- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 96b3eb8db..42f6f2680 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -3364,7 +3364,6 @@ TEST_F(ParamReturnTests, mips64ExternalCallUseStacksIf8RegistersUsed) checkModuleAgainstExpectedIr(exp); } -/* TEST_F(ParamReturnTests, x86FastcallBasic) { parseInput(R"( @@ -3390,6 +3389,10 @@ TEST_F(ParamReturnTests, x86FastcallBasic) "endian" : "little", "name" : "x86" }, + "tools" : + [ + { "name" : "gcc" } + ], "functions" : [ { "name" : "fnc", @@ -3402,12 +3405,12 @@ TEST_F(ParamReturnTests, x86FastcallBasic) "name" : "stack_-8", "storage" : { "type" : "stack", "value" : -8 } } - ] + ], + "callingConvention" : "fastcall", } ] })"); - AbiMips64 abi(module.get(), &config); abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); @@ -3469,6 +3472,10 @@ TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) "endian" : "little", "name" : "x86" }, + "tools" : + [ + { "name" : "gcc" } + ], "functions" : [ { "name" : "fnc", @@ -3481,7 +3488,8 @@ TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) "name" : "stack_-8", "storage" : { "type" : "stack", "value" : -8 } } - ] + ], + "calingConvention" : "fastcall", } ] @@ -3540,6 +3548,10 @@ TEST_F(ParamReturnTests, x86PascalBasic) "endian" : "little", "name" : "x86" }, + "tools" : + [ + { "name" : "borland" } + ], "functions" : [ { "name" : "fnc", @@ -3604,6 +3616,10 @@ TEST_F(ParamReturnTests, x86PascalFastcallBasic) "endian" : "little", "name" : "x86" }, + "tools" : + [ + { "name" : "borland" } + ], "functions" : [ { "name" : "fnc", @@ -3616,7 +3632,8 @@ TEST_F(ParamReturnTests, x86PascalFastcallBasic) "name" : "stack_-8", "storage" : { "type" : "stack", "value" : -8 } } - ] + ], + "callingConvention" : "fastcall", } ] })"); @@ -3683,6 +3700,10 @@ TEST_F(ParamReturnTests, x86PascalFastcallLargeType) "endian" : "little", "name" : "x86" }, + "tools" : + [ + { "name" : "borland" } + ], "functions" : [ { "name" : "fnc", @@ -3695,7 +3716,8 @@ TEST_F(ParamReturnTests, x86PascalFastcallLargeType) "name" : "stack_-8", "storage" : { "type" : "stack", "value" : -8 } } - ] + ], + "callingConvention" : "fastcall", } ] })"); @@ -3762,6 +3784,10 @@ TEST_F(ParamReturnTests, x86WatcomBasic) "endian" : "little", "name" : "x86" }, + "tools" : + [ + { "name" : "open_watcom" } + ], "functions" : [ { "name" : "fnc", @@ -3845,6 +3871,10 @@ TEST_F(ParamReturnTests, x86WatcomPassDouble) "endian" : "little", "name" : "x86" }, + "tools" : + [ + { "name" : "open_watcom" } + ], "functions" : [ { "name" : "fnc", @@ -3895,7 +3925,6 @@ TEST_F(ParamReturnTests, x86WatcomPassDouble) )"; checkModuleAgainstExpectedIr(exp); } -*/ } // namespace tests } // namespace bin2llvmir From a19aeee9a76160defb87cd1d598771d7f700485d Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 15:21:19 +0100 Subject: [PATCH 150/159] calling_convention: fastcall: pascal: fix parameter registers --- .../providers/calling_convention/x86/x86_fastcall.cpp | 3 ++- src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp index 95430b948..995620a79 100644 --- a/src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp @@ -22,8 +22,9 @@ PascalFastcallCallingConvention::PascalFastcallCallingConvention(const Abi* a) : { _paramRegs = { - X86_REG_ECX, + X86_REG_EAX, X86_REG_EDX, + X86_REG_ECX }; _returnRegs = { diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp index 0cfe72b69..34abcb773 100644 --- a/src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp @@ -16,6 +16,9 @@ WatcomCallingConvention::WatcomCallingConvention(const Abi* a) : { _paramRegs = { + X86_REG_EAX, + X86_REG_EDX, + X86_REG_EBX, X86_REG_ECX }; From 07e1b7e4ec98aa4d3ab66f50426ee4b2ad78e271 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 15:21:54 +0100 Subject: [PATCH 151/159] param_return_tests: fix caling conventions tests --- .../param_return/param_return_tests.cpp | 149 +++++++++++------- 1 file changed, 90 insertions(+), 59 deletions(-) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 42f6f2680..0df87aba4 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -3371,6 +3371,7 @@ TEST_F(ParamReturnTests, x86FastcallBasic) @edx = global i32 0 @ecx = global i32 0 @r = global i32 0 + declare void @a() define void @fnc() { %stack_-4 = alloca i32 %stack_-8 = alloca i32 @@ -3378,8 +3379,7 @@ TEST_F(ParamReturnTests, x86FastcallBasic) store i32 1, i32* @edx store i32 123, i32* %stack_-4 store i32 456, i32* %stack_-8 - %a = bitcast i32* @r to void()* - call void %a() + call void @a() ret void } )"); @@ -3405,18 +3405,21 @@ TEST_F(ParamReturnTests, x86FastcallBasic) "name" : "stack_-8", "storage" : { "type" : "stack", "value" : -8 } } - ], - "callingConvention" : "fastcall", + ] + }, + { + "name" : "a", + "callingConvention" : "fastcall" } ] })"); - AbiMips64 abi(module.get(), &config); - abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); - abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); - abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi->addRegister(X86_REG_ECX, getGlobalByName("ecx")); + abi->addRegister(X86_REG_EDX, getGlobalByName("edx")); - pass.runOnModuleCustom(*module, &config, &abi); + pass.runOnModuleCustom(*module, &config, abi); std::string exp = R"( @eax = global i32 0 @@ -3424,6 +3427,10 @@ TEST_F(ParamReturnTests, x86FastcallBasic) @ecx = global i32 0 @r = global i32 0 + declare i32 @a(i32, i32, i32, i32) + + declare void @0() + define i32 @fnc() { %stack_-4 = alloca i32 %stack_-8 = alloca i32 @@ -3431,18 +3438,17 @@ TEST_F(ParamReturnTests, x86FastcallBasic) store i32 1, i32* @edx store i32 123, i32* %stack_-4 store i32 456, i32* %stack_-8 - %a = bitcast i32* @r to void()* %1 = load i32, i32* @ecx %2 = load i32, i32* @edx %3 = load i32, i32* %stack_-8 %4 = load i32, i32* %stack_-4 - %5 = bitcast void ()* %a to void (i32, i32, i32, i32)* - call void %5(i32 %1, i32 %2, i32 %3, i32 %4) + %5 = call i32 @a(i32 %1, i32 %2, i32 %3, i32 %4) + store i32 %5, i32* @eax %6 = load i32, i32* @eax ret i32 %6 } - declare void @0() + declare void @1() )"; checkModuleAgainstExpectedIr(exp); } @@ -3455,14 +3461,14 @@ TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) @ecx = global i32 0 @edx = global i32 0 @eax = global i32 0 + declare void @a() define void @fnc() { %stack_-4 = alloca i32 %stack_-8 = alloca i32 store i32 123, i32* @ecx store i32 456, i32* %stack_-4 store i32 789, i32* %stack_-8 - %a = bitcast i32* @r to void()* - call void %a() + call void @a() ret void } )"); @@ -3489,17 +3495,21 @@ TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) "storage" : { "type" : "stack", "value" : -8 } } ], - "calingConvention" : "fastcall", + "calingConvention" : "fastcall" + }, + { + "name" : "a", + "callingConvention" : "fastcall" } ] })"); - AbiMips64 abi(module.get(), &config); - abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); - abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_ECX, getGlobalByName("ecx")); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); - pass.runOnModuleCustom(*module, &config, &abi); + pass.runOnModuleCustom(*module, &config, abi); std::string exp = R"( @r = global i32 0 @@ -3507,23 +3517,26 @@ TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) @edx = global i32 0 @eax = global i32 0 + declare i32 @a(i32, i32, i32) + + declare void @0() + define i32 @fnc() { %stack_-4 = alloca i32 %stack_-8 = alloca i32 store i32 123, i32* @ecx store i32 456, i32* %stack_-4 store i32 789, i32* %stack_-8 - %a = bitcast i32* @r to void()* %1 = load i32, i32* @ecx %2 = load i32, i32* %stack_-8 %3 = load i32, i32* %stack_-4 - %4 = bitcast void ()* %a to void (i32, i32, i32)* - call void %4(i32 %1, i32 %2, i32 %3) + %4 = call i32 @a(i32 %1, i32 %2, i32 %3) + store i32 %4, i32* @eax %5 = load i32, i32* @eax ret i32 %5 } - declare void @0() + declare void @1() )"; checkModuleAgainstExpectedIr(exp); } @@ -3568,9 +3581,9 @@ TEST_F(ParamReturnTests, x86PascalBasic) } ] })"); - AbiMips64 abi(module.get(), &config); - pass.runOnModuleCustom(*module, &config, &abi); + auto abi = AbiProvider::addAbi(module.get(), &config); + pass.runOnModuleCustom(*module, &config, abi); std::string exp = R"( @r = global i32 0 @@ -3597,6 +3610,9 @@ TEST_F(ParamReturnTests, x86PascalFastcallBasic) @edx = global i32 0 @ecx = global i32 0 @r = global i32 0 + + declare void @a() + define void @fnc() { %stack_-4 = alloca i32 %stack_-8 = alloca i32 @@ -3605,8 +3621,7 @@ TEST_F(ParamReturnTests, x86PascalFastcallBasic) store i32 1, i32* @edx store i32 123, i32* %stack_-4 store i32 456, i32* %stack_-8 - %a = bitcast i32* @r to void()* - call void %a() + call void @a() ret void } )"); @@ -3633,17 +3648,21 @@ TEST_F(ParamReturnTests, x86PascalFastcallBasic) "storage" : { "type" : "stack", "value" : -8 } } ], - "callingConvention" : "fastcall", + "callingConvention" : "fastcall" + }, + { + "name" : "a", + "callingConvention" : "fastcall" } ] })"); - AbiMips64 abi(module.get(), &config); - abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); - abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); - abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi->addRegister(X86_REG_EDX, getGlobalByName("edx")); + abi->addRegister(X86_REG_ECX, getGlobalByName("ecx")); - pass.runOnModuleCustom(*module, &config, &abi); + pass.runOnModuleCustom(*module, &config, abi); std::string exp = R"( @eax = global i32 0 @@ -3651,6 +3670,10 @@ TEST_F(ParamReturnTests, x86PascalFastcallBasic) @ecx = global i32 0 @r = global i32 0 + declare i32 @a(i32, i32, i32, i32, i32) + + declare void @0() + define i32 @fnc() { %stack_-4 = alloca i32 %stack_-8 = alloca i32 @@ -3659,19 +3682,18 @@ TEST_F(ParamReturnTests, x86PascalFastcallBasic) store i32 1, i32* @edx store i32 123, i32* %stack_-4 store i32 456, i32* %stack_-8 - %a = bitcast i32* @r to void()* %1 = load i32, i32* @eax %2 = load i32, i32* @edx %3 = load i32, i32* @ecx %4 = load i32, i32* %stack_-4 %5 = load i32, i32* %stack_-8 - %6 = bitcast void ()* %a to void (i32, i32, i32, i32, i32)* - call void %6(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5) + %6 = call i32 @a(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5) + store i32 %6, i32* @eax %7 = load i32, i32* @eax ret i32 %7 } - declare void @0() + declare void @1() )"; checkModuleAgainstExpectedIr(exp); } @@ -3682,6 +3704,9 @@ TEST_F(ParamReturnTests, x86PascalFastcallLargeType) @eax = global i32 0 @edx = global i32 0 @r = global i32 0 + + declare void @a() + define void @fnc() { %stack_-4 = alloca i32 %stack_-8 = alloca i32 @@ -3689,8 +3714,7 @@ TEST_F(ParamReturnTests, x86PascalFastcallLargeType) store i32 456, i32* %stack_-8 store i32 123, i32* %stack_-4 store i32 1, i32* @edx - %a = bitcast i32* @r to void()* - call void %a() + call void @a() ret void } )"); @@ -3717,22 +3741,30 @@ TEST_F(ParamReturnTests, x86PascalFastcallLargeType) "storage" : { "type" : "stack", "value" : -8 } } ], - "callingConvention" : "fastcall", + "callingConvention" : "fastcall" + }, + { + "name" : "a", + "callingConvention" : "fastcall" } ] })"); - AbiMips64 abi(module.get(), &config); - abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); - abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi->addRegister(X86_REG_EDX, getGlobalByName("edx")); - pass.runOnModuleCustom(*module, &config, &abi); + pass.runOnModuleCustom(*module, &config, abi); std::string exp = R"( @eax = global i32 0 @edx = global i32 0 @r = global i32 0 + declare i32 @a(i32, i32, i32, i32) + + declare void @0() + define i32 @fnc() { %stack_-4 = alloca i32 %stack_-8 = alloca i32 @@ -3740,18 +3772,17 @@ TEST_F(ParamReturnTests, x86PascalFastcallLargeType) store i32 456, i32* %stack_-8 store i32 123, i32* %stack_-4 store i32 1, i32* @edx - %a = bitcast i32* @r to void()* %1 = load i32, i32* @eax %2 = load i32, i32* @edx %3 = load i32, i32* %stack_-4 %4 = load i32, i32* %stack_-8 - %5 = bitcast void ()* %a to void (i32, i32, i32, i32)* - call void %5(i32 %1, i32 %2, i32 %3, i32 %4) + %5 = call i32 @a(i32 %1, i32 %2, i32 %3, i32 %4) + store i32 %5, i32* @eax %6 = load i32, i32* @eax ret i32 %6 } - declare void @0() + declare void @1() )"; checkModuleAgainstExpectedIr(exp); } @@ -3805,13 +3836,13 @@ TEST_F(ParamReturnTests, x86WatcomBasic) ] })"); - AbiMips64 abi(module.get(), &config); - abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); - abi.addRegister(X86_REG_EBX, getGlobalByName("ebx")); - abi.addRegister(X86_REG_ECX, getGlobalByName("ecx")); - abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi->addRegister(X86_REG_EBX, getGlobalByName("ebx")); + abi->addRegister(X86_REG_ECX, getGlobalByName("ecx")); + abi->addRegister(X86_REG_EDX, getGlobalByName("edx")); - pass.runOnModuleCustom(*module, &config, &abi); + pass.runOnModuleCustom(*module, &config, abi); std::string exp = R"( @eax = global i32 0 @@ -3892,11 +3923,11 @@ TEST_F(ParamReturnTests, x86WatcomPassDouble) ] })"); - AbiMips64 abi(module.get(), &config); - abi.addRegister(X86_REG_EAX, getGlobalByName("eax")); - abi.addRegister(X86_REG_EDX, getGlobalByName("edx")); + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi->addRegister(X86_REG_EDX, getGlobalByName("edx")); - pass.runOnModuleCustom(*module, &config, &abi); + pass.runOnModuleCustom(*module, &config, abi); std::string exp = R"( @eax = global i32 0 From e02ae8daf665a75f37711e10e1e3be400990c99c Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 15:28:22 +0100 Subject: [PATCH 152/159] param_return_tests: enable ms x64 unit tests --- .../param_return/param_return_tests.cpp | 157 +++++++++--------- 1 file changed, 75 insertions(+), 82 deletions(-) diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 0df87aba4..00f29a5c9 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -1348,7 +1348,6 @@ TEST_F(ParamReturnTests, x86_64UsesJustContinuousSequenceOfRegisters) checkModuleAgainstExpectedIr(exp); } -/* TEST_F(ParamReturnTests, ms_x64PtrCallBasicFunctionality) { parseInput(R"( @@ -1605,8 +1604,6 @@ TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegisters) declare void @print() define void @fnc() { - store i64 1, i64* @r9 - store i64 1, i64* @r8 store double 2.0, double* @xmm1 store double 2.0, double* @xmm0 call void @print() @@ -1645,25 +1642,19 @@ TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegisters) @xmm0 = global double 0.000000e+00 @xmm1 = global double 0.000000e+00 - declare i64 @print(i64, i64, float, float) + declare i64 @print(double, double) declare void @0() define i64 @fnc() { - store i64 1, i64* @r9 - store i64 1, i64* @r8 store double 2.000000e+00, double* @xmm1 store double 2.000000e+00, double* @xmm0 - %1 = load i64, i64* @r8 - %2 = load i64, i64* @r9 - %3 = load double, double* @xmm0 - %4 = fptrunc double %3 to float - %5 = load double, double* @xmm1 - %6 = fptrunc double %5 to float - %7 = call i64 @print(i64 %1, i64 %2, float %4, float %6) - store i64 %7, i64* @rax - %8 = load i64, i64* @rax - ret i64 %8 + %1 = load double, double* @xmm0 + %2 = load double, double* @xmm1 + %3 = call i64 @print(double %1, double %2) + store i64 %3, i64* @rax + %4 = load i64, i64* @rax + ret i64 %4 } declare void @1() @@ -1672,23 +1663,22 @@ TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegisters) checkModuleAgainstExpectedIr(exp); } -TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegistersAdvanced) +TEST_F(ParamReturnTests, ms_x64UsesJustContinuousSequenceOfRegisters) { parseInput(R"( target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + @rax = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 @rcx = global i64 0 @rdx = global i64 0 - @rax = global i64 0 - @xmm2 = global double 0.0 - @xmm3 = global double 0.0 declare void @print() define void @fnc() { + store i64 1, i64* @r9 + store i64 1, i64* @r8 store i64 1, i64* @rcx - store i64 1, i64* @rdx - store double 2.0, double* @xmm2 - store double 2.0, double* @xmm3 call void @print() ret void } @@ -1705,69 +1695,63 @@ TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegistersAdvanced) {"name" : "gcc"} ] })"); - auto abi = AbiProvider::addAbi(module.get(), &config); abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); - abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); - abi->addRegister(X86_REG_XMM2, getGlobalByName("xmm2")); - abi->addRegister(X86_REG_XMM3, getGlobalByName("xmm3")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); pass.runOnModuleCustom(*module, &config, abi); std::string exp = R"( - target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - - @rcx = global i64 0 - @rdx = global i64 0 - @rax = global i64 0 - @xmm2 = global double 0.000000e+00 - @xmm3 = global double 0.000000e+00 + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - declare i64 @print(i64, i64, float, float) + @rax = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 - declare void @0() + declare i64 @print(i64) - define i64 @fnc() { - store i64 1, i64* @rcx - store i64 1, i64* @rdx - store double 2.000000e+00, double* @xmm2 - store double 2.000000e+00, double* @xmm3 - %1 = load i64, i64* @rcx - %2 = load i64, i64* @rdx - %3 = load double, double* @xmm2 - %4 = fptrunc double %3 to float - %5 = load double, double* @xmm3 - %6 = fptrunc double %5 to float - %7 = call i64 @print(i64 %1, i64 %2, float %4, float %6) - store i64 %7, i64* @rax - %8 = load i64, i64* @rax - ret i64 %8 - } + declare void @0() - declare void @1() + define i64 @fnc() { + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store i64 1, i64* @rcx + %1 = load i64, i64* @rcx + %2 = call i64 @print(i64 %1) + store i64 %2, i64* @rax + %3 = load i64, i64* @rax + ret i64 %3 + } + declare void @1() )"; checkModuleAgainstExpectedIr(exp); } -TEST_F(ParamReturnTests, ms_x64UsesJustContinuousSequenceOfRegisters) +/* +TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegistersAdvanced) { parseInput(R"( target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - @rax = global i64 0 - @r8 = global i64 0 - @r9 = global i64 0 @rcx = global i64 0 @rdx = global i64 0 + @rax = global i64 0 + @xmm2 = global double 0.0 + @xmm3 = global double 0.0 declare void @print() define void @fnc() { - store i64 1, i64* @r9 - store i64 1, i64* @r8 store i64 1, i64* @rcx + store i64 1, i64* @rdx + store double 2.0, double* @xmm2 + store double 2.0, double* @xmm3 call void @print() ret void } @@ -1784,44 +1768,53 @@ TEST_F(ParamReturnTests, ms_x64UsesJustContinuousSequenceOfRegisters) {"name" : "gcc"} ] })"); + auto abi = AbiProvider::addAbi(module.get(), &config); abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); - abi->addRegister(X86_REG_R8, getGlobalByName("r8")); - abi->addRegister(X86_REG_R9, getGlobalByName("r9")); - abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_XMM2, getGlobalByName("xmm2")); + abi->addRegister(X86_REG_XMM3, getGlobalByName("xmm3")); pass.runOnModuleCustom(*module, &config, abi); std::string exp = R"( - target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - @rax = global i64 0 - @r8 = global i64 0 - @r9 = global i64 0 - @rcx = global i64 0 - @rdx = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + @xmm2 = global double 0.000000e+00 + @xmm3 = global double 0.000000e+00 - declare i64 @print(i64) + declare i64 @print(i64, i64, float, float) - declare void @0() + declare void @0() - define i64 @fnc() { - store i64 1, i64* @r9 - store i64 1, i64* @r8 - store i64 1, i64* @rcx - %1 = load i64, i64* @rcx - %2 = call i64 @print(i64 %1) - store i64 %2, i64* @rax - %3 = load i64, i64* @rax - ret i64 %3 - } + define i64 @fnc() { + store i64 1, i64* @rcx + store i64 1, i64* @rdx + store double 2.000000e+00, double* @xmm2 + store double 2.000000e+00, double* @xmm3 + %1 = load i64, i64* @rcx + %2 = load i64, i64* @rdx + %3 = load double, double* @xmm2 + %4 = fptrunc double %3 to float + %5 = load double, double* @xmm3 + %6 = fptrunc double %5 to float + %7 = call i64 @print(i64 %1, i64 %2, float %4, float %6) + store i64 %7, i64* @rax + %8 = load i64, i64* @rax + ret i64 %8 + } + + declare void @1() - declare void @1() )"; checkModuleAgainstExpectedIr(exp); -}*/ +} +*/ // //TEST_F(ParamReturnTests, x86PtrCallOnlyContinuousStackOffsetsAreUsed) From c76d1bdb876ed738f6c0a10fe3a951faa97c6441 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 17:06:31 +0100 Subject: [PATCH 153/159] param_return/filter: provide explanaiton --- .../optimizations/param_return/filter/filter.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp index 7a911884e..fae666c70 100644 --- a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp +++ b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp @@ -66,6 +66,10 @@ void Filter::estimateRetValue(DataFlowEntry* de) const else { // TODO: double-read-modf.x86.clang-3.2.O0.g.elf +// In test above return type is found from configuration to be +// double but collector finds only stores to EAX which results in failure in +// decompilation. +// // if (!de->retEntries().empty() // && !de->retEntries().front().retValues().empty()) // { @@ -181,7 +185,13 @@ void Filter::filterCalls(DataFlowEntry* de) const de->argTypes()); if (!de->isVoidarg() && !de->argTypes().empty()) { - // We need order + // This function is called because + // in case when we have info about + // types and order of the parameters + // we would loose it by plain creation + // of template. + // This order is estimated in function + // below. filterArgsByKnownTypes(defArgs); } else if (de->args().empty()) @@ -821,7 +831,6 @@ void Filter::leaveCommon(std::vector& lays) const lay.vectorRegisters.assign(commonVR.begin(), commonVR.end()); lay.stacks.resize(minStacks, nullptr); - // TODO: move commons to layout and order just it. orderFiterableLayout(lay); } } From 4ba8a3773f7db9e339ff72c35868c1e79fdf5c83 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 17:10:38 +0100 Subject: [PATCH 154/159] param_return/collector: provide explanaion --- .../param_return/collector/collector.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/bin2llvmir/optimizations/param_return/collector/collector.cpp b/src/bin2llvmir/optimizations/param_return/collector/collector.cpp index 5179d6686..805b8ab4c 100644 --- a/src/bin2llvmir/optimizations/param_return/collector/collector.cpp +++ b/src/bin2llvmir/optimizations/param_return/collector/collector.cpp @@ -113,6 +113,17 @@ void Collector::collectRetStores(ReturnEntry* re) const { std::vector foundStores; +// TODO: +// This method should be used only after +// speed comparation of below methods. +// +// In this implementation of parameter +// analysis return type is estimated +// only as last option from colelcted +// values. This iss reason why quicklier +// but not reliable method is used +// instead of more reliable one. +// // collectStoresBeforeInstruction( // re->getRetInstruction(), // foundStores); From eb62ec69a882c01c770f01d621ecd958432eae09 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 16:55:27 +0100 Subject: [PATCH 155/159] ms_x64: new filter for x64 ms conention --- .../param_return/filter/ms_x64.h | 38 ++++ src/bin2llvmir/CMakeLists.txt | 1 + .../param_return/filter/filter.cpp | 11 + .../param_return/filter/ms_x64.cpp | 195 ++++++++++++++++++ .../param_return/param_return_tests.cpp | 16 +- 5 files changed, 251 insertions(+), 10 deletions(-) create mode 100644 include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h create mode 100644 src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp diff --git a/include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h b/include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h new file mode 100644 index 000000000..6f266d7e8 --- /dev/null +++ b/include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h @@ -0,0 +1,38 @@ +/** +* @file include/retdec/bin2llvmir/optimizations/param_return/ms_x64.h +* @brief Microsoft x64 specific filtration of registers. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_FILTER_MS_X64_H +#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_FILTER_MS_X64_H + +#include "retdec/bin2llvmir/optimizations/param_return/filter/filter.h" + +namespace retdec { +namespace bin2llvmir { + +class MSX64Filter : public Filter +{ + public: + MSX64Filter(const Abi* _abi, const CallingConvention* _cc); + virtual ~MSX64Filter() override; + + virtual void filterDefinitionArgs( + FilterableLayout& args, + bool isVoidarg) const override; + + virtual void filterCallArgs( + FilterableLayout& args, + bool isVoidarg) const override; + + virtual void filterArgsByKnownTypes(FilterableLayout& lay) const override; + + private: + void leaveOnlyAlternatingArgRegisters(FilterableLayout& lay) const; +}; + +} +} + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index bd310f736..d1dd647fa 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -51,6 +51,7 @@ set(BIN2LLVMIR_SOURCES optimizations/param_return/collector/collector.cpp optimizations/param_return/collector/pic32.cpp optimizations/param_return/filter/filter.cpp + optimizations/param_return/filter/ms_x64.cpp optimizations/param_return/param_return.cpp optimizations/param_return/data_entries.cpp optimizations/phi2seq/phi2seq.cpp diff --git a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp index fae666c70..361009730 100644 --- a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp +++ b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp @@ -7,6 +7,7 @@ #include #include "retdec/bin2llvmir/optimizations/param_return/filter/filter.h" +#include "retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h" using namespace retdec::utils; using namespace llvm; @@ -1335,6 +1336,16 @@ Filter::Ptr FilterProvider::createFilter(Abi* abi, const CallingConvention::ID& } assert(cc); + + auto c = abi->getConfig(); + bool isMinGW = c->getConfig().tools.isGcc() + && c->getConfig().fileFormat.isPe(); + + if (isMinGW || c->getConfig().tools.isMsvc()) + { + return std::make_unique(abi, cc); + } + return std::make_unique(abi, cc); } diff --git a/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp b/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp new file mode 100644 index 000000000..e2ffddcb0 --- /dev/null +++ b/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp @@ -0,0 +1,195 @@ +/** +* @file src/bin2llvmir/optimizations/param_return/filter.cpp +* @brief Microsoft x64 specific filtration of registers. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#include + +#include "retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h" + +using namespace retdec::utils; +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +MSX64Filter::MSX64Filter( + const Abi* abi, + const CallingConvention* cc) : + Filter(abi, cc) +{ +} + +MSX64Filter::~MSX64Filter() +{ +} + +void MSX64Filter::filterDefinitionArgs(FilterableLayout& args, bool isVoidarg) const +{ + leaveOnlyPositiveStacks(args); + + if (isVoidarg) + { + args.gpRegisters.clear(); + args.fpRegisters.clear(); + args.doubleRegisters.clear(); + args.vectorRegisters.clear(); + args.stacks.clear(); + } + else if (!args.knownTypes.empty()) + { + filterArgsByKnownTypes(args); + } + else + { + leaveOnlyAlternatingArgRegisters(args); + } + + leaveOnlyContinuousStack(args); +} + +void MSX64Filter::filterCallArgs(FilterableLayout& args, bool isVoidarg) const +{ + if (isVoidarg) + { + args.gpRegisters.clear(); + args.fpRegisters.clear(); + args.doubleRegisters.clear(); + args.vectorRegisters.clear(); + args.stacks.clear(); + } + else if (!args.knownTypes.empty()) + { + filterArgsByKnownTypes(args); + } + else + { + leaveOnlyAlternatingArgRegisters(args); + } + + leaveOnlyContinuousStack(args); +} + +void MSX64Filter::filterArgsByKnownTypes(FilterableLayout& lay) const +{ + FilterableLayout newLayout; + newLayout.knownTypes = lay.knownTypes; + + auto& gpRegs = _cc->getParamRegisters(); + auto& fpRegs = _cc->getParamFPRegisters(); + + // Indexes of registers to be used next as particular parameter. + auto sIt = lay.stacks.begin(); + + std::size_t regEnd = gpRegs.size(); + + std::vector registers; + + std::vector types = expandTypes(lay.knownTypes); + + for (auto t: types) + { + std::size_t requiredStacks = 0; + OrderID stackOrd = OrderID::ORD_STACK; + + if (t->isFloatingPointTy() || t->isVectorTy()) + { + if (registers.size() < regEnd) + { + requiredStacks = fetchRegsForType( + t, + registers, + fpRegs, + _cc->getMaxNumOfRegsPerParam()); + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + else + { + if (registers.size() < regEnd) + { + requiredStacks = fetchRegsForType( + t, + registers, + gpRegs, + _cc->getMaxNumOfRegsPerParam()); + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + + + if (!requiredStacks && stackOrd == OrderID::ORD_STACK) + { + requiredStacks = getNumberOfStacksForType(t); + } + + for (std::size_t i = 0; i < requiredStacks; i++) + { + if (sIt != lay.stacks.end()) + { + newLayout.stacks.push_back(*sIt); + sIt++; + } + else + { + newLayout.stacks.push_back(nullptr); + } + + newLayout.knownOrder.push_back( + i == 0 ? stackOrd : + OrderID::ORD_STACK_GROUP); + } + } + + std::vector regVals; + for (auto r : registers) + { + regVals.push_back(_abi->getRegister(r)); + } + + lay = separateArgValues(regVals); + lay.stacks = newLayout.stacks; + lay.knownTypes = newLayout.knownTypes; + lay.knownOrder = newLayout.knownOrder; +} + +void MSX64Filter::leaveOnlyAlternatingArgRegisters(FilterableLayout& lay) const +{ + auto& templRegs = _cc->getParamRegisters(); + auto& fpTemplRegs = _cc->getParamFPRegisters(); + + auto it = lay.gpRegisters.begin(); + auto fIt = lay.fpRegisters.begin(); + + std::size_t idx = 0; + while (idx < fpTemplRegs.size() && idx < templRegs.size()) + { + if (it == lay.gpRegisters.end() && fIt == lay.fpRegisters.end()) + { + lay.stacks.clear(); + return; + } + + if (it != lay.gpRegisters.end() && *it == templRegs[idx]) + { + it++; + } + else if (fIt != lay.fpRegisters.end() && *fIt == fpTemplRegs[idx]) + { + fIt++; + } + else + { + lay.gpRegisters.erase(it, lay.gpRegisters.end()); + lay.fpRegisters.erase(fIt, lay.fpRegisters.end()); + lay.stacks.clear(); + return; + } + + idx++; + } +} + +} +} diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 00f29a5c9..28651f303 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -1734,7 +1734,6 @@ TEST_F(ParamReturnTests, ms_x64UsesJustContinuousSequenceOfRegisters) checkModuleAgainstExpectedIr(exp); } -/* TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegistersAdvanced) { parseInput(R"( @@ -1788,7 +1787,7 @@ TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegistersAdvanced) @xmm2 = global double 0.000000e+00 @xmm3 = global double 0.000000e+00 - declare i64 @print(i64, i64, float, float) + declare i64 @print(i64, i64, double, double) declare void @0() @@ -1800,13 +1799,11 @@ TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegistersAdvanced) %1 = load i64, i64* @rcx %2 = load i64, i64* @rdx %3 = load double, double* @xmm2 - %4 = fptrunc double %3 to float - %5 = load double, double* @xmm3 - %6 = fptrunc double %5 to float - %7 = call i64 @print(i64 %1, i64 %2, float %4, float %6) - store i64 %7, i64* @rax - %8 = load i64, i64* @rax - ret i64 %8 + %4 = load double, double* @xmm3 + %5 = call i64 @print(i64 %1, i64 %2, double %3, double %4) + store i64 %5, i64* @rax + %6 = load i64, i64* @rax + ret i64 %6 } declare void @1() @@ -1814,7 +1811,6 @@ TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegistersAdvanced) )"; checkModuleAgainstExpectedIr(exp); } -*/ // //TEST_F(ParamReturnTests, x86PtrCallOnlyContinuousStackOffsetsAreUsed) From 8e044b080e499c285213288534e6efff2ed3a68c Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 17:46:32 +0100 Subject: [PATCH 156/159] param_return/filter: fix condition on special ms filter --- src/bin2llvmir/optimizations/param_return/filter/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp index 361009730..00678ef92 100644 --- a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp +++ b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp @@ -1341,7 +1341,7 @@ Filter::Ptr FilterProvider::createFilter(Abi* abi, const CallingConvention::ID& bool isMinGW = c->getConfig().tools.isGcc() && c->getConfig().fileFormat.isPe(); - if (isMinGW || c->getConfig().tools.isMsvc()) + if (abi->isX64() && (isMinGW || c->getConfig().tools.isMsvc())) { return std::make_unique(abi, cc); } From 9cc98e33fda74d9f55d3f94fe635d9cc80eab6e1 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Tue, 5 Mar 2019 18:14:07 +0100 Subject: [PATCH 157/159] parm_return: filter/ms_x64: fix filtering by known type --- .../param_return/filter/ms_x64.cpp | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp b/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp index e2ffddcb0..9bda18362 100644 --- a/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp +++ b/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp @@ -77,7 +77,6 @@ void MSX64Filter::filterArgsByKnownTypes(FilterableLayout& lay) const newLayout.knownTypes = lay.knownTypes; auto& gpRegs = _cc->getParamRegisters(); - auto& fpRegs = _cc->getParamFPRegisters(); // Indexes of registers to be used next as particular parameter. auto sIt = lay.stacks.begin(); @@ -97,11 +96,9 @@ void MSX64Filter::filterArgsByKnownTypes(FilterableLayout& lay) const { if (registers.size() < regEnd) { - requiredStacks = fetchRegsForType( - t, - registers, - fpRegs, - _cc->getMaxNumOfRegsPerParam()); + newLayout.fpRegisters = registers; + requiredStacks = fetchFPRegsForType(t, newLayout); + registers = newLayout.fpRegisters; stackOrd = OrderID::ORD_STACK_GROUP; } } @@ -109,15 +106,12 @@ void MSX64Filter::filterArgsByKnownTypes(FilterableLayout& lay) const { if (registers.size() < regEnd) { - requiredStacks = fetchRegsForType( - t, - registers, - gpRegs, - _cc->getMaxNumOfRegsPerParam()); + newLayout.gpRegisters = registers; + requiredStacks = fetchGPRegsForType(t, newLayout); + registers = newLayout.gpRegisters; stackOrd = OrderID::ORD_STACK_GROUP; } } - if (!requiredStacks && stackOrd == OrderID::ORD_STACK) { @@ -150,8 +144,8 @@ void MSX64Filter::filterArgsByKnownTypes(FilterableLayout& lay) const lay = separateArgValues(regVals); lay.stacks = newLayout.stacks; - lay.knownTypes = newLayout.knownTypes; lay.knownOrder = newLayout.knownOrder; + lay.knownTypes = newLayout.knownTypes; } void MSX64Filter::leaveOnlyAlternatingArgRegisters(FilterableLayout& lay) const From 3f8db4689831a06acb26e3d79541e7b39e902a8e Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 12 Sep 2018 09:25:00 +0200 Subject: [PATCH 158/159] stacofin: x64: provide application of x64 YARA signatures Currently it was unable to apply the x64 YARA signatures because path to existing sgnatures was incorrect and code in module stacofin did not expect to get binary of x64 format. --- scripts/retdec-decompiler.py | 2 ++ src/stacofin/stacofin.cpp | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/retdec-decompiler.py b/scripts/retdec-decompiler.py index 4e7247d84..17f3feaf8 100644 --- a/scripts/retdec-decompiler.py +++ b/scripts/retdec-decompiler.py @@ -973,6 +973,8 @@ def decompile(self): if sig_arch == 'pic32': sig_arch = 'mips' + elif sig_arch == 'x86-64': + sig_arch = 'x86'; signatures_dir = os.path.join(config.GENERIC_SIGNATURES_DIR, sig_format, fileclass, sig_endian, sig_arch) diff --git a/src/stacofin/stacofin.cpp b/src/stacofin/stacofin.cpp index ec630338a..d96c74df6 100644 --- a/src/stacofin/stacofin.cpp +++ b/src/stacofin/stacofin.cpp @@ -108,10 +108,14 @@ std::set selectSignaturePaths( selectSignaturesWithName(allSigs, sigs, "ucrt"); std::string arch; - if (c.architecture.isX86()) + if (c.architecture.isX86_32()) { arch = "x86"; } + else if (c.architecture.isX86_64()) + { + arch = "x64"; + } else if (c.architecture.isArmOrThumb()) { arch = "arm"; @@ -855,7 +859,7 @@ void Finder::solveReferences() utils::Address Finder::getAddressFromRef(utils::Address ref) { - if (_config->architecture.isX86_32()) + if (_config->architecture.isX86()) { return getAddressFromRef_x86(ref); } From b546103aa5fdda2caf8c080c903bedf7e84176e2 Mon Sep 17 00:00:00 2001 From: Peter Kubov Date: Wed, 6 Mar 2019 12:30:01 +0100 Subject: [PATCH 159/159] doxygen: fix warnings --- .../param_return/collector/collector.h | 2 +- .../param_return/filter/filter.h | 2 +- .../param_return/filter/ms_x64.h | 2 +- .../retdec/bin2llvmir/providers/abi/ms_x64.h | 2 +- .../retdec/bin2llvmir/providers/abi/pic32.h | 2 +- include/retdec/bin2llvmir/providers/abi/x64.h | 2 +- .../calling_convention/arm/arm_conv.h | 2 +- .../calling_convention/arm64/arm64_conv.h | 2 +- .../calling_convention/mips/mips_conv.h | 2 +- .../calling_convention/mips/mips_psp.h | 3 +- .../calling_convention/mips64/mips64_conv.h | 2 +- .../calling_convention/pic32/pic32_conv.h | 2 +- .../calling_convention/powerpc/powerpc_conv.h | 2 +- .../powerpc64/powerpc64_conv.h | 2 +- .../calling_convention/x64/x64_conv.h | 2 +- .../calling_convention/x64/x64_microsoft.h | 2 +- .../calling_convention/x64/x64_systemv.h | 2 +- .../calling_convention/x86/x86_cdecl.h | 2 +- .../calling_convention/x86/x86_conv.h | 2 +- .../calling_convention/x86/x86_fastcall.h | 2 +- .../calling_convention/x86/x86_pascal.h | 2 +- .../calling_convention/x86/x86_thiscall.h | 2 +- .../calling_convention/x86/x86_watcom.h | 2 +- .../param_return/collector/collector.cpp | 2 +- .../param_return/collector/pic32.cpp | 2 +- .../param_return/data_entries.cpp | 36 +++++++++---------- .../param_return/filter/filter.cpp | 26 +++++++------- .../param_return/filter/ms_x64.cpp | 2 +- src/bin2llvmir/providers/abi/ms_x64.cpp | 2 +- src/bin2llvmir/providers/abi/pic32.cpp | 2 +- src/bin2llvmir/providers/abi/x64.cpp | 2 +- .../calling_convention/calling_convention.cpp | 2 +- .../calling_convention/x64/x64_conv.cpp | 2 +- .../calling_convention/x64/x64_microsoft.cpp | 2 +- .../calling_convention/x64/x64_systemv.cpp | 2 +- 35 files changed, 64 insertions(+), 65 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h b/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h index 9a4daf199..67e3c4c17 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h @@ -1,5 +1,5 @@ /** -* @file include/retdec/bin2llvmir/optimizations/param_return/collector.h +* @file include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h * @brief Collects possible arguments and returns of functions. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h b/include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h index 3dc28ab1c..46bb0c37b 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h @@ -1,5 +1,5 @@ /** -* @file include/retdec/bin2llvmir/optimizations/param_return/filter.h +* @file include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h * @brief Filters potentail values according to calling convention. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h b/include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h index 6f266d7e8..cb6e9c967 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h @@ -1,5 +1,5 @@ /** -* @file include/retdec/bin2llvmir/optimizations/param_return/ms_x64.h +* @file include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h * @brief Microsoft x64 specific filtration of registers. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/abi/ms_x64.h b/include/retdec/bin2llvmir/providers/abi/ms_x64.h index 3a8f7a325..8c64e5176 100644 --- a/include/retdec/bin2llvmir/providers/abi/ms_x64.h +++ b/include/retdec/bin2llvmir/providers/abi/ms_x64.h @@ -1,5 +1,5 @@ /** - * @file include/retdec/bin2llvmir/providers/abi/x86_64.h + * @file include/retdec/bin2llvmir/providers/abi/ms_x64.h * @brief ABI information for x86_64. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/abi/pic32.h b/include/retdec/bin2llvmir/providers/abi/pic32.h index 4f060455d..e22863a33 100644 --- a/include/retdec/bin2llvmir/providers/abi/pic32.h +++ b/include/retdec/bin2llvmir/providers/abi/pic32.h @@ -1,5 +1,5 @@ /** - * @file include/retdec/bin2llvmir/providers/abi/mips.h + * @file include/retdec/bin2llvmir/providers/abi/pic32.h * @brief ABI information for MIPS. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/abi/x64.h b/include/retdec/bin2llvmir/providers/abi/x64.h index ab07e8bd7..2b5a1b34e 100644 --- a/include/retdec/bin2llvmir/providers/abi/x64.h +++ b/include/retdec/bin2llvmir/providers/abi/x64.h @@ -1,5 +1,5 @@ /** - * @file include/retdec/bin2llvmir/providers/abi/x86_64.h + * @file include/retdec/bin2llvmir/providers/abi/x64.h * @brief ABI information for x86_64. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h index b70b3fe97..b72f8112f 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/arm/arm_conv.h + * @file include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h * @brief Calling conventions of ARM architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h index 54001d0c0..ee9bf298c 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h + * @file include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h * @brief Calling conventions of ARM64 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h index ad626ff36..0af41dadf 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/mips/mips_conv.h + * @file include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h * @brief Calling convention of MIPS architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h index d5a9dec1c..8b1eacb13 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h @@ -1,6 +1,5 @@ - /** - * @file retdec/include/bin2llvmir/providers/calling_convention/mips/mips_psp.h + * @file include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h * @brief Calling convention of MIPS architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h index 27ed87fc3..2ade02f52 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/mips64/mips64_convention.h + * @file include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h * @brief Calling convention of Mips64 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h index 34a986c76..3af3180f6 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin3llvmir/providers/calling_convention/pic32/pic32_conv.h + * @file include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h * @brief Calling conventions of PIC32 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h index b9808d049..ac2b11eca 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h + * @file include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h * @brief Calling conventions of PowerPC architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h index fdca77deb..e8fd47637 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h + * @file include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h * @brief Calling conventions of PowerPC64 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h index 2aa209797..0ca84ac24 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/x64/x64_conv.h + * @file include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h * @brief Calling convention of X64 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h index 063933316..bf8cdbb64 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h + * @file include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h * @brief MS Windows calling convention of X64 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h index 7dd896e37..9e7ecaf98 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/x64/x64_systemv.h + * @file include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h * @brief System V calling convention of X64 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h index a29cfe219..28c6fe708 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h * @brief Cdecl calling convention of x86 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h index bdcab88f7..2f683b70c 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_conv.h + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h * @brief Common calling convention of x86 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h index 1202f17b5..6030da656 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h * @brief Fastcall calling convention of x86 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h index ba617468b..626411097 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_pascal.h + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h * @brief Pascal calling convention of x86 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h index 0a69a6607..96d2a91c6 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h * @brief Thiscall calling convention of x86 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h index cf2c90552..97ca05f60 100644 --- a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h @@ -1,5 +1,5 @@ /** - * @file retdec/include/bin2llvmir/providers/calling_convention/x86/x86_watcom.h + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h * @brief Common calling convention of x86 architecture. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/src/bin2llvmir/optimizations/param_return/collector/collector.cpp b/src/bin2llvmir/optimizations/param_return/collector/collector.cpp index 805b8ab4c..86f642fcd 100644 --- a/src/bin2llvmir/optimizations/param_return/collector/collector.cpp +++ b/src/bin2llvmir/optimizations/param_return/collector/collector.cpp @@ -1,5 +1,5 @@ /** -* @file src/bin2llvmir/optimizations/param_return/collector.cpp +* @file src/bin2llvmir/optimizations/param_return/collector/collector.cpp * @brief Collects possible arguments and returns of functions. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ diff --git a/src/bin2llvmir/optimizations/param_return/collector/pic32.cpp b/src/bin2llvmir/optimizations/param_return/collector/pic32.cpp index 1a0f368c6..af16b418e 100644 --- a/src/bin2llvmir/optimizations/param_return/collector/pic32.cpp +++ b/src/bin2llvmir/optimizations/param_return/collector/pic32.cpp @@ -1,5 +1,5 @@ /** -* @file src/bin2llvmir/optimizations/param_return/collector.cpp +* @file src/bin2llvmir/optimizations/param_return/collector/pic32.cpp * @brief Pic32 specific collection algorithms. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ diff --git a/src/bin2llvmir/optimizations/param_return/data_entries.cpp b/src/bin2llvmir/optimizations/param_return/data_entries.cpp index c64a8b076..55bf8f935 100644 --- a/src/bin2llvmir/optimizations/param_return/data_entries.cpp +++ b/src/bin2llvmir/optimizations/param_return/data_entries.cpp @@ -19,12 +19,12 @@ namespace bin2llvmir { //============================================================================= // -ReturnEntry::ReturnEntry(ReturnInst* r) : +ReturnEntry::ReturnEntry(llvm::ReturnInst* r) : _retInst(r) { } -void ReturnEntry::addRetStore(StoreInst* st) +void ReturnEntry::addRetStore(llvm::StoreInst* st) { _retStores.push_back(st); @@ -37,42 +37,42 @@ void ReturnEntry::addRetStore(StoreInst* st) } } -void ReturnEntry::setRetStores(std::vector&& stores) +void ReturnEntry::setRetStores(std::vector&& stores) { _retStores = std::move(stores); - std::set vals; + std::set vals; for (auto& i: _retStores) { vals.insert(i->getPointerOperand()); } - _retValues = std::vector( + _retValues = std::vector( std::make_move_iterator(vals.begin()), std::make_move_iterator(vals.end())); } -void ReturnEntry::setRetStores(const std::vector& stores) +void ReturnEntry::setRetStores(const std::vector& stores) { _retStores = stores; - std::set vals; + std::set vals; for (auto& i: _retStores) { vals.insert(i->getPointerOperand()); } - _retValues = std::vector( + _retValues = std::vector( std::make_move_iterator(vals.begin()), std::make_move_iterator(vals.end())); } -void ReturnEntry::setRetValues(std::vector&& values) +void ReturnEntry::setRetValues(std::vector&& values) { _retStores.erase(std::remove_if( _retStores.begin(), _retStores.end(), - [values](llvm::StoreInst* st) + [values](StoreInst* st) { auto* op = st->getPointerOperand(); return std::find( @@ -84,12 +84,12 @@ void ReturnEntry::setRetValues(std::vector&& values) _retValues = std::move(values); } -void ReturnEntry::setRetValues(const std::vector& values) +void ReturnEntry::setRetValues(const std::vector& values) { _retStores.erase(std::remove_if( _retStores.begin(), _retStores.end(), - [values](llvm::StoreInst* st) + [values](StoreInst* st) { auto* op = st->getPointerOperand(); return std::find( @@ -106,12 +106,12 @@ ReturnInst* ReturnEntry::getRetInstruction() const return _retInst; } -const std::vector& ReturnEntry::retStores() const +const std::vector& ReturnEntry::retStores() const { return _retStores; } -const std::vector& ReturnEntry::retValues() const +const std::vector& ReturnEntry::retValues() const { return _retValues; } @@ -127,7 +127,7 @@ bool CallableEntry::isVoidarg() const return _voidarg; } -void CallableEntry::addArg(Value* arg) +void CallableEntry::addArg(llvm::Value* arg) { _args.push_back(arg); } @@ -207,7 +207,7 @@ void FunctionEntry::setVariadic(bool variadic) _variadic = variadic; } -void FunctionEntry::setArgs(std::vector&& args) +void FunctionEntry::setArgs(std::vector&& args) { _args = std::move(args); } @@ -315,7 +315,7 @@ void CallEntry::setArgs(std::vector&& args) std::remove_if( _argStores.begin(), _argStores.end(), - [args](llvm::StoreInst* st) + [args](StoreInst* st) { auto* op = st->getPointerOperand(); return std::find( @@ -373,7 +373,7 @@ std::string CallEntry::getFormatString() const return _fmtStr; } -const std::vector& CallEntry::argStores() const +const std::vector& CallEntry::argStores() const { return _argStores; } diff --git a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp index 00678ef92..ae6223601 100644 --- a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp +++ b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp @@ -1,5 +1,5 @@ /** -* @file src/bin2llvmir/optimizations/param_return/filter.cpp +* @file src/bin2llvmir/optimizations/param_return/filter/filter.cpp * @brief Filters potentail values according to calling convention. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ @@ -885,8 +885,8 @@ void Filter::orderRegistersBy( } FilterableLayout Filter::createArgsFilterableLayout( - const std::vector& group, - const std::vector& knownTypes) const + const std::vector& group, + const std::vector& knownTypes) const { FilterableLayout layout = separateArgValues(group); layout.knownTypes = knownTypes; @@ -897,16 +897,16 @@ FilterableLayout Filter::createArgsFilterableLayout( } FilterableLayout Filter::createRetsFilterableLayout( - const std::vector& group, - Type* knownType) const + const std::vector& group, + llvm::Type* knownType) const { std::vector knownTypes = {knownType}; return createRetsFilterableLayout(group, knownTypes); } FilterableLayout Filter::createRetsFilterableLayout( - const std::vector& group, - const std::vector& knownTypes) const + const std::vector& group, + const std::vector& knownTypes) const { FilterableLayout layout = separateRetValues(group); layout.knownTypes = knownTypes; @@ -916,7 +916,7 @@ FilterableLayout Filter::createRetsFilterableLayout( return layout; } -FilterableLayout Filter::separateArgValues(const std::vector& paramValues) const +FilterableLayout Filter::separateArgValues(const std::vector& paramValues) const { auto& regs = _cc->getParamRegisters(); auto& fpRegs = _cc->getParamFPRegisters(); @@ -926,7 +926,7 @@ FilterableLayout Filter::separateArgValues(const std::vector& paramValue return separateValues(paramValues, regs, fpRegs, doubleRegs, vecRegs); } -FilterableLayout Filter::separateRetValues(const std::vector& paramValues) const +FilterableLayout Filter::separateRetValues(const std::vector& paramValues) const { auto& regs = _cc->getReturnRegisters(); auto& fpRegs = _cc->getReturnFPRegisters(); @@ -940,7 +940,7 @@ FilterableLayout Filter::separateRetValues(const std::vector& paramValue } FilterableLayout Filter::separateValues( - const std::vector& paramValues, + const std::vector& paramValues, const std::vector& gpRegs, const std::vector& fpRegs, const std::vector& doubleRegs, @@ -983,17 +983,17 @@ FilterableLayout Filter::separateValues( return layout; } -std::vector Filter::createGroupedArgValues(const FilterableLayout& lay) const +std::vector Filter::createGroupedArgValues(const FilterableLayout& lay) const { return createGroupedValues(lay); } -std::vector Filter::createGroupedRetValues(const FilterableLayout& lay) const +std::vector Filter::createGroupedRetValues(const FilterableLayout& lay) const { return createGroupedValues(lay); } -std::vector Filter::createGroupedValues(const FilterableLayout& lay) const +std::vector Filter::createGroupedValues(const FilterableLayout& lay) const { std::vector paramValues; diff --git a/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp b/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp index 9bda18362..eb03c46de 100644 --- a/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp +++ b/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp @@ -1,5 +1,5 @@ /** -* @file src/bin2llvmir/optimizations/param_return/filter.cpp +* @file src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp * @brief Microsoft x64 specific filtration of registers. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ diff --git a/src/bin2llvmir/providers/abi/ms_x64.cpp b/src/bin2llvmir/providers/abi/ms_x64.cpp index 4a8a53e75..f943bc5da 100644 --- a/src/bin2llvmir/providers/abi/ms_x64.cpp +++ b/src/bin2llvmir/providers/abi/ms_x64.cpp @@ -1,5 +1,5 @@ /** - * @file src/bin2llvmir/providers/abi/x86_64.cp + * @file src/bin2llvmir/providers/abi/ms_x64.cpp * @brief ABI information for x86_64. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/src/bin2llvmir/providers/abi/pic32.cpp b/src/bin2llvmir/providers/abi/pic32.cpp index f035b2f1e..ff629e090 100644 --- a/src/bin2llvmir/providers/abi/pic32.cpp +++ b/src/bin2llvmir/providers/abi/pic32.cpp @@ -1,5 +1,5 @@ /** - * @file src/bin2llvmir/providers/abi/mips.h + * @file src/bin2llvmir/providers/abi/pic32.cpp * @brief ABI information for MIPS. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/src/bin2llvmir/providers/abi/x64.cpp b/src/bin2llvmir/providers/abi/x64.cpp index 5ec5246f9..304c20aa2 100644 --- a/src/bin2llvmir/providers/abi/x64.cpp +++ b/src/bin2llvmir/providers/abi/x64.cpp @@ -1,5 +1,5 @@ /** - * @file src/bin2llvmir/providers/abi/x86_64.cp + * @file src/bin2llvmir/providers/abi/x64.cpp * @brief ABI information for x86_64. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ diff --git a/src/bin2llvmir/providers/calling_convention/calling_convention.cpp b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp index 02ec90c57..cd3e882ee 100644 --- a/src/bin2llvmir/providers/calling_convention/calling_convention.cpp +++ b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp @@ -1,5 +1,5 @@ /** - * @file src/retdec/bin2llvmir/providers/calling_convention/calling_convention.cpp + * @file src/bin2llvmir/providers/calling_convention/calling_convention.cpp * @brief Calling convention information. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ diff --git a/src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp b/src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp index c2b5ae8db..fe99afab6 100644 --- a/src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp +++ b/src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp @@ -1,5 +1,5 @@ /** - * @file src/bin2llvmir/providers/calling_convention/x64.cpp + * @file src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp * @brief Calling conventions of X64 architecture. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ diff --git a/src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp b/src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp index df90e42ba..5e824052d 100644 --- a/src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp +++ b/src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp @@ -1,5 +1,5 @@ /** - * @file src/bin2llvmir/providers/calling_convention/x64.cpp + * @file src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp * @brief Microsoft calling convention of X64 architecture. * @copyright (c) 2019 Avast Software, licensed under the MIT license */ diff --git a/src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp b/src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp index 6e6062e4b..56dd105cc 100644 --- a/src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp +++ b/src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp @@ -1,5 +1,5 @@ /** - * @file src/bin2llvmir/providers/calling_convention/x64.cpp + * @file src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp * @brief System V Calling convention of X64 architecture. * @copyright (c) 2019 Avast Software, licensed under the MIT license */