From 7762c4b2ce8bd98ded24e3365e676ef768138f3c Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 3 Jul 2023 13:37:41 +0200 Subject: [PATCH] Light refactor of the IDetour interface - Use std::map for mapping vtables to interface objects, previously done with a set and a vector. - Objects are no longer inline, which significantly reduced output code size as all redundant dynamic initializers (created for each translation unit) have been pruned. --- r5dev/core/init.cpp | 28 +++++++++++------- r5dev/thirdparty/detours/CMakeLists.txt | 1 + r5dev/thirdparty/detours/include/idetour.h | 34 +++++----------------- r5dev/thirdparty/detours/src/idetour.cpp | 30 +++++++++++++++++++ 4 files changed, 56 insertions(+), 37 deletions(-) create mode 100644 r5dev/thirdparty/detours/src/idetour.cpp diff --git a/r5dev/core/init.cpp b/r5dev/core/init.cpp index 1a32c110..4b3a6a3f 100644 --- a/r5dev/core/init.cpp +++ b/r5dev/core/init.cpp @@ -170,9 +170,10 @@ void Systems_Init() DetourUpdateThread(GetCurrentThread()); // Hook functions - for (const IDetour* pDetour : g_DetourVector) + for (const auto& elem : g_DetourMap) { - pDetour->Attach(); + const IDetour* detour = elem.second; + detour->Attach(); } // Patch instructions @@ -215,9 +216,10 @@ void Systems_Shutdown() DetourUpdateThread(GetCurrentThread()); // Unhook functions - for (const IDetour* pDetour : g_DetourVector) + for (const auto& elem : g_DetourMap) { - pDetour->Detach(); + const IDetour* detour = elem.second; + detour->Detach(); } // Commit the transaction @@ -342,11 +344,13 @@ void DetourInit() // Run the sigscan g_SigCache.SetDisabled(bNoSmap); g_SigCache.LoadCache(SIGDB_FILE); - for (const IDetour* pDetour : g_DetourVector) + for (const auto& elem : g_DetourMap) { - pDetour->GetCon(); // Constants. - pDetour->GetFun(); // Functions. - pDetour->GetVar(); // Variables. + const IDetour* detour = elem.second; + + detour->GetCon(); // Constants. + detour->GetFun(); // Functions. + detour->GetVar(); // Variables. if (bLogAdr) { @@ -355,7 +359,7 @@ void DetourInit() // Run the sigscan bInitDivider = true; spdlog::debug("+---------------------------------------------------------------------+\n"); } - pDetour->GetAdr(); + detour->GetAdr(); spdlog::debug("+---------------------------------------------------------------------+\n"); } } @@ -372,9 +376,11 @@ void DetourInit() // Run the sigscan void DetourAddress() // Test the sigscan results { spdlog::debug("+---------------------------------------------------------------------+\n"); - for (const IDetour* pDetour : g_DetourVector) + for (const auto& elem : g_DetourMap) { - pDetour->GetAdr(); + const IDetour* detour = elem.second; + + detour->GetAdr(); spdlog::debug("+---------------------------------------------------------------------+\n"); } } diff --git a/r5dev/thirdparty/detours/CMakeLists.txt b/r5dev/thirdparty/detours/CMakeLists.txt index ba2b7b09..da7f3793 100644 --- a/r5dev/thirdparty/detours/CMakeLists.txt +++ b/r5dev/thirdparty/detours/CMakeLists.txt @@ -7,6 +7,7 @@ add_sources( SOURCE_GROUP "Source" "src/creatwth.cpp" "src/detours.cpp" "src/disasm.cpp" + "src/idetour.cpp" "src/modules.cpp" ) diff --git a/r5dev/thirdparty/detours/include/idetour.h b/r5dev/thirdparty/detours/include/idetour.h index 40b5166c..84e4bf2e 100644 --- a/r5dev/thirdparty/detours/include/idetour.h +++ b/r5dev/thirdparty/detours/include/idetour.h @@ -1,10 +1,9 @@ #ifndef IDETOUR_H #define IDETOUR_H -#define ADDDETOUR(x,y) static std::size_t dummy_reg_##y = AddDetour( new x() ); -#define XREGISTER(x,y) ADDDETOUR(x, y) -#define REGISTER(x) XREGISTER(x, __COUNTER__) - +//----------------------------------------------------------------------------- +// Interface class for context hooks +//----------------------------------------------------------------------------- class IDetour { public: @@ -18,28 +17,11 @@ public: virtual void Detach(void) const = 0; }; -class VDetour : public IDetour -{ - virtual void GetAdr(void) const { } - virtual void GetFun(void) const { } - virtual void GetVar(void) const { } - virtual void GetCon(void) const { } +extern std::map<const void*, const IDetour*> g_DetourMap; +std::size_t AddDetour(IDetour* pDetour); - virtual void Attach(void) const { } - virtual void Detach(void) const { } -}; - -inline static std::vector<IDetour*> g_DetourVector; -inline static std::unordered_set<IDetour*> g_DetourSet; -inline std::size_t AddDetour(IDetour* pDetour) -{ - IDetour* pVFTable = reinterpret_cast<IDetour**>(pDetour)[0]; - auto p = g_DetourSet.insert(pVFTable); // Only register if VFTable isn't already registered. - - assert(p.second); // Code bug: duplicate registration!!! (called 'REGISTER(...)' from a header file?). - p.second ? g_DetourVector.push_back(pDetour) : delete pDetour; - - return g_DetourVector.size(); -} +#define ADDDETOUR(x,y) static std::size_t dummy_reg_##y = AddDetour( new x() ); +#define XREGISTER(x,y) ADDDETOUR(x, y) +#define REGISTER(x) XREGISTER(x, __COUNTER__) #endif // IDETOUR_H diff --git a/r5dev/thirdparty/detours/src/idetour.cpp b/r5dev/thirdparty/detours/src/idetour.cpp new file mode 100644 index 00000000..45accf1a --- /dev/null +++ b/r5dev/thirdparty/detours/src/idetour.cpp @@ -0,0 +1,30 @@ +//===========================================================================// +// +// Purpose: Hook interface +// +//===========================================================================// +#include <cassert> +#include <map> +#include "../include/idetour.h" + +//----------------------------------------------------------------------------- +// Contains a VFTable pointer, and the class instance. A VFTable can only be +// used by one class instance. This is to avoid duplicate registrations. +//----------------------------------------------------------------------------- +std::map<const void*, const IDetour*> g_DetourMap; + +//----------------------------------------------------------------------------- +// Purpose: adds a detour context to the list +//----------------------------------------------------------------------------- +std::size_t AddDetour(IDetour* pDetour) +{ + const void* pVFTable = reinterpret_cast<const void**>(pDetour)[0]; + auto p = g_DetourMap.emplace(pVFTable, pDetour); // Only register if VFTable isn't already registered. + + assert(p.second); // Code bug: duplicate registration!!! (called 'REGISTER(...)' from a header file?). + + if (!p.second) + delete pDetour; + + return g_DetourMap.size(); +}