From db189468a97885b6ecc63eff7dc9974bd1bc075d Mon Sep 17 00:00:00 2001 From: janwas Date: Mon, 4 Jun 2007 00:00:57 +0000 Subject: [PATCH] (update-workspace required) found another means of doing startup/shutdown that doesn't require hooking and allows init callbacks to use CRT functions (avoiding problems similar to the recent rash of pre-libc bugs). also, callback registration no longer needs ugly #pragma syntax. remove 'Detours' (evil and no longer needed) This was SVN commit r5137. --- build/premake/extern_libs.lua | 3 - build/premake/premake.lua | 16 +- source/lib/sysdep/win/detours/detours.cpp | 505 ---------- source/lib/sysdep/win/detours/detours.h | 51 - source/lib/sysdep/win/detours/disasm.cpp | 1083 --------------------- source/lib/sysdep/win/wcpu.cpp | 6 +- source/lib/sysdep/win/wdbg.cpp | 11 +- source/lib/sysdep/win/wdbg_sym.cpp | 19 +- source/lib/sysdep/win/wdir_watch.cpp | 11 +- source/lib/sysdep/win/wdll_delay_load.cpp | 7 +- source/lib/sysdep/win/whrt/whrt.cpp | 10 +- source/lib/sysdep/win/winit.cpp | 20 +- source/lib/sysdep/win/winit.h | 185 ++-- source/lib/sysdep/win/wposix/waio.cpp | 14 +- source/lib/sysdep/win/wposix/wposix.cpp | 14 +- source/lib/sysdep/win/wposix/wsock.cpp | 15 +- source/lib/sysdep/win/wposix/wtime.cpp | 7 +- source/lib/sysdep/win/wstartup.cpp | 120 +-- source/lib/sysdep/win/wstartup.h | 14 +- source/lib/sysdep/win/wutil.cpp | 13 +- 20 files changed, 199 insertions(+), 1925 deletions(-) delete mode 100644 source/lib/sysdep/win/detours/detours.cpp delete mode 100644 source/lib/sysdep/win/detours/detours.h delete mode 100644 source/lib/sysdep/win/detours/disasm.cpp diff --git a/build/premake/extern_libs.lua b/build/premake/extern_libs.lua index 738d65ab9e..174eb51a64 100644 --- a/build/premake/extern_libs.lua +++ b/build/premake/extern_libs.lua @@ -71,9 +71,6 @@ extern_lib_defs = { devil = { unix_names = { "IL", "ILU" }, }, - detours = { - dbg_suffix = "", - }, directx = { win_names = { "ddraw", }, dbg_suffix = "", diff --git a/build/premake/premake.lua b/build/premake/premake.lua index 30ad181a8b..32098f6482 100755 --- a/build/premake/premake.lua +++ b/build/premake/premake.lua @@ -404,15 +404,14 @@ function setup_all_libs () "libjpg", "dbghelp", "directx", - "cryptopp", - "detours" + "cryptopp" } setup_static_lib_package("lowlevel", source_dirs, extern_libs, {}) sysdep_dirs = { linux = { "lib/sysdep/unix" }, -- note: RC file must be added to main_exe package. -- note: don't add "lib/sysdep/win/aken.cpp" because that must be compiled with the DDK. - windows = { "lib/sysdep/win", "lib/sysdep/win/wposix", "lib/sysdep/win/whrt", "lib/sysdep/win/detours" }, + windows = { "lib/sysdep/win", "lib/sysdep/win/wposix", "lib/sysdep/win/whrt" }, macosx = { "lib/sysdep/osx", "lib/sysdep/unix" }, } tinsert(package.files, sourcesfromdirs(source_root, sysdep_dirs[OS])); @@ -441,8 +440,7 @@ used_extern_libs = { "boost", "dbghelp", "cxxtest", - "directx", - "detours" + "directx" } -- Bundles static libs together with main.cpp and builds game executable. @@ -476,8 +474,8 @@ function setup_main_exe () end package.linkoptions = { - -- required for winit.cpp's init mechanism - "/ENTRY:entry", + -- required since main.cpp uses main instead of WinMain and subsystem=Win32 + "/ENTRY:mainCRTStartup", -- delay loading of various Windows DLLs (not specific to any of the -- external libraries; those are handled separately) @@ -801,9 +799,7 @@ function setup_tests() package_add_extern_libs(used_extern_libs) if OS == "windows" then - -- required for win.cpp's init mechanism - tinsert(package.linkoptions, "/ENTRY:entry_noSEH") - + -- from "lowlevel" static lib; must be added here to be linked in tinsert(package.files, source_root.."lib/sysdep/win/error_dialog.rc") diff --git a/source/lib/sysdep/win/detours/detours.cpp b/source/lib/sysdep/win/detours/detours.cpp deleted file mode 100644 index a3e53f9b0f..0000000000 --- a/source/lib/sysdep/win/detours/detours.cpp +++ /dev/null @@ -1,505 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// Core Detours Functionality (detours.cpp of detours.lib) -// -// Microsoft Research Detours Package, Version 2.1. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// - -#include "precompiled.h" -#include "lib/sysdep/win/win.h" - -#if (_MSC_VER < 1299) -#pragma warning(disable: 4710) -#endif - -//#define DETOUR_DEBUG 1 -#define DETOURS_INTERNAL - -#include "detours.h" - -#if !CPU_IA32 -#error "detours currently only supports x86" -#endif - -////////////////////////////////////////////////////////////////////////////// -// -static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress) -{ - MEMORY_BASIC_INFORMATION mbi; - VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi)); - __try { - PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase; - if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { - return false; - } - - PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + - pDosHeader->e_lfanew); - if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { - return false; - } - - if (pbAddress >= ((PBYTE)pDosHeader + - pNtHeader->OptionalHeader - .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && - pbAddress < ((PBYTE)pDosHeader + - pNtHeader->OptionalHeader - .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + - pNtHeader->OptionalHeader - .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) { - return true; - } - return false; - } - __except(EXCEPTION_EXECUTE_HANDLER) { - return false; - } -} - -///////////////////////////////////////////////////////////////////////// X86. -// -#ifdef DETOURS_X86 - -struct _DETOUR_TRAMPOLINE -{ - BYTE rbCode[23]; // target code + jmp to pbRemain - BYTE cbTarget; // size of target code moved. - PBYTE pbRemain; // first instruction after moved code. [free list] - PBYTE pbDetour; // first instruction of detour function. -}; - -enum { - SIZE_OF_JMP = 5 -}; - -inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal) -{ - PBYTE pbJmpSrc = pbCode + 5; - *pbCode++ = 0xE9; // jmp +imm32 - *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc); - return pbCode; -} - -inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal) -{ - PBYTE pbJmpSrc = pbCode + 6; - *pbCode++ = 0xff; // jmp [+imm32] - *pbCode++ = 0x25; - *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal - pbJmpSrc); - return pbCode; -} - -inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) -{ - while (pbCode < pbLimit) { - *pbCode++ = 0xcc; // brk; - } - return pbCode; -} - -inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) -{ - if (pbCode == NULL) { - return NULL; - } - if (ppGlobals != NULL) { - *ppGlobals = NULL; - } - if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] - // Looks like an import alias jump, then get the code it points to. - PBYTE pbTarget = *(PBYTE *)&pbCode[2]; - if (detour_is_imported(pbCode, pbTarget)) { - PBYTE pbNew = *(PBYTE *)pbTarget; - DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); - return pbNew; - } - } - else if (pbCode[0] == 0xeb) { // jmp +imm8 - // These just started appearing with CL13. - PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1]; - DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); - if (pbNew[0] == 0xe9) { // jmp +imm32 - pbCode = pbNew; - pbNew = pbCode + *(INT32 *)&pbCode[1]; - DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); - } - return pbNew; - } - return pbCode; -} - -inline BOOL detour_does_code_end_function(PBYTE pbCode) -{ - if (pbCode[0] == 0xe9 || // jmp +imm32 - pbCode[0] == 0xe0 || // jmp eax - pbCode[0] == 0xc2 || // ret +imm8 - pbCode[0] == 0xc3 || // ret - pbCode[0] == 0xcc) { // brk - return TRUE; - } - else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] - return TRUE; - } - else if ((pbCode[0] == 0x26 || // jmp es: - pbCode[0] == 0x2e || // jmp cs: - pbCode[0] == 0x36 || // jmp ss: - pbCode[0] == 0xe3 || // jmp ds: - pbCode[0] == 0x64 || // jmp fs: - pbCode[0] == 0x65) && // jmp gs: - pbCode[1] == 0xff && // jmp [+imm32] - pbCode[2] == 0x25) { - return TRUE; - } - return FALSE; -} -#endif // DETOURS_X86 - -//////////////////////////////////////////////// Trampoline Memory Management. -// -struct DETOUR_REGION -{ - ULONG dwSignature; - DETOUR_REGION * pNext; // Next region in list of regions. - DETOUR_TRAMPOLINE * pFree; // List of free trampolines in this region. -}; -typedef DETOUR_REGION * PDETOUR_REGION; - -const ULONG DETOUR_REGION_SIGNATURE = 'Rrtd'; -const ULONG DETOUR_REGION_SIZE = 0x10000; -const ULONG DETOUR_TRAMPOLINES_PER_REGION = (DETOUR_REGION_SIZE - / sizeof(DETOUR_TRAMPOLINE)) - 1; -static PDETOUR_REGION s_pRegions = NULL; // List of all regions. -static PDETOUR_REGION s_pRegion = NULL; // Default region. - -static void detour_writable_trampoline_regions() -{ - // Mark all of the regions as writable. - for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) { - DWORD dwOld; - VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READWRITE, &dwOld); - } -} - -static void detour_runnable_trampoline_regions() -{ - // Mark all of the regions as executable. - for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) { - DWORD dwOld; - VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READ, &dwOld); - } -} - -static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget) -{ - // We have to place trampolines within +/- 2GB of target. - // The allocation code assumes that - - PDETOUR_TRAMPOLINE pLo = (PDETOUR_TRAMPOLINE) - ((pbTarget > (PBYTE)0x7ff80000) - ? pbTarget - 0x7ff80000 : (PBYTE)(ULONG_PTR)DETOUR_REGION_SIZE); - PDETOUR_TRAMPOLINE pHi = (PDETOUR_TRAMPOLINE) - ((pbTarget < (PBYTE)0xffffffff80000000) - ? pbTarget + 0x7ff80000 : (PBYTE)0xfffffffffff80000); - DETOUR_TRACE(("[%p..%p..%p]\n", pLo, pbTarget, pHi)); - - PDETOUR_TRAMPOLINE pTrampoline = NULL; - - // Insure that there is a default region. - if (s_pRegion == NULL && s_pRegions != NULL) { - s_pRegion = s_pRegions; - } - - // First check the default region for an valid free block. - if (s_pRegion != NULL && s_pRegion->pFree != NULL && - s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) { - - found_region: - pTrampoline = s_pRegion->pFree; - // do a last sanity check on region. - if (pTrampoline < pLo || pTrampoline > pHi) { - return NULL; - } - s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pTrampoline->pbRemain; - memset(pTrampoline, 0xcc, sizeof(*pTrampoline)); - return pTrampoline; - } - - // Then check the existing regions for a valid free block. - for (s_pRegion = s_pRegions; s_pRegion != NULL; s_pRegion = s_pRegion->pNext) { - if (s_pRegion != NULL && s_pRegion->pFree != NULL && - s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) { - goto found_region; - } - } - - // We need to allocate a new region. - - // Round pbTarget down to 64K block. - pbTarget = pbTarget - (PtrToUlong(pbTarget) & 0xffff); - - // First we search down (within the valid region) - - DETOUR_TRACE((" Looking for free region below %p:\n", pbTarget)); - - PBYTE pbTry; - for (pbTry = pbTarget; pbTry > (PBYTE)pLo;) { - MEMORY_BASIC_INFORMATION mbi; - - DETOUR_TRACE((" Try %p\n", pbTry)); - if (pbTry >= (PBYTE)(ULONG_PTR)0x70000000 && - pbTry <= (PBYTE)(ULONG_PTR)0x80000000) { - // Skip region reserved for system DLLs. - pbTry = (PBYTE)(ULONG_PTR)(0x70000000 - DETOUR_REGION_SIZE); - } - if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) { - break; - } - - DETOUR_TRACE((" Try %p => %p..%p %6x\n", - pbTry, - mbi.BaseAddress, - (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, - mbi.State)); - - if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) { - s_pRegion = (DETOUR_REGION*)VirtualAlloc(pbTry, - DETOUR_REGION_SIZE, - MEM_COMMIT|MEM_RESERVE, - PAGE_EXECUTE_READWRITE); - if (s_pRegion != NULL) { - alloced_region: - s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE; - s_pRegion->pFree = NULL; - s_pRegion->pNext = s_pRegions; - s_pRegions = s_pRegion; - DETOUR_TRACE((" Allocated region %p..%p\n\n", - s_pRegion, ((PBYTE)s_pRegion) + DETOUR_REGION_SIZE - 1)); - - // Put everything but the first trampoline on the free list. - PBYTE pFree = NULL; - pTrampoline = ((PDETOUR_TRAMPOLINE)s_pRegion) + 1; - for (int i = DETOUR_TRAMPOLINES_PER_REGION - 1; i > 1; i--) { - pTrampoline[i].pbRemain = pFree; - pFree = (PBYTE)&pTrampoline[i]; - } - s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pFree; - goto found_region; - } - else { - DETOUR_TRACE(("Error: %p %d\n", pbTry, GetLastError())); - break; - } - } - pbTry = (PBYTE)mbi.AllocationBase - DETOUR_REGION_SIZE; - } - - DETOUR_TRACE((" Looking for free region above %p:\n", pbTarget)); - - for (pbTry = pbTarget; pbTry < (PBYTE)pHi;) { - MEMORY_BASIC_INFORMATION mbi; - - if (pbTry >= (PBYTE)(ULONG_PTR)0x70000000 && - pbTry <= (PBYTE)(ULONG_PTR)0x80000000) { - // Skip region reserved for system DLLs. - pbTry = (PBYTE)(ULONG_PTR)(0x80000000 + DETOUR_REGION_SIZE); - } - if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) { - break; - } - - DETOUR_TRACE((" Try %p => %p..%p %6x\n", - pbTry, - mbi.BaseAddress, - (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, - mbi.State)); - - if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) { - ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1); - if (extra != 0) { - // WinXP64 returns free areas that aren't REGION aligned to - // 32-bit applications. - ULONG_PTR adjust = DETOUR_REGION_SIZE - extra; - mbi.RegionSize -= adjust; - ((PBYTE&)mbi.BaseAddress) += adjust; - DETOUR_TRACE(("--Try %p => %p..%p %6x\n", - pbTry, - mbi.BaseAddress, - (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, - mbi.State)); - pbTry = (PBYTE)mbi.BaseAddress; - } - s_pRegion = (DETOUR_REGION*)VirtualAlloc(pbTry, - DETOUR_REGION_SIZE, - MEM_COMMIT|MEM_RESERVE, - PAGE_EXECUTE_READWRITE); - if (s_pRegion != NULL) { - goto alloced_region; - } - else { - DETOUR_TRACE(("Error: %p %d\n", pbTry, GetLastError())); - } - } - - pbTry = (PBYTE)mbi.BaseAddress + mbi.RegionSize; - } - - DETOUR_TRACE(("Couldn't find available memory region!\n")); - throw std::bad_alloc(""); -} - - -///////////////////////////////////////////////////////// Transaction Structs. -// - -struct DetourOperation -{ - DetourOperation * pNext; - PBYTE * ppbPointer; - PBYTE pbTarget; - PDETOUR_TRAMPOLINE pTrampoline; - ULONG dwPerm; -}; - -static DetourOperation * s_pPendingOperations = NULL; - -////////////////////////////////////////////////////////////////////////////// -// -PVOID DetourCodeFromPointer(PVOID pPointer, PVOID *ppGlobals) -{ - return detour_skip_jmp((PBYTE)pPointer, ppGlobals); -} - -//////////////////////////////////////////////////////////// Transaction APIs. -// - -LONG DetourTransactionBegin() -{ - // Make sure only one thread can start a transaction. -/// if (InterlockedCompareExchange(&s_nPendingThreadId, (LONG)GetCurrentThreadId(), 0) != 0) -/// return ERROR_INVALID_OPERATION; - - s_pPendingOperations = NULL; - - // Make sure the trampoline pages are writable. - detour_writable_trampoline_regions(); - - return NO_ERROR; -} - -LONG DetourTransactionCommit() -{ - // Common variables. - DetourOperation *o; - - // Insert or remove each of the detours. - for (o = s_pPendingOperations; o != NULL; o = o->pNext) - { -#ifdef DETOURS_X86 - PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->pbDetour); - pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain); - *o->ppbPointer = o->pTrampoline->rbCode; -#endif // DETOURS_X86 - } - - // Restore all of the page permissions and flush the icache. - HANDLE hProcess = GetCurrentProcess(); - for (o = s_pPendingOperations; o != NULL;) { - // We don't care if this fails, because the code is still accessible. - DWORD dwOld; - VirtualProtect(o->pbTarget, o->pTrampoline->cbTarget, o->dwPerm, &dwOld); - FlushInstructionCache(hProcess, o->pbTarget, o->pTrampoline->cbTarget); - - DetourOperation *n = o->pNext; - delete o; - o = n; - } - s_pPendingOperations = NULL; - - // Make sure the trampoline pages are no longer writable. - detour_runnable_trampoline_regions(); - - return NO_ERROR; -} - -///////////////////////////////////////////////////////////// Transacted APIs. -// - -LONG DetourAttach(PVOID *ppPointer, PVOID pDetour) -{ - LONG error = NO_ERROR; - - if (*ppPointer == NULL) { - error = ERROR_INVALID_HANDLE; - DETOUR_TRACE(("*ppPointer is null (ppPointer=%p)\n", ppPointer)); - DETOUR_BREAK(); - return error; - } - - PBYTE pbTarget = (PBYTE)*ppPointer; - PDETOUR_TRAMPOLINE pTrampoline = NULL; - DetourOperation *o = NULL; - - pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL); - pDetour = DetourCodeFromPointer(pDetour, NULL); - - // Don't follow a jump if its destination is the target function. - // This happens when the detour does nothing other than call the target. - if (pDetour == (PVOID)pbTarget) - exit(1); - - o = new DetourOperation; - pTrampoline = detour_alloc_trampoline(pbTarget); - - // Determine the number of movable target instructions. - PBYTE pbSrc = pbTarget; - LONG cbTarget = 0; - while (cbTarget < SIZE_OF_JMP) { - PBYTE pbOp = pbSrc; - LONG lExtra = 0; - - DETOUR_TRACE((" DetourCopyInstructionEx(%p,%p)\n", pTrampoline->rbCode + cbTarget, pbSrc)); - pbSrc = (PBYTE)DetourCopyInstructionEx(pTrampoline->rbCode + cbTarget, pbSrc, NULL, &lExtra); - DETOUR_TRACE((" DetourCopyInstructionEx() = %p (%d bytes)\n", pbSrc, (int)(pbSrc - pbOp))); - - if (lExtra != 0) { - break; // Abort if offset doesn't fit. - } - cbTarget = (LONG)(pbSrc - pbTarget); - - if (detour_does_code_end_function(pbOp)) { - break; - } - } - // Too few instructions. - if (cbTarget < SIZE_OF_JMP) - exit(2); - - // Too many instructions. - if (cbTarget > sizeof(pTrampoline->rbCode) - SIZE_OF_JMP) - exit(3); - - pTrampoline->pbRemain = pbTarget + cbTarget; - pTrampoline->pbDetour = (PBYTE)pDetour; - pTrampoline->cbTarget = (BYTE)cbTarget; - -#ifdef DETOURS_X86 - pbSrc = detour_gen_jmp_immediate(pTrampoline->rbCode + cbTarget, pTrampoline->pbRemain); - pbSrc = detour_gen_brk(pbSrc, - pTrampoline->rbCode + sizeof(pTrampoline->rbCode)); -#endif // DETOURS_X86 - - DWORD dwOld = 0; - if (!VirtualProtect(pbTarget, cbTarget, PAGE_EXECUTE_READWRITE, &dwOld)) - exit(4); - - o->ppbPointer = (PBYTE*)ppPointer; - o->pTrampoline = pTrampoline; - o->pbTarget = pbTarget; - o->dwPerm = dwOld; - o->pNext = s_pPendingOperations; - s_pPendingOperations = o; - - return NO_ERROR; -} diff --git a/source/lib/sysdep/win/detours/detours.h b/source/lib/sysdep/win/detours/detours.h deleted file mode 100644 index e04220a6eb..0000000000 --- a/source/lib/sysdep/win/detours/detours.h +++ /dev/null @@ -1,51 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// Core Detours Functionality (detours.h of detours.lib) -// -// Microsoft Research Detours Package, Version 2.1. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// - -#ifndef _DETOURS_H_ -#define _DETOURS_H_ - -#define DETOURS_X86 - - -#define DETOURS_VERSION 20100 // 2.1.0 - - -#define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) -#define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) - - -#define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! -typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; - - -LONG DetourTransactionBegin(); -LONG DetourTransactionCommit(); -LONG DetourAttach(PVOID *ppPointer, PVOID pDetour); - - -PVOID WINAPI DetourCopyInstructionEx(PVOID pDst, PVOID pSrc, PVOID *ppTarget, LONG *plExtra); - - -////////////////////////////////////////////////////////////////////////////// -// -#include - -#ifndef DETOUR_TRACE -#if DETOUR_DEBUG -#define DETOUR_TRACE(x) printf x -#define DETOUR_BREAK() DebugBreak() -#include -#include -#else -#define DETOUR_TRACE(x) -#define DETOUR_BREAK() -#endif -#endif - -#endif // _DETOURS_H_ diff --git a/source/lib/sysdep/win/detours/disasm.cpp b/source/lib/sysdep/win/detours/disasm.cpp deleted file mode 100644 index ddf67d773a..0000000000 --- a/source/lib/sysdep/win/detours/disasm.cpp +++ /dev/null @@ -1,1083 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// -// Detours Disassembler (disasm.cpp of detours.lib) -// -// Microsoft Research Detours Package, Version 2.1. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// - -#include "precompiled.h" -#include "lib/sysdep/win/win.h" - -#include - -// #define DETOUR_DEBUG 1 -#define DETOURS_INTERNAL - -#include "detours.h" - -#if !defined(DETOURS_X86) && !defined(DETOURS_X64) && !defined(DETOURS_IA64) -#error Must define one of DETOURS_X86, DETOURS_X64, or DETOURS_IA64 -#endif - -#undef ASSERT -#define ASSERT(x) - -////////////////////////////////////////////////////////////////////////////// -// -// Function: -// DetourCopyInstructionEx(PVOID pDst, -// PVOID pSrc, -// PVOID *ppTarget, -// LONG *plExtra) -// Purpose: -// Copy a single instruction from pSrc to pDst. -// -// Arguments: -// pDst: -// Destination address for the instruction. May be NULL in which -// case DetourCopyInstruction is used to measure an instruction. -// If not NULL then the source instruction is copied to the -// destination instruction and any relative arguments are adjusted. -// pSrc: -// Source address of the instruction. -// ppTarget: -// Out parameter for any target instruction address pointed to by -// the instruction. For example, a branch or a jump insruction has -// a target, but a load or store instruction doesn't. A target is -// another instruction that may be executed as a result of this -// instruction. ppTarget may be NULL. -// plExtra: -// Out parameter for the number of extra bytes needed by the -// instruction to reach the target. For example, lExtra = 3 if the -// instruction had an 8-bit relative offset, but needs a 32-bit -// relative offset. -// -// Returns: -// Returns the address of the next instruction (following in the source) -// instruction. By subtracting pSrc from the return value, the caller -// can determinte the size of the instruction copied. -// -// Comments: -// By following the pTarget, the caller can follow alternate -// instruction streams. However, it is not always possible to determine -// the target based on static analysis. For example, the destination of -// a jump relative to a register cannot be determined from just the -// instruction stream. The output value, pTarget, can have any of the -// following outputs: -// DETOUR_INSTRUCTION_TARGET_NONE: -// The instruction has no targets. -// DETOUR_INSTRUCTION_TARGET_DYNAMIC: -// The instruction has a non-deterministic (dynamic) target. -// (i.e. the jump is to an address held in a register.) -// Address: The instruction has the specified target. -// -// When copying instructions, DetourCopyInstruction insures that any -// targets remain constant. It does so by adjusting any IP relative -// offsets. -// - -PVOID WINAPI DetourCopyInstruction(PVOID pDst, PVOID pSrc, PVOID *ppTarget) -{ - return DetourCopyInstructionEx(pDst, pSrc, ppTarget, NULL); -} - -//////////////////////////////////////////////////// X86 and X64 Disassembler. -// -// Includes full support for all x86 chips prior to the Pentium III. -// -#if defined(DETOURS_X64) || defined(DETOURS_X86) - -class CDetourDis -{ - public: - CDetourDis(PBYTE *ppbTarget, LONG *plExtra); - - PBYTE CopyInstruction(PBYTE pbDst, PBYTE pbSrc); - static BOOL SanityCheckSystem(); - - public: - struct COPYENTRY; - typedef const COPYENTRY * REFCOPYENTRY; - - typedef PBYTE (CDetourDis::* COPYFUNC)(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - - enum { - DYNAMIC = 0x1u, - ADDRESS = 0x2u, - NOENLARGE = 0x4u, - RAX = 0x8u, - - SIB = 0x10u, - RIP = 0x20u, - NOTSIB = 0x0fu, - }; - struct COPYENTRY - { - ULONG nOpcode : 8; // Opcode - ULONG nFixedSize : 4; // Fixed size of opcode - ULONG nFixedSize16 : 4; // Fixed size when 16 bit operand - ULONG nModOffset : 4; // Offset to mod/rm byte (0=none) - LONG nRelOffset : 4; // Offset to relative target. - LONG nTargetBack : 4; // Offset back to absolute or rip target - ULONG nFlagBits : 4; // Flags for DYNAMIC, etc. - COPYFUNC pfCopy; // Function pointer. - }; - - protected: - // These macros define common uses of nFixedSize..pfCopy. -#define ENTRY_CopyBytes1 1, 1, 0, 0, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes1Dynamic 1, 1, 0, 0, 0, DYNAMIC, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes2 2, 2, 0, 0, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes2Jump 2, 2, 0, 1, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes2CantJump 2, 2, 0, 1, 0, NOENLARGE, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes2Dynamic 2, 2, 0, 0, 0, DYNAMIC, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes3 3, 3, 0, 0, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes3Dynamic 3, 3, 0, 0, 0, DYNAMIC, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes3Or5 5, 3, 0, 0, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes3Or5Rax 5, 3, 0, 0, 0, RAX, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes3Or5Target 5, 3, 0, 1, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes5Or7Dynamic 7, 5, 0, 0, 0, DYNAMIC, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes3Or5Address 5, 3, 0, 0, 0, ADDRESS, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes4 4, 4, 0, 0, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes5 5, 5, 0, 0, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes7 7, 7, 0, 0, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes2Mod 2, 2, 1, 0, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes2Mod1 3, 3, 1, 0, 1, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes2ModOperand 6, 4, 1, 0, 4, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytes3Mod 3, 3, 2, 0, 0, 0, &CDetourDis::CopyBytes -#define ENTRY_CopyBytesPrefix 1, 1, 0, 0, 0, 0, &CDetourDis::CopyBytesPrefix -#define ENTRY_CopyBytesRax 1, 1, 0, 0, 0, 0, &CDetourDis::CopyBytesRax -#define ENTRY_Copy0F 1, 1, 0, 0, 0, 0, &CDetourDis::Copy0F -#define ENTRY_Copy66 1, 1, 0, 0, 0, 0, &CDetourDis::Copy66 -#define ENTRY_Copy67 1, 1, 0, 0, 0, 0, &CDetourDis::Copy67 -#define ENTRY_CopyF6 0, 0, 0, 0, 0, 0, &CDetourDis::CopyF6 -#define ENTRY_CopyF7 0, 0, 0, 0, 0, 0, &CDetourDis::CopyF7 -#define ENTRY_CopyFF 0, 0, 0, 0, 0, 0, &CDetourDis::CopyFF -#define ENTRY_Invalid 1, 1, 0, 0, 0, 0, &CDetourDis::Invalid -#define ENTRY_End 0, 0, 0, 0, 0, 0, NULL - - PBYTE CopyBytes(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - PBYTE CopyBytesPrefix(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - PBYTE CopyBytesRax(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - - PBYTE Invalid(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - - PBYTE AdjustTarget(PBYTE pbDst, PBYTE pbSrc, LONG cbOp, - LONG cbTargetOffset, LONG cbTargetSize); - - protected: - PBYTE Copy0F(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - PBYTE Copy66(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - PBYTE Copy67(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - PBYTE CopyF6(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - PBYTE CopyF7(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - PBYTE CopyFF(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc); - - protected: - static const COPYENTRY s_rceCopyTable[257]; - static const COPYENTRY s_rceCopyTable0F[257]; - static const BYTE s_rbModRm[256]; - - protected: - BOOL m_bOperandOverride; - BOOL m_bAddressOverride; - BOOL m_bRaxOverride; - - PBYTE * m_ppbTarget; - LONG * m_plExtra; - - LONG m_lScratchExtra; - PBYTE m_pbScratchTarget; - BYTE m_rbScratchDst[64]; -}; - -PVOID WINAPI DetourCopyInstructionEx(PVOID pDst, - PVOID pSrc, - PVOID *ppTarget, - LONG *plExtra) -{ - CDetourDis oDetourDisasm((PBYTE*)ppTarget, plExtra); - return oDetourDisasm.CopyInstruction((PBYTE)pDst, (PBYTE)pSrc); -} - -/////////////////////////////////////////////////////////// Disassembler Code. -// -CDetourDis::CDetourDis(PBYTE *ppbTarget, LONG *plExtra) -{ - m_bOperandOverride = FALSE; - m_bAddressOverride = FALSE; - m_bRaxOverride = FALSE; - - m_ppbTarget = ppbTarget ? ppbTarget : &m_pbScratchTarget; - m_plExtra = plExtra ? plExtra : &m_lScratchExtra; - - *m_ppbTarget = (PBYTE)DETOUR_INSTRUCTION_TARGET_NONE; - *m_plExtra = 0; -} - -PBYTE CDetourDis::CopyInstruction(PBYTE pbDst, PBYTE pbSrc) -{ - // Configure scratch areas if real areas are not available. - if (NULL == pbDst) { - pbDst = m_rbScratchDst; - } - if (NULL == pbSrc) { - // We can't copy a non-existent instruction. - SetLastError(ERROR_INVALID_DATA); - return NULL; - } - - // Figure out how big the instruction is, do the appropriate copy, - // and figure out what the target of the instruction is if any. - // - REFCOPYENTRY pEntry = &s_rceCopyTable[pbSrc[0]]; - return (this->*pEntry->pfCopy)(pEntry, pbDst, pbSrc); -} - -PBYTE CDetourDis::CopyBytes(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) -{ -#ifdef DETOURS_X64 -#error Feature not supported in this release. - - - - -#else - LONG nBytesFixed = (pEntry->nFlagBits & ADDRESS) - ? (m_bAddressOverride ? pEntry->nFixedSize16 : pEntry->nFixedSize) - : (m_bOperandOverride ? pEntry->nFixedSize16 : pEntry->nFixedSize); -#endif - - LONG nBytes = nBytesFixed; - LONG nRelOffset = pEntry->nRelOffset; - LONG cbTarget = nBytes - nRelOffset; - if (pEntry->nModOffset > 0) { - BYTE bModRm = pbSrc[pEntry->nModOffset]; - BYTE bFlags = s_rbModRm[bModRm]; - - nBytes += bFlags & NOTSIB; - - if (bFlags & SIB) { - BYTE bSib = pbSrc[pEntry->nModOffset + 1]; - - if ((bSib & 0x07) == 0x05) { - if ((bModRm & 0xc0) == 0x00) { - nBytes += 4; - } - else if ((bModRm & 0xc0) == 0x40) { - nBytes += 1; - } - else if ((bModRm & 0xc0) == 0x80) { - nBytes += 4; - } - } - cbTarget = nBytes - nRelOffset; - } - else if (bFlags & RIP) { -#ifdef DETOURS_X64 -#error Feature not supported in this release. - - -#endif - } - } - CopyMemory(pbDst, pbSrc, nBytes); - - if (nRelOffset) { - *m_ppbTarget = AdjustTarget(pbDst, pbSrc, nBytesFixed, nRelOffset, cbTarget); -#ifdef DETOURS_X64 -#error Feature not supported in this release. - - - -#endif - } - if (pEntry->nFlagBits & NOENLARGE) { - *m_plExtra = -*m_plExtra; - } - if (pEntry->nFlagBits & DYNAMIC) { - *m_ppbTarget = (PBYTE)DETOUR_INSTRUCTION_TARGET_DYNAMIC; - } - return pbSrc + nBytes; -} - -PBYTE CDetourDis::CopyBytesPrefix(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) -{ - CopyBytes(pEntry, pbDst, pbSrc); - - pEntry = &s_rceCopyTable[pbSrc[1]]; - return (this->*pEntry->pfCopy)(pEntry, pbDst + 1, pbSrc + 1); -} - -PBYTE CDetourDis::CopyBytesRax(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) -{ - CopyBytes(pEntry, pbDst, pbSrc); - - if (*pbSrc & 0x8) { - m_bRaxOverride = TRUE; - } - - pEntry = &s_rceCopyTable[pbSrc[1]]; - return (this->*pEntry->pfCopy)(pEntry, pbDst + 1, pbSrc + 1); -} - -PBYTE CDetourDis::AdjustTarget(PBYTE pbDst, PBYTE pbSrc, LONG cbOp, - LONG cbTargetOffset, LONG cbTargetSize) -{ - PBYTE pbTarget = NULL; - PVOID pvTargetAddr = &pbDst[cbTargetOffset]; - LONG_PTR nOldOffset = 0; - - switch (cbTargetSize) { - case 1: - nOldOffset = (LONG_PTR)*(CHAR*&)pvTargetAddr; - break; - case 2: - nOldOffset = (LONG_PTR)*(SHORT*&)pvTargetAddr; - break; - case 4: - nOldOffset = (LONG_PTR)*(LONG*&)pvTargetAddr; - break; - case 8: - nOldOffset = (LONG_PTR)*(LONG_PTR*&)pvTargetAddr; - break; - default: - ASSERT(!"cbTargetSize is invalid."); - break; - } - - pbTarget = pbSrc + cbOp + nOldOffset; - LONG_PTR nNewOffset = nOldOffset - (pbDst - pbSrc); - - switch (cbTargetSize) { - case 1: - *(CHAR*&)pvTargetAddr = (CHAR)nNewOffset; - if (nNewOffset < SCHAR_MIN || nNewOffset > SCHAR_MAX) { - *m_plExtra = sizeof(ULONG_PTR) - 1; - } - break; - case 2: - *(SHORT*&)pvTargetAddr = (SHORT)nNewOffset; - if (nNewOffset < SHRT_MIN || nNewOffset > SHRT_MAX) { - *m_plExtra = sizeof(ULONG_PTR) - 2; - } - break; - case 4: - *(LONG*&)pvTargetAddr = (LONG)nNewOffset; - if (nNewOffset < LONG_MIN || nNewOffset > LONG_MAX) { - *m_plExtra = sizeof(ULONG_PTR) - 4; - } - break; - case 8: - *(LONG_PTR*&)pvTargetAddr = (LONG_PTR)nNewOffset; - break; - } - ASSERT(pbDst + cbOp + nNewOffset == pbTarget); - return pbTarget; -} - -PBYTE CDetourDis::Invalid(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) -{ - (void)pbDst; - (void)pEntry; - ASSERT(!"Invalid Instruction"); - return pbSrc + 1; -} - -////////////////////////////////////////////////////// Individual Bytes Codes. -// -PBYTE CDetourDis::Copy0F(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) -{ - CopyBytes(pEntry, pbDst, pbSrc); - - pEntry = &s_rceCopyTable0F[pbSrc[1]]; - return (this->*pEntry->pfCopy)(pEntry, pbDst + 1, pbSrc + 1); -} - -PBYTE CDetourDis::Copy66(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) -{ // Operand-size override prefix - m_bOperandOverride = TRUE; - return CopyBytesPrefix(pEntry, pbDst, pbSrc); -} - -PBYTE CDetourDis::Copy67(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) -{ // Address size override prefix - m_bAddressOverride = TRUE; - return CopyBytesPrefix(pEntry, pbDst, pbSrc); -} - -PBYTE CDetourDis::CopyF6(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) -{ - (void)pEntry; - - // TEST BYTE /0 - if (0x00 == (0x38 & pbSrc[1])) { // reg(bits 543) of ModR/M == 0 - const COPYENTRY ce = { 0xf6, ENTRY_CopyBytes2Mod1 }; - return (this->*ce.pfCopy)(&ce, pbDst, pbSrc); - } - // DIV /6 - // IDIV /7 - // IMUL /5 - // MUL /4 - // NEG /3 - // NOT /2 - - const COPYENTRY ce = { 0xf6, ENTRY_CopyBytes2Mod }; - return (this->*ce.pfCopy)(&ce, pbDst, pbSrc); -} - -PBYTE CDetourDis::CopyF7(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) -{ - (void)pEntry; - - // TEST WORD /0 - if (0x00 == (0x38 & pbSrc[1])) { // reg(bits 543) of ModR/M == 0 - const COPYENTRY ce = { 0xf7, ENTRY_CopyBytes2ModOperand }; - return (this->*ce.pfCopy)(&ce, pbDst, pbSrc); - } - - // DIV /6 - // IDIV /7 - // IMUL /5 - // MUL /4 - // NEG /3 - // NOT /2 - const COPYENTRY ce = { 0xf7, ENTRY_CopyBytes2Mod }; - return (this->*ce.pfCopy)(&ce, pbDst, pbSrc); -} - -PBYTE CDetourDis::CopyFF(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc) -{ // CALL /2 - // CALL /3 - // INC /0 - // JMP /4 - // JMP /5 - // PUSH /6 - (void)pEntry; - - if (0x15 == pbSrc[1] || 0x25 == pbSrc[1]) { // CALL [], JMP [] -#ifdef DETOURS_X64 -#error Feature not supported in this release. - - -#else - PBYTE *ppbTarget = *(PBYTE**)&pbSrc[2]; - *m_ppbTarget = *ppbTarget; -#endif - } - else if (0x10 == (0x38 & pbSrc[1]) || // CALL /2 --> reg(bits 543) of ModR/M == 010 - 0x18 == (0x38 & pbSrc[1]) || // CALL /3 --> reg(bits 543) of ModR/M == 011 - 0x20 == (0x38 & pbSrc[1]) || // JMP /4 --> reg(bits 543) of ModR/M == 100 - 0x28 == (0x38 & pbSrc[1]) // JMP /5 --> reg(bits 543) of ModR/M == 101 - ) { - *m_ppbTarget = (PBYTE)DETOUR_INSTRUCTION_TARGET_DYNAMIC; - } - const COPYENTRY ce = { 0xff, ENTRY_CopyBytes2Mod }; - return (this->*ce.pfCopy)(&ce, pbDst, pbSrc); -} - -///////////////////////////////////////////////////////// Disassembler Tables. -// -const BYTE CDetourDis::s_rbModRm[256] = { - 0,0,0,0, SIB|1,RIP|4,0,0, 0,0,0,0, SIB|1,RIP|4,0,0, // 0x - 0,0,0,0, SIB|1,RIP|4,0,0, 0,0,0,0, SIB|1,RIP|4,0,0, // 1x - 0,0,0,0, SIB|1,RIP|4,0,0, 0,0,0,0, SIB|1,RIP|4,0,0, // 2x - 0,0,0,0, SIB|1,RIP|4,0,0, 0,0,0,0, SIB|1,RIP|4,0,0, // 3x - 1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 4x - 1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 5x - 1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 6x - 1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 7x - 4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // 8x - 4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // 9x - 4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // Ax - 4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // Bx - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Cx - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Dx - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Ex - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 // Fx -}; - -const CDetourDis::COPYENTRY CDetourDis::s_rceCopyTable[257] = -{ - { 0x00, ENTRY_CopyBytes2Mod }, // ADD /r - { 0x01, ENTRY_CopyBytes2Mod }, // ADD /r - { 0x02, ENTRY_CopyBytes2Mod }, // ADD /r - { 0x03, ENTRY_CopyBytes2Mod }, // ADD /r - { 0x04, ENTRY_CopyBytes2 }, // ADD ib - { 0x05, ENTRY_CopyBytes3Or5 }, // ADD iw - { 0x06, ENTRY_CopyBytes1 }, // PUSH - { 0x07, ENTRY_CopyBytes1 }, // POP - { 0x08, ENTRY_CopyBytes2Mod }, // OR /r - { 0x09, ENTRY_CopyBytes2Mod }, // OR /r - { 0x0A, ENTRY_CopyBytes2Mod }, // OR /r - { 0x0B, ENTRY_CopyBytes2Mod }, // OR /r - { 0x0C, ENTRY_CopyBytes2 }, // OR ib - { 0x0D, ENTRY_CopyBytes3Or5 }, // OR iw - { 0x0E, ENTRY_CopyBytes1 }, // PUSH - { 0x0F, ENTRY_Copy0F }, // Extension Ops - { 0x10, ENTRY_CopyBytes2Mod }, // ADC /r - { 0x11, ENTRY_CopyBytes2Mod }, // ADC /r - { 0x12, ENTRY_CopyBytes2Mod }, // ADC /r - { 0x13, ENTRY_CopyBytes2Mod }, // ADC /r - { 0x14, ENTRY_CopyBytes2 }, // ADC ib - { 0x15, ENTRY_CopyBytes3Or5 }, // ADC id - { 0x16, ENTRY_CopyBytes1 }, // PUSH - { 0x17, ENTRY_CopyBytes1 }, // POP - { 0x18, ENTRY_CopyBytes2Mod }, // SBB /r - { 0x19, ENTRY_CopyBytes2Mod }, // SBB /r - { 0x1A, ENTRY_CopyBytes2Mod }, // SBB /r - { 0x1B, ENTRY_CopyBytes2Mod }, // SBB /r - { 0x1C, ENTRY_CopyBytes2 }, // SBB ib - { 0x1D, ENTRY_CopyBytes3Or5 }, // SBB id - { 0x1E, ENTRY_CopyBytes1 }, // PUSH - { 0x1F, ENTRY_CopyBytes1 }, // POP - { 0x20, ENTRY_CopyBytes2Mod }, // AND /r - { 0x21, ENTRY_CopyBytes2Mod }, // AND /r - { 0x22, ENTRY_CopyBytes2Mod }, // AND /r - { 0x23, ENTRY_CopyBytes2Mod }, // AND /r - { 0x24, ENTRY_CopyBytes2 }, // AND ib - { 0x25, ENTRY_CopyBytes3Or5 }, // AND id - { 0x26, ENTRY_CopyBytesPrefix }, // ES prefix - { 0x27, ENTRY_CopyBytes1 }, // DAA - { 0x28, ENTRY_CopyBytes2Mod }, // SUB /r - { 0x29, ENTRY_CopyBytes2Mod }, // SUB /r - { 0x2A, ENTRY_CopyBytes2Mod }, // SUB /r - { 0x2B, ENTRY_CopyBytes2Mod }, // SUB /r - { 0x2C, ENTRY_CopyBytes2 }, // SUB ib - { 0x2D, ENTRY_CopyBytes3Or5 }, // SUB id - { 0x2E, ENTRY_CopyBytesPrefix }, // CS prefix - { 0x2F, ENTRY_CopyBytes1 }, // DAS - { 0x30, ENTRY_CopyBytes2Mod }, // XOR /r - { 0x31, ENTRY_CopyBytes2Mod }, // XOR /r - { 0x32, ENTRY_CopyBytes2Mod }, // XOR /r - { 0x33, ENTRY_CopyBytes2Mod }, // XOR /r - { 0x34, ENTRY_CopyBytes2 }, // XOR ib - { 0x35, ENTRY_CopyBytes3Or5 }, // XOR id - { 0x36, ENTRY_CopyBytesPrefix }, // SS prefix - { 0x37, ENTRY_CopyBytes1 }, // AAA - { 0x38, ENTRY_CopyBytes2Mod }, // CMP /r - { 0x39, ENTRY_CopyBytes2Mod }, // CMP /r - { 0x3A, ENTRY_CopyBytes2Mod }, // CMP /r - { 0x3B, ENTRY_CopyBytes2Mod }, // CMP /r - { 0x3C, ENTRY_CopyBytes2 }, // CMP ib - { 0x3D, ENTRY_CopyBytes3Or5 }, // CMP id - { 0x3E, ENTRY_CopyBytesPrefix }, // DS prefix - { 0x3F, ENTRY_CopyBytes1 }, // AAS -#ifdef DETOURS_X64 // For Rax Prefix -#error Feature not supported in this release. - - - - - - - - - - - - - - - -#else - { 0x40, ENTRY_CopyBytes1 }, // INC - { 0x41, ENTRY_CopyBytes1 }, // INC - { 0x42, ENTRY_CopyBytes1 }, // INC - { 0x43, ENTRY_CopyBytes1 }, // INC - { 0x44, ENTRY_CopyBytes1 }, // INC - { 0x45, ENTRY_CopyBytes1 }, // INC - { 0x46, ENTRY_CopyBytes1 }, // INC - { 0x47, ENTRY_CopyBytes1 }, // INC - { 0x48, ENTRY_CopyBytes1 }, // DEC - { 0x49, ENTRY_CopyBytes1 }, // DEC - { 0x4A, ENTRY_CopyBytes1 }, // DEC - { 0x4B, ENTRY_CopyBytes1 }, // DEC - { 0x4C, ENTRY_CopyBytes1 }, // DEC - { 0x4D, ENTRY_CopyBytes1 }, // DEC - { 0x4E, ENTRY_CopyBytes1 }, // DEC - { 0x4F, ENTRY_CopyBytes1 }, // DEC -#endif - { 0x50, ENTRY_CopyBytes1 }, // PUSH - { 0x51, ENTRY_CopyBytes1 }, // PUSH - { 0x52, ENTRY_CopyBytes1 }, // PUSH - { 0x53, ENTRY_CopyBytes1 }, // PUSH - { 0x54, ENTRY_CopyBytes1 }, // PUSH - { 0x55, ENTRY_CopyBytes1 }, // PUSH - { 0x56, ENTRY_CopyBytes1 }, // PUSH - { 0x57, ENTRY_CopyBytes1 }, // PUSH - { 0x58, ENTRY_CopyBytes1 }, // POP - { 0x59, ENTRY_CopyBytes1 }, // POP - { 0x5A, ENTRY_CopyBytes1 }, // POP - { 0x5B, ENTRY_CopyBytes1 }, // POP - { 0x5C, ENTRY_CopyBytes1 }, // POP - { 0x5D, ENTRY_CopyBytes1 }, // POP - { 0x5E, ENTRY_CopyBytes1 }, // POP - { 0x5F, ENTRY_CopyBytes1 }, // POP - { 0x60, ENTRY_CopyBytes1 }, // PUSHAD - { 0x61, ENTRY_CopyBytes1 }, // POPAD - { 0x62, ENTRY_CopyBytes2Mod }, // BOUND /r - { 0x63, ENTRY_CopyBytes2Mod }, // ARPL /r - { 0x64, ENTRY_CopyBytesPrefix }, // FS prefix - { 0x65, ENTRY_CopyBytesPrefix }, // GS prefix - { 0x66, ENTRY_Copy66 }, // Operand Prefix - { 0x67, ENTRY_Copy67 }, // Address Prefix - { 0x68, ENTRY_CopyBytes3Or5 }, // PUSH - { 0x69, ENTRY_CopyBytes2ModOperand }, // - { 0x6A, ENTRY_CopyBytes2 }, // PUSH - { 0x6B, ENTRY_CopyBytes2Mod1 }, // IMUL /r ib - { 0x6C, ENTRY_CopyBytes1 }, // INS - { 0x6D, ENTRY_CopyBytes1 }, // INS - { 0x6E, ENTRY_CopyBytes1 }, // OUTS/OUTSB - { 0x6F, ENTRY_CopyBytes1 }, // OUTS/OUTSW - { 0x70, ENTRY_CopyBytes2Jump }, // JO - { 0x71, ENTRY_CopyBytes2Jump }, // JNO - { 0x72, ENTRY_CopyBytes2Jump }, // JB/JC/JNAE - { 0x73, ENTRY_CopyBytes2Jump }, // JAE/JNB/JNC - { 0x74, ENTRY_CopyBytes2Jump }, // JE/JZ - { 0x75, ENTRY_CopyBytes2Jump }, // JNE/JNZ - { 0x76, ENTRY_CopyBytes2Jump }, // JBE/JNA - { 0x77, ENTRY_CopyBytes2Jump }, // JA/JNBE - { 0x78, ENTRY_CopyBytes2Jump }, // JS - { 0x79, ENTRY_CopyBytes2Jump }, // JNS - { 0x7A, ENTRY_CopyBytes2Jump }, // JP/JPE - { 0x7B, ENTRY_CopyBytes2Jump }, // JNP/JPO - { 0x7C, ENTRY_CopyBytes2Jump }, // JL/JNGE - { 0x7D, ENTRY_CopyBytes2Jump }, // JGE/JNL - { 0x7E, ENTRY_CopyBytes2Jump }, // JLE/JNG - { 0x7F, ENTRY_CopyBytes2Jump }, // JG/JNLE - { 0x80, ENTRY_CopyBytes2Mod1 }, // ADC/2 ib, etc.s - { 0x81, ENTRY_CopyBytes2ModOperand }, // - { 0x82, ENTRY_CopyBytes2 }, // MOV al,x - { 0x83, ENTRY_CopyBytes2Mod1 }, // ADC/2 ib, etc. - { 0x84, ENTRY_CopyBytes2Mod }, // TEST /r - { 0x85, ENTRY_CopyBytes2Mod }, // TEST /r - { 0x86, ENTRY_CopyBytes2Mod }, // XCHG /r @todo - { 0x87, ENTRY_CopyBytes2Mod }, // XCHG /r @todo - { 0x88, ENTRY_CopyBytes2Mod }, // MOV /r - { 0x89, ENTRY_CopyBytes2Mod }, // MOV /r - { 0x8A, ENTRY_CopyBytes2Mod }, // MOV /r - { 0x8B, ENTRY_CopyBytes2Mod }, // MOV /r - { 0x8C, ENTRY_CopyBytes2Mod }, // MOV /r - { 0x8D, ENTRY_CopyBytes2Mod }, // LEA /r - { 0x8E, ENTRY_CopyBytes2Mod }, // MOV /r - { 0x8F, ENTRY_CopyBytes2Mod }, // POP /0 - { 0x90, ENTRY_CopyBytes1 }, // NOP - { 0x91, ENTRY_CopyBytes1 }, // XCHG - { 0x92, ENTRY_CopyBytes1 }, // XCHG - { 0x93, ENTRY_CopyBytes1 }, // XCHG - { 0x94, ENTRY_CopyBytes1 }, // XCHG - { 0x95, ENTRY_CopyBytes1 }, // XCHG - { 0x96, ENTRY_CopyBytes1 }, // XCHG - { 0x97, ENTRY_CopyBytes1 }, // XCHG - { 0x98, ENTRY_CopyBytes1 }, // CWDE - { 0x99, ENTRY_CopyBytes1 }, // CDQ - { 0x9A, ENTRY_CopyBytes5Or7Dynamic }, // CALL cp - { 0x9B, ENTRY_CopyBytes1 }, // WAIT/FWAIT - { 0x9C, ENTRY_CopyBytes1 }, // PUSHFD - { 0x9D, ENTRY_CopyBytes1 }, // POPFD - { 0x9E, ENTRY_CopyBytes1 }, // SAHF - { 0x9F, ENTRY_CopyBytes1 }, // LAHF - { 0xA0, ENTRY_CopyBytes3Or5Address }, // MOV - { 0xA1, ENTRY_CopyBytes3Or5Address }, // MOV - { 0xA2, ENTRY_CopyBytes3Or5Address }, // MOV - { 0xA3, ENTRY_CopyBytes3Or5Address }, // MOV - { 0xA4, ENTRY_CopyBytes1 }, // MOVS - { 0xA5, ENTRY_CopyBytes1 }, // MOVS/MOVSD - { 0xA6, ENTRY_CopyBytes1 }, // CMPS/CMPSB - { 0xA7, ENTRY_CopyBytes1 }, // CMPS/CMPSW - { 0xA8, ENTRY_CopyBytes2 }, // TEST - { 0xA9, ENTRY_CopyBytes3Or5 }, // TEST - { 0xAA, ENTRY_CopyBytes1 }, // STOS/STOSB - { 0xAB, ENTRY_CopyBytes1 }, // STOS/STOSW - { 0xAC, ENTRY_CopyBytes1 }, // LODS/LODSB - { 0xAD, ENTRY_CopyBytes1 }, // LODS/LODSW - { 0xAE, ENTRY_CopyBytes1 }, // SCAS/SCASB - { 0xAF, ENTRY_CopyBytes1 }, // SCAS/SCASD - { 0xB0, ENTRY_CopyBytes2 }, // MOV B0+rb - { 0xB1, ENTRY_CopyBytes2 }, // MOV B0+rb - { 0xB2, ENTRY_CopyBytes2 }, // MOV B0+rb - { 0xB3, ENTRY_CopyBytes2 }, // MOV B0+rb - { 0xB4, ENTRY_CopyBytes2 }, // MOV B0+rb - { 0xB5, ENTRY_CopyBytes2 }, // MOV B0+rb - { 0xB6, ENTRY_CopyBytes2 }, // MOV B0+rb - { 0xB7, ENTRY_CopyBytes2 }, // MOV B0+rb - { 0xB8, ENTRY_CopyBytes3Or5Rax }, // MOV B8+rb - { 0xB9, ENTRY_CopyBytes3Or5 }, // MOV B8+rb - { 0xBA, ENTRY_CopyBytes3Or5 }, // MOV B8+rb - { 0xBB, ENTRY_CopyBytes3Or5 }, // MOV B8+rb - { 0xBC, ENTRY_CopyBytes3Or5 }, // MOV B8+rb - { 0xBD, ENTRY_CopyBytes3Or5 }, // MOV B8+rb - { 0xBE, ENTRY_CopyBytes3Or5 }, // MOV B8+rb - { 0xBF, ENTRY_CopyBytes3Or5 }, // MOV B8+rb - { 0xC0, ENTRY_CopyBytes2Mod1 }, // RCL/2 ib, etc. - { 0xC1, ENTRY_CopyBytes2Mod1 }, // RCL/2 ib, etc. - { 0xC2, ENTRY_CopyBytes3 }, // RET - { 0xC3, ENTRY_CopyBytes1 }, // RET - { 0xC4, ENTRY_CopyBytes2Mod }, // LES - { 0xC5, ENTRY_CopyBytes2Mod }, // LDS - { 0xC6, ENTRY_CopyBytes2Mod1 }, // MOV - { 0xC7, ENTRY_CopyBytes2ModOperand }, // MOV - { 0xC8, ENTRY_CopyBytes4 }, // ENTER - { 0xC9, ENTRY_CopyBytes1 }, // LEAVE - { 0xCA, ENTRY_CopyBytes3Dynamic }, // RET - { 0xCB, ENTRY_CopyBytes1Dynamic }, // RET - { 0xCC, ENTRY_CopyBytes1Dynamic }, // INT 3 - { 0xCD, ENTRY_CopyBytes2Dynamic }, // INT ib - { 0xCE, ENTRY_CopyBytes1Dynamic }, // INTO - { 0xCF, ENTRY_CopyBytes1Dynamic }, // IRET - { 0xD0, ENTRY_CopyBytes2Mod }, // RCL/2, etc. - { 0xD1, ENTRY_CopyBytes2Mod }, // RCL/2, etc. - { 0xD2, ENTRY_CopyBytes2Mod }, // RCL/2, etc. - { 0xD3, ENTRY_CopyBytes2Mod }, // RCL/2, etc. - { 0xD4, ENTRY_CopyBytes2 }, // AAM - { 0xD5, ENTRY_CopyBytes2 }, // AAD - { 0xD6, ENTRY_Invalid }, // - { 0xD7, ENTRY_CopyBytes1 }, // XLAT/XLATB - { 0xD8, ENTRY_CopyBytes2Mod }, // FADD, etc. - { 0xD9, ENTRY_CopyBytes2Mod }, // F2XM1, etc. - { 0xDA, ENTRY_CopyBytes2Mod }, // FLADD, etc. - { 0xDB, ENTRY_CopyBytes2Mod }, // FCLEX, etc. - { 0xDC, ENTRY_CopyBytes2Mod }, // FADD/0, etc. - { 0xDD, ENTRY_CopyBytes2Mod }, // FFREE, etc. - { 0xDE, ENTRY_CopyBytes2Mod }, // FADDP, etc. - { 0xDF, ENTRY_CopyBytes2Mod }, // FBLD/4, etc. - { 0xE0, ENTRY_CopyBytes2CantJump }, // LOOPNE cb - { 0xE1, ENTRY_CopyBytes2CantJump }, // LOOPE cb - { 0xE2, ENTRY_CopyBytes2CantJump }, // LOOP cb - { 0xE3, ENTRY_CopyBytes2Jump }, // JCXZ/JECXZ - { 0xE4, ENTRY_CopyBytes2 }, // IN ib - { 0xE5, ENTRY_CopyBytes2 }, // IN id - { 0xE6, ENTRY_CopyBytes2 }, // OUT ib - { 0xE7, ENTRY_CopyBytes2 }, // OUT ib - { 0xE8, ENTRY_CopyBytes3Or5Target }, // CALL cd - { 0xE9, ENTRY_CopyBytes3Or5Target }, // JMP cd - { 0xEA, ENTRY_CopyBytes5Or7Dynamic }, // JMP cp - { 0xEB, ENTRY_CopyBytes2Jump }, // JMP cb - { 0xEC, ENTRY_CopyBytes1 }, // IN ib - { 0xED, ENTRY_CopyBytes1 }, // IN id - { 0xEE, ENTRY_CopyBytes1 }, // OUT - { 0xEF, ENTRY_CopyBytes1 }, // OUT - { 0xF0, ENTRY_CopyBytesPrefix }, // LOCK prefix - { 0xF1, ENTRY_Invalid }, // - { 0xF2, ENTRY_CopyBytesPrefix }, // REPNE prefix - { 0xF3, ENTRY_CopyBytesPrefix }, // REPE prefix - { 0xF4, ENTRY_CopyBytes1 }, // HLT - { 0xF5, ENTRY_CopyBytes1 }, // CMC - { 0xF6, ENTRY_CopyF6 }, // TEST/0, DIV/6 - { 0xF7, ENTRY_CopyF7 }, // TEST/0, DIV/6 - { 0xF8, ENTRY_CopyBytes1 }, // CLC - { 0xF9, ENTRY_CopyBytes1 }, // STC - { 0xFA, ENTRY_CopyBytes1 }, // CLI - { 0xFB, ENTRY_CopyBytes1 }, // STI - { 0xFC, ENTRY_CopyBytes1 }, // CLD - { 0xFD, ENTRY_CopyBytes1 }, // STD - { 0xFE, ENTRY_CopyBytes2Mod }, // DEC/1,INC/0 - { 0xFF, ENTRY_CopyFF }, // CALL/2 - { 0, ENTRY_End }, -}; - -const CDetourDis::COPYENTRY CDetourDis::s_rceCopyTable0F[257] = -{ - { 0x00, ENTRY_CopyBytes2Mod }, // LLDT/2, etc. - { 0x01, ENTRY_CopyBytes2Mod }, // INVLPG/7, etc. - { 0x02, ENTRY_CopyBytes2Mod }, // LAR/r - { 0x03, ENTRY_CopyBytes2Mod }, // LSL/r - { 0x04, ENTRY_Invalid }, // _04 - { 0x05, ENTRY_Invalid }, // _05 - { 0x06, ENTRY_CopyBytes2 }, // CLTS - { 0x07, ENTRY_Invalid }, // _07 - { 0x08, ENTRY_CopyBytes2 }, // INVD - { 0x09, ENTRY_CopyBytes2 }, // WBINVD - { 0x0A, ENTRY_Invalid }, // _0A - { 0x0B, ENTRY_CopyBytes2 }, // UD2 - { 0x0C, ENTRY_Invalid }, // _0C - { 0x0D, ENTRY_CopyBytes2Mod }, // PREFETCH - { 0x0E, ENTRY_CopyBytes2 }, // FEMMS - { 0x0F, ENTRY_CopyBytes3Mod }, // 3DNow Opcodes - { 0x10, ENTRY_CopyBytes2Mod }, // MOVSS MOVUPD MOVSD - { 0x11, ENTRY_CopyBytes2Mod }, // MOVSS MOVUPD MOVSD - { 0x12, ENTRY_CopyBytes2Mod }, // MOVLPD - { 0x13, ENTRY_CopyBytes2Mod }, // MOVLPD - { 0x14, ENTRY_CopyBytes2Mod }, // UNPCKLPD - { 0x15, ENTRY_CopyBytes2Mod }, // UNPCKHPD - { 0x16, ENTRY_CopyBytes2Mod }, // MOVHPD - { 0x17, ENTRY_CopyBytes2Mod }, // MOVHPD - { 0x18, ENTRY_CopyBytes2Mod }, // PREFETCHINTA... - { 0x19, ENTRY_Invalid }, // _19 - { 0x1A, ENTRY_Invalid }, // _1A - { 0x1B, ENTRY_Invalid }, // _1B - { 0x1C, ENTRY_Invalid }, // _1C - { 0x1D, ENTRY_Invalid }, // _1D - { 0x1E, ENTRY_Invalid }, // _1E - { 0x1F, ENTRY_Invalid }, // _1F - { 0x20, ENTRY_CopyBytes2Mod }, // MOV/r - { 0x21, ENTRY_CopyBytes2Mod }, // MOV/r - { 0x22, ENTRY_CopyBytes2Mod }, // MOV/r - { 0x23, ENTRY_CopyBytes2Mod }, // MOV/r - { 0x24, ENTRY_Invalid }, // _24 - { 0x25, ENTRY_Invalid }, // _25 - { 0x26, ENTRY_Invalid }, // _26 - { 0x27, ENTRY_Invalid }, // _27 - { 0x28, ENTRY_CopyBytes2Mod }, // MOVAPS MOVAPD - { 0x29, ENTRY_CopyBytes2Mod }, // MOVAPS MOVAPD - { 0x2A, ENTRY_CopyBytes2Mod }, // CVPI2PS & - { 0x2B, ENTRY_CopyBytes2Mod }, // MOVNTPS MOVNTPD - { 0x2C, ENTRY_CopyBytes2Mod }, // CVTTPS2PI & - { 0x2D, ENTRY_CopyBytes2Mod }, // CVTPS2PI & - { 0x2E, ENTRY_CopyBytes2Mod }, // UCOMISS UCOMISD - { 0x2F, ENTRY_CopyBytes2Mod }, // COMISS COMISD - { 0x30, ENTRY_CopyBytes2 }, // WRMSR - { 0x31, ENTRY_CopyBytes2 }, // RDTSC - { 0x32, ENTRY_CopyBytes2 }, // RDMSR - { 0x33, ENTRY_CopyBytes2 }, // RDPMC - { 0x34, ENTRY_CopyBytes2 }, // SYSENTER - { 0x35, ENTRY_CopyBytes2 }, // SYSEXIT - { 0x36, ENTRY_Invalid }, // _36 - { 0x37, ENTRY_Invalid }, // _37 - { 0x38, ENTRY_Invalid }, // _38 - { 0x39, ENTRY_Invalid }, // _39 - { 0x3A, ENTRY_Invalid }, // _3A - { 0x3B, ENTRY_Invalid }, // _3B - { 0x3C, ENTRY_Invalid }, // _3C - { 0x3D, ENTRY_Invalid }, // _3D - { 0x3E, ENTRY_Invalid }, // _3E - { 0x3F, ENTRY_Invalid }, // _3F - { 0x40, ENTRY_CopyBytes2Mod }, // CMOVO (0F 40) - { 0x41, ENTRY_CopyBytes2Mod }, // CMOVNO (0F 41) - { 0x42, ENTRY_CopyBytes2Mod }, // CMOVB & CMOVNE (0F 42) - { 0x43, ENTRY_CopyBytes2Mod }, // CMOVAE & CMOVNB (0F 43) - { 0x44, ENTRY_CopyBytes2Mod }, // CMOVE & CMOVZ (0F 44) - { 0x45, ENTRY_CopyBytes2Mod }, // CMOVNE & CMOVNZ (0F 45) - { 0x46, ENTRY_CopyBytes2Mod }, // CMOVBE & CMOVNA (0F 46) - { 0x47, ENTRY_CopyBytes2Mod }, // CMOVA & CMOVNBE (0F 47) - { 0x48, ENTRY_CopyBytes2Mod }, // CMOVS (0F 48) - { 0x49, ENTRY_CopyBytes2Mod }, // CMOVNS (0F 49) - { 0x4A, ENTRY_CopyBytes2Mod }, // CMOVP & CMOVPE (0F 4A) - { 0x4B, ENTRY_CopyBytes2Mod }, // CMOVNP & CMOVPO (0F 4B) - { 0x4C, ENTRY_CopyBytes2Mod }, // CMOVL & CMOVNGE (0F 4C) - { 0x4D, ENTRY_CopyBytes2Mod }, // CMOVGE & CMOVNL (0F 4D) - { 0x4E, ENTRY_CopyBytes2Mod }, // CMOVLE & CMOVNG (0F 4E) - { 0x4F, ENTRY_CopyBytes2Mod }, // CMOVG & CMOVNLE (0F 4F) - { 0x50, ENTRY_CopyBytes2Mod }, // MOVMSKPD MOVMSKPD - { 0x51, ENTRY_CopyBytes2Mod }, // SQRTPS & - { 0x52, ENTRY_CopyBytes2Mod }, // RSQRTTS RSQRTPS - { 0x53, ENTRY_CopyBytes2Mod }, // RCPPS RCPSS - { 0x54, ENTRY_CopyBytes2Mod }, // ANDPS ANDPD - { 0x55, ENTRY_CopyBytes2Mod }, // ANDNPS ANDNPD - { 0x56, ENTRY_CopyBytes2Mod }, // ORPS ORPD - { 0x57, ENTRY_CopyBytes2Mod }, // XORPS XORPD - { 0x58, ENTRY_CopyBytes2Mod }, // ADDPS & - { 0x59, ENTRY_CopyBytes2Mod }, // MULPS & - { 0x5A, ENTRY_CopyBytes2Mod }, // CVTPS2PD & - { 0x5B, ENTRY_CopyBytes2Mod }, // CVTDQ2PS & - { 0x5C, ENTRY_CopyBytes2Mod }, // SUBPS & - { 0x5D, ENTRY_CopyBytes2Mod }, // MINPS & - { 0x5E, ENTRY_CopyBytes2Mod }, // DIVPS & - { 0x5F, ENTRY_CopyBytes2Mod }, // MASPS & - { 0x60, ENTRY_CopyBytes2Mod }, // PUNPCKLBW/r - { 0x61, ENTRY_CopyBytes2Mod }, // PUNPCKLWD/r - { 0x62, ENTRY_CopyBytes2Mod }, // PUNPCKLWD/r - { 0x63, ENTRY_CopyBytes2Mod }, // PACKSSWB/r - { 0x64, ENTRY_CopyBytes2Mod }, // PCMPGTB/r - { 0x65, ENTRY_CopyBytes2Mod }, // PCMPGTW/r - { 0x66, ENTRY_CopyBytes2Mod }, // PCMPGTD/r - { 0x67, ENTRY_CopyBytes2Mod }, // PACKUSWB/r - { 0x68, ENTRY_CopyBytes2Mod }, // PUNPCKHBW/r - { 0x69, ENTRY_CopyBytes2Mod }, // PUNPCKHWD/r - { 0x6A, ENTRY_CopyBytes2Mod }, // PUNPCKHDQ/r - { 0x6B, ENTRY_CopyBytes2Mod }, // PACKSSDW/r - { 0x6C, ENTRY_CopyBytes2Mod }, // PUNPCKLQDQ - { 0x6D, ENTRY_CopyBytes2Mod }, // PUNPCKHQDQ - { 0x6E, ENTRY_CopyBytes2Mod }, // MOVD/r - { 0x6F, ENTRY_CopyBytes2Mod }, // MOV/r - { 0x70, ENTRY_CopyBytes2Mod1 }, // PSHUFW/r ib - { 0x71, ENTRY_CopyBytes2Mod1 }, // PSLLW/6 ib,PSRAW/4 ib,PSRLW/2 ib - { 0x72, ENTRY_CopyBytes2Mod1 }, // PSLLD/6 ib,PSRAD/4 ib,PSRLD/2 ib - { 0x73, ENTRY_CopyBytes2Mod1 }, // PSLLQ/6 ib,PSRLQ/2 ib - { 0x74, ENTRY_CopyBytes2Mod }, // PCMPEQB/r - { 0x75, ENTRY_CopyBytes2Mod }, // PCMPEQW/r - { 0x76, ENTRY_CopyBytes2Mod }, // PCMPEQD/r - { 0x77, ENTRY_CopyBytes2 }, // EMMS - { 0x78, ENTRY_Invalid }, // _78 - { 0x79, ENTRY_Invalid }, // _79 - { 0x7A, ENTRY_Invalid }, // _7A - { 0x7B, ENTRY_Invalid }, // _7B - { 0x7C, ENTRY_Invalid }, // _7C - { 0x7D, ENTRY_Invalid }, // _7D - { 0x7E, ENTRY_CopyBytes2Mod }, // MOVD/r - { 0x7F, ENTRY_CopyBytes2Mod }, // MOV/r - { 0x80, ENTRY_CopyBytes3Or5Target }, // JO - { 0x81, ENTRY_CopyBytes3Or5Target }, // JNO - { 0x82, ENTRY_CopyBytes3Or5Target }, // JB,JC,JNAE - { 0x83, ENTRY_CopyBytes3Or5Target }, // JAE,JNB,JNC - { 0x84, ENTRY_CopyBytes3Or5Target }, // JE,JZ,JZ - { 0x85, ENTRY_CopyBytes3Or5Target }, // JNE,JNZ - { 0x86, ENTRY_CopyBytes3Or5Target }, // JBE,JNA - { 0x87, ENTRY_CopyBytes3Or5Target }, // JA,JNBE - { 0x88, ENTRY_CopyBytes3Or5Target }, // JS - { 0x89, ENTRY_CopyBytes3Or5Target }, // JNS - { 0x8A, ENTRY_CopyBytes3Or5Target }, // JP,JPE - { 0x8B, ENTRY_CopyBytes3Or5Target }, // JNP,JPO - { 0x8C, ENTRY_CopyBytes3Or5Target }, // JL,NGE - { 0x8D, ENTRY_CopyBytes3Or5Target }, // JGE,JNL - { 0x8E, ENTRY_CopyBytes3Or5Target }, // JLE,JNG - { 0x8F, ENTRY_CopyBytes3Or5Target }, // JG,JNLE - { 0x90, ENTRY_CopyBytes2Mod }, // CMOVO (0F 40) - { 0x91, ENTRY_CopyBytes2Mod }, // CMOVNO (0F 41) - { 0x92, ENTRY_CopyBytes2Mod }, // CMOVB & CMOVC & CMOVNAE (0F 42) - { 0x93, ENTRY_CopyBytes2Mod }, // CMOVAE & CMOVNB & CMOVNC (0F 43) - { 0x94, ENTRY_CopyBytes2Mod }, // CMOVE & CMOVZ (0F 44) - { 0x95, ENTRY_CopyBytes2Mod }, // CMOVNE & CMOVNZ (0F 45) - { 0x96, ENTRY_CopyBytes2Mod }, // CMOVBE & CMOVNA (0F 46) - { 0x97, ENTRY_CopyBytes2Mod }, // CMOVA & CMOVNBE (0F 47) - { 0x98, ENTRY_CopyBytes2Mod }, // CMOVS (0F 48) - { 0x99, ENTRY_CopyBytes2Mod }, // CMOVNS (0F 49) - { 0x9A, ENTRY_CopyBytes2Mod }, // CMOVP & CMOVPE (0F 4A) - { 0x9B, ENTRY_CopyBytes2Mod }, // CMOVNP & CMOVPO (0F 4B) - { 0x9C, ENTRY_CopyBytes2Mod }, // CMOVL & CMOVNGE (0F 4C) - { 0x9D, ENTRY_CopyBytes2Mod }, // CMOVGE & CMOVNL (0F 4D) - { 0x9E, ENTRY_CopyBytes2Mod }, // CMOVLE & CMOVNG (0F 4E) - { 0x9F, ENTRY_CopyBytes2Mod }, // CMOVG & CMOVNLE (0F 4F) - { 0xA0, ENTRY_CopyBytes2 }, // PUSH - { 0xA1, ENTRY_CopyBytes2 }, // POP - { 0xA2, ENTRY_CopyBytes2 }, // CPUID - { 0xA3, ENTRY_CopyBytes2Mod }, // BT (0F A3) - { 0xA4, ENTRY_CopyBytes2Mod1 }, // SHLD - { 0xA5, ENTRY_CopyBytes2Mod }, // SHLD - { 0xA6, ENTRY_Invalid }, // _A6 - { 0xA7, ENTRY_Invalid }, // _A7 - { 0xA8, ENTRY_CopyBytes2 }, // PUSH - { 0xA9, ENTRY_CopyBytes2 }, // POP - { 0xAA, ENTRY_CopyBytes2 }, // RSM - { 0xAB, ENTRY_CopyBytes2Mod }, // BTS (0F AB) - { 0xAC, ENTRY_CopyBytes2Mod1 }, // SHRD - { 0xAD, ENTRY_CopyBytes2Mod }, // SHRD - { 0xAE, ENTRY_CopyBytes2Mod }, // FXRSTOR/1,FXSAVE/0 - { 0xAF, ENTRY_CopyBytes2Mod }, // IMUL (0F AF) - { 0xB0, ENTRY_CopyBytes2Mod }, // CMPXCHG (0F B0) - { 0xB1, ENTRY_CopyBytes2Mod }, // CMPXCHG (0F B1) - { 0xB2, ENTRY_CopyBytes2Mod }, // LSS/r - { 0xB3, ENTRY_CopyBytes2Mod }, // BTR (0F B3) - { 0xB4, ENTRY_CopyBytes2Mod }, // LFS/r - { 0xB5, ENTRY_CopyBytes2Mod }, // LGS/r - { 0xB6, ENTRY_CopyBytes2Mod }, // MOVZX/r - { 0xB7, ENTRY_CopyBytes2Mod }, // MOVZX/r - { 0xB8, ENTRY_Invalid }, // _B8 - { 0xB9, ENTRY_Invalid }, // _B9 - { 0xBA, ENTRY_CopyBytes2Mod1 }, // BT & BTC & BTR & BTS (0F BA) - { 0xBB, ENTRY_CopyBytes2Mod }, // BTC (0F BB) - { 0xBC, ENTRY_CopyBytes2Mod }, // BSF (0F BC) - { 0xBD, ENTRY_CopyBytes2Mod }, // BSR (0F BD) - { 0xBE, ENTRY_CopyBytes2Mod }, // MOVSX/r - { 0xBF, ENTRY_CopyBytes2Mod }, // MOVSX/r - { 0xC0, ENTRY_CopyBytes2Mod }, // XADD/r - { 0xC1, ENTRY_CopyBytes2Mod }, // XADD/r - { 0xC2, ENTRY_CopyBytes2Mod }, // CMPPS & - { 0xC3, ENTRY_CopyBytes2Mod }, // MOVNTI - { 0xC4, ENTRY_CopyBytes2Mod1 }, // PINSRW /r ib - { 0xC5, ENTRY_CopyBytes2Mod1 }, // PEXTRW /r ib - { 0xC6, ENTRY_CopyBytes2Mod1 }, // SHUFPS & SHUFPD - { 0xC7, ENTRY_CopyBytes2Mod }, // CMPXCHG8B (0F C7) - { 0xC8, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd - { 0xC9, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd - { 0xCA, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd - { 0xCB, ENTRY_CopyBytes2 }, //CVTPD2PI BSWAP 0F C8 + rd - { 0xCC, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd - { 0xCD, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd - { 0xCE, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd - { 0xCF, ENTRY_CopyBytes2 }, // BSWAP 0F C8 + rd - { 0xD0, ENTRY_Invalid }, // _D0 - { 0xD1, ENTRY_CopyBytes2Mod }, // PSRLW/r - { 0xD2, ENTRY_CopyBytes2Mod }, // PSRLD/r - { 0xD3, ENTRY_CopyBytes2Mod }, // PSRLQ/r - { 0xD4, ENTRY_CopyBytes2Mod }, // PADDQ - { 0xD5, ENTRY_CopyBytes2Mod }, // PMULLW/r - { 0xD6, ENTRY_CopyBytes2Mod }, // MOVDQ2Q / MOVQ2DQ - { 0xD7, ENTRY_CopyBytes2Mod }, // PMOVMSKB/r - { 0xD8, ENTRY_CopyBytes2Mod }, // PSUBUSB/r - { 0xD9, ENTRY_CopyBytes2Mod }, // PSUBUSW/r - { 0xDA, ENTRY_CopyBytes2Mod }, // PMINUB/r - { 0xDB, ENTRY_CopyBytes2Mod }, // PAND/r - { 0xDC, ENTRY_CopyBytes2Mod }, // PADDUSB/r - { 0xDD, ENTRY_CopyBytes2Mod }, // PADDUSW/r - { 0xDE, ENTRY_CopyBytes2Mod }, // PMAXUB/r - { 0xDF, ENTRY_CopyBytes2Mod }, // PANDN/r - { 0xE0, ENTRY_CopyBytes2Mod }, // PAVGB - { 0xE1, ENTRY_CopyBytes2Mod }, // PSRAW/r - { 0xE2, ENTRY_CopyBytes2Mod }, // PSRAD/r - { 0xE3, ENTRY_CopyBytes2Mod }, // PAVGW - { 0xE4, ENTRY_CopyBytes2Mod }, // PMULHUW/r - { 0xE5, ENTRY_CopyBytes2Mod }, // PMULHW/r - { 0xE6, ENTRY_CopyBytes2Mod }, // CTDQ2PD & - { 0xE7, ENTRY_CopyBytes2Mod }, // MOVNTQ - { 0xE8, ENTRY_CopyBytes2Mod }, // PSUBB/r - { 0xE9, ENTRY_CopyBytes2Mod }, // PSUBW/r - { 0xEA, ENTRY_CopyBytes2Mod }, // PMINSW/r - { 0xEB, ENTRY_CopyBytes2Mod }, // POR/r - { 0xEC, ENTRY_CopyBytes2Mod }, // PADDSB/r - { 0xED, ENTRY_CopyBytes2Mod }, // PADDSW/r - { 0xEE, ENTRY_CopyBytes2Mod }, // PMAXSW /r - { 0xEF, ENTRY_CopyBytes2Mod }, // PXOR/r - { 0xF0, ENTRY_Invalid }, // _F0 - { 0xF1, ENTRY_CopyBytes2Mod }, // PSLLW/r - { 0xF2, ENTRY_CopyBytes2Mod }, // PSLLD/r - { 0xF3, ENTRY_CopyBytes2Mod }, // PSLLQ/r - { 0xF4, ENTRY_CopyBytes2Mod }, // PMULUDQ/r - { 0xF5, ENTRY_CopyBytes2Mod }, // PMADDWD/r - { 0xF6, ENTRY_CopyBytes2Mod }, // PSADBW/r - { 0xF7, ENTRY_CopyBytes2Mod }, // MASKMOVQ - { 0xF8, ENTRY_CopyBytes2Mod }, // PSUBB/r - { 0xF9, ENTRY_CopyBytes2Mod }, // PSUBW/r - { 0xFA, ENTRY_CopyBytes2Mod }, // PSUBD/r - { 0xFB, ENTRY_CopyBytes2Mod }, // FSUBQ/r - { 0xFC, ENTRY_CopyBytes2Mod }, // PADDB/r - { 0xFD, ENTRY_CopyBytes2Mod }, // PADDW/r - { 0xFE, ENTRY_CopyBytes2Mod }, // PADDD/r - { 0xFF, ENTRY_Invalid }, // _FF - { 0, ENTRY_End }, -}; - -BOOL CDetourDis::SanityCheckSystem() -{ - ULONG n = 0; - for (; n < 256; n++) { - REFCOPYENTRY pEntry = &s_rceCopyTable[n]; - - if (n != pEntry->nOpcode) { - ASSERT(n == pEntry->nOpcode); - return FALSE; - } - } - if (s_rceCopyTable[256].pfCopy != NULL) { - ASSERT(!"Missing end marker."); - return FALSE; - } - - for (n = 0; n < 256; n++) { - REFCOPYENTRY pEntry = &s_rceCopyTable0F[n]; - - if (n != pEntry->nOpcode) { - ASSERT(n == pEntry->nOpcode); - return FALSE; - } - } - if (s_rceCopyTable0F[256].pfCopy != NULL) { - ASSERT(!"Missing end marker."); - return FALSE; - } - - return TRUE; -} -#endif // defined(DETOURS_X64) || defined(DETOURS_X86) - -/////////////////////////////////////////////////////////// IA64 Disassembler. -// -#ifdef DETOURS_IA64 -#error Feature not supported in this release. -#endif // DETOURS_IA64 - -// -///////////////////////////////////////////////////////////////// End of File. diff --git a/source/lib/sysdep/win/wcpu.cpp b/source/lib/sysdep/win/wcpu.cpp index 73aae76c98..bf9e0d4eeb 100644 --- a/source/lib/sysdep/win/wcpu.cpp +++ b/source/lib/sysdep/win/wcpu.cpp @@ -17,11 +17,7 @@ #include "wutil.h" #include "winit.h" -#pragma SECTION_INIT(2) // early; whrt depends on us -WINIT_REGISTER_FUNC(wcpu_Init); -#pragma FORCE_INCLUDE(wcpu_Init) -#pragma SECTION_RESTORE - +WINIT_REGISTER_INIT_EARLY(wcpu_Init); // wcpu -> whrt static uint numProcessors = 0; diff --git a/source/lib/sysdep/win/wdbg.cpp b/source/lib/sysdep/win/wdbg.cpp index aa43aae739..1d1718d7a6 100644 --- a/source/lib/sysdep/win/wdbg.cpp +++ b/source/lib/sysdep/win/wdbg.cpp @@ -25,16 +25,11 @@ #include "winit.h" #include "wutil.h" - -#pragma SECTION_INIT(5) -WINIT_REGISTER_FUNC(wdbg_init); -#pragma FORCE_INCLUDE(wdbg_init) -#pragma SECTION_RESTORE - +WINIT_REGISTER_INIT_MAIN(wdbg_Init); // used to prevent the vectored exception handler from taking charge when // an exception is raised from the main thread (allows __try blocks to -// get control). latched in wdbg_init. +// get control). latched in wdbg_Init. static DWORD main_thread_id; @@ -710,7 +705,7 @@ static LONG WINAPI vectored_exception_handler(EXCEPTION_POINTERS* ep) } -static LibError wdbg_init(void) +static LibError wdbg_Init(void) { // see decl main_thread_id = GetCurrentThreadId(); diff --git a/source/lib/sysdep/win/wdbg_sym.cpp b/source/lib/sysdep/win/wdbg_sym.cpp index 4e088bffbd..228065cd48 100644 --- a/source/lib/sysdep/win/wdbg_sym.cpp +++ b/source/lib/sysdep/win/wdbg_sym.cpp @@ -37,15 +37,8 @@ #pragma comment(lib, "oleaut32.lib") // VariantChangeType #endif - -#pragma SECTION_INIT(5) -WINIT_REGISTER_FUNC(wdbg_sym_init); -#pragma FORCE_INCLUDE(wdbg_sym_init) -#pragma SECTION_SHUTDOWN(5) -WINIT_REGISTER_FUNC(wdbg_sym_shutdown); -#pragma FORCE_INCLUDE(wdbg_sym_shutdown) -#pragma SECTION_RESTORE - +WINIT_REGISTER_INIT_MAIN(wdbg_sym_Init); +WINIT_REGISTER_SHUTDOWN_MAIN(wdbg_sym_Shutdown); // note: it is safe to use debug_assert/debug_warn/CHECK_ERR even during a // stack trace (which is triggered by debug_assert et al. in app code) because @@ -117,7 +110,7 @@ static LibError sym_init() } -// called from wdbg_sym_shutdown. +// called from wdbg_sym_Shutdown. static LibError sym_shutdown() { SymCleanup(hProcess); @@ -1312,7 +1305,7 @@ static PtrSet* already_visited_ptrs; // if we put it in a function, construction still fails on VC7 because // the atexit table will not have been initialized yet. -// called by debug_dump_stack and wdbg_sym_shutdown +// called by debug_dump_stack and wdbg_sym_Shutdown static void ptr_reset_visited() { delete already_visited_ptrs; @@ -1922,7 +1915,7 @@ fail: -static LibError wdbg_sym_init() +static LibError wdbg_sym_Init() { // try to import RtlCaptureContext (available on WinXP and later). // it's used in walk_stack; import here to avoid overhead of doing so @@ -1937,7 +1930,7 @@ static LibError wdbg_sym_init() } -static LibError wdbg_sym_shutdown() +static LibError wdbg_sym_Shutdown() { ptr_reset_visited(); return sym_shutdown(); diff --git a/source/lib/sysdep/win/wdir_watch.cpp b/source/lib/sysdep/win/wdir_watch.cpp index f59681c095..fe6b87f157 100644 --- a/source/lib/sysdep/win/wdir_watch.cpp +++ b/source/lib/sysdep/win/wdir_watch.cpp @@ -22,15 +22,8 @@ #include "winit.h" #include "wutil.h" - -#pragma SECTION_INIT(5) -WINIT_REGISTER_FUNC(wdir_watch_Init); -#pragma FORCE_INCLUDE(wdir_watch_Init) -#pragma SECTION_SHUTDOWN(5) -WINIT_REGISTER_FUNC(wdir_watch_Shutdown); -#pragma FORCE_INCLUDE(wdir_watch_Shutdown) -#pragma SECTION_RESTORE - +WINIT_REGISTER_INIT_MAIN(wdir_watch_Init); +WINIT_REGISTER_SHUTDOWN_MAIN(wdir_watch_Shutdown); // rationale for polling: // much simpler than pure asynchronous notification: no need for a diff --git a/source/lib/sysdep/win/wdll_delay_load.cpp b/source/lib/sysdep/win/wdll_delay_load.cpp index 7bb07a4571..27cbaceb85 100644 --- a/source/lib/sysdep/win/wdll_delay_load.cpp +++ b/source/lib/sysdep/win/wdll_delay_load.cpp @@ -15,12 +15,7 @@ #include "win.h" #include "winit.h" - -#pragma SECTION_SHUTDOWN(9) // last, since DLLs are unloaded here -WINIT_REGISTER_FUNC(wdll_Shutdown); -#pragma FORCE_INCLUDE(wdll_Shutdown) -#pragma SECTION_RESTORE - +WINIT_REGISTER_SHUTDOWN_LATE2(wdll_Shutdown); // last - DLLs are unloaded here //----------------------------------------------------------------------------- // delay loading (modified from VC7 DelayHlp.cpp and DelayImp.h) diff --git a/source/lib/sysdep/win/whrt/whrt.cpp b/source/lib/sysdep/win/whrt/whrt.cpp index cc952260eb..1238cca595 100644 --- a/source/lib/sysdep/win/whrt/whrt.cpp +++ b/source/lib/sysdep/win/whrt/whrt.cpp @@ -22,14 +22,8 @@ #include "counter.h" - -#pragma SECTION_INIT(4) // wtime depends on us -WINIT_REGISTER_FUNC(whrt_Init); -#pragma FORCE_INCLUDE(whrt_Init) -#pragma SECTION_SHUTDOWN(8) -WINIT_REGISTER_FUNC(whrt_Shutdown); -#pragma FORCE_INCLUDE(whrt_Shutdown) -#pragma SECTION_RESTORE +WINIT_REGISTER_INIT_EARLY2(whrt_Init); // whrt -> wtime +WINIT_REGISTER_SHUTDOWN_LATE(whrt_Shutdown); namespace ERR diff --git a/source/lib/sysdep/win/winit.cpp b/source/lib/sysdep/win/winit.cpp index f0453e06da..36efec5579 100644 --- a/source/lib/sysdep/win/winit.cpp +++ b/source/lib/sysdep/win/winit.cpp @@ -13,6 +13,8 @@ #include "win.h" // GetTickCount +// see http://blogs.msdn.com/larryosterman/archive/2004/09/27/234840.aspx + typedef LibError (*PfnLibErrorVoid)(void); @@ -22,18 +24,12 @@ typedef LibError (*PfnLibErrorVoid)(void); // (zero, because CallFunctionPointers has to ignore entries =0 anyway). // - ASCII '$' and 'Z' come before resp. after '0'..'9', so use that to // bound the section names. -#pragma SECTION_INIT($) -PfnLibErrorVoid initBegin = 0; -#pragma SECTION_INIT(Z) -PfnLibErrorVoid initEnd = 0; -#pragma SECTION_SHUTDOWN($) -PfnLibErrorVoid shutdownBegin = 0; -#pragma SECTION_SHUTDOWN(Z) -PfnLibErrorVoid shutdownEnd = 0; -#pragma SECTION_RESTORE -// note: /include is not necessary, since these are referenced below. - -#pragma comment(linker, "/merge:.WINIT=.data") +__declspec(allocate("WINIT$I$")) PfnLibErrorVoid initBegin = 0; +__declspec(allocate("WINIT$IZ")) PfnLibErrorVoid initEnd = 0; +__declspec(allocate("WINIT$S$")) PfnLibErrorVoid shutdownBegin = 0; +__declspec(allocate("WINIT$SZ")) PfnLibErrorVoid shutdownEnd = 0; +// note: #pragma comment(linker, "/include") is not necessary since +// these are referenced below. /** diff --git a/source/lib/sysdep/win/winit.h b/source/lib/sysdep/win/winit.h index fc0bc805ef..1929ab74e2 100644 --- a/source/lib/sysdep/win/winit.h +++ b/source/lib/sysdep/win/winit.h @@ -11,78 +11,135 @@ #ifndef INCLUDED_WINIT #define INCLUDED_WINIT -// overview: -// participating modules store function pointer(s) to their init and/or -// shutdown function in a specific COFF section. the sections are -// grouped according to the desired notification and the order in which -// functions are to be called (useful if one module depends on another). -// they are then gathered by the linker and arranged in alphabetical order. -// placeholder variables in the sections indicate where the series of -// functions begins and ends for a given notification time. -// at runtime, all of the function pointers between the markers are invoked. -// -// details: -// the section names are of the format ".LIB${type}{group}". +/* + +Overview +-------- + +participating modules store function pointer(s) to their init and/or +shutdown function in a specific COFF section. the sections are +grouped according to the desired notification and the order in which +functions are to be called (useful if one module depends on another). +they are then gathered by the linker and arranged in alphabetical order. +placeholder variables in the sections indicate where the series of +functions begins and ends for a given notification time. +at runtime, all of the function pointers between the markers are invoked. + + +Example +------- + +WINIT_REGISTER_INIT_MAIN(wtime_Init); // whrt -> wtime + + +Rationale +--------- + +several methods of module init are possible: (see Large Scale C++ Design) +- on-demand initialization: each exported function would have to check + if init already happened. that would be brittle and hard to verify. +- singleton: variant of the above, but not applicable to a + procedural interface (and quite ugly to boot). +- registration: static constructors call a central notification function. + module dependencies would be quite difficult to express - this would + require a graph or separate lists for each priority (clunky). + worse, a fatal flaw is that other C++ constructors may depend on the + modules we are initializing and already have run. there is no way + to influence ctor call order between separate source files, so + this is out of the question. +- linker-based registration: same as above, but the linker takes care + of assembling various functions into one sorted table. the list of + init functions is available before C++ ctors have run. incidentally, + zero runtime overhead is incurred. unfortunately, this approach is + MSVC-specific. however, the MS CRT uses a similar method for its + init, so this is expected to remain supported. + +*/ + +//----------------------------------------------------------------------------- +// section declarations + +// section names are of the format "WINIT${type}{group}". // {type} is I for initialization- or S for shutdown functions. -// {group} is [0, 9]; all functions in a group are called before those of -// the next higher group, but order within the group is undefined. -// (this is because the linker sorts sections alphabetically but doesn't -// specify the order in which object files are processed.) -// -// example: -// #pragma SECTION_INIT(7)) -// WINIT_REGISTER_FUNC(wtime_init); -// #pragma FORCE_INCLUDE(wtime_init) -// #pragma SECTION_SHUTDOWN(3)) -// WINIT_REGISTER_FUNC(wtime_shutdown); -// #pragma FORCE_INCLUDE(wtime_shutdown) -// #pragma SECTION_RESTORE -// +// {group} is [0, 9] - see below. +// note: __declspec(allocate) requires sections to be 'declared' +// before using them. + +#pragma section("WINIT$I$", read) +#pragma section("WINIT$I0", read) +#pragma section("WINIT$I1", read) +#pragma section("WINIT$I2", read) +#pragma section("WINIT$I6", read) +#pragma section("WINIT$I7", read) +#pragma section("WINIT$IZ", read) +#pragma section("WINIT$S$", read) +#pragma section("WINIT$S0", read) +#pragma section("WINIT$S1", read) +#pragma section("WINIT$S6", read) +#pragma section("WINIT$S7", read) +#pragma section("WINIT$S8", read) +#pragma section("WINIT$SZ", read) +#pragma comment(linker, "/merge:WINIT=.rdata") + +//----------------------------------------------------------------------------- +// Function groups + +// to allow correct ordering of module init in the face of dependencies, +// we introduce 'groups'. all functions in one are called before those in +// the next higher group, but order within the group is undefined. +// (this is because the linker sorts sections alphabetically but doesn't +// specify the order in which object files are processed.) + +// register a function to be called at the given time. +// usage: invoke at file scope, passing a function identifier/symbol. // rationale: -// several methods of module init are possible: (see Large Scale C++ Design) -// - on-demand initialization: each exported function would have to check -// if init already happened. that would be brittle and hard to verify. -// - singleton: variant of the above, but not applicable to a -// procedural interface (and quite ugly to boot). -// - registration: static constructors call a central notification function. -// module dependencies would be quite difficult to express - this would -// require a graph or separate lists for each priority (clunky). -// worse, a fatal flaw is that other C++ constructors may depend on the -// modules we are initializing and already have run. there is no way -// to influence ctor call order between separate source files, so -// this is out of the question. -// - linker-based registration: same as above, but the linker takes care -// of assembling various functions into one sorted table. the list of -// init functions is available before C++ ctors have run. incidentally, -// zero runtime overhead is incurred. unfortunately, this approach is -// MSVC-specific. however, the MS CRT uses a similar method for its -// init, so this is expected to remain supported. +// - __declspec(allocate) requires section declarations, but allows users to +// write only one line (instead of needing an additional #pragma data_seg) +// - fixed groups instead of passing a group number are more clear and +// encourage thinking about init order. (__declspec(allocate) requires +// a single string literal anyway and doesn't support merging) +// - why EXTERN_C and __pragma? VC8's link-stage optimizer believes +// the static function pointers defined by WINIT_REGISTER_* to be unused; +// unless action is taken, they would be removed. to prevent this, we +// forcibly include the function pointer symbols. this means the variable +// must be extern, not static. the linker needs to know the decorated +// symbol name, so we disable mangling via EXTERN_C. -// macros to simplify usage. -// notes: -// - #pragma cannot be packaged in macros due to expansion rules. -// - __declspec(allocate) would be tempting, since that could be -// wrapped in WINIT_REGISTER_FUNC. unfortunately it inexplicably cannot -// cope with split string literals (e.g. "ab" "c"). that disqualifies -// it, since we want to hide the section name behind a macro, which -// would require the abovementioned merging. +// very early init; must not fail, since error handling code *crashes* +// if called before these have completed. +#define WINIT_REGISTER_INIT_CRITICAL(func) static LibError func(void); EXTERN_C __declspec(allocate("WINIT$I0")) LibError (*p##func)(void) = func; __pragma(comment(linker, "/include:_p"#func)) -// note: init functions are called before _cinit and MUST NOT use -// any stateful CRT functions (e.g. atexit)! -#define SECTION_INIT(group) data_seg(".WINIT$I" #group) -#define SECTION_SHUTDOWN(group) data_seg(".WINIT$S" #group) -#define SECTION_RESTORE data_seg() -// use to make sure the link-stage optimizer doesn't discard the -// function pointers (happens on VC8) -#define FORCE_INCLUDE(id) comment(linker, "/include:_p"#id) +// meant for modules with dependents but whose init is complicated and may +// raise error/warning messages (=> can't go in WINIT_REGISTER_INIT_CRITICAL) +#define WINIT_REGISTER_INIT_EARLY(func) static LibError func(void); EXTERN_C __declspec(allocate("WINIT$I1")) LibError (*p##func)(void) = func; __pragma(comment(linker, "/include:_p"#func)) -#define WINIT_REGISTER_FUNC(func)\ - static LibError func(void);\ - EXTERN_C LibError (*p##func)(void) = func +// available for dependents of WINIT_REGISTER_INIT_EARLY-modules that +// must still come before WINIT_REGISTER_INIT_MAIN. +#define WINIT_REGISTER_INIT_EARLY2(func) static LibError func(void); EXTERN_C __declspec(allocate("WINIT$I2")) LibError (*p##func)(void) = func; __pragma(comment(linker, "/include:_p"#func)) + +// most modules will go here unless they are often used or +// have many dependents. +#define WINIT_REGISTER_INIT_MAIN(func) static LibError func(void); EXTERN_C __declspec(allocate("WINIT$I6")) LibError (*p##func)(void) = func; __pragma(comment(linker, "/include:_p"#func)) + +// available for any modules that may need to come after +// WINIT_REGISTER_INIT_MAIN (unlikely) +#define WINIT_REGISTER_INIT_LATE(func) static LibError func(void); EXTERN_C __declspec(allocate("WINIT$I7")) LibError (*p##func)(void) = func; __pragma(comment(linker, "/include:_p"#func)) + +#define WINIT_REGISTER_SHUTDOWN_EARLY(func) static LibError func(void); EXTERN_C __declspec(allocate("WINIT$S0")) LibError (*p##func)(void) = func; __pragma(comment(linker, "/include:_p"#func)) +#define WINIT_REGISTER_SHUTDOWN_EARLY2(func) static LibError func(void); EXTERN_C __declspec(allocate("WINIT$S1")) LibError (*p##func)(void) = func; __pragma(comment(linker, "/include:_p"#func)) +#define WINIT_REGISTER_SHUTDOWN_MAIN(func) static LibError func(void); EXTERN_C __declspec(allocate("WINIT$S6")) LibError (*p##func)(void) = func; __pragma(comment(linker, "/include:_p"#func)) +#define WINIT_REGISTER_SHUTDOWN_LATE(func) static LibError func(void); EXTERN_C __declspec(allocate("WINIT$S7")) LibError (*p##func)(void) = func; __pragma(comment(linker, "/include:_p"#func)) +#define WINIT_REGISTER_SHUTDOWN_LATE2(func) static LibError func(void); EXTERN_C __declspec(allocate("WINIT$S8")) LibError (*p##func)(void) = func; __pragma(comment(linker, "/include:_p"#func)) + + +//----------------------------------------------------------------------------- /** * call each registered function. - * these are invoked by wstartup at the appropriate times. + * + * if this is called before CRT initialization, callbacks must not use any + * non-stateless CRT functions such as atexit. see wstartup.h for the + * current status on this issue. **/ extern void winit_CallInitFunctions(); extern void winit_CallShutdownFunctions(); diff --git a/source/lib/sysdep/win/wposix/waio.cpp b/source/lib/sysdep/win/wposix/waio.cpp index bf80ece8e7..97c29da965 100644 --- a/source/lib/sysdep/win/wposix/waio.cpp +++ b/source/lib/sysdep/win/wposix/waio.cpp @@ -20,14 +20,8 @@ #include "lib/sysdep/cpu.h" #include "lib/bits.h" - -#pragma SECTION_INIT(5) -WINIT_REGISTER_FUNC(waio_init); -#pragma FORCE_INCLUDE(waio_init) -#pragma SECTION_SHUTDOWN(5) -WINIT_REGISTER_FUNC(waio_shutdown); -#pragma FORCE_INCLUDE(waio_shutdown) -#pragma SECTION_RESTORE +WINIT_REGISTER_INIT_MAIN(waio_Init); +WINIT_REGISTER_SHUTDOWN_MAIN(waio_Shutdown); static void lock() @@ -889,14 +883,14 @@ int aio_fsync(int, struct aiocb*) ////////////////////////////////////////////////////////////////////////////// -static LibError waio_init() +static LibError waio_Init() { req_init(); return INFO::OK; } -static LibError waio_shutdown() +static LibError waio_Shutdown() { req_cleanup(); aio_h_cleanup(); diff --git a/source/lib/sysdep/win/wposix/wposix.cpp b/source/lib/sysdep/win/wposix/wposix.cpp index 0c918e6465..ac92115db6 100644 --- a/source/lib/sysdep/win/wposix/wposix.cpp +++ b/source/lib/sysdep/win/wposix/wposix.cpp @@ -15,12 +15,7 @@ #include "crt_posix.h" // _getcwd #include "lib/bits.h" - -#pragma SECTION_INIT(0) // very early (pageSize is needed by debug_error_message_build) -WINIT_REGISTER_FUNC(wposix_Init); -#pragma FORCE_INCLUDE(wposix_Init) -#pragma SECTION_RESTORE - +WINIT_REGISTER_INIT_CRITICAL(wposix_Init); // wposix -> error handling //----------------------------------------------------------------------------- // sysconf @@ -46,7 +41,12 @@ static void InitSysconf() long sysconf(int name) { - debug_assert(pageSize); // must not be called before InitSysconf + // called before InitSysconf => winit/wstartup are broken. this is + // going to cause a hard crash because debug.cpp's error reporting + // code requires the page size to be known. we'll exit with a unique + // value to hopefully help track down the problem. + if(!pageSize) + exit(239786); // 0x3A8AA switch(name) { diff --git a/source/lib/sysdep/win/wposix/wsock.cpp b/source/lib/sysdep/win/wposix/wsock.cpp index 4715fa4d20..449d297013 100644 --- a/source/lib/sysdep/win/wposix/wsock.cpp +++ b/source/lib/sysdep/win/wposix/wsock.cpp @@ -20,15 +20,8 @@ #pragma comment(lib, "ws2_32.lib") #endif - -#pragma SECTION_INIT(5) -WINIT_REGISTER_FUNC(wsock_init); -#pragma FORCE_INCLUDE(wsock_init) -#pragma SECTION_SHUTDOWN(5) -WINIT_REGISTER_FUNC(wsock_shutdown); -#pragma FORCE_INCLUDE(wsock_shutdown) -#pragma SECTION_RESTORE - +WINIT_REGISTER_INIT_MAIN(wsock_Init); +WINIT_REGISTER_SHUTDOWN_MAIN(wsock_Shutdown); uint16_t htons(uint16_t s) { @@ -102,7 +95,7 @@ static LibError wsock_actual_init() return INFO::OK; } -static LibError wsock_init() +static LibError wsock_Init() { // trigger wsock_actual_init when someone first calls a wsock function. static WdllLoadNotify loadNotify = { "ws2_32", wsock_actual_init }; @@ -111,7 +104,7 @@ static LibError wsock_init() } -static LibError wsock_shutdown() +static LibError wsock_Shutdown() { if(!ModuleShouldShutdown(&initState)) return INFO::OK; diff --git a/source/lib/sysdep/win/wposix/wtime.cpp b/source/lib/sysdep/win/wposix/wtime.cpp index 05549ee462..266a3310a5 100644 --- a/source/lib/sysdep/win/wposix/wtime.cpp +++ b/source/lib/sysdep/win/wposix/wtime.cpp @@ -19,12 +19,7 @@ #include "lib/sysdep/cpu.h" // cpu_i64FromDouble #include "lib/sysdep/win/whrt/whrt.h" - -#pragma SECTION_INIT(7) // depends on whrt -WINIT_REGISTER_FUNC(wtime_Init); -#pragma FORCE_INCLUDE(wtime_Init) -#pragma SECTION_RESTORE - +WINIT_REGISTER_INIT_MAIN(wtime_Init); // whrt -> wtime // NT system time and FILETIME are hectonanoseconds since Jan. 1, 1601 UTC. // SYSTEMTIME is a struct containing month, year, etc. diff --git a/source/lib/sysdep/win/wstartup.cpp b/source/lib/sysdep/win/wstartup.cpp index 78d27aba12..30ba5c7e73 100644 --- a/source/lib/sysdep/win/wstartup.cpp +++ b/source/lib/sysdep/win/wstartup.cpp @@ -2,35 +2,20 @@ * ========================================================================= * File : wstartup.cpp * Project : 0 A.D. - * Description : windows-specific entry point and startup code + * Description : windows-specific startup code * ========================================================================= */ // license: GPL; see lib/license.txt -// this module can wrap the program in a SEH __try block and takes care of -// calling winit's functions at the appropriate times. -// to use it, set Linker Options -> Advanced -> Entry Point to -// "entry" (without quotes). -// -// besides commandeering the entry point, it hooks ExitProcess. -// control flow overview: entry [-> RunWithinTryBlock] -> InitAndCallMain -> -// (init) -> mainCRTStartup -> main -> exit -> HookedExitProcess -> -// (shutdown) -> ExitProcess. - #include "precompiled.h" #include "wstartup.h" -#include "win.h" -#include // __security_init_cookie -#include "lib/sysdep/win/detours/detours.h" - #include "winit.h" -#include "wdbg.h" // wdbg_exception_filter //----------------------------------------------------------------------------- -// do shutdown at exit +// shutdown // note: the alternative of using atexit has two disadvantages. // - the call to atexit must come after _cinit, which means we'd need to be @@ -39,30 +24,12 @@ // for static objects would cause those handlers to be called after ours, // which may cause shutdown order bugs. -static VOID (WINAPI *RealExitProcess)(UINT uExitCode); - -static VOID WINAPI HookedExitProcess(UINT uExitCode) -{ - winit_CallShutdownFunctions(); - - RealExitProcess(uExitCode); -} - -static void InstallExitHook() -{ - // (can't do this in a static initializer because they haven't run yet!) - RealExitProcess = ExitProcess; - - DetourTransactionBegin(); - DetourAttach(&(PVOID&)RealExitProcess, HookedExitProcess); - DetourTransactionCommit(); -} - //----------------------------------------------------------------------------- // init // the init functions need to be called before any use of Windows-specific -// code. +// code. in particular, static ctors may use whrt or wpthread, so we ought to +// be initialized before them as well. // // one possibility is using WinMain as the entry point, and then calling the // application's main(), but this is expressly forbidden by the C standard. @@ -78,41 +45,32 @@ static void InstallExitHook() // the 0ad executable as well as the separate self-test. this means // we can't enable the main() hook for one and disable it in the other. // -// requiring users to call us at the beginning of main is brittle in general -// and not possible with the self-test's auto-generated main file. +// requiring users to call us at the beginning of main is brittle in general, +// comes after static ctors, and is difficult to achieve in external code +// such as the (automatically generated) self-test. // -// the only alternative is to commandeer the entry point and do all init -// before calling mainCRTStartup. this means init will be finished before -// C++ static ctors run (allowing our APIs to be called from those ctors), -// but also denies init the use of any non-stateless CRT functions! +// commandeering the entry point, doing init there and then calling +// mainCRTStartup would work, but doesn't help with shutdown - additional +// measures are required (see above). note that this approach means we're +// initialized before _cinit, denying the use of non-stateless CRT functions. -// these aren't defined in VC include files, so we have to do it manually. -#ifdef USE_WINMAIN -EXTERN_C int WinMainCRTStartup(void); -#else -EXTERN_C int mainCRTStartup(void); -#endif -// (moved into a separate function because it's used by both -// entry and entry_noSEH) -static int InitAndCallMain() +EXTERN_C void InitAndRegisterShutdown() { winit_CallInitFunctions(); - - InstallExitHook(); - - int ret; -#ifdef USE_WINMAIN - ret = WinMainCRTStartup(); // calls _cinit and then our WinMain -#else - ret = mainCRTStartup(); // calls _cinit and then our main -#endif - return ret; + atexit(winit_CallShutdownFunctions); } +#pragma data_seg(".CRT$XCB") +EXTERN_C void(*pInitAndRegisterShutdown)() = InitAndRegisterShutdown; +#pragma comment(linker, "/include:_pInitAndRegisterShutdown") +#pragma data_seg() + //----------------------------------------------------------------------------- -// entry point and SEH wrapper +// SEH wrapper + +#include "wdbg.h" // wdbg_exception_filter typedef int(*PfnIntVoid)(void); @@ -129,39 +87,3 @@ static int RunWithinTryBlock(PfnIntVoid func) } return ret; } - - -int entry() -{ -#if MSC_VERSION >= 1400 - // 2006-02-16 workaround for R6035 on VC8: - // - // SEH code compiled with /GS pushes a "security cookie" onto the - // stack. since we're called before _cinit, the cookie won't have - // been initialized yet, which would cause the CRT to FatalAppExit. - // to solve this, we must call __security_init_cookie before any - // hidden compiler-generated SEH registration code runs, - // which means the __try block must be moved into a helper function. - // - // NB: entry() must not contain local string buffers, either - - // /GS would install a cookie here as well (same problem). - // - // see http://msdn2.microsoft.com/en-US/library/ms235603.aspx - __security_init_cookie(); -#endif - return RunWithinTryBlock(InitAndCallMain); -} - - -// Alternative entry point, for programs that don't want the SEH handler -// (e.g. unit tests, where it's better to let the debugger handle any errors) -int entry_noSEH() -{ -#if MSC_VERSION >= 1400 - // see above. this is also necessary here in case pre-libc init - // functions use SEH. - __security_init_cookie(); -#endif - - return InitAndCallMain(); -} diff --git a/source/lib/sysdep/win/wstartup.h b/source/lib/sysdep/win/wstartup.h index 3cfd3c34e3..850c184033 100644 --- a/source/lib/sysdep/win/wstartup.h +++ b/source/lib/sysdep/win/wstartup.h @@ -2,17 +2,21 @@ * ========================================================================= * File : wstartup.h * Project : 0 A.D. - * Description : windows-specific entry point and startup code + * Description : windows-specific startup code * ========================================================================= */ // license: GPL; see lib/license.txt +// linking with this component automatically causes winit's functions to +// be called at the appropriate times. +// +// the current implementation manages to trigger winit initialization +// between CRT init and static C++ ctors. that means wpthread etc. APIs +// are safe to use from the ctors and also that winit initializers are +// allowed to use non-stateless CRT functions such as atexit. + #ifndef INCLUDED_WSTARTUP #define INCLUDED_WSTARTUP -// entry points (normal and without SEH wrapper; see definition) -EXTERN_C int entry(); -EXTERN_C int entry_noSEH(); - #endif // #ifndef INCLUDED_WSTARTUP diff --git a/source/lib/sysdep/win/wutil.cpp b/source/lib/sysdep/win/wutil.cpp index 3b79752f9c..de18a10549 100644 --- a/source/lib/sysdep/win/wutil.cpp +++ b/source/lib/sysdep/win/wutil.cpp @@ -19,15 +19,8 @@ #include "win.h" #include "winit.h" - -#pragma SECTION_INIT(1) // early, several modules depend on us -WINIT_REGISTER_FUNC(wutil_PreLibcInit); -#pragma FORCE_INCLUDE(wutil_PreLibcInit) -#pragma SECTION_SHUTDOWN(8) -WINIT_REGISTER_FUNC(wutil_Shutdown); -#pragma FORCE_INCLUDE(wutil_Shutdown) -#pragma SECTION_RESTORE - +WINIT_REGISTER_INIT_EARLY(wutil_Init); +WINIT_REGISTER_SHUTDOWN_LATE(wutil_Shutdown); //----------------------------------------------------------------------------- // safe allocator @@ -331,7 +324,7 @@ void wutil_RevertWow64Redirection(void* wasRedirectionEnabled) //----------------------------------------------------------------------------- -static LibError wutil_PreLibcInit() +static LibError wutil_Init() { InitLocks();