Index: trunk/src/kWorker/Makefile.kmk
===================================================================
--- trunk/src/kWorker/Makefile.kmk	(revision 3041)
+++ trunk/src/kWorker/Makefile.kmk	(revision 3042)
@@ -153,4 +153,23 @@
 
 
+#
+# A couple of dummy DLLs we use for grabbing LDR TLS entries.
+#
+DLLS += kWorkerTls1K kWorkerTls64K kWorkerTls512K
+kWorkerTls1K_TEMPLATE   = BIN-STATIC-THREADED
+kWorkerTls1K_DEFS       = KWORKER_BASE=0x10000 TLS_SIZE=1024
+kWorkerTls1K_SOURCES    = kWorkerTlsXxxK.c
+kWorkerTls1K_LDFLAGS    = /Entry:DummyDllEntry
+
+kWorkerTls64K_TEMPLATE  = BIN-STATIC-THREADED
+kWorkerTls64K_DEFS      = KWORKER_BASE=0x10000 TLS_SIZE=65536
+kWorkerTls64K_SOURCES   = kWorkerTlsXxxK.c
+kWorkerTls64K_LDFLAGS   = /Entry:DummyDllEntry
+
+kWorkerTls512K_TEMPLATE = BIN-STATIC-THREADED
+kWorkerTls512K_DEFS     = KWORKER_BASE=0x10000 TLS_SIZE=524288
+kWorkerTls512K_SOURCES  = kWorkerTlsXxxK.c
+kWorkerTls512K_LDFLAGS  = /Entry:DummyDllEntry
+
 
 include $(KBUILD_PATH)/subfooter.kmk
Index: trunk/src/kWorker/kWorker.c
===================================================================
--- trunk/src/kWorker/kWorker.c	(revision 3041)
+++ trunk/src/kWorker/kWorker.c	(revision 3042)
@@ -293,4 +293,18 @@
                 KSIZE           cbToZero;
             } aQuickZeroChunks[3];
+
+            /** TLS index if one was allocated, otherwise KU32_MAX. */
+            KU32                idxTls;
+            /** Offset (RVA) of the TLS initialization data. */
+            KU32                offTlsInitData;
+            /** Number of bytes of TLS initialization data. */
+            KU32                cbTlsInitData;
+            /** Number of allocated bytes for TLS. */
+            KU32                cbTlsAlloc;
+            /** Number of TLS callbacks. */
+            KU32                cTlsCallbacks;
+            /** Offset (RVA) of the TLS callback table. */
+            KU32                offTlsCallbacks;
+
             /** Number of imported modules. */
             KSIZE               cImpMods;
@@ -893,4 +907,7 @@
 };
 
+/** Module pending TLS allocation. See kwLdrModuleCreateNonNativeSetupTls. */
+static PKWMODULE    g_pModPendingTlsAlloc = NULL;
+
 
 /** The file system cache. */
@@ -1023,4 +1040,5 @@
 static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWOUTPUTSTREAMBUF pLineBuf, const char *pchBuffer, KU32 cchToWrite);
 #endif
+static PPEB kwSandboxGetProcessEnvironmentBlock(void);
 
 
@@ -2002,4 +2020,176 @@
 
 /**
+ * Called from TLS allocation DLL during DLL_PROCESS_ATTACH.
+ *
+ * @param   hDll            The DLL handle.
+ * @param   idxTls          The allocated TLS index.
+ * @param   ppfnTlsCallback Pointer to the TLS callback table entry.
+ */
+__declspec(dllexport) void kwLdrTlsAllocationHook(void *hDll, ULONG idxTls, PIMAGE_TLS_CALLBACK *ppfnTlsCallback)
+{
+    /*
+     * Do the module initialization thing first.
+     */
+    PKWMODULE pMod = g_pModPendingTlsAlloc;
+    if (pMod)
+    {
+        PPEB        pPeb = kwSandboxGetProcessEnvironmentBlock();
+        LIST_ENTRY *pHead;
+        LIST_ENTRY *pCur;
+
+        pMod->u.Manual.idxTls = idxTls;
+        KWLDR_LOG(("kwLdrTlsAllocationHook: idxTls=%d (%#x) for %s\n", idxTls, idxTls, pMod->pszPath));
+
+        /*
+         * Try sabotage the DLL name so we can load this module again.
+         */
+        pHead = &pPeb->Ldr->InMemoryOrderModuleList;
+        for (pCur = pHead->Blink; pCur != pHead; pCur = pCur->Blink)
+        {
+            LDR_DATA_TABLE_ENTRY *pMte;
+            pMte = (LDR_DATA_TABLE_ENTRY *)((KUPTR)pCur - K_OFFSETOF(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks));
+            if (((KUPTR)pMte->DllBase & ~(KUPTR)31) == ((KUPTR)hDll & ~(KUPTR)31))
+            {
+                PUNICODE_STRING pStr = &pMte->FullDllName;
+                KSIZE off = pStr->Length / sizeof(pStr->Buffer[0]);
+                pStr->Buffer[--off]++;
+                pStr->Buffer[--off]++;
+                pStr->Buffer[--off]++;
+                KWLDR_LOG(("kwLdrTlsAllocationHook: patched the MTE (%p) for %p\n", pMte, hDll));
+                break;
+            }
+        }
+    }
+}
+
+
+/**
+ * Allocates and initializes TLS variables.
+ *
+ * @returns 0 on success, non-zero failure.
+ * @param   pMod                The module.
+ */
+static int kwLdrModuleCreateNonNativeSetupTls(PKWMODULE pMod)
+{
+    KU8                        *pbImg = (KU8 *)pMod->u.Manual.pbCopy;
+    IMAGE_NT_HEADERS const     *pNtHdrs;
+    IMAGE_DATA_DIRECTORY const *pTlsDir;
+
+    if (((PIMAGE_DOS_HEADER)pbImg)->e_magic == IMAGE_DOS_SIGNATURE)
+        pNtHdrs = (PIMAGE_NT_HEADERS)&pbImg[((PIMAGE_DOS_HEADER)pbImg)->e_lfanew];
+    else
+        pNtHdrs = (PIMAGE_NT_HEADERS)pbImg;
+    kHlpAssert(pNtHdrs->Signature == IMAGE_NT_SIGNATURE);
+
+    pTlsDir = &pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS];
+    if (pTlsDir->Size >= sizeof(IMAGE_TLS_DIRECTORY))
+    {
+        PIMAGE_TLS_DIRECTORY const  paEntries = (PIMAGE_TLS_DIRECTORY)&pbImg[pTlsDir->VirtualAddress];
+        KU32 const                  cEntries  = pTlsDir->Size / sizeof(IMAGE_TLS_DIRECTORY);
+        KU32                        iEntry;
+        KUPTR                       offIndex;
+        KUPTR                       offCallbacks;
+        KUPTR const                *puCallbacks;
+        KSIZE                       cbData;
+        const wchar_t              *pwszTlsDll;
+        HMODULE                     hmodTlsDll;
+
+        /*
+         * Check and log.
+         */
+        for (iEntry = 0; iEntry < cEntries; iEntry++)
+        {
+            KUPTR        offIndex     = (KUPTR)paEntries[iEntry].AddressOfIndex     - (KUPTR)pMod->u.Manual.pbLoad;
+            KUPTR        offCallbacks = (KUPTR)paEntries[iEntry].AddressOfCallBacks - (KUPTR)pMod->u.Manual.pbLoad;
+            KUPTR const *puCallbacks  = (KUPTR const *)&pbImg[offCallbacks];
+            KWLDR_LOG(("TLS DIR #%u: %#x-%#x idx=@%#x (%#x) callbacks=@%#x (%#x) cbZero=%#x flags=%#x\n",
+                       iEntry, paEntries[iEntry].StartAddressOfRawData, paEntries[iEntry].EndAddressOfRawData,
+                       paEntries[iEntry].AddressOfIndex, offIndex, paEntries[iEntry].AddressOfCallBacks, offCallbacks,
+                       paEntries[iEntry].SizeOfZeroFill, paEntries[iEntry].Characteristics));
+
+            if (offIndex >= pMod->cbImage)
+            {
+                kwErrPrintf("TLS entry #%u in %s has an invalid index address: %p, RVA %p, image size %#x\n",
+                            iEntry, pMod->pszPath, paEntries[iEntry].AddressOfIndex, offIndex, pMod->cbImage);
+                return -1;
+            }
+            if (offCallbacks >= pMod->cbImage)
+            {
+                kwErrPrintf("TLS entry #%u in %s has an invalid callbacks address: %p, RVA %p, image size %#x\n",
+                            iEntry, pMod->pszPath, paEntries[iEntry].AddressOfCallBacks, offCallbacks, pMod->cbImage);
+                return -1;
+            }
+            while (*puCallbacks != 0)
+            {
+                KWLDR_LOG(("TLS DIR #%u:   callback %p, RVA %#x\n",
+                            iEntry, *puCallbacks, *puCallbacks - (KUPTR)pMod->u.Manual.pbLoad));
+                puCallbacks++;
+            }
+            if (paEntries[iEntry].Characteristics > IMAGE_SCN_ALIGN_16BYTES)
+            {
+                kwErrPrintf("TLS entry #%u in %s has an unsupported alignment restriction: %#x\n",
+                            iEntry, pMod->pszPath, paEntries[iEntry].Characteristics);
+                return -1;
+            }
+        }
+
+        if (cEntries > 1)
+        {
+            kwErrPrintf("More than one TLS directory entry in %s: %u\n", pMod->pszPath, cEntries);
+            return -1;
+        }
+
+        /*
+         * Make the allocation by loading a new instance of one of the TLS dlls.
+         * The DLL will make a call to
+         */
+        offIndex     = (KUPTR)paEntries[0].AddressOfIndex     - (KUPTR)pMod->u.Manual.pbLoad;
+        offCallbacks = (KUPTR)paEntries[0].AddressOfCallBacks - (KUPTR)pMod->u.Manual.pbLoad;
+        puCallbacks  = (KUPTR const *)&pbImg[offCallbacks];
+        cbData = paEntries[0].SizeOfZeroFill + (paEntries[0].EndAddressOfRawData - paEntries[0].StartAddressOfRawData);
+        if (cbData <= 1024)
+            pwszTlsDll = L"kWorkerTls1K.dll";
+        else if (cbData <= 65536)
+            pwszTlsDll = L"kWorkerTls64K.dll";
+        else if (cbData <= 524288)
+            pwszTlsDll = L"kWorkerTls512K.dll";
+        else
+        {
+            kwErrPrintf("TLS data size in %s is too big: %u (%#p), max 512KB\n", pMod->pszPath, (unsigned)cbData, cbData);
+            return -1;
+        }
+
+        pMod->u.Manual.idxTls         = KU32_MAX;
+        pMod->u.Manual.offTlsInitData = (KU32)((KUPTR)paEntries[0].StartAddressOfRawData - (KUPTR)pMod->u.Manual.pbLoad);
+        pMod->u.Manual.cbTlsInitData  = (KU32)(paEntries[0].EndAddressOfRawData - paEntries[0].StartAddressOfRawData);
+        pMod->u.Manual.cbTlsAlloc     = (KU32)cbData;
+        pMod->u.Manual.cTlsCallbacks  = 0;
+        while (puCallbacks[pMod->u.Manual.cTlsCallbacks] != 0)
+            pMod->u.Manual.cTlsCallbacks++;
+        pMod->u.Manual.offTlsCallbacks = pMod->u.Manual.cTlsCallbacks ? (KU32)offCallbacks : KU32_MAX;
+
+        g_pModPendingTlsAlloc = pMod;
+        hmodTlsDll = LoadLibraryExW(pwszTlsDll, NULL /*hFile*/, 0);
+        g_pModPendingTlsAlloc = NULL;
+        if (hmodTlsDll == NULL)
+        {
+            kwErrPrintf("TLS allocation failed for '%s': LoadLibraryExW(%ls) -> %u\n", pMod->pszPath, pwszTlsDll, GetLastError());
+            return -1;
+        }
+        if (pMod->u.Manual.idxTls == KU32_MAX)
+        {
+            kwErrPrintf("TLS allocation failed for '%s': idxTls = KU32_MAX\n", pMod->pszPath, GetLastError());
+            return -1;
+        }
+
+        *(KU32 *)&pMod->u.Manual.pbCopy[offIndex] = pMod->u.Manual.idxTls;
+        KWLDR_LOG(("kwLdrModuleCreateNonNativeSetupTls: idxTls=%d hmodTlsDll=%p (%ls) cbData=%#x\n",
+                   pMod->u.Manual.idxTls, hmodTlsDll, pwszTlsDll, cbData));
+    }
+    return 0;
+}
+
+
+/**
  * Creates a module using the our own loader.
  *
@@ -2069,8 +2259,14 @@
                     pMod->u.Manual.fRegisteredFunctionTable = K_FALSE;
 #endif
-                    pMod->u.Manual.fUseLdBuf = K_FALSE;
-                    pMod->u.Manual.fCanDoQuick = K_FALSE;
+                    pMod->u.Manual.fUseLdBuf        = K_FALSE;
+                    pMod->u.Manual.fCanDoQuick      = K_FALSE;
                     pMod->u.Manual.cQuickZeroChunks = 0;
                     pMod->u.Manual.cQuickCopyChunks = 0;
+                    pMod->u.Manual.idxTls           = KU32_MAX;
+                    pMod->u.Manual.offTlsInitData   = KU32_MAX;
+                    pMod->u.Manual.cbTlsInitData    = 0;
+                    pMod->u.Manual.cbTlsAlloc       = 0;
+                    pMod->u.Manual.cTlsCallbacks    = 0;
+                    pMod->u.Manual.offTlsCallbacks  = 0;
                     pMod->pszPath       = (char *)kHlpMemCopy(&pMod->u.Manual.apImpMods[cImports + 1], pszPath, cbPath);
                     pMod->pwszPath      = (wchar_t *)(pMod->pszPath + cbPath + (cbPath & 1));
@@ -2106,4 +2302,5 @@
                             KW_LOG(("New module: %p LB %#010x %s (kLdr)\n",
                                     pMod->u.Manual.pbLoad, pMod->cbImage, pMod->pszPath));
+                            KW_LOG(("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pbLoad));
                             kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pbLoad);
 
@@ -2157,13 +2354,19 @@
                                     kwLdrModuleCreateNonNativeSetupQuickZeroAndCopy(pMod);
 
-                                    /*
-                                     * Final finish.
-                                     */
-                                    pMod->u.Manual.pvBits = pMod->u.Manual.pbCopy;
-                                    pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
-                                    g_cModules++;
-                                    g_cNonNativeModules++;
-                                    return pMod;
+                                    rc = kwLdrModuleCreateNonNativeSetupTls(pMod);
+                                    if (rc == 0)
+                                    {
+                                        /*
+                                         * Final finish.
+                                         */
+                                        pMod->u.Manual.pvBits = pMod->u.Manual.pbCopy;
+                                        pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
+                                        g_cModules++;
+                                        g_cNonNativeModules++;
+                                        return pMod;
+                                    }
                                 }
+                                else
+                                    kwErrPrintf("kLdrModGetBits failed for %s: %#x (%d)\n", pszPath, rc, rc);
                             }
 
@@ -2232,4 +2435,5 @@
 
     //printf("iImport=%u (%s) %*.*s rc=%d\n", iImport, &pImpMod->pszPath[pImpMod->offFilename], cchSymbol, cchSymbol, pchSymbol, rc);
+    KW_LOG(("iImport=%u (%s) %*.*s rc=%d\n", iImport, &pImpMod->pszPath[pImpMod->offFilename], cchSymbol, cchSymbol, pchSymbol, rc));
     return rc;
 
@@ -2523,4 +2727,48 @@
 
 /**
+ * Does the TLS memory initialization for a module on the current thread.
+ *
+ * @returns 0 on success, error on failure.
+ * @param   pMod                The module.
+ */
+static int kwLdrCallTlsAllocateAndInit(PKWMODULE pMod)
+{
+    if (pMod->u.Manual.idxTls != KU32_MAX)
+    {
+        PTEB pTeb = NtCurrentTeb();
+        void **ppvTls = *(void ***)( (KUPTR)pTeb + (sizeof(void *) == 4 ? 0x2c : 0x58) );
+        KU8   *pbData = (KU8 *)ppvTls[pMod->u.Manual.idxTls];
+        KWLDR_LOG(("%s: TLS: Initializing %#x (%#x), idxTls=%d\n",
+                   pMod->pszPath, pbData, pMod->u.Manual.cbTlsAlloc, pMod->u.Manual.cbTlsInitData, pMod->u.Manual.idxTls));
+        if (pMod->u.Manual.cbTlsInitData < pMod->u.Manual.cbTlsAlloc)
+            kHlpMemSet(&pbData[pMod->u.Manual.cbTlsInitData], 0, pMod->u.Manual.cbTlsAlloc);
+        if (pMod->u.Manual.cbTlsInitData)
+            kHlpMemCopy(pbData, &pMod->u.Manual.pbCopy[pMod->u.Manual.offTlsInitData], pMod->u.Manual.cbTlsInitData);
+    }
+    return 0;
+}
+
+
+/**
+ * Does the TLS callbacks for a module.
+ *
+ * @param   pMod                The module.
+ * @param   dwReason            The callback reason.
+ */
+static void kwLdrCallTlsCallbacks(PKWMODULE pMod, DWORD dwReason)
+{
+    if (pMod->u.Manual.cTlsCallbacks)
+    {
+        PIMAGE_TLS_CALLBACK *pCallback = (PIMAGE_TLS_CALLBACK *)&pMod->u.Manual.pbLoad[pMod->u.Manual.offTlsCallbacks];
+        do
+        {
+            KWLDR_LOG(("%s: Calling TLS callback %p(%p,%#x,0)\n", pMod->pszPath, *pCallback, pMod->hOurMod, dwReason));
+            (*pCallback)(pMod->hOurMod, dwReason, 0);
+        } while (*++pCallback);
+    }
+}
+
+
+/**
  * Does module initialization starting at @a pMod.
  *
@@ -2536,4 +2784,7 @@
     if (!pMod->fNative)
     {
+        KWLDR_LOG(("kwLdrModuleInitTree: enmState=%#x idxTls=%u %s\n",
+                   pMod->u.Manual.enmState, pMod->u.Manual.idxTls, pMod->pszPath));
+
         /*
          * Need to copy bits?
@@ -2607,4 +2858,5 @@
 #endif
 
+
         if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_INIT)
         {
@@ -2623,4 +2875,12 @@
             }
 
+            /* Do TLS allocations for module init? */
+            rc = kwLdrCallTlsAllocateAndInit(pMod);
+            if (rc != 0)
+                return rc;
+            if (pMod->u.Manual.cTlsCallbacks > 0)
+                kwLdrCallTlsCallbacks(pMod, DLL_PROCESS_ATTACH);
+
+            /* Finally call the entry point. */
             rc = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pbLoad, (KUPTR)pMod->hOurMod);
             if (rc == 0)
@@ -2892,7 +3152,16 @@
     /*
      * We associate the tools instances with the file system objects.
+     *
+     * We'd like to do the lookup without invaliding the volatile parts of the
+     * cache, thus the double lookup here.  The cache gets invalidate later on.
      */
     KFSLOOKUPERROR  enmError;
     PKFSOBJ         pToolFsObj = kFsCacheLookupA(g_pFsCache, pszExe, &enmError);
+    if (   !pToolFsObj
+        || pToolFsObj->bObjType != KFSOBJ_TYPE_FILE)
+    {
+        kFsCacheInvalidateCustomBoth(g_pFsCache);
+        pToolFsObj = kFsCacheLookupA(g_pFsCache, pszExe, &enmError);
+    }
     if (pToolFsObj)
     {
@@ -2913,4 +3182,6 @@
         kFsCacheObjRelease(g_pFsCache, pToolFsObj);
     }
+    else
+        pToolFsObj = kFsCacheLookupA(g_pFsCache, pszExe, &enmError);
     return NULL;
 }
@@ -3474,4 +3745,40 @@
 
 
+/** _beginthreadex - create a new thread, msvcr120.dll hack for c2.dll. */
+static uintptr_t __cdecl kwSandbox_msvcr120__beginthreadex(void *pvSecAttr, unsigned cbStack,
+                                                           unsigned (__stdcall *pfnThreadProc)(void *), void *pvUser,
+                                                           unsigned fCreate, unsigned *pidThread)
+{
+    /*
+     * The VC++ 12 (VS 2013) compiler pass two is now threaded.  Let it do
+     * whatever it needs to.
+     */
+    KW_LOG(("kwSandbox_msvcr120__beginthreadex: pvSecAttr=%p (inh=%d) cbStack=%#x pfnThreadProc=%p pvUser=%p fCreate=%#x pidThread=%p\n",
+            pvSecAttr, pvSecAttr ? ((LPSECURITY_ATTRIBUTES)pvSecAttr)->bInheritHandle : 0, cbStack,
+            pfnThreadProc, pvUser, fCreate, pidThread));
+    if (g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
+    {
+        uintptr_t rcRet;
+        static uintptr_t (__cdecl *s_pfnReal)(void *, unsigned , unsigned (__stdcall *)(void *), void *, unsigned , unsigned *);
+        if (!s_pfnReal)
+        {
+            *(FARPROC *)&s_pfnReal = GetProcAddress(GetModuleHandleA("msvcr120.dll"), "_beginthreadex");
+            if (!s_pfnReal)
+            {
+                kwErrPrintf("kwSandbox_msvcr120__beginthreadex: Failed to resolve _beginthreadex in msvcr120.dll!\n");
+                __debugbreak();
+            }
+        }
+        rcRet = s_pfnReal(pvSecAttr, cbStack, pfnThreadProc, pvUser, fCreate, pidThread);
+        KW_LOG(("kwSandbox_msvcr120__beginthreadex: returns %p *pidThread=%#x\n", rcRet, pidThread ? *pidThread : -1));
+        return rcRet;
+    }
+
+    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
+    KWFS_TODO();
+    return 0;
+}
+
+
 /** _beginthreadex - create a new thread. */
 static uintptr_t __cdecl kwSandbox_msvcrt__beginthreadex(void *pvSecAttr, unsigned cbStack,
@@ -4340,5 +4647,6 @@
      * Deal with a couple of extremely unlikely special cases right away.
      */
-    if (   !(fFlags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)
+    if (   (   !(fFlags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)
+            || (fFlags & LOAD_LIBRARY_AS_IMAGE_RESOURCE))
         && (hFile == NULL || hFile == INVALID_HANDLE_VALUE) )
     { /* likely */ }
@@ -4390,4 +4698,5 @@
     if (fFlags & (  DONT_RESOLVE_DLL_REFERENCES
                   | LOAD_LIBRARY_AS_DATAFILE
+                  | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
                   | LOAD_LIBRARY_AS_IMAGE_RESOURCE) )
         return kwSandbox_Kernel32_LoadLibraryExA_Resource(pDynLoad, fFlags);
@@ -4412,5 +4721,5 @@
             pMod = NULL;
     }
-    if (pMod)
+    if (pMod && pMod != (PKWMODULE)~(KUPTR)0)
     {
         /* Enter it into the tool module table and dynamic link request cache. */
@@ -4440,7 +4749,36 @@
         KWFS_TODO();
         kHlpFree(pDynLoad);
-        SetLastError(ERROR_MOD_NOT_FOUND);
+        SetLastError(pMod ? ERROR_BAD_EXE_FORMAT : ERROR_MOD_NOT_FOUND);
     }
     return NULL;
+}
+
+
+/** Kernel32 - LoadLibraryExA() for native overloads */
+static HMODULE WINAPI kwSandbox_Kernel32_Native_LoadLibraryExA(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags)
+{
+    char szTmp[512];
+    KWLDR_LOG(("kwSandbox_Kernel32_Native_LoadLibraryExA(%s, %p, %#x)\n", pszFilename, hFile, fFlags));
+
+    /*
+     * We may have to help resolved unqualified DLLs living in the executable directory.
+     */
+    if (kHlpIsFilenameOnly(pszFilename))
+    {
+        KSIZE cchFilename = kHlpStrLen(pszFilename);
+        KSIZE cchExePath  = g_Sandbox.pTool->u.Sandboxed.pExe->offFilename;
+        if (cchExePath + cchFilename + 1 <= sizeof(szTmp))
+        {
+            kHlpMemCopy(szTmp, g_Sandbox.pTool->u.Sandboxed.pExe->pszPath, cchExePath);
+            kHlpMemCopy(&szTmp[cchExePath], pszFilename, cchFilename + 1);
+            if (kwFsPathExists(szTmp))
+            {
+                KWLDR_LOG(("kwSandbox_Kernel32_Native_LoadLibraryExA: %s -> %s\n", pszFilename, szTmp));
+                pszFilename = szTmp;
+            }
+        }
+    }
+
+    return LoadLibraryExA(pszFilename, hFile, fFlags);
 }
 
@@ -4493,4 +4831,5 @@
     KSIZE i;
     KSIZE cchModule;
+    PKWDYNLOAD pDynLoad;
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
@@ -4514,5 +4853,25 @@
         }
 
+    /*
+     * Modules we've dynamically loaded.
+     */
+    for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad; pDynLoad = pDynLoad->pNext)
+        if (   pDynLoad->pMod
+            && (   stricmp(pDynLoad->pMod->pszPath, pszModule) == 0
+                || stricmp(&pDynLoad->pMod->pszPath[pDynLoad->pMod->offFilename], pszModule) == 0) )
+        {
+            if (   pDynLoad->pMod->fNative
+                || pDynLoad->pMod->u.Manual.enmState == KWMODSTATE_READY)
+            {
+                KW_LOG(("kwSandbox_Kernel32_GetModuleHandleA(%s,,) -> %p [dynload]\n", pszModule, pDynLoad->hmod));
+                return pDynLoad->hmod;
+            }
+            SetLastError(ERROR_MOD_NOT_FOUND);
+            return NULL;
+        }
+
+    kwErrPrintf("pszModule=%s\n", pszModule);
     KWFS_TODO();
+    SetLastError(ERROR_MOD_NOT_FOUND);
     return NULL;
 }
@@ -4524,4 +4883,5 @@
     KSIZE i;
     KSIZE cwcModule;
+    PKWDYNLOAD pDynLoad;
     kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
 
@@ -4545,5 +4905,25 @@
         }
 
+    /*
+     * Modules we've dynamically loaded.
+     */
+    for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad; pDynLoad = pDynLoad->pNext)
+        if (   pDynLoad->pMod
+            && (   _wcsicmp(pDynLoad->pMod->pwszPath, pwszModule) == 0
+                || _wcsicmp(&pDynLoad->pMod->pwszPath[pDynLoad->pMod->offFilename], pwszModule) == 0) ) /** @todo wrong offset */
+        {
+            if (   pDynLoad->pMod->fNative
+                || pDynLoad->pMod->u.Manual.enmState == KWMODSTATE_READY)
+            {
+                KW_LOG(("kwSandbox_Kernel32_GetModuleHandleW(%ls,,) -> %p [dynload]\n", pwszModule, pDynLoad->hmod));
+                return pDynLoad->hmod;
+            }
+            SetLastError(ERROR_MOD_NOT_FOUND);
+            return NULL;
+        }
+
+    kwErrPrintf("pwszModule=%ls\n", pwszModule);
     KWFS_TODO();
+    SetLastError(ERROR_MOD_NOT_FOUND);
     return NULL;
 }
@@ -8760,4 +9140,15 @@
 }
 
+
+/** CRT - memset   */
+static void * __cdecl kwSandbox_msvcrt_memset(void *pvDst, int bFiller, size_t cb)
+{
+    KU8       *pbDst = (KU8 *)pvDst;
+    KSIZE      cbLeft = cb;
+    while (cbLeft-- > 0)
+        *pbDst++ = bFiller;
+    return pvDst;
+}
+
 #endif /* NDEBUG */
 
@@ -8882,4 +9273,5 @@
     { TUPLE("_beginthread"),                NULL,       (KUPTR)kwSandbox_msvcrt__beginthread },
     { TUPLE("_beginthreadex"),              NULL,       (KUPTR)kwSandbox_msvcrt__beginthreadex },
+    { TUPLE("_beginthreadex"),          "msvcr120.dll", (KUPTR)kwSandbox_msvcr120__beginthreadex }, /* higher priority last */
 
     { TUPLE("__argc"),                      NULL,       (KUPTR)&g_Sandbox.cArgs },
@@ -8921,4 +9313,5 @@
 #ifndef NDEBUG
     { TUPLE("memcpy"),                      NULL,       (KUPTR)kwSandbox_msvcrt_memcpy },
+    { TUPLE("memset"),                      NULL,       (KUPTR)kwSandbox_msvcrt_memset },
 #endif
 };
@@ -8970,4 +9363,5 @@
 #endif
     { TUPLE("SetConsoleCtrlHandler"),       NULL,       (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler },
+    { TUPLE("LoadLibraryExA"),              NULL,       (KUPTR)kwSandbox_Kernel32_Native_LoadLibraryExA },
 
     { TUPLE("WriteConsoleA"),               NULL,       (KUPTR)kwSandbox_Kernel32_WriteConsoleA },
@@ -9888,5 +10282,8 @@
     }
     else
+    {
+        kwErrPrintf("kwToolLookup(%s) -> NULL\n", pszExecutable);
         rcExit = 42 + 1;
+    }
     return rcExit;
 }
Index: trunk/src/kWorker/kWorkerTlsXxxK.c
===================================================================
--- trunk/src/kWorker/kWorkerTlsXxxK.c	(revision 3042)
+++ trunk/src/kWorker/kWorkerTlsXxxK.c	(revision 3042)
@@ -0,0 +1,110 @@
+/* $Id$ */
+/** @file
+ * kWorkerTlsXxxK - Loader TLS allocation hack DLL.
+ */
+
+/*
+ * Copyright (c) 2017 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <windows.h>
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+typedef void KWLDRTLSALLOCATIONHOOK(void *hDll, ULONG idxTls, PIMAGE_TLS_CALLBACK *ppfnTlsCallback);
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+__declspec(dllexport) void __stdcall DummyTlsCallback(void *hDll, DWORD dwReason, void *pvContext);
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+/** The TLS pointer array. The 2nd entry is NULL and serve to terminate the array.
+ * The first entry can be used by kWorker if it needs to. */
+__declspec(dllexport) PIMAGE_TLS_CALLBACK g_apfnTlsCallbacks[2] = { DummyTlsCallback, NULL };
+
+/**
+ * The TLS index.
+ */
+__declspec(dllexport) ULONG               g_idxTls              = ~(ULONG)0;
+
+/**
+ * Initialization data.
+ */
+static char const g_abDummy[TLS_SIZE] = {0x42};
+
+/**
+ * The TLS directory entry.  Not possible to get more than one from the linker
+ * and probably also the loader doesn't want more than one anyway.
+ */
+#pragma section(".rdata$T", long, read)
+__declspec(allocate(".rdata$T")) const IMAGE_TLS_DIRECTORY _tls_used =
+{
+    (ULONG_PTR)&g_abDummy,
+    (ULONG_PTR)&g_abDummy + sizeof(g_abDummy),
+    (ULONG_PTR)&g_idxTls,
+    (ULONG_PTR)&g_apfnTlsCallbacks,
+    0, /* This SizeOfZeroFill bugger doesn't work on w10/amd64 from what I can tell! */
+    IMAGE_SCN_ALIGN_32BYTES
+};
+
+
+/*
+ * This is just a dummy TLS callback function.
+ * We'll be replacing g_apfnTlsCallbacks[0] from kWorker.c after loading it.
+ *
+ * Note! W10 doesn't seem to want to process the TLS directory if the DLL
+ *       doesn't have any imports (to snap).
+ */
+__declspec(dllexport) void __stdcall DummyTlsCallback(void *hDll, DWORD dwReason, void *pvContext)
+{
+    (void)hDll; (void)dwReason; (void)pvContext;
+    if (dwReason == DLL_PROCESS_ATTACH)
+    {
+        HMODULE hModExe = (HMODULE)(ULONG_PTR)KWORKER_BASE;
+        KWLDRTLSALLOCATIONHOOK *pfnHook = (KWLDRTLSALLOCATIONHOOK *)GetProcAddress(hModExe, "kwLdrTlsAllocationHook");
+        if (pfnHook)
+        {
+            pfnHook(hDll, g_idxTls, &g_apfnTlsCallbacks[0]);
+            return;
+        }
+        __debugbreak();
+    }
+}
+
+
+/*
+ * Dummy DLL entry point to avoid dragging in unnecessary CRT stuff. kWorkerTls1K!_tls_index
+ */
+BOOL __stdcall DummyDllEntry(void *hDll, DWORD dwReason, void *pvContext)
+{
+    (void)hDll; (void)dwReason; (void)pvContext;
+    return TRUE;
+}
+
