⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dovtableinfo.hpp

📁 The library provides supports for run-time loaded plugin classes in C++
💻 HPP
字号:
// Copyright (c) 2007, Arne Steinarson// Licensing for DynObj project - see DynObj-license.txt in this folder#ifndef VTABLEINFO_HPP#define VTABLEINFO_HPP/*    Note: This file is not part of the 'core' features of DynObj, but rather more     experimental. DynObj does not reqire any changes to VTables for normal operation.*//*	This code is inspired and partly built on the work with FastDelegates by Don Clugston.	The problem soved here is similar, but opposite in a way. From a bound member function	pointer he retrieved the address of a function to call (and the adjusted 'this' pointer).	We don't care about those, but want to find the index of a virtual function in the VTable.		For most compilers, the information is there, in a field in the member function pointer.	However, for Intel and MSVC compilers, they don't use the offset into the VTable when	calling it, but rather a fix address to a stub function that has the offset hard coded	into it (not efficient nor pretty IMHO). We make a special case for that and obtain 	the function address using some inline assembly. 		Also, DMC (Digital Mars) solve the whole problem with member function pointers using 	stub callers to a function for the various cases. For DMC, we look for the address	contained in the function pointer in the VTable.		NOTE: It is quite possible for the compiler to point to stubs that are not in the VTable,	but rather refer the VTable themselves. The assembly code to extract the function 	address of a virtual function (VTblSizer::AVfunc) is currently in MSVC syntax but 	should be straight forward to move to another syntax.		NOTE: The C++ standard ABI has settled on using the GNU solution below, where the 	index is directly available, so most newer compilers will do that.		Single stepping through assembly code calling member function pointers and looking	at where the VTable entries are used will help in cases not covered below.*/#include <string.h>#if defined(_MSC_VER) || defined(__INTEL_COMPILER)	// For Microsoft & Intel compilers, it is not possible to get VTable	// index from member function pointer. Get the address of the function	// by calling it instead, using inline assembly to extract function 	// address.	#define GET_ADDR_VIA_CALL#endif// This says how many entries to copy from before the VTable start// It is somewhat arbitrary now.#define VTP_N_ENTRIES_BEFORE 4// Declared in vt_test.cppextern void *g_do_TFA;extern void *g_do_RA1;// When looking for a function index in a VTable, how long do we go?#define MAX_VTABLE_SEARCH 256// A class to measure VTable size of Base // This just gives us ability to construct base with one ctor argtemplate<class Base,class ARG>struct VTblSizerBase : public Base {    VTblSizerBase() : Base( (ARG)0 ) { }};// No arg casetemplate<class Base>struct VTblSizerBase<Base,void> : public Base {    VTblSizerBase() : Base() { }};template<class Base,class ARG>struct VTblSizer : public VTblSizerBase<Base,ARG> {	virtual int  AVFunc( ){#ifdef GET_ADDR_VIA_CALL		static bool b_inside = false;		// We want two things (one might be enough):		// - A return address inside this function (call recursively once)		// - The plain non-virtual address of this function 		if( !b_inside ){			b_inside = true;			//VTblSizer_VFunc();			AVFunc();			b_inside = false;			return 0;		}		// There are two different symbols: AVFunc and VTblSizer<SomeClass>		// AVfunc jumps here [VTblSizer<SomeClass>] and AVfunc is the one		// we find in the VTable. The templatig may add some complexity 		// to function calling, but we're lucky here.		__asm{			//mov eax, VTblSizer_VFunc			mov eax, AVFunc			mov g_do_TFA, eax			mov eax, [ebp+4];			mov g_do_RA1, eax		}#endif 		return 0;	}	};//template <class MIB,ARG>//int GetVIndex( int (VTblSizer<MIB,ARG>::*mfn)(), void **vtbl ){template <class C>int GetVIndex( int (C::*mfn)(), void **vtbl ){	// These are convenient to have later	void **ppvfn = reinterpret_cast<void**>(&mfn);	void *pvfn = ppvfn ? *ppvfn : NULL;		// Size of member function pointer, what we have to look through 	int mfn_size = sizeof(mfn);	#if defined(__GNUC__) || defined(__VISAGECPP__) || defined(__xlc__) || defined(__xlC__) 	// G++ case	if( mfn_size==sizeof(void*)+sizeof(int) ){		int i = *(int*)&mfn;		//return (i>0 && i&1) ? (i+1)/2 : -1;		// G++ stores the actual offset+1 into the VTable, so we get:		// entry 0: 1		// entry 1: 5		// entry 2: 9 ,...etc		return (i>0 && i&1) ? i/4 : -1;	}#elif defined(__BORLANDC__) || defined(__TURBOC__) || defined(__WATCOMC__) 	if( mfn_size==sizeof(void*)+2*sizeof(int) ){		// Integer at offset 2 is vindex+1		int *pi = (int*)(((char*)ppvfn)+sizeof(void*)+sizeof(int));		return (*pi)-1;	}#elif defined(__MWERKS__)	if( mfn_size==sizeof(void*)+2*sizeof(int) ){		// Integer at offset 1 is vindex		int *pi = (int*)(((char*)ppvfn)+sizeof(int));		return *pi;	}#elif defined (__sgi) || defined (__EDG__) || defined(__COMO__)	// MrCpp, MIPS Pro, Pro64, Open64 should go here also  // Edison Grouop, Comeau	if( mfn_size==2*sizeof(short)+sizeof(void*) ){		// Short at offset 1 is vindex		int *ps = (short*)(((char*)ppvfn)+sizeof(short));		return (int)*ps;	}#elif defined (_MSC_VER) || defined(__INTEL_COMPILER)	// These apparently behaves similar. We have called the function now and can read	// the globals it has written to.#endif	// The alternative that is left (and rather good) is to search the VTable	// for an address and when found, return the index. We have up to 3 addresses	// to look for.	void *pvs[3];	pvs[0] = NULL;	pvs[1] = g_do_TFA;	pvs[2] = g_do_RA1;	// If member function pointer is same size as void*, then look directly	// in supplied VTable for this value	if( mfn_size==sizeof(void*) ){		if( vtbl && ppvfn )			pvs[0] = pvfn;	}		// Iterate	for( int ix=0; ix<MAX_VTABLE_SEARCH; ix++ ){		if( !vtbl[ix] ) continue;         void *pv = vtbl[ix]; 		if( pv==pvs[0] || pv==pvs[1] || pv==pvs[2] )			/*|| (pvs[2]>vtbl[ix] && pvs[2]<vtbl[ix+1]) )*/ // The 'in between' case (inside function body) 			return ix;	}	// Exhausted possibilities for now 		return -1;}/*template<class C>void** GetVTableOf(){	C c;	return *(void***)&c;}*/template<class C,class ARG>int GetVTableSizeOf( ){	VTblSizer<C,ARG> vtbs;				// Object derived from side base	int (VTblSizer<C,ARG>::*mfn)() = &VTblSizer<C,ARG>::AVFunc;	// Call the virtual function (for MSVC and Intel compilers, but it is cheap to do anyway	g_do_TFA = g_do_RA1 = NULL;	vtbs.AVFunc();	int ix = GetVIndex( mfn, *(void***)&vtbs );	return ix>=0 ? ix : -1;}//////////////////////////////////////////////////////////////////////////// Structure used for keeping original, derived and replacement VTables//#define VTP_N_ENTRIES_BEFORE 4struct DynObjType;class VTableInfo {public:	VTableInfo( void** td, void **to, int sz) : vtbl_d(td), vtbl_o(to), vtbl_r(NULL), size(sz), pdt(NULL) { } 	~VTableInfo(){ delete [] (vtbl_r-VTP_N_ENTRIES_BEFORE); }	bool AllocSoftVTbl(){		void **vtbl_a = new void*[size+VTP_N_ENTRIES_BEFORE];		if( !vtbl_a ) return false;		vtbl_r = vtbl_a+VTP_N_ENTRIES_BEFORE;		// Copy entries		memcpy( vtbl_a, vtbl_d-VTP_N_ENTRIES_BEFORE, sizeof(void*)*(size+VTP_N_ENTRIES_BEFORE) );		return true;	}		void **vtbl_d;	 // Derived VTable	void **vtbl_o;	 // Original VTable	void **vtbl_r;   // Ram VTable 	int  size;		 // Number of entries in dervied VTable	DynObjType *pdt;	//bool operator == (void** vtbl){ return vtbl_d==vtbl || vtbl_o==vtbl || vtbl_r==vtbl; } 	bool operator == (void** vtbl){ return vtbl_d==vtbl || vtbl_r==vtbl; } };#endif // VTABLEINFO_HPP

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -