mirror of
https://github.com/Chuyu-Team/YY-Thunks.git
synced 2026-10-16 20:57:16 +08:00
Fea #83, Windows XP添加动态DLL TLS兼容
This commit is contained in:
@@ -14,3 +14,6 @@ indent_size = 4
|
||||
[*.{vcxproj,xml,nuspec,targets}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.cmd]
|
||||
charset = unset
|
||||
|
||||
@@ -132,13 +132,13 @@ jobs:
|
||||
|
||||
$RunFaild = 0
|
||||
|
||||
&vstest.console src\Release\YY-Thunks.UnitTest.dll "/logger:trx;LogFileName=UnitTestWin32.trx" "/Blame:CollectDump;CollectAlways=false;DumpType=full /Diag:TestResults\Win32.log"
|
||||
&vstest.console src\Release\YY-Thunks.UnitTest.dll "/logger:trx;LogFileName=UnitTestWin32.trx" "/Blame:CollectDump;CollectAlways=false;DumpType=full" "/Diag:TestResults\Win32.log"
|
||||
if($lastexitcode -ne 0)
|
||||
{
|
||||
$RunFaild = 1
|
||||
}
|
||||
|
||||
&vstest.console src\x64\Release\YY-Thunks.UnitTest.dll "/logger:trx;LogFileName=UnitTestWin64.trx" "/Blame:CollectDump;CollectAlways=false;DumpType=full /Diag:TestResults\Win64.log"
|
||||
&vstest.console src\x64\Release\YY-Thunks.UnitTest.dll "/logger:trx;LogFileName=UnitTestWin64.trx" "/Blame:CollectDump;CollectAlways=false;DumpType=full" "/Diag:TestResults\Win64.log"
|
||||
if($lastexitcode -ne 0)
|
||||
{
|
||||
$RunFaild = 1
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<MinimumRequiredVersion Condition=" '%(Link.MinimumRequiredVersion)' == '' and '$(PlatformShortName)'=='x86' and '$(YY_Thunks_File)'=='YY_Thunks_for_WinXP.obj' ">5.01</MinimumRequiredVersion>
|
||||
<MinimumRequiredVersion Condition=" '%(Link.MinimumRequiredVersion)' == '' and '$(PlatformShortName)'=='x64' and '$(YY_Thunks_File)'=='YY_Thunks_for_WinXP.obj' ">5.02</MinimumRequiredVersion>
|
||||
<AdditionalDependencies>$(MSBuildThisFileDirectory)objs\$(PlatformShortName)\$(YY_Thunks_File);%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<EntryPointSymbol Condition="'$(ConfigurationType)'=='DynamicLibrary' and ('$(YY_Thunks_File)'=='YY_Thunks_for_WinXP.obj' or '$(YY_Thunks_File)'=='YY_Thunks_for_Win2K.obj')">DllMainCRTStartupForYY_Thunks</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@@ -21,4 +22,4 @@
|
||||
<Target Name="YY_Thunks_Update_MinimumRequiredVersion" Condition="'$(YY_Thunks_File)'=='YY_Thunks_for_Win2K.obj' and Exists('$(MSBuildThisFileDirectory)objs\$(PlatformShortName)\$(YY_Thunks_File)') and ('$(ConfigurationType)' == 'Application' Or '$(ConfigurationType)' == 'DynamicLibrary') " AfterTargets="AfterLink">
|
||||
<Exec Command="%22$(MSBuildThisFileDirectory)Bin\MinimumRequiredVersionHelper.exe%22 %22$(TargetPath)%22 /MinimumRequiredVersion:5.0"/>
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
[](https://www.nuget.org/packages/YY-Thunks)
|
||||
[](https://github.com/Chuyu-Team/YY-Thunks/actions/workflows/Build&Test.yml)
|
||||
|
||||
- [英语](Readme.md)
|
||||
|
||||
## 1. 关于 YY-Thunks
|
||||
|
||||
众所周知,从 Windows 的每次更新又会新增大量 API,这使得兼容不同版本的 Windows
|
||||
@@ -22,8 +24,20 @@ YY-Thunks(鸭船),存在的目的就是抹平不同系统的差异,编
|
||||
### 1.1. 原理
|
||||
|
||||
使用 `LoadLibrary` 以及 `GetProcAddress` 动态加载 API,不存在时做出补偿措施,
|
||||
最大限度模拟原始 API 行为,让你的程序正常运行。
|
||||
最大限度模拟原始 API 行为,让你的程序正常运行。大概就像下面这个`GetTickCount64`函数:
|
||||
|
||||
```cpp
|
||||
// 注意:Windows XP 不支持 GetTickCount64
|
||||
ULONGLONG WINAPI GetTickCount64(VOID)
|
||||
{
|
||||
if (auto const _pfnGetTickCount64 = try_get_GetTickCount64())
|
||||
{
|
||||
return _pfnGetTickCount64();
|
||||
}
|
||||
// Fallback
|
||||
return GetTickCount();
|
||||
}
|
||||
```
|
||||
### 1.2. 亮点
|
||||
|
||||
* 更快!更安全!`鸭船`内建2级缓存以及按需加载机制,同时自动加密所有函数指针,
|
||||
@@ -57,7 +71,8 @@ YY-Thunks(鸭船),存在的目的就是抹平不同系统的差异,编
|
||||
2. 【链接器】-【输入】-【附加依赖项】,添加
|
||||
`objs\$(PlatformShortName)\YY_Thunks_for_WinXP.obj`。
|
||||
3. 【链接器】-【系统】-【所需的最低版本】,根据实际情况填写 `5.01`(WinXP 32位) 或者 `5.02`(WinXP x64、2003)。
|
||||
4. 重新编译代码。
|
||||
4. 如果是编译DLL,那么【链接器】-【高级】-【自定义入口点】更改为`DllMainCRTStartupForYY_Thunks`(不这样做XP下使用thread_local可能崩溃!)
|
||||
5. 重新编译代码。
|
||||
|
||||
> 温馨提示:如果需要兼容 Vista,【所需的最低版本】无需修改,但是【附加依赖项】请选择
|
||||
`objs\$(PlatformShortName)\YY_Thunks_for_Vista.obj`。
|
||||
+6
-6
@@ -1,8 +1,8 @@
|
||||
@echo off
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
::需要设置LibMaker.exe路径到环境变量Path。
|
||||
::如果你需要LibMaker.exe,请自行到 初雨开源项目交流QQ群(633710173)群文件中下载。
|
||||
::需要设置LibMaker.exe路径到环境变量Path。
|
||||
::如果你需要LibMaker.exe,请自行到 初雨开源项目交流QQ群(633710173)群文件中下载。
|
||||
|
||||
pushd "%~dp0.."
|
||||
|
||||
@@ -12,7 +12,7 @@ if "%Platform%"=="" set Platform=x86
|
||||
|
||||
md "objs\\%Platform%"
|
||||
|
||||
::先生成 YY_Thunks_List.hpp
|
||||
::先生成 YY_Thunks_List.hpp
|
||||
msbuild "%~dp0YY-Thunks.UnitTest\YY-Thunks.UnitTest.vcxproj" -t:Build_YY_Thunks_List_hpp
|
||||
|
||||
call:Build%Platform%
|
||||
@@ -26,8 +26,8 @@ goto:eof
|
||||
:BuildObj
|
||||
cl /O1 /Os /Oi /GS- /std:c++17 /arch:IA32 /Z7 /MT /Fo"objs\\%Platform%\\%1" /Zl /c /D "NDEBUG" /D "YY_Thunks_Support_Version=%2" "%~dp0Thunks\YY_Thunks.cpp"
|
||||
|
||||
::进行函数名称进行修正 __imp__%s_%u -> __imp__%s@%u
|
||||
LibMaker.exe FixObj "%~dp0..\\objs\\%Platform%\\%1" /WeakExternFix:__security_cookie=%PointType% /WeakExternFix:__YY_Thunks_Process_Terminating=4 /WeakExternFix:__acrt_atexit_table=%PointType%
|
||||
::进行函数名称进行修正 __imp__%s_%u -> __imp__%s@%u
|
||||
LibMaker.exe FixObj "%~dp0..\\objs\\%Platform%\\%1" /WeakExternFix:__security_cookie=%PointType% /WeakExternFix:__YY_Thunks_Process_Terminating=4 /WeakExternFix:__acrt_atexit_table=%PointType% /WeakExternFix:__pfnDllMainCRTStartupForYY_Thunks=%PointType%
|
||||
|
||||
LibMaker.exe AppendWeak /MACHINE:%Platform% /DEF:"%~dp0def\\%Platform%\\PSAPI2Kernel32.def" /OUT:"%~dp0..\\objs\\%Platform%\\%1"
|
||||
|
||||
|
||||
@@ -0,0 +1,463 @@
|
||||
#if defined(YY_Thunks_Implemented)
|
||||
|
||||
namespace YY::Thunks::internal
|
||||
{
|
||||
extern "C" BOOL WINAPI _DllMainCRTStartup(
|
||||
HINSTANCE const instance,
|
||||
DWORD const reason,
|
||||
LPVOID const reserved
|
||||
);
|
||||
|
||||
// 如果希望自定义函数入口点,可以设置此函数
|
||||
extern "C" extern decltype(_DllMainCRTStartup)* const __pfnDllMainCRTStartupForYY_Thunks;
|
||||
|
||||
#if YY_Thunks_Support_Version < NTDDI_WIN6
|
||||
extern "C" ULONG _tls_index;
|
||||
static ULONG _tls_index_old;
|
||||
#ifdef _WIN64
|
||||
extern "C" const IMAGE_TLS_DIRECTORY64 _tls_used;
|
||||
#else
|
||||
extern "C" const IMAGE_TLS_DIRECTORY _tls_used;
|
||||
#endif
|
||||
|
||||
#pragma section(".CRT$XLB", long, read) // First MS CRT Loader TLS Callback
|
||||
|
||||
enum class TlsMode
|
||||
{
|
||||
None,
|
||||
ByFirstCallback,
|
||||
ByDllMainCRTStartupForYY_Thunks,
|
||||
};
|
||||
|
||||
// 用来记录第一次Tls回调的时机
|
||||
// 如果来自ByFirstCallback,那么说明当前模块的TLS功能完全正常(模块是EXE或者来自于隐式依赖的DLL),YY-Thunks无需额外修复
|
||||
// 如果来自ByDllMainCRTStartupForYY_Thunks,那么说明它是动态加载的DLL,TLS没有初始化
|
||||
static TlsMode g_TlsMode;
|
||||
|
||||
static
|
||||
VOID
|
||||
NTAPI
|
||||
FirstCallback(
|
||||
PVOID DllHandle,
|
||||
DWORD Reason,
|
||||
PVOID Reserved
|
||||
)
|
||||
{
|
||||
if (DLL_PROCESS_ATTACH == Reason)
|
||||
{
|
||||
if (g_TlsMode == TlsMode::None)
|
||||
{
|
||||
g_TlsMode = TlsMode::ByFirstCallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TlsRawItem
|
||||
{
|
||||
TlsRawItem* pNext;
|
||||
TlsRawItem* pPrev;
|
||||
BYTE* pBase;
|
||||
void** pOldTlsIndex;
|
||||
};
|
||||
static thread_local TlsRawItem s_CurrentNode;
|
||||
|
||||
static volatile LONG uStatus = 0;
|
||||
static TlsRawItem* volatile pRoot = nullptr;
|
||||
|
||||
static ULONG __fastcall GetTlsIndexBufferCount(TEB* _pTeb)
|
||||
{
|
||||
auto _ppThreadLocalStoragePointer = (void**)_pTeb->ThreadLocalStoragePointer;
|
||||
if (!_ppThreadLocalStoragePointer)
|
||||
return 0;
|
||||
|
||||
return HeapSize(_pTeb->ProcessEnvironmentBlock->ProcessHeap, 0, _ppThreadLocalStoragePointer) / sizeof(void*);
|
||||
}
|
||||
static PVOID NTAPI RtlImageDirectoryEntryToData(
|
||||
__in PVOID pBaseAddress,
|
||||
__in ULONG dwDirectory,
|
||||
__out PULONG pSize
|
||||
)
|
||||
{
|
||||
auto _pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
|
||||
auto _pNtHerder = reinterpret_cast<PIMAGE_NT_HEADERS>(PBYTE(pBaseAddress) + _pDosHeader->e_lfanew);
|
||||
auto& _DataDirectory = _pNtHerder->OptionalHeader.DataDirectory[dwDirectory];
|
||||
|
||||
*pSize = _DataDirectory.Size;
|
||||
if (_DataDirectory.Size == 0 || _DataDirectory.VirtualAddress == 0)
|
||||
return nullptr;
|
||||
|
||||
return PBYTE(pBaseAddress) + _DataDirectory.VirtualAddress;
|
||||
}
|
||||
|
||||
static ULONG __fastcall GetMaxTlsIndex() noexcept
|
||||
{
|
||||
ULONG uMaxTlsIndex = 0;
|
||||
|
||||
auto _pLdr = (_PEB_LDR_DATA_XP*)(TEB*)NtCurrentTeb()->ProcessEnvironmentBlock->Ldr;
|
||||
auto _pHerder = &_pLdr->InLoadOrderModuleList;
|
||||
for (auto _pItem = _pHerder->Flink; _pItem != _pHerder; )
|
||||
{
|
||||
auto _pEntry = CONTAINING_RECORD(_pItem, _LDR_DATA_TABLE_ENTRY_XP, InLoadOrderModuleList);
|
||||
_pItem = _pItem->Flink;
|
||||
|
||||
__try
|
||||
{
|
||||
// XP不会为动态加载的DLL设置这个字段(符合预期,毕竟没有真的初始化)
|
||||
/*if (!_pEntry->TlsIndex)
|
||||
continue;*/
|
||||
ULONG TlsSize;
|
||||
auto pTlsImage = (PIMAGE_TLS_DIRECTORY)RtlImageDirectoryEntryToData(
|
||||
_pEntry->BaseAddress,
|
||||
IMAGE_DIRECTORY_ENTRY_TLS,
|
||||
&TlsSize);
|
||||
|
||||
if (pTlsImage == nullptr || pTlsImage->AddressOfIndex == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto _TlsIndex = *(ULONG*)pTlsImage->AddressOfIndex;
|
||||
if (uMaxTlsIndex < _TlsIndex)
|
||||
uMaxTlsIndex = _TlsIndex;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return uMaxTlsIndex;
|
||||
|
||||
}
|
||||
|
||||
static SYSTEM_PROCESS_INFORMATION* __fastcall GetCurrentProcessInfo(StringBuffer<char>& _szBuffer)
|
||||
{
|
||||
const auto _pfnNtQuerySystemInformation = try_get_NtQuerySystemInformation();
|
||||
if (!_pfnNtQuerySystemInformation)
|
||||
return nullptr;
|
||||
|
||||
ULONG _cbBuffer = max(4096, _szBuffer.uBufferLength);
|
||||
ULONG _cbRet = 0;
|
||||
for (;;)
|
||||
{
|
||||
auto _pBuffer = _szBuffer.GetBuffer(_cbBuffer);
|
||||
if (!_pBuffer)
|
||||
return nullptr;
|
||||
|
||||
LONG _Status = _pfnNtQuerySystemInformation(SystemProcessInformation, _pBuffer, _cbBuffer, &_cbRet);
|
||||
if (_Status >= 0)
|
||||
break;
|
||||
|
||||
if (STATUS_INFO_LENGTH_MISMATCH != _Status)
|
||||
return nullptr;
|
||||
|
||||
_cbBuffer = _cbRet;
|
||||
}
|
||||
|
||||
const auto _uCurrentProcessId = GetCurrentProcessId();
|
||||
auto _pInfo = (SYSTEM_PROCESS_INFORMATION*)_szBuffer.GetBuffer(0);
|
||||
for (;;)
|
||||
{
|
||||
if (_pInfo->ProcessId == (HANDLE)_uCurrentProcessId)
|
||||
return _pInfo;
|
||||
|
||||
if (_pInfo->NextEntryDelta == 0)
|
||||
break;
|
||||
|
||||
_pInfo = reinterpret_cast<SYSTEM_PROCESS_INFORMATION*>(reinterpret_cast<char*>(_pInfo) + _pInfo->NextEntryDelta);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool __fastcall AllocTlsData(TEB* _pTeb = nullptr) noexcept
|
||||
{
|
||||
if (_tls_index == 0)
|
||||
return false;
|
||||
if (!_pTeb)
|
||||
_pTeb = (TEB*)NtCurrentTeb();
|
||||
|
||||
auto _pTlsIndex = (void**)_pTeb->ThreadLocalStoragePointer;
|
||||
void** _pOldTlsIndex = nullptr;
|
||||
auto _cTlsIndexLength = GetTlsIndexBufferCount(_pTeb);
|
||||
if (_cTlsIndexLength <= _tls_index)
|
||||
{
|
||||
// Index不足,扩充……
|
||||
auto _cNewTlsIndexLength = _tls_index + 128;
|
||||
auto _pNewTlsIndex = (void**)Alloc(_cNewTlsIndexLength * sizeof(void*), HEAP_ZERO_MEMORY);
|
||||
if (!_pNewTlsIndex)
|
||||
return false;
|
||||
|
||||
memcpy(_pNewTlsIndex, _pTlsIndex, _cTlsIndexLength * sizeof(void*));
|
||||
if ((void*)InterlockedCompareExchange((uintptr_t*)&_pTeb->ThreadLocalStoragePointer, (uintptr_t)_pNewTlsIndex, (uintptr_t)_pTlsIndex) != _pTlsIndex)
|
||||
{
|
||||
Free(_pNewTlsIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_pTeb == (TEB*)NtCurrentTeb())
|
||||
{
|
||||
Free(_pTlsIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 其他线程的无法直接释放,玩意缓存里恰好正在使用这块那么会崩溃的
|
||||
_pOldTlsIndex = _pTlsIndex;
|
||||
}
|
||||
_pTlsIndex = _pNewTlsIndex;
|
||||
}
|
||||
const size_t _cbTlsRaw = _tls_used.EndAddressOfRawData - _tls_used.StartAddressOfRawData;
|
||||
auto _pRawTlsData = (BYTE*)Alloc(_cbTlsRaw, HEAP_ZERO_MEMORY);
|
||||
if (!_pRawTlsData)
|
||||
{
|
||||
// 释放不是安全的,极小的概率可能野,但是现在现在就这样吧。
|
||||
Free(_pOldTlsIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(_pRawTlsData, (void*)_tls_used.StartAddressOfRawData, _cbTlsRaw);
|
||||
InterlockedExchange((uintptr_t*)&_pTlsIndex[_tls_index], (uintptr_t)_pRawTlsData);
|
||||
|
||||
s_CurrentNode.pBase = _pRawTlsData;
|
||||
s_CurrentNode.pOldTlsIndex = _pOldTlsIndex;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!_interlockedbittestandset(&uStatus, 0))
|
||||
{
|
||||
s_CurrentNode.pNext = pRoot;
|
||||
if (pRoot)
|
||||
{
|
||||
pRoot->pPrev = &s_CurrentNode;
|
||||
}
|
||||
pRoot = &s_CurrentNode;
|
||||
_interlockedbittestandreset(&uStatus, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __fastcall FreeTlsData()
|
||||
{
|
||||
if (_tls_index == 0)
|
||||
return;
|
||||
auto _pTeb = (TEB*)NtCurrentTeb();
|
||||
if (_tls_index >= GetTlsIndexBufferCount(_pTeb))
|
||||
return;
|
||||
|
||||
auto _ppTlsIndex = (void**)_pTeb->ThreadLocalStoragePointer;
|
||||
if (_ppTlsIndex[_tls_index] == nullptr)
|
||||
return;
|
||||
|
||||
if (s_CurrentNode.pBase != _ppTlsIndex[_tls_index])
|
||||
return;
|
||||
|
||||
if (s_CurrentNode.pOldTlsIndex)
|
||||
{
|
||||
Free(s_CurrentNode.pOldTlsIndex);
|
||||
s_CurrentNode.pOldTlsIndex = nullptr;
|
||||
}
|
||||
|
||||
s_CurrentNode.pBase = nullptr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!_interlockedbittestandset(&uStatus, 0))
|
||||
{
|
||||
auto pPrev = s_CurrentNode.pPrev;
|
||||
auto pNext = s_CurrentNode.pNext;
|
||||
if (pPrev)
|
||||
{
|
||||
pPrev->pNext = pNext;
|
||||
}
|
||||
else
|
||||
{
|
||||
pRoot = pNext;
|
||||
}
|
||||
|
||||
if (pNext)
|
||||
{
|
||||
pNext->pPrev = pPrev;
|
||||
}
|
||||
_interlockedbittestandreset(&uStatus, 0);
|
||||
|
||||
auto _pTlsRawData = (void*)InterlockedExchange((uintptr_t*)&_ppTlsIndex[_tls_index], 0);
|
||||
Free(_pTlsRawData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool __fastcall CreateTlsIndex() noexcept
|
||||
{
|
||||
if (_tls_index != 0)
|
||||
return false;
|
||||
|
||||
_tls_index = GetMaxTlsIndex() + 1;
|
||||
AllocTlsData((TEB*)NtCurrentTeb());
|
||||
|
||||
// 同时给所有历史的线程追加新DLL产生的Tls内存
|
||||
do
|
||||
{
|
||||
const auto _pfnNtQueryInformationThread = try_get_NtQueryInformationThread();
|
||||
if (!_pfnNtQueryInformationThread)
|
||||
break;
|
||||
|
||||
StringBuffer<char> _Buffer;
|
||||
auto _pProcessInfo = GetCurrentProcessInfo(_Buffer);
|
||||
if (!_pProcessInfo)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const auto _uCurrentThreadId = GetCurrentThreadId();
|
||||
|
||||
for (ULONG i = 0; i != _pProcessInfo->ThreadCount; ++i)
|
||||
{
|
||||
auto& _Thread = _pProcessInfo->Threads[i];
|
||||
|
||||
if (_uCurrentThreadId == (DWORD)_Thread.ClientId.UniqueThread)
|
||||
continue;
|
||||
|
||||
auto _hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, (DWORD)_Thread.ClientId.UniqueThread);
|
||||
if (!_hThread)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
THREAD_BASIC_INFORMATION _ThreadBasicInfo = {};
|
||||
LONG _Status = _pfnNtQueryInformationThread(_hThread, ThreadBasicInformation, &_ThreadBasicInfo, sizeof(_ThreadBasicInfo), nullptr);
|
||||
if (_Status >= 0 && _ThreadBasicInfo.TebBaseAddress)
|
||||
{
|
||||
AllocTlsData((TEB*)_ThreadBasicInfo.TebBaseAddress);
|
||||
}
|
||||
|
||||
CloseHandle(_hThread);
|
||||
}
|
||||
} while (false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __fastcall FreeTlsIndex() noexcept
|
||||
{
|
||||
if (_tls_index == 0)
|
||||
return;
|
||||
|
||||
// 故意不加锁……
|
||||
for (auto _pItem = pRoot; _pItem;)
|
||||
{
|
||||
auto _pNext = _pItem->pNext;
|
||||
if (_pItem->pOldTlsIndex)
|
||||
{
|
||||
Free(_pItem->pOldTlsIndex);
|
||||
_pItem->pOldTlsIndex = nullptr;
|
||||
}
|
||||
Free(_pItem->pBase);
|
||||
_pItem = _pNext;
|
||||
}
|
||||
}
|
||||
|
||||
static void __fastcall CallTlsCallback(
|
||||
HINSTANCE const _hInstance,
|
||||
DWORD const _uReason)
|
||||
{
|
||||
if (_tls_index == 0)
|
||||
return;
|
||||
|
||||
auto _pTeb = (TEB*)NtCurrentTeb();
|
||||
auto _ppThreadLocalStoragePointer = (void**)_pTeb->ThreadLocalStoragePointer;
|
||||
if (!_ppThreadLocalStoragePointer)
|
||||
return;
|
||||
|
||||
if (_tls_index >= GetTlsIndexBufferCount(_pTeb))
|
||||
return;
|
||||
|
||||
if (!_ppThreadLocalStoragePointer[_tls_index])
|
||||
return;
|
||||
|
||||
__try
|
||||
{
|
||||
auto _pfnTlsCallbacks = reinterpret_cast<PIMAGE_TLS_CALLBACK*>(_tls_used.AddressOfCallBacks);
|
||||
if (_pfnTlsCallbacks)
|
||||
{
|
||||
for (; *_pfnTlsCallbacks; ++_pfnTlsCallbacks)
|
||||
{
|
||||
(*_pfnTlsCallbacks)(_hInstance, _uReason, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif // YY_Thunks_Support_Version < NTDDI_WIN6
|
||||
|
||||
// 我们始终提供DllMainCRTStartupForYY_Thunks函数,虽然理论上Vista(包含)以上就不用修正了,但是为了做到体验统一
|
||||
// 避免Vista模式设置 DllMainCRTStartupForYY_Thunks 就发生链接失败问题。
|
||||
// 这个函数的存在意义是修复Windows XP系统显式加载的DLL里无法使用TLS问题。
|
||||
extern "C" BOOL WINAPI DllMainCRTStartupForYY_Thunks(
|
||||
HINSTANCE const _hInstance,
|
||||
DWORD const _uReason,
|
||||
LPVOID const _pReserved
|
||||
)
|
||||
{
|
||||
const auto _pfnDllMainCRTStartup = __pfnDllMainCRTStartupForYY_Thunks ? __pfnDllMainCRTStartupForYY_Thunks : &_DllMainCRTStartup;
|
||||
|
||||
#if YY_Thunks_Support_Version < NTDDI_WIN6
|
||||
__declspec(allocate(".CRT$XLB")) static const PIMAGE_TLS_CALLBACK s_FirstCallback = FirstCallback;
|
||||
__foreinclude(s_FirstCallback);
|
||||
__foreinclude(_tls_used);
|
||||
if (internal::GetSystemVersion() < internal::MakeVersion(6, 0))
|
||||
{
|
||||
// Vista开始已经可以动态的处理TLS问题了,所以这里只针对老系统处理。
|
||||
switch (_uReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
if (g_TlsMode == TlsMode::None)
|
||||
{
|
||||
g_TlsMode = TlsMode::ByDllMainCRTStartupForYY_Thunks;
|
||||
}
|
||||
_tls_index_old = _tls_index;
|
||||
if (_tls_index == 0 && g_TlsMode == TlsMode::ByDllMainCRTStartupForYY_Thunks)
|
||||
{
|
||||
CreateTlsIndex();
|
||||
return _pfnDllMainCRTStartup(_hInstance, _uReason, _pReserved);
|
||||
}
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
if (_tls_index_old == 0 && g_TlsMode == TlsMode::ByDllMainCRTStartupForYY_Thunks)
|
||||
{
|
||||
AllocTlsData();
|
||||
CallTlsCallback(_hInstance, _uReason);
|
||||
return _pfnDllMainCRTStartup(_hInstance, _uReason, _pReserved);
|
||||
}
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
if (_tls_index_old == 0 && g_TlsMode == TlsMode::ByDllMainCRTStartupForYY_Thunks)
|
||||
{
|
||||
CallTlsCallback(_hInstance, _uReason);
|
||||
auto _bRet = _pfnDllMainCRTStartup(_hInstance, _uReason, _pReserved);
|
||||
FreeTlsData();
|
||||
return _bRet;
|
||||
}
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
#if (YY_Thunks_Support_Version < NTDDI_WINXP)
|
||||
__YY_Thunks_Process_Terminating = _pReserved != nullptr;
|
||||
#endif
|
||||
if (_tls_index_old == 0 && g_TlsMode == TlsMode::ByDllMainCRTStartupForYY_Thunks)
|
||||
{
|
||||
CallTlsCallback(_hInstance, _uReason);
|
||||
auto _bRet = _pfnDllMainCRTStartup(_hInstance, _uReason, _pReserved);
|
||||
FreeTlsIndex();
|
||||
return _bRet;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return _pfnDllMainCRTStartup(_hInstance, _uReason, _pReserved);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -174,11 +174,11 @@ static __forceinline unsigned __int64 __fastcall __crt_rotate_pointer_value(unsi
|
||||
#ifdef _WIN64
|
||||
#define __foreinclude(p) \
|
||||
__pragma(warning(suppress:6031)) \
|
||||
_bittest64(reinterpret_cast<LONG_PTR*>(&p), 0)
|
||||
_bittest64((LONG_PTR*)(&p), 0)
|
||||
#else
|
||||
#define __foreinclude(p) \
|
||||
__pragma(warning(suppress:6031)) \
|
||||
_bittest(reinterpret_cast<LONG_PTR*>(&p), 0)
|
||||
_bittest((LONG_PTR*)(&p), 0)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<EntryPointSymbol>DllMainCRTStartupForYY_Thunks</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
@@ -128,6 +129,7 @@
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<EntryPointSymbol>DllMainCRTStartupForYY_Thunks</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -146,6 +148,7 @@
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<EntryPointSymbol>DllMainCRTStartupForYY_Thunks</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -168,6 +171,7 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<EntryPointSymbol>DllMainCRTStartupForYY_Thunks</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@@ -222,6 +226,7 @@
|
||||
<ClInclude Include="..\Thunks\d3d11.hpp" />
|
||||
<ClInclude Include="..\Thunks\d3d9.hpp" />
|
||||
<ClInclude Include="..\Thunks\dbghelp.hpp" />
|
||||
<ClInclude Include="..\Thunks\DllMainCRTStartup.hpp" />
|
||||
<ClInclude Include="..\Thunks\dwmapi.hpp" />
|
||||
<ClInclude Include="..\Thunks\dwrite.hpp" />
|
||||
<ClInclude Include="..\Thunks\dxgi.hpp" />
|
||||
|
||||
@@ -308,6 +308,9 @@
|
||||
<ClInclude Include="..\Thunks\dbghelp.hpp">
|
||||
<Filter>Thunks</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Thunks\DllMainCRTStartup.hpp">
|
||||
<Filter>Thunks</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\def\x86\PSAPI2Kernel32.def">
|
||||
|
||||
@@ -2,3 +2,5 @@
|
||||
const int __YY_Thunks_Process_Terminating;
|
||||
|
||||
const void* __acrt_atexit_table;
|
||||
|
||||
const void* __pfnDllMainCRTStartupForYY_Thunks;
|
||||
|
||||
Reference in New Issue
Block a user