diff --git a/sourcehook/sourcehook_hookmangen.cpp b/sourcehook/sourcehook_hookmangen.cpp index c28cf99..fbe0242 100644 --- a/sourcehook/sourcehook_hookmangen.cpp +++ b/sourcehook/sourcehook_hookmangen.cpp @@ -196,6 +196,39 @@ namespace SourceHook IA32_Pop_Reg(&m_HookFunc, REG_EDI); } + short GenContext::GetParamsStackSize() + { + short acc = 0; + for (int i = 0; i < m_Proto.GetNumOfParams(); ++i) + { + acc += GetStackSize(m_Proto.GetParam(i)); + } + + // Memory return: address is first param + if (m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem) + acc += SIZE_PTR; + + // :TODO: cdecl: THIS POINTER AS FIRST PARAM!!! + + return acc; + } + + short GenContext::GetForcedByRefParamOffset(int p) + { + short off = 0; + for (int i = 0; i < p; ++i) + { + if (m_Proto.GetParam(i).flags & PassFlag_ForcedByRef) + off += GetStackSize(m_Proto.GetParam(i)); + } + return off; + } + + short GenContext::GetForcedByRefParamsSize() + { + return GetForcedByRefParamOffset(m_Proto.GetNumOfParams()); + } + jit_int32_t GenContext::PushRef(jit_int32_t param_offset, const IntPassInfo &pi) { // push [ebp+] @@ -282,23 +315,31 @@ namespace SourceHook } } - jit_int32_t GenContext::PushObject(jit_int32_t param_offset, const IntPassInfo &pi) + jit_int32_t GenContext::PushObject(jit_int32_t param_offset, const IntPassInfo &pi, jit_int32_t place_fbrr) { - // make room on the stack - // sub esp, - IA32_Sub_Rm_ImmAuto(&m_HookFunc, REG_ESP, GetStackSize(pi), MOD_REG); + if ((pi.flags & PassFlag_ForcedByRef) == 0) + { + // make room on the stack + // sub esp, + IA32_Sub_Rm_ImmAuto(&m_HookFunc, REG_ESP, GetStackSize(pi), MOD_REG); + } // if there is a copy constructor.. if (pi.pCopyCtor) { // save eax // push src addr - // this= target addr = esp+12 + // this= target addr = forcedbyref ? ebp+place_fbrr : esp+12 // call copy constructor // restore eax IA32_Push_Reg(&m_HookFunc, REG_EAX); - IA32_Lea_Reg_DispRegMultImm8(&m_HookFunc, REG_ECX, REG_NOIDX, REG_ESP, NOSCALE, 4); + + if (pi.flags & PassFlag_ForcedByRef) + IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, place_fbrr); + else + IA32_Lea_Reg_DispRegMultImm8(&m_HookFunc, REG_ECX, REG_NOIDX, REG_ESP, NOSCALE, 4); + IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EAX, REG_EBP, param_offset); IA32_Push_Reg(&m_HookFunc, REG_EAX); GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX)); @@ -314,19 +355,50 @@ namespace SourceHook BitwiseCopy_Setup(); - //lea edi, [esp+8] + //if forcedbyref: + // lea edi, [ebp_place_fbrr] + //else + // lea edi, [esp+8] - bc_setup pushed two regs onto the stack! //lea esi, [ebp+] - IA32_Lea_Reg_DispRegMultImm8(&m_HookFunc, REG_EDI, REG_NOIDX, REG_ESP, NOSCALE, 8); + if (pi.flags & PassFlag_ForcedByRef) + IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_EDI, REG_EBP, place_fbrr); + else + IA32_Lea_Reg_DispRegMultImm8(&m_HookFunc, REG_EDI, REG_NOIDX, REG_ESP, NOSCALE, 8); + IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ESI, REG_EBP, param_offset); BitwiseCopy_Do(pi.size); } + // forcedref: push reference to ebp+place_fbrr + if (pi.flags & PassFlag_ForcedByRef) + { + IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, place_fbrr); + IA32_Push_Reg(&m_HookFunc, REG_ECX); + return SIZE_PTR; + } + return DownCastSize(pi.size); } + void GenContext::DestroyParams(jit_int32_t fbrr_base) + { + for (int i = m_Proto.GetNumOfParams() - 1; i >= 0; --i) + { + const IntPassInfo &pi = m_Proto.GetParam(i); + if (pi.type == PassInfo::PassType_Object && (pi.flags & PassInfo::PassFlag_ODtor) && + (pi.flags & PassInfo::PassFlag_ByVal) && (pi.flags & PassFlag_ForcedByRef)) + { + IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, fbrr_base + GetForcedByRefParamOffset(i)); + IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(pi.pDtor)); + IA32_Call_Reg(&m_HookFunc, REG_EAX); + } + } + } + // May not touch eax! - jit_int32_t GenContext::PushParams(jit_int32_t param_base_offset, jit_int32_t save_ret_to, int v_place_for_memret) + jit_int32_t GenContext::PushParams(jit_int32_t param_base_offset, jit_int32_t save_ret_to, int v_place_for_memret, + jit_int32_t v_place_fbrr_base) { jit_int32_t added_to_stack = 0; jit_int32_t ret = 0; @@ -354,7 +426,7 @@ namespace SourceHook ret = PushFloat(cur_offset, pi); break; case PassInfo::PassType_Object: - ret = PushObject(cur_offset, pi); + ret = PushObject(cur_offset, pi, v_place_fbrr_base + GetForcedByRefParamOffset(i)); break; } } @@ -768,7 +840,7 @@ namespace SourceHook } void GenContext::GenerateCallHooks(int v_status, int v_prev_res, int v_cur_res, int v_iter, - int v_pContext, int base_param_offset, int v_plugin_ret, int v_place_for_memret) + int v_pContext, int base_param_offset, int v_plugin_ret, int v_place_for_memret, jit_int32_t v_place_fbrr_base) { jitoffs_t counter, tmppos; jitoffs_t counter2, tmppos2; @@ -815,7 +887,7 @@ namespace SourceHook // call eax // gcc: clean up - jit_int32_t gcc_clean_bytes = PushParams(base_param_offset, v_plugin_ret, v_place_for_memret); + jit_int32_t gcc_clean_bytes = PushParams(base_param_offset, v_plugin_ret, v_place_for_memret, v_place_fbrr_base); IA32_Mov_Reg_Rm(&m_HookFunc, REG_ECX, REG_EAX, MOD_REG); GCC_ONLY(IA32_Push_Reg(&m_HookFunc, REG_ECX)); @@ -823,11 +895,16 @@ namespace SourceHook IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_EAX, REG_EAX, 2*SIZE_PTR); IA32_Call_Reg(&m_HookFunc, REG_EAX); + DestroyParams(v_place_fbrr_base); + SaveRetVal(v_plugin_ret, v_place_for_memret); // cleanup +#if SH_COMP == SH_COMP_GCC + IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, gcc_clean_bytes + SIZE_PTR, MOD_REG); +#endif + // params + thisptr - GCC_ONLY(IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, gcc_clean_bytes + SIZE_PTR, MOD_REG)); // process meta return: // prev_res = cur_res @@ -866,25 +943,8 @@ namespace SourceHook m_HookFunc.rewrite(tmppos, static_cast(counter)); } - short GenContext::GetParamsStackSize() - { - short acc = 0; - for (int i = 0; i < m_Proto.GetNumOfParams(); ++i) - { - acc += GetStackSize(m_Proto.GetParam(i)); - } - - // Memory return: address is first param - if (m_Proto.GetRet().flags & PassInfo::PassFlag_RetMem) - acc += SIZE_PTR; - - // :TODO: cdecl: THIS POINTER AS FIRST PARAM!!! - - return acc; - } - void GenContext::GenerateCallOrig(int v_status, int v_pContext, int param_base_offs, int v_this, - int v_vfnptr_origentry, int v_orig_ret, int v_override_ret, int v_place_for_memret) + int v_vfnptr_origentry, int v_orig_ret, int v_override_ret, int v_place_for_memret, jit_int32_t v_place_fbrr_base) { jitoffs_t counter, tmppos; jitoffs_t counter2, tmppos2; @@ -937,7 +997,7 @@ namespace SourceHook m_HookFunc.start_count(counter2); // push params - jit_int32_t gcc_clean_bytes = PushParams(param_base_offs, v_orig_ret, v_place_for_memret); + jit_int32_t gcc_clean_bytes = PushParams(param_base_offs, v_orig_ret, v_place_for_memret, v_place_fbrr_base); // thisptr IA32_Mov_Reg_Rm_DispAuto(&m_HookFunc, REG_ECX, REG_EBP, v_this); @@ -953,10 +1013,11 @@ namespace SourceHook // cleanup #if SH_COMP == SH_COMP_GCC - // params + thisptr IA32_Add_Rm_ImmAuto(&m_HookFunc, REG_ESP, gcc_clean_bytes + SIZE_PTR, MOD_REG); #endif + DestroyParams(v_place_fbrr_base); + // save retval SaveRetVal(v_orig_ret, v_place_for_memret); @@ -1166,6 +1227,9 @@ namespace SourceHook // if required: // my_rettype place_for_memret ebp - 28 - sizeof(my_rettype)*4 -4 + + // gcc only: if required: + // place forced byref params ebp - 28 - sizeof(my_rettype)*{4 or 5} const jit_int8_t v_vfnptr_origentry = -4 + addstackoffset; @@ -1196,11 +1260,14 @@ namespace SourceHook jit_int32_t v_place_for_memret = -28 + addstackoffset - GetStackSize(m_Proto.GetRet()) * 4; + jit_int32_t v_place_fbrr_base = -28 + addstackoffset - GetStackSize(m_Proto.GetRet()) * (MemRetWithTempObj() ? 5 : 4); + // Hash for temporary storage for byval params with copy constructors // (param, offset into stack) short usedStackBytes = 3*SIZE_MWORD + 3*SIZE_PTR // vfnptr_origentry, status, prev_res, cur_res, iter, pContext + 3 * GetStackSize(m_Proto.GetRet()) + (m_Proto.GetRet().size == 0 ? 0 : SIZE_PTR) // ret_ptr, orig_ret, override_ret, plugin_ret + (MemRetWithTempObj() ? GetStackSize(m_Proto.GetRet()) : 0) + + GetForcedByRefParamsSize() - addstackoffset; // msvc: current thisptr IA32_Sub_Rm_Imm32(&m_HookFunc, REG_ESP, usedStackBytes, MOD_REG); @@ -1244,15 +1311,15 @@ namespace SourceHook // ********************** call pre hooks ********************** GenerateCallHooks(v_status, v_prev_res, v_cur_res, v_iter, v_pContext, param_base_offs, - v_plugin_ret, v_place_for_memret); + v_plugin_ret, v_place_for_memret, v_place_fbrr_base); // ********************** call orig func ********************** GenerateCallOrig(v_status, v_pContext, param_base_offs, v_this, v_vfnptr_origentry, v_orig_ret, - v_override_ret, v_place_for_memret); + v_override_ret, v_place_for_memret, v_place_fbrr_base); // ********************** call post hooks ********************** GenerateCallHooks(v_status, v_prev_res, v_cur_res, v_iter, v_pContext, param_base_offs, - v_plugin_ret, v_place_for_memret); + v_plugin_ret, v_place_for_memret, v_place_fbrr_base); // ********************** end context and return ********************** @@ -1265,8 +1332,9 @@ namespace SourceHook for (int i = 0; i < m_Proto.GetNumOfParams(); ++i) { const IntPassInfo &pi = m_Proto.GetParam(i); + // GCC: NOT of forced byref params. the caller destructs those. if (pi.type == PassInfo::PassType_Object && (pi.flags & PassInfo::PassFlag_ODtor) && - (pi.flags & PassInfo::PassFlag_ByVal)) + (pi.flags & PassInfo::PassFlag_ByVal) && !(pi.flags & PassFlag_ForcedByRef)) { IA32_Lea_DispRegImmAuto(&m_HookFunc, REG_ECX, REG_EBP, cur_param_pos); IA32_Mov_Reg_Imm32(&m_HookFunc, REG_EAX, DownCastPtr(pi.pDtor)); @@ -1420,6 +1488,7 @@ namespace SourceHook pi.type != PassInfo::PassType_Float && pi.type != PassInfo::PassType_Object) { + printf("A\n"); return false; } @@ -1427,16 +1496,28 @@ namespace SourceHook (pi.flags & PassInfo::PassFlag_ByVal)) { if ((pi.flags & PassInfo::PassFlag_CCtor) && !pi.pCopyCtor) + { + printf("B\n"); return false; + } if ((pi.flags & PassInfo::PassFlag_ODtor) && !pi.pDtor) + { + printf("C\n"); return false; - + } + if ((pi.flags & PassInfo::PassFlag_AssignOp) && !pi.pAssignOperator) + { + printf("D\n"); return false; + } if ((pi.flags & PassInfo::PassFlag_OCtor) && !pi.pNormalCtor) + { + printf("D\n"); return false; + } } if ((pi.flags & (PassInfo::PassFlag_ByVal | PassInfo::PassFlag_ByRef)) == 0) @@ -1505,8 +1586,7 @@ namespace SourceHook if (pi.type == PassInfo::PassType_Object && (pi.flags & PassInfo::PassFlag_ODtor)) { - pi.flags &= ~PassInfo::PassFlag_ByVal; - pi.flags |= PassInfo::PassFlag_ByRef; + pi.flags |= PassFlag_ForcedByRef; } } #endif diff --git a/sourcehook/sourcehook_hookmangen.h b/sourcehook/sourcehook_hookmangen.h index c1edde5..8443b2c 100644 --- a/sourcehook/sourcehook_hookmangen.h +++ b/sourcehook/sourcehook_hookmangen.h @@ -156,6 +156,7 @@ namespace SourceHook { const static int SIZE_MWORD = 4; const static int SIZE_PTR = sizeof(void*); + const static int PassFlag_ForcedByRef = (1<<30); // ByVal in source, but actually passed by reference (GCC) -> private pass, destruct CProto m_Proto; int m_VtblOffs; @@ -180,19 +181,22 @@ namespace SourceHook // size info jit_int32_t GetRealSize(const IntPassInfo &info); jit_int32_t GetStackSize(const IntPassInfo &info); - short GetParamsStackSize(); // sum(GetStackSize(i), 0 <= i < numOfParams) + short GetParamsStackSize(); // sum(GetStackSize(param[i]), 0 <= i < numOfParams) // Helpers void BitwiseCopy_Setup(); void BitwiseCopy_Do(size_t size); // Param push + short GetForcedByRefParamsSize(); // sum(param[i] is forcedbyref ? GetStackSize(param[i]) : 0, 0 <= i < numOfParams) + short GetForcedByRefParamOffset(int p); // sum(param[i] is forcedbyref ? GetStackSize(param[i]) : 0, 0 <= i < p) jit_int32_t PushParams(jit_int32_t param_base_offset, jit_int32_t save_ret_to, - jit_int32_t v_place_for_memret); // save_ret_to and v_place_for_memret only used for memory returns + jit_int32_t v_place_for_memret, jit_int32_t v_place_fbrr_base); // save_ret_to and v_place_for_memret only used for memory returns jit_int32_t PushRef(jit_int32_t param_offset, const IntPassInfo &pi); jit_int32_t PushBasic(jit_int32_t param_offset, const IntPassInfo &pi); jit_int32_t PushFloat(jit_int32_t param_offset, const IntPassInfo &pi); - jit_int32_t PushObject(jit_int32_t param_offset, const IntPassInfo &pi); + jit_int32_t PushObject(jit_int32_t param_offset, const IntPassInfo &pi, jit_int32_t v_place_fbrr); + void DestroyParams(jit_int32_t fbrr_base); // Ret val processing void SaveRetVal(jit_int32_t v_where, jit_int32_t v_place_for_memret); @@ -205,11 +209,11 @@ namespace SourceHook // Call hooks void GenerateCallHooks(int v_status, int v_prev_res, int v_cur_res, int v_iter, - int v_pContext, int base_param_offset, int v_plugin_ret, int v_place_for_memret); + int v_pContext, int base_param_offset, int v_plugin_ret, int v_place_for_memret, jit_int32_t v_place_fbrr_base); // Call orig void GenerateCallOrig(int v_status, int v_pContext, int param_base_offs, int v_this, - int v_vfnptr_origentry, int v_orig_ret, int v_override_ret, int v_place_for_memret); + int v_vfnptr_origentry, int v_orig_ret, int v_override_ret, int v_place_for_memret, jit_int32_t v_place_fbrr_base); // Hook loop void CallSetupHookLoop(int v_orig_ret, int v_override_ret, diff --git a/sourcehook/test/testhookmangen.cpp b/sourcehook/test/testhookmangen.cpp index 828bd38..475ea64 100644 --- a/sourcehook/test/testhookmangen.cpp +++ b/sourcehook/test/testhookmangen.cpp @@ -114,7 +114,7 @@ namespace template std::ostream& operator <<(std::ostream &os, const Object &obj) { - os << "Some Obj!"; + os << "Some Obj" << static_cast(obj.x[0]); return os; } diff --git a/sourcehook/test/testhookmangen.h b/sourcehook/test/testhookmangen.h index cc8c831..c010678 100644 --- a/sourcehook/test/testhookmangen.h +++ b/sourcehook/test/testhookmangen.h @@ -40,18 +40,13 @@ public: template void *FindFuncAddr(T mfp) { - if (sizeof(mfp) != sizeof(void*)) - return NULL; - else + union { - union - { - T a; - void *b; - } u; - u.a = mfp; - return u.b; - } + T a; + void *b; + } u; + u.a = mfp; + return u.b; } // Reference carrier diff --git a/sourcehook/test/testhookmangen.hxx b/sourcehook/test/testhookmangen.hxx index f633ebf..49fb473 100644 --- a/sourcehook/test/testhookmangen.hxx +++ b/sourcehook/test/testhookmangen.hxx @@ -40,18 +40,13 @@ public: template void *FindFuncAddr(T mfp) { - if (sizeof(mfp) != sizeof(void*)) - return NULL; - else + union { - union - { - T a; - void *b; - } u; - u.a = mfp; - return u.b; - } + T a; + void *b; + } u; + u.a = mfp; + return u.b; } // Reference carrier