atl thunk源码
atlstdthunk.h// This is a part of the Active Template Library.// Copyright (C) Microsoft Corporation// All rights reserved.//// This source code is only intended as a supplement to the// Active Template Library Reference and related// electronic documentation provided with the library.// See these sources for detailed information regarding the// Active Template Library product.#ifndef __ATLSTDTHUNK_H__#define __ATLSTDTHUNK_H__#pragma once#pragma push_macro("malloc")#undef malloc#pragma push_macro("realloc")#undef realloc#pragma push_macro("free")#undef free#pragma push_macro("new")#undef new#pragma push_macro("HeapAlloc")#undef HeapAlloc#pragma push_macro("HeapFree")#undef HeapFree#pragma push_macro("GetProcessHeap")#undef GetProcessHeapnamespace ATL{/////////////////////////////////////////////////////////////////////////////// Thunks for __stdcall member functions#if defined(_M_IX86)PVOID __stdcall __AllocStdCallThunk(VOID);VOID__stdcall __FreeStdCallThunk(PVOID);#pragma pack(push,1)struct _stdcallthunk{DWORD m_mov; // mov dword ptr , pThis (esp+0x4 is hWnd)DWORD m_this; //BYTE m_jmp; // jmp WndProcDWORD m_relproc; // relative jmpBOOL Init(DWORD_PTR proc, void* pThis){m_mov = 0x042444C7;//C7 44 24 0Cm_this = PtrToUlong(pThis);m_jmp = 0xe9;m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(_stdcallthunk)));// write block from data cache and//flush from instruction cacheFlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk));return TRUE;}//some thunks will dynamically allocate the memory for the codevoid* GetCodeAddress(){return this;}void* operator new(size_t){ return __AllocStdCallThunk(); } void operator delete(void* pThunk) { __FreeStdCallThunk(pThunk); }};#pragma pack(pop)#elif defined(_M_AMD64)PVOID __AllocStdCallThunk(VOID);VOID__FreeStdCallThunk(PVOID);#pragma pack(push,2)struct _stdcallthunk{ USHORTRcxMov; // mov rcx, pThis ULONG64 RcxImm; // USHORTRaxMov; // mov rax, target ULONG64 RaxImm; // USHORTRaxJmp; // jmp target BOOL Init(DWORD_PTR proc, void *pThis) { RcxMov = 0xb948; // mov rcx, pThis RcxImm = (ULONG64)pThis;// RaxMov = 0xb848; // mov rax, target RaxImm = (ULONG64)proc; // RaxJmp = 0xe0ff; // jmp rax FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk));return TRUE; }//some thunks will dynamically allocate the memory for the codevoid* GetCodeAddress(){return this;}void* operator new(size_t){ return __AllocStdCallThunk(); } void operator delete(void* pThunk) { __FreeStdCallThunk(pThunk); }};#pragma pack(pop)#elif defined (_M_ALPHA)// For ALPHA we will stick the this pointer into a0, which is where// the HWND is.However, we don't actually need the HWND so this is OK.#pragma pack(push,4)struct _stdcallthunk //this should come out to 20 bytes{DWORD ldah_at; //ldah at, HIWORD(func)DWORD ldah_a0; //ldah a0, HIWORD(this)DWORD lda_at; //lda at, LOWORD(func)(at)DWORD lda_a0; //lda a0, LOWORD(this)(a0)DWORD jmp; //jmp zero,(at),0BOOL Init(DWORD_PTR proc, void* pThis){ldah_at = (0x279f0000 | HIWORD(proc)) + (LOWORD(proc)>>15);ldah_a0 = (0x261f0000 | HIWORD(pThis)) + (LOWORD(pThis)>>15);lda_at = 0x239c0000 | LOWORD(proc);lda_a0 = 0x22100000 | LOWORD(pThis);jmp = 0x6bfc0000;// write block from data cache and//flush from instruction cacheFlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk));return TRUE;}void* GetCodeAddress(){return this;}};#pragma pack(pop)#elif defined(_SH3_)#pragma pack(push,4)struct _stdcallthunk // this should come out to 16 bytes{WORDm_mov_r0;// mov.lpFunc,r0WORDm_mov_r1;// mov.lpThis,r1WORDm_jmp;// jmp@r0WORDm_nop;// nopDWORDm_pFunc;DWORDm_pThis;BOOL Init(DWORD_PTR proc, void* pThis){m_mov_r0 = 0xd001;m_mov_r1 = 0xd402;m_jmp = 0x402b;m_nop = 0x0009;m_pFunc = (DWORD)proc;m_pThis = (DWORD)pThis;// write block from data cache and//flush from instruction cacheFlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk));return TRUE;}void* GetCodeAddress(){return this;}};#pragma pack(pop)#elif defined(_MIPS_)#pragma pack(push,4)struct _stdcallthunk{WORDm_pFuncHi;WORDm_lui_t0;// luit0,PFUNC_HIGHWORDm_pFuncLo;WORDm_ori_t0;// orit0,t0,PFUNC_LOWWORDm_pThisHi;WORDm_lui_a0;// luia0,PTHIS_HIGHDWORDm_jr_t0;// jrt0WORDm_pThisLo;WORDm_ori_a0;// oria0,PTHIS_LOWBOOL Init(DWORD_PTR proc, void* pThis){m_pFuncHi = HIWORD(proc);m_lui_t0= 0x3c08;m_pFuncLo = LOWORD(proc);m_ori_t0= 0x3508;m_pThisHi = HIWORD(pThis);m_lui_a0= 0x3c04;m_jr_t0 = 0x01000008;m_pThisLo = LOWORD(pThis);m_ori_a0= 0x3484;// write block from data cache and//flush from instruction cacheFlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk));return TRUE;}void* GetCodeAddress(){return this;}};#pragma pack(pop)#elif defined(_ARM_)#pragma pack(push,4)struct _stdcallthunk // this should come out to 16 bytes{DWORDm_mov_r0;// movr0, pThisDWORDm_mov_pc;// movpc, pFuncDWORDm_pThis;DWORDm_pFunc;BOOL Init(DWORD_PTR proc, void* pThis){m_mov_r0 = 0xE59F0000;m_mov_pc = 0xE59FF000;m_pThis = (DWORD)pThis;m_pFunc = (DWORD)proc;// write block from data cache and//flush from instruction cacheFlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk));return TRUE;}void* GetCodeAddress(){return this;}};#pragma pack(pop)#elif defined(_M_IA64)#pragma pack(push,8)extern "C" void _StdCallThunkProcProc(void);struct _FuncDesc{ void* pfn; void* gp;};struct _stdcallthunk{ _FuncDesc m_funcdesc; void* m_pFunc; void* m_pThis; BOOL Init(DWORD_PTR proc, void* pThis) { m_funcdesc.pfn = ((_FuncDesc*)(&_StdCallThunkProcProc))->pfn;// Pointer to actual beginning of StdCallThunkProc m_funcdesc.gp = &m_pFunc; m_pFunc = reinterpret_cast< void* >( proc ); m_pThis = pThis; ::FlushInstructionCache( GetCurrentProcess(), this, sizeof( _stdcallthunk ) );return TRUE; } void* GetCodeAddress() { return( &m_funcdesc ); }};#pragma pack(pop)//IA64 thunks do not currently use the atlhunk.cpp allocator.#else#error Only ARM, ALPHA, SH3, MIPS, IA64, AMD64 and X86 supported#endif#if defined(_M_IX86) || defined (_M_AMD64) #pragma pack(push,8)class CDynamicStdCallThunk{public:_stdcallthunk *pThunk;CDynamicStdCallThunk(){pThunk = NULL;}~CDynamicStdCallThunk(){if (pThunk){delete pThunk;}}BOOL Init(DWORD_PTR proc, void *pThis){if (pThunk == NULL) {pThunk = new _stdcallthunk;if (pThunk == NULL){return FALSE;}}return pThunk->Init(proc, pThis);}void* GetCodeAddress(){return pThunk->GetCodeAddress();}};#pragma pack(pop)typedef CDynamicStdCallThunk CStdCallThunk;#elsetypedef _stdcallthunk CStdCallThunk;#endif// _M_IX86 || _M_AMD64} // namespace ATL #pragma pop_macro("GetProcessHeap")#pragma pop_macro("HeapAlloc")#pragma pop_macro("HeapFree")#pragma pop_macro("new")#pragma pop_macro("free")#pragma pop_macro("realloc")#pragma pop_macro("malloc")#endif // __ATLSTDTHUNK_H__atlthunk.cpp/*++Copyright (c) 1989Microsoft CorporationModule Name: thunkpool.cppAbstract: This module contains the support routines for managing a pool of ATL thunk structures. An ATL thunk contains object code that is built on the fly.Normally ATL allocates these structures from standard usermode heap.On platforms supporting "no-execute" operation, however, heap is protected no-execute so this isn't an option. The code here manages a separate "heap" of thunk structures that are allocated from execute-enabled page allocations.Author: Forrest Foltz (forrestf) 16-May-2002Environment: User mode only.Revision History:--*/#include <windows.h>#include "atlstdthunk.h" extern "C"{typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread;} CLIENT_ID;typedef CLIENT_ID *PCLIENT_ID;struct _PEB;typedef struct _PEB * PPEB;typedef struct _TEB { NT_TIB NtTib; PVOID EnvironmentPointer; CLIENT_ID ClientId; PVOID ActiveRpcHandle; PVOID ThreadLocalStoragePointer; PPEB ProcessEnvironmentBlock; /* .... Don't need any thing below this*/} TEB, *PTEB; _inline struct _TEB * Atl_NtCurrentTeb( void ) { __asm mov eax, fs: } }#if !defined(_X86_)#error Unsupported platform#endif#if !defined(PAGE_SIZE)#define PAGE_SIZE 4096#endif#if !defined(DECLSPEC_NOINLINE)#define DECLSPEC_NOINLINE __declspec(noinline)#endif#define ATL_THUNKS_PER_PAGE (PAGE_SIZE / sizeof(ATL_THUNK_ENTRY))//// Local function prototypes and typedefs//BOOLstatic__InitializeThunkPool ( VOID );typedefPSINGLE_LIST_ENTRY(__stdcall *PINTERLOCKED_PUSH_ENTRY_SLIST) ( PSLIST_HEADER ListHead, PSINGLE_LIST_ENTRY ListEntry );typedefPSINGLE_LIST_ENTRY(__stdcall *PINTERLOCKED_POP_ENTRY_SLIST) ( PSLIST_HEADER ListHead );//// An ATL thunk structure, used to manage free thunks in the pool//typedef union _ATL_THUNK_ENTRY { SLIST_ENTRY SListEntry;struct ATL::_stdcallthunk Thunk;} ATL_THUNK_ENTRY, *PATL_THUNK_ENTRY;//// Pointer to the process-wide ATL thunk slist.//PSLIST_HEADER __AtlThunkPool = NULL;//// Special value for __AtlThunkPool indicating that the standard// heap should be used for thunk allocation.//#define ATLTHUNK_USE_HEAP_VALUE (PSLIST_HEADER)UlongToPtr(1)#define ATLTHUNK_USE_HEAP() (__AtlThunkPool == ATLTHUNK_USE_HEAP_VALUE)PINTERLOCKED_PUSH_ENTRY_SLIST __AtlInterlockedPushEntrySList = NULL;PINTERLOCKED_POP_ENTRY_SLIST__AtlInterlockedPopEntrySList = NULL;PVOID__AllocStdCallThunk_cmn ( VOID )/*++Routine Description: This function is called by ATL to allocate a thunk structure from executable memory.Arguments: None.Return Value: Returns a pointer to a thunk structure on success.Raises an exception on failure.--*/{ PATL_THUNK_ENTRY lastThunkEntry; PATL_THUNK_ENTRY thunkEntry; PVOID thunkPage; // // Perform initialization if this is the first time through. // if (__AtlThunkPool == NULL) { if (__InitializeThunkPool() == FALSE) { goto outOfMemory; } } if (ATLTHUNK_USE_HEAP()) { // // On a non-NX capable platform, use the standard heap. // thunkEntry = (PATL_THUNK_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(ATL::_stdcallthunk)); if (thunkEntry == NULL) { goto outOfMemory; } return thunkEntry; } // // Attempt to pop a thunk structure from the list and return it // thunkEntry = (PATL_THUNK_ENTRY)__AtlInterlockedPopEntrySList(__AtlThunkPool); if (thunkEntry != NULL) { return &thunkEntry->Thunk; } // // The thunk list was empty.Allocate a new page of executable // memory. // thunkPage = (PATL_THUNK_ENTRY)VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (thunkPage == NULL) { goto outOfMemory; } // // See if another thread has replenished the pool while we were off // allocating memory.This does not close the window but makes it much // smaller. // // The volatile reference moves the overhead of making the page present // outside of the window. // *(DWORD volatile *)thunkPage; thunkEntry = (PATL_THUNK_ENTRY)__AtlInterlockedPopEntrySList(__AtlThunkPool); if (thunkEntry != NULL) { // // The pool has been replenished.Free the page and use the thunk // entry that we just received. // VirtualFree(thunkPage,0,MEM_RELEASE); return thunkEntry; } // // Create an array of thunk structures on the page and insert all but // the last into the free thunk list. // // The last is kept out of the list and represents the thunk allocation. // thunkEntry = (PATL_THUNK_ENTRY)thunkPage; lastThunkEntry = thunkEntry + ATL_THUNKS_PER_PAGE - 1; do { __AtlInterlockedPushEntrySList(__AtlThunkPool,&thunkEntry->SListEntry); thunkEntry += 1; } while (thunkEntry < lastThunkEntry); return thunkEntry;outOfMemory: return NULL;}VOID__FreeStdCallThunk_cmn ( IN PVOID Thunk )/*++Routine Description: This function is called by ATL to release a thunk structure back to the process-wide free thunk pool.Arguments: Thunk - supplies a pointer to a thunk structure that was allocated with __AllocStdCallThunk().Return Value: None.--*/{ PATL_THUNK_ENTRY thunkEntry; if (ATLTHUNK_USE_HEAP()) { // // On a non-NX capable platform, use the standard heap. // HeapFree(GetProcessHeap(),0,Thunk); } else { // // Simply push the free thunk structure back onto the pool // thunkEntry = (PATL_THUNK_ENTRY)Thunk; __AtlInterlockedPushEntrySList(__AtlThunkPool,&thunkEntry->SListEntry); }}BOOLstaticDECLSPEC_NOINLINE__InitializeThunkPool ( VOID )/*++Routine Description: This function is called on the first invocation of __AllocStdCallThunk(). It retrieves a pointer to the process-wide thunk pool SLIST_HEADER, if one already exists, otherwise this routine supplies an initialized SLIST_HEADER.Arguments: None.Return Value: Returns TRUE if initialization succeeded, FALSE otherwise.--*/{ #define PEB_POINTER_OFFSET 0x34 PSLIST_HEADER *atlThunkPoolPtr; PSLIST_HEADER atlThunkPool; // // On Win64, a per-process ATL thunk "heap" (anchored in the PEB) is always // mantained as an SLIST. // // On X86, such a heap is conditional.If the OS is < 5.1 (Windows XP) then // thunks are allocated/freed from/to the heap, otherwise they are mantained // as they would be on Win64. // // Two reasons for this: // // - We can't guarantee that the SLIST slot in the PEB is available downlevel // - Downlevel OSs may not offer the SLIST functionality // HMODULE kernel32Module; BOOL result; result = IsProcessorFeaturePresent( 12 /*PF_NX_ENABLED*/ ); if (result == FALSE) { // // NX execution is not happening on this machine. // // Indicate that the regular heap should be used by setting // __AtlThunkPool to a special value. // __AtlThunkPool = ATLTHUNK_USE_HEAP_VALUE; return TRUE; } // // We are running on Windows NT5.1 or later.Get the kernel32 pointers to // InterlockedPushEntrySList and InterlockedPopEntrySList.They can't be // simply imported as this library may run in environments without those // routines. // kernel32Module = LoadLibrary( "kernel32.dll" ); if (kernel32Module != NULL) { __AtlInterlockedPushEntrySList = (PINTERLOCKED_PUSH_ENTRY_SLIST) GetProcAddress( kernel32Module, "InterlockedPushEntrySList" ); __AtlInterlockedPopEntrySList = (PINTERLOCKED_POP_ENTRY_SLIST) GetProcAddress( kernel32Module, "InterlockedPopEntrySList" ); } if (__AtlInterlockedPushEntrySList == NULL || __AtlInterlockedPopEntrySList == NULL) { // // If either address could not be retrieved then fail the // initialization. // return FALSE; } atlThunkPoolPtr = (PSLIST_HEADER *)((PCHAR)(Atl_NtCurrentTeb()->ProcessEnvironmentBlock) + PEB_POINTER_OFFSET); atlThunkPool = *atlThunkPoolPtr; if (atlThunkPool == NULL) { // // The pool list has not yet been initialized.Try to use ours. // // Normally we would simply call InitializeSListHead() to initialize // the SLIST_HEADER.However, this creates linkage that conflicts with // modules (such as duser) which also link to ntslist.lib. // // So to avoid that, the SLIST_HEADER is initialized manually.This // code is platform-specific. // atlThunkPool = (PSLIST_HEADER)HeapAlloc( GetProcessHeap(), 0, sizeof(SLIST_HEADER) ); if (atlThunkPool == NULL) { return FALSE; } //InitializeSListHead(atlThunkPool); atlThunkPool->Alignment = 0; if (InterlockedCompareExchangePointer( (PVOID *)atlThunkPoolPtr, atlThunkPool, NULL ) != NULL) { // // Another thread was initializing as well, and won the race. // Free our slist header and use the one that is now there. // HeapFree( GetProcessHeap(), 0, atlThunkPool ); } atlThunkPool = *atlThunkPoolPtr; } __AtlThunkPool = atlThunkPool; return TRUE;}//// Now create the actual routines, one pair within an ATL namespace and one// without.// PVOID__stdcall __AllocStdCallThunk ( VOID ){ return __AllocStdCallThunk_cmn();}VOID__stdcall __FreeStdCallThunk ( IN PVOID Thunk ){ __FreeStdCallThunk_cmn(Thunk);}namespace ATL {PVOID__stdcall __AllocStdCallThunk ( VOID ){ return __AllocStdCallThunk_cmn();}VOID__stdcall __FreeStdCallThunk ( IN PVOID Thunk ){ __FreeStdCallThunk_cmn(Thunk);}} // namespace ATL
http://union.keepc.com/templates/default/images/1/728X90.gif
页:
[1]