From b7e00841b0f15a01d44c62dfc17e5aa19d25d13b Mon Sep 17 00:00:00 2001 From: Pavol Marko Date: Fri, 2 Nov 2007 12:41:00 +0000 Subject: [PATCH] Completed support for reference returns + added simple test for it --HG-- branch : hookman_autogen extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/branches/hookman_autogen%40539 --- sourcehook/sourcehook_hookmangen.cpp | 61 +++++++++++++++++----------- sourcehook/test/testhookmangen.cpp | 47 +++++++++++++++++++++ sourcehook/test/testhookmangen.h | 22 +++++++++- sourcehook/test/testhookmangen.hxx | 16 +++++++- 4 files changed, 118 insertions(+), 28 deletions(-) diff --git a/sourcehook/sourcehook_hookmangen.cpp b/sourcehook/sourcehook_hookmangen.cpp index 6aea6cc..217d00b 100644 --- a/sourcehook/sourcehook_hookmangen.cpp +++ b/sourcehook/sourcehook_hookmangen.cpp @@ -965,35 +965,46 @@ namespace SourceHook m_HookFunc.rewrite(tmppos2, static_cast(counter2)); // *v_orig_ret = *v_override_ret - if (m_Proto.GetRet().pAssignOperator) + if (m_Proto.GetRet().flags & PassInfo::PassFlag_ByRef) { - // lea edx, [ebp + v_override_ret] <-- src addr - // lea ecx, [ebp + v_orig_ret] <-- dest addr - // gcc: push ecx - // push edx <-- src addr - // call it + // mov ecx, [ebp + v_override_ret] + // mov [ebp + v_orig_ret], ecx - IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_override_ret); - IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_orig_ret); -#if SH_COMP == SH_COMP_GCC - IA32_Push_Reg(&m_HookFunc, REG_ECX); -#endif - IA32_Push_Reg(&m_HookFunc, REG_EDX); - - IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pAssignOperator)); - IA32_Call_Reg(&m_HookFunc, REG_EAX); + IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_override_ret); + IA32_Mov_Rm_Reg_DispAuto(&m_HookFunc, REG_EBP, REG_ECX, v_orig_ret); } else { - // bitwise copy - BitwiseCopy_Setup(); + if (m_Proto.GetRet().pAssignOperator) + { + // lea edx, [ebp + v_override_ret] <-- src addr + // lea ecx, [ebp + v_orig_ret] <-- dest addr + // gcc: push ecx + // push edx <-- src addr + // call it - //lea edi, [ebp+v_orig_ret] <-- destination - //lea esi, [ebp+v_override_ret] <-- src - IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDI, REG_EBP, v_orig_ret); - IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, v_override_ret); + IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDX, REG_EBP, v_override_ret); + IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, v_orig_ret); +#if SH_COMP == SH_COMP_GCC + IA32_Push_Reg(&m_HookFunc, REG_ECX); +#endif + IA32_Push_Reg(&m_HookFunc, REG_EDX); - BitwiseCopy_Do(m_Proto.GetRet().size); + IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(m_Proto.GetRet().pAssignOperator)); + IA32_Call_Reg(&m_HookFunc, REG_EAX); + } + else + { + // bitwise copy + BitwiseCopy_Setup(); + + //lea edi, [ebp+v_orig_ret] <-- destination + //lea esi, [ebp+v_override_ret] <-- src + IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDI, REG_EBP, v_orig_ret); + IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, v_override_ret); + + BitwiseCopy_Do(m_Proto.GetRet().size); + } } // skip don't call label target: @@ -1194,7 +1205,8 @@ namespace SourceHook IA32_Mov_Rm_Imm32_Disp8(&m_HookFunc, REG_EBP, MRES_IGNORED, v_status); // Call constructors for ret vars if required - if(m_Proto.GetRet().pNormalCtor) + if((m_Proto.GetRet().flags & PassInfo::PassFlag_ByVal) && + m_Proto.GetRet().pNormalCtor) { // :TODO: Gcc version @@ -1256,7 +1268,8 @@ namespace SourceHook DoReturn(v_ret_ptr, v_memret_addr); // Call destructors of orig_ret/ ... - if(m_Proto.GetRet().pDtor) + if((m_Proto.GetRet().flags & PassInfo::PassFlag_ByVal) && + m_Proto.GetRet().pDtor) { // Preserve return value in EAX(:EDX) IA32_Push_Reg(&m_HookFunc, REG_EAX); diff --git a/sourcehook/test/testhookmangen.cpp b/sourcehook/test/testhookmangen.cpp index 1fc307e..7418e86 100644 --- a/sourcehook/test/testhookmangen.cpp +++ b/sourcehook/test/testhookmangen.cpp @@ -371,6 +371,40 @@ namespace THGM_SETUP_RI(110, ObjRet13, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor | SourceHook::PassInfo::PassFlag_CCtor | SourceHook::PassInfo::PassFlag_AssignOp); + + MAKE_OBJRET(111); + ObjRet111 g_O111_0; + ObjRet111 g_O111_1; + ObjRet111 g_O111_2; + ObjRet111 g_O111_3; + ObjRet111 g_O111_4; + + template <> + struct MakeRet< ObjRet111& > + { + static ObjRet111 &Do(int a) + { + switch (a) + { + case 0: + return g_O111_0; + case 1: + return g_O111_1; + case 2: + return g_O111_2; + case 3: + return g_O111_3; + default: + return g_O111_4; + } + } + }; + + THGM_MAKE_TEST0(111, ObjRet111& ); + THGM_SETUP_PI0(111); + THGM_SETUP_RI(111, ObjRet111& , SourceHook::PassInfo::PassType_Object, + SourceHook::PassInfo::PassFlag_ByRef | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor | + SourceHook::PassInfo::PassFlag_CCtor | SourceHook::PassInfo::PassFlag_AssignOp); } bool TestHookManGen(std::string &error) @@ -378,6 +412,15 @@ bool TestHookManGen(std::string &error) GET_SHPTR(g_SHPtr); g_PLID = 1337; + // 5 Global constructors (g_O111_*) + CHECK_STATES((&g_States, + new State_ObjOCtor_Called(111), + new State_ObjOCtor_Called(111), + new State_ObjOCtor_Called(111), + new State_ObjOCtor_Called(111), + new State_ObjOCtor_Called(111), + NULL), "GlobCtors"); + THGM_DO_TEST_void(0, ()); THGM_DO_TEST_void(1, (100)); @@ -750,6 +793,10 @@ bool TestHookManGen(std::string &error) THGM_REMOVE_HOOK(110, 3); THGM_REMOVE_HOOK(110, 4); + + // RefRet + THGM_DO_TEST(111, ()); + // Shutdown now! // If we don't SH will auto-shutdown _after_ genc's destructor is called // -> crash diff --git a/sourcehook/test/testhookmangen.h b/sourcehook/test/testhookmangen.h index 117e5c0..3419315 100644 --- a/sourcehook/test/testhookmangen.h +++ b/sourcehook/test/testhookmangen.h @@ -518,6 +518,7 @@ std::ostream& operator <<(std::ostream &os,const ParamState6<0, p1, p2, p3, p4, #define THGM_MAKE_TEST0(id, ret_type) \ struct TestClass##id; \ + typedef ret_type RetType##id; \ typedef ParamState0<0 > ParamState_m##id; \ MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \ MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \ @@ -728,6 +729,7 @@ std::ostream& operator <<(std::ostream &os,const ParamState6<0, p1, p2, p3, p4, #define THGM_MAKE_TEST1(id, ret_type, param1) \ struct TestClass##id; \ + typedef ret_type RetType##id; \ typedef ParamState1<0, param1 > ParamState_m##id; \ MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \ MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \ @@ -938,6 +940,7 @@ std::ostream& operator <<(std::ostream &os,const ParamState6<0, p1, p2, p3, p4, #define THGM_MAKE_TEST2(id, ret_type, param1, param2) \ struct TestClass##id; \ + typedef ret_type RetType##id; \ typedef ParamState2<0, param1, param2 > ParamState_m##id; \ MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \ MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \ @@ -1148,6 +1151,7 @@ std::ostream& operator <<(std::ostream &os,const ParamState6<0, p1, p2, p3, p4, #define THGM_MAKE_TEST3(id, ret_type, param1, param2, param3) \ struct TestClass##id; \ + typedef ret_type RetType##id; \ typedef ParamState3<0, param1, param2, param3 > ParamState_m##id; \ MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \ MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \ @@ -1358,6 +1362,7 @@ std::ostream& operator <<(std::ostream &os,const ParamState6<0, p1, p2, p3, p4, #define THGM_MAKE_TEST4(id, ret_type, param1, param2, param3, param4) \ struct TestClass##id; \ + typedef ret_type RetType##id; \ typedef ParamState4<0, param1, param2, param3, param4 > ParamState_m##id; \ MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \ MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \ @@ -1568,6 +1573,7 @@ std::ostream& operator <<(std::ostream &os,const ParamState6<0, p1, p2, p3, p4, #define THGM_MAKE_TEST5(id, ret_type, param1, param2, param3, param4, param5) \ struct TestClass##id; \ + typedef ret_type RetType##id; \ typedef ParamState5<0, param1, param2, param3, param4, param5 > ParamState_m##id; \ MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \ MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \ @@ -1778,6 +1784,7 @@ std::ostream& operator <<(std::ostream &os,const ParamState6<0, p1, p2, p3, p4, #define THGM_MAKE_TEST6(id, ret_type, param1, param2, param3, param4, param5, param6) \ struct TestClass##id; \ + typedef ret_type RetType##id; \ typedef ParamState6<0, param1, param2, param3, param4, param5, param6 > ParamState_m##id; \ MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \ MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \ @@ -2015,10 +2022,21 @@ std::ostream& operator <<(std::ostream &os,const ParamState6<0, p1, p2, p3, p4, THGM_REMOVE_HOOK(id, 3); \ THGM_REMOVE_HOOK(id, 4); +template +T ComparableRef(T x) +{ + return x; +} + +template +T* ComparableRef(T& x) +{ + return &x; +} #define THGM_CALLS(id, call_params, exp_ret_norm, exp_ret_shcall, err) \ - CHECK_COND(pTest##id->Func call_params == exp_ret_norm, err " /retcallnorm"); \ - CHECK_COND(SH_CALL(pTest##id, &TestClass##id::Func) call_params == exp_ret_shcall, err " /retcallshcall"); + CHECK_COND(ComparableRef(pTest##id->Func call_params) == ComparableRef(MakeRet< RetType##id >::Do(exp_ret_norm)), err " /retcallnorm"); \ + CHECK_COND(ComparableRef(SH_CALL(pTest##id, &TestClass##id::Func) call_params) == ComparableRef(MakeRet< RetType##id >::Do(exp_ret_shcall)), err " /retcallshcall"); #define THGM_DO_TEST(id, call_params) \ setuppi_##id(); \ diff --git a/sourcehook/test/testhookmangen.hxx b/sourcehook/test/testhookmangen.hxx index 3b488cd..864973e 100644 --- a/sourcehook/test/testhookmangen.hxx +++ b/sourcehook/test/testhookmangen.hxx @@ -260,6 +260,7 @@ std::ostream& operator <<(std::ostream &os,const ParamState$1<0@[$2,1,$1:, p$2@] #define THGM_MAKE_TEST$1(id, ret_type@[$2,1,$1:, param$2@]) \ struct TestClass##id; \ + typedef ret_type RetType##id; \ typedef ParamState$1<0@[$2,1,$1:, param$2@] > ParamState_m##id; \ MAKE_STATE_2(State_Func##id, TestClass##id* /*thisptr*/, ParamState_m##id ); \ MAKE_STATE_3(State_Deleg1_##id, TestClass##id* /*ifptr*/, int /*deleg thisptr*/, ParamState_m##id ); \ @@ -497,10 +498,21 @@ std::ostream& operator <<(std::ostream &os,const ParamState$1<0@[$2,1,$1:, p$2@] THGM_REMOVE_HOOK(id, 3); \ THGM_REMOVE_HOOK(id, 4); +template +T ComparableRef(T x) +{ + return x; +} + +template +T* ComparableRef(T& x) +{ + return &x; +} #define THGM_CALLS(id, call_params, exp_ret_norm, exp_ret_shcall, err) \ - CHECK_COND(pTest##id->Func call_params == exp_ret_norm, err " /retcallnorm"); \ - CHECK_COND(SH_CALL(pTest##id, &TestClass##id::Func) call_params == exp_ret_shcall, err " /retcallshcall"); + CHECK_COND(ComparableRef(pTest##id->Func call_params) == ComparableRef(MakeRet< RetType##id >::Do(exp_ret_norm)), err " /retcallnorm"); \ + CHECK_COND(ComparableRef(SH_CALL(pTest##id, &TestClass##id::Func) call_params) == ComparableRef(MakeRet< RetType##id >::Do(exp_ret_shcall)), err " /retcallshcall"); #define THGM_DO_TEST(id, call_params) \ setuppi_##id(); \