From 0688ed9cce8c4a5cb0e27e2e2c543cbdae57dad8 Mon Sep 17 00:00:00 2001 From: Rainer Schuetze Date: Wed, 1 Nov 2017 10:17:15 +0100 Subject: [PATCH 1/4] add tool to build a simple replacement for the VC runtime and the Windows SDK using the preinstalled MSVCRT.DLL and import libraries generated from MinGW definition files. --- winsdk/buildsdk.d | 184 ++++++++++++++++++++++++++++++++++++++++++ winsdk/msvcrt_abs.asm | 8 ++ winsdk/msvcrt_data.c | 58 +++++++++++++ winsdk/msvcrt_stub.c | 110 +++++++++++++++++++++++++ 4 files changed, 360 insertions(+) create mode 100644 winsdk/buildsdk.d create mode 100644 winsdk/msvcrt_abs.asm create mode 100644 winsdk/msvcrt_data.c create mode 100644 winsdk/msvcrt_stub.c diff --git a/winsdk/buildsdk.d b/winsdk/buildsdk.d new file mode 100644 index 0000000000..b7fedb20b1 --- /dev/null +++ b/winsdk/buildsdk.d @@ -0,0 +1,184 @@ +// +// Convert MingGW definition files to COFF import librries +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// usage: buildsdk [x86|x64] [def-folder] [output-folder] [msvcrt.def.in] +// +// Source files extracted from the MinGW reositories +// +// def-folder: https://sourceforge.net/p/mingw/mingw-org-wsl/ci/5.0-active/tree/w32api/lib/ +// msvcrt.def.in: https://sourceforge.net/p/mingw/mingw-org-wsl/ci/5.0-active/tree/mingwrt/msvcrt-xref/msvcrt.def.in +// +// assumes VC tools cl,link,lib and ml installed and found through path +// and configured to the appropriate architecture +// + +import std.file; +import std.regex; +import std.string; +import std.stdio; +import std.path; +import std.process; +import std.algorithm; + +version = verbose; + +void runShell(string cmd) +{ + version(verbose) + writeln(cmd); + auto rc = executeShell(cmd); + if (rc.status) + { + writeln("'", cmd, "' failed with status ", rc.status); + writeln(rc.output); + throw new Exception("'" ~ cmd ~ "' failed"); + } +} + +// x86: the exported symbols have stdcall mangling (including trailing @n) +// but the internal names of the platform DLLs have names with @n stripped off +// lib /DEF doesn't support renaming symbols so we have to go through compiling +// a C file with the symbols and building a DLL with renamed exports to get +// the appropriate import library +// +// x64: strip any @ from the symbol names +bool def2implib(bool x64, string f, string dir) +{ + static auto re = regex(r"@?([a-zA-Z0-9_]+)(@[0-9]*)"); + char[] content = cast(char[])std.file.read(f); + auto pos = content.indexOf("EXPORTS"); + if (pos < 0) + return false; + + char[] def = content[0..pos]; + char[] csrc; + bool[string] written; + auto lines = content[pos..$].splitLines; + foreach(line; lines) + { + line = line.strip; + if (line.length == 0 || line[0] == ';') + continue; + const(char)[] sym; + char[] cline; + auto m = matchFirst(line, re); + if (m) + { + if (x64) + def ~= m[1] ~ "\n"; + else + def ~= m[0] ~ "=" ~ m[1] ~ "\n"; + sym = m[1]; + cline = "void " ~ m[1] ~ "() {}\n"; + } + else + { + def ~= line ~ "\n"; + if (line.endsWith(" DATA")) + { + sym = strip(line[0..$-5]); + cline = "int " ~ sym ~ ";\n"; + } + else + { + auto idx = line.indexOf('='); + if (idx > 0) + sym = line[idx+1 .. $].strip; + else + sym = line; + cline = "void " ~ sym ~ "() {}\n"; + } + } + if(sym.length && sym !in written) + { + csrc ~= cline; + written[sym.idup] = true; + } + } + string base = stripExtension(baseName(f)); + string dirbase = dir ~ base; + std.file.write(dirbase ~ ".def", def); + std.file.write(dirbase ~ ".c", csrc); + + runShell("cl /c /Fo" ~ dirbase ~ ".obj " ~ dirbase ~ ".c"); + runShell("link /NOD /NOENTRY /DLL " ~ dirbase ~ ".obj /out:" ~ dirbase ~ ".dll /def:" ~ dirbase ~ ".def"); + + // cleanup + std.file.remove(dirbase ~ ".def"); + std.file.remove(dirbase ~ ".c"); + std.file.remove(dirbase ~ ".obj"); + std.file.remove(dirbase ~ ".dll"); + std.file.remove(dirbase ~ ".exp"); + return true; +} + +void buildLibs(bool x64, string defdir, string dir) +{ + mkdirRecurse(dir ~ "ddk"); + + //goto LnoDef; + foreach(f; std.file.dirEntries("def", SpanMode.shallow)) + if (extension(f).toLower == ".def") + def2implib(x64, f, dir); + foreach(f; std.file.dirEntries("def/directx", SpanMode.shallow)) + if (extension(f).toLower == ".def") + def2implib(x64, f, dir); + + foreach(f; std.file.dirEntries("def/ddk", SpanMode.shallow)) + if (extension(f).toLower == ".def") + def2implib(x64, f, dir ~ "ddk/"); +} + +void buildMsvcrt(bool x64, string dir, string msvcdef) +{ + string arch = x64 ? "x64" : "x86"; + string ml = x64 ? "ml64" : "ml"; + string lib = "lib /MACHINE:" ~ arch ~ " "; + string msvcrtlib = "msvcrt51.lib"; + + // build msvcrt.lib for WinXP + runShell("cl /EP -D__MSVCRT_VERSION__=0x0501UL -D__DLLNAME__=msvcrt " ~ msvcdef ~ " >" ~ dir ~ "msvcrt.def"); + runShell(lib ~ "/OUT:" ~ dir ~ msvcrtlib ~ " /DEF:" ~ dir ~ "msvcrt.def"); // no translation necessary + runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_stub0.obj /D_APPTYPE=0 msvcrt_stub.c"); + runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_stub1.obj /D_APPTYPE=1 msvcrt_stub.c"); + runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_stub2.obj /D_APPTYPE=2 msvcrt_stub.c"); + runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_data.obj msvcrt_data.c"); + runShell(ml ~ " /c /Fo" ~ dir ~ "msvcrt_abs.obj msvcrt_abs.asm"); + auto files = ["msvcrt_abs.obj", "msvcrt_stub0.obj", "msvcrt_stub1.obj", "msvcrt_stub2.obj", "msvcrt_data.obj" ]; + auto objs = files.map!(a => dir ~ a).join(" "); + runShell(lib ~ dir ~ msvcrtlib ~ " " ~ objs); + + // create empty oldnames.lib (expected by dmd) + std.file.write(dir ~ "empty.c", ""); + runShell("cl /c /Zl /Fo" ~ dir ~ "oldnames.obj " ~ dir ~ "empty.c"); + runShell(lib ~ "/OUT:" ~ dir ~ "oldnames.lib " ~ dir ~ "oldnames.obj"); + + // create empty uuid.lib (expected by dmd, but UUIDs already in druntime) + runShell("cl /c /Zl /Fo" ~ dir ~ "uuid.obj " ~ dir ~ "empty.c"); + runShell(lib ~ "/OUT:" ~ dir ~ "uuid.lib " ~ dir ~ "uuid.obj"); + + foreach(f; files) + std.file.remove(dir ~ f); + std.file.remove(dir ~ stripExtension(msvcrtlib) ~ ".exp"); + std.file.remove(dir ~ "msvcrt.def"); + std.file.remove(dir ~ "oldnames.obj"); + std.file.remove(dir ~ "uuid.obj"); + std.file.remove(dir ~ "empty.c"); +} + +void main(string[] args) +{ + bool x64 = (args.length > 1 && args[1] == "x64"); + string defdir = (args.length > 2 ? args[2] : "def"); + string outdir = x64 ? "lib64/" : "lib32mscoff/"; + if (args.length > 3) + outdir = args[3] ~ "/"; + string msvcdef = (args.length > 4 ? args[4] : "msvcrt.def.in"); + + buildLibs(x64, defdir, outdir); + buildMsvcrt(x64, outdir, msvcdef); +} diff --git a/winsdk/msvcrt_abs.asm b/winsdk/msvcrt_abs.asm new file mode 100644 index 0000000000..edf5293901 --- /dev/null +++ b/winsdk/msvcrt_abs.asm @@ -0,0 +1,8 @@ + +public __except_list +public __tls_array + +__except_list EQU 0 +__tls_array EQU 02ch + +end diff --git a/winsdk/msvcrt_data.c b/winsdk/msvcrt_data.c new file mode 100644 index 0000000000..38ea561bad --- /dev/null +++ b/winsdk/msvcrt_data.c @@ -0,0 +1,58 @@ +#include + +#define _CRTALLOC(x) __declspec(allocate(x)) + +ULONG _tls_index = 0; + +#pragma section(".tls") +#pragma section(".tls$AAA") +#pragma section(".tls$ZZZ") +#pragma section(".CRT$XLA") +#pragma section(".CRT$XLZ") +#pragma section(".CRT$XIA") +#pragma section(".CRT$XIZ") +#pragma section(".CRT$XCA") +#pragma section(".CRT$XCZ") +#pragma section(".CRT$XPA") +#pragma section(".CRT$XPZ") +#pragma section(".CRT$XTA") +#pragma section(".CRT$XTZ") + +/* TLS raw template data start and end. */ +_CRTALLOC(".tls$AAA") char _tls_start = 0; +_CRTALLOC(".tls$ZZZ") char _tls_end = 0; + +// TLS init/exit callbacks +_CRTALLOC(".CRT$XLA") PIMAGE_TLS_CALLBACK __xl_a = 0; +_CRTALLOC(".CRT$XLZ") PIMAGE_TLS_CALLBACK __xl_z = 0; + +// #pragma section(".tls") +_CRTALLOC(".tls") const IMAGE_TLS_DIRECTORY _tls_used = +{ + (SIZE_T) &_tls_start, + (SIZE_T) &_tls_end, + (SIZE_T) &_tls_index, + (SIZE_T) (&__xl_a+1), + (ULONG) 0, // SizeOfZeroFill + (ULONG) 0 // Characteristics +}; + +typedef void(*_PVFV)(); + +// C init +_CRTALLOC(".CRT$XIA") _PVFV __xi_a[] = { NULL }; +_CRTALLOC(".CRT$XIZ") _PVFV __xi_z[] = { NULL }; +// C++ init +_CRTALLOC(".CRT$XCA") _PVFV __xc_a[] = { NULL }; +_CRTALLOC(".CRT$XCZ") _PVFV __xc_z[] = { NULL }; +// C pre-terminators +_CRTALLOC(".CRT$XPA") _PVFV __xp_a[] = { NULL }; +_CRTALLOC(".CRT$XPZ") _PVFV __xp_z[] = { NULL }; +// C terminators +_CRTALLOC(".CRT$XTA") _PVFV __xt_a[] = { NULL }; +_CRTALLOC(".CRT$XTZ") _PVFV __xt_z[] = { NULL }; + +char _fltused; + +int _argc = 0; +char **_argv = NULL; diff --git a/winsdk/msvcrt_stub.c b/winsdk/msvcrt_stub.c new file mode 100644 index 0000000000..e8278e3526 --- /dev/null +++ b/winsdk/msvcrt_stub.c @@ -0,0 +1,110 @@ +#include + +#define _CRTALLOC(x) __declspec(allocate(x)) + +#define __UNKNOWN_APP 0 // abused for DLL +#define __CONSOLE_APP 1 +#define __GUI_APP 2 + +#ifndef _APPTYPE +#define _APPTYPE __CONSOLE_APP +#endif + +typedef void(*_PVFV)(); + +// C init +extern _PVFV __xi_a[]; +extern _PVFV __xi_z[]; +// C++ init +extern _PVFV __xc_a[]; +extern _PVFV __xc_z[]; +// C pre-terminators +extern _PVFV __xp_a[]; +extern _PVFV __xp_z[]; +// C terminators +extern _PVFV __xt_a[]; +extern _PVFV __xt_z[]; + +extern int main (int, char **, char **); +extern void _setargv (void); + +extern IMAGE_DOS_HEADER __ImageBase; // linker generated + +#if _APPTYPE == __UNKNOWN_APP +BOOL WINAPI +DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved) +{ + BOOL bRet; + + if (dwReason == DLL_PROCESS_ATTACH) + { + _initterm_e(__xi_a, __xi_z); + _initterm(__xc_a, __xc_z); + } + + bRet = DllMain (hDll, dwReason, lpReserved); + + if (dwReason == DLL_PROCESS_ATTACH || dwReason == DLL_PROCESS_ATTACH && !bRet) + { + _initterm(__xp_a, __xp_z); + _initterm(__xt_a, __xt_z); + } + return bRet; +} + +#else // _APPTYPE != __UNKNOWN_APP + +extern int _argc; +extern char **_argv; + +/* In MSVCRT.DLL, Microsoft's initialization hook is called __getmainargs(), + * and it expects a further structure argument, (which we don't use, but pass + * it as a dummy, with a declared size of zero in its first and only field). + */ +typedef struct _startupinfo { int mode; } _startupinfo; +extern void __getmainargs( int *argc, char ***argv, char ***penv, int glob, _startupinfo *info ); + +/* The function mainCRTStartup() is the entry point for all + * console/desktop programs. + */ +#if _APPTYPE == __CONSOLE_APP +void mainCRTStartup(void) +#else +void WinMainCRTStartup(void) +#endif +{ + int nRet, xRet; + __set_app_type(_APPTYPE); + + /* The MSVCRT.DLL start-up hook requires this invocation + * protocol... + */ + char **envp = NULL; + _startupinfo start_info = { 0 }; + __getmainargs(&_argc, &_argv, &envp, 0, &start_info); + + _initterm(__xi_a, __xi_z); + _initterm(__xc_a, __xc_z); + +#if _APPTYPE == __CONSOLE_APP + nRet = main(_argc, _argv, envp); +#else + { + STARTUPINFOA startupInfo; + GetStartupInfoA(&startupInfo); + int showWindowMode = startupInfo.dwFlags & STARTF_USESHOWWINDOW + ? startupInfo.wShowWindow : SW_SHOWDEFAULT; + PCSTR lpszCommandLine = GetCommandLineA(); + nRet = WinMain((HINSTANCE)&__ImageBase, NULL, lpszCommandLine, showWindowMode); + } +#endif + + _initterm(__xp_a, __xp_z); + _initterm(__xt_a, __xt_z); + + if (nRet == 0) + nRet = xRet; + + ExitProcess(nRet); +} +#endif // _APPTYPE != __UNKNOWN_APP From a1aa5195080fecb3e965b1a6b1b53955d38fd436 Mon Sep 17 00:00:00 2001 From: Rainer Schuetze Date: Wed, 1 Nov 2017 11:29:46 +0100 Subject: [PATCH 2/4] fix section attributes, automatically pull in kernel32.lib --- winsdk/msvcrt_data.c | 31 ++++++++++++++++--------------- winsdk/msvcrt_stub.c | 2 ++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/winsdk/msvcrt_data.c b/winsdk/msvcrt_data.c index 38ea561bad..e023f477fc 100644 --- a/winsdk/msvcrt_data.c +++ b/winsdk/msvcrt_data.c @@ -4,30 +4,31 @@ ULONG _tls_index = 0; -#pragma section(".tls") #pragma section(".tls$AAA") #pragma section(".tls$ZZZ") -#pragma section(".CRT$XLA") -#pragma section(".CRT$XLZ") -#pragma section(".CRT$XIA") -#pragma section(".CRT$XIZ") -#pragma section(".CRT$XCA") -#pragma section(".CRT$XCZ") -#pragma section(".CRT$XPA") -#pragma section(".CRT$XPZ") -#pragma section(".CRT$XTA") -#pragma section(".CRT$XTZ") +#pragma section(".CRT$XLA", long, read) +#pragma section(".CRT$XLZ", long, read) +#pragma section(".CRT$XIA", long, read) +#pragma section(".CRT$XIZ", long, read) +#pragma section(".CRT$XCA", long, read) +#pragma section(".CRT$XCZ", long, read) +#pragma section(".CRT$XPA", long, read) +#pragma section(".CRT$XPZ", long, read) +#pragma section(".CRT$XTA", long, read) +#pragma section(".CRT$XTZ", long, read) +#pragma section(".rdata$T", long, read) + +#pragma comment(linker, "/merge:.CRT=.rdata") /* TLS raw template data start and end. */ -_CRTALLOC(".tls$AAA") char _tls_start = 0; -_CRTALLOC(".tls$ZZZ") char _tls_end = 0; +_CRTALLOC(".tls$AAA") int _tls_start = 0; +_CRTALLOC(".tls$ZZZ") int _tls_end = 0; // TLS init/exit callbacks _CRTALLOC(".CRT$XLA") PIMAGE_TLS_CALLBACK __xl_a = 0; _CRTALLOC(".CRT$XLZ") PIMAGE_TLS_CALLBACK __xl_z = 0; -// #pragma section(".tls") -_CRTALLOC(".tls") const IMAGE_TLS_DIRECTORY _tls_used = +_CRTALLOC(".rdata$T") const IMAGE_TLS_DIRECTORY _tls_used = { (SIZE_T) &_tls_start, (SIZE_T) &_tls_end, diff --git a/winsdk/msvcrt_stub.c b/winsdk/msvcrt_stub.c index e8278e3526..2e729e4191 100644 --- a/winsdk/msvcrt_stub.c +++ b/winsdk/msvcrt_stub.c @@ -30,6 +30,8 @@ extern void _setargv (void); extern IMAGE_DOS_HEADER __ImageBase; // linker generated +#pragma comment(lib, "kernel32.lib") + #if _APPTYPE == __UNKNOWN_APP BOOL WINAPI DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved) From 57ab76f1bd88025733ac25ed651a99f7b87a5d5a Mon Sep 17 00:00:00 2001 From: Rainer Schuetze Date: Thu, 2 Nov 2017 16:11:54 +0100 Subject: [PATCH 3/4] build for VS2010 redistributable build proper oldnames.lib implement atexit --- winsdk/buildsdk.d | 33 +++++----- winsdk/msvcrt_atexit.c | 34 ++++++++++ winsdk/msvcrt_data.c | 4 +- winsdk/msvcrt_stub.c | 13 +++- winsdk/oldnames.c | 140 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 206 insertions(+), 18 deletions(-) create mode 100644 winsdk/msvcrt_atexit.c create mode 100644 winsdk/oldnames.c diff --git a/winsdk/buildsdk.d b/winsdk/buildsdk.d index b7fedb20b1..59768ea909 100644 --- a/winsdk/buildsdk.d +++ b/winsdk/buildsdk.d @@ -46,7 +46,7 @@ void runShell(string cmd) // the appropriate import library // // x64: strip any @ from the symbol names -bool def2implib(bool x64, string f, string dir) +bool def2implib(bool x64, string f, string dir, string linkopt = null) { static auto re = regex(r"@?([a-zA-Z0-9_]+)(@[0-9]*)"); char[] content = cast(char[])std.file.read(f); @@ -105,20 +105,20 @@ bool def2implib(bool x64, string f, string dir) std.file.write(dirbase ~ ".c", csrc); runShell("cl /c /Fo" ~ dirbase ~ ".obj " ~ dirbase ~ ".c"); - runShell("link /NOD /NOENTRY /DLL " ~ dirbase ~ ".obj /out:" ~ dirbase ~ ".dll /def:" ~ dirbase ~ ".def"); + runShell("link /NOD /NOENTRY /DLL " ~ dirbase ~ ".obj /out:" ~ dirbase ~ ".dll /def:" ~ dirbase ~ ".def" ~ linkopt); // cleanup std.file.remove(dirbase ~ ".def"); std.file.remove(dirbase ~ ".c"); std.file.remove(dirbase ~ ".obj"); std.file.remove(dirbase ~ ".dll"); - std.file.remove(dirbase ~ ".exp"); + std.file.remove(dirbase ~ ".exp"); return true; } void buildLibs(bool x64, string defdir, string dir) { - mkdirRecurse(dir ~ "ddk"); + mkdirRecurse(dir); //goto LnoDef; foreach(f; std.file.dirEntries("def", SpanMode.shallow)) @@ -128,9 +128,13 @@ void buildLibs(bool x64, string defdir, string dir) if (extension(f).toLower == ".def") def2implib(x64, f, dir); - foreach(f; std.file.dirEntries("def/ddk", SpanMode.shallow)) - if (extension(f).toLower == ".def") - def2implib(x64, f, dir ~ "ddk/"); + version(DDK) // disable for now + { + mkdirRecurse(dir ~ ddk); + foreach(f; std.file.dirEntries("def/ddk", SpanMode.shallow)) + if (extension(f).toLower == ".def") + def2implib(x64, f, dir ~ "ddk/"); + } } void buildMsvcrt(bool x64, string dir, string msvcdef) @@ -138,26 +142,27 @@ void buildMsvcrt(bool x64, string dir, string msvcdef) string arch = x64 ? "x64" : "x86"; string ml = x64 ? "ml64" : "ml"; string lib = "lib /MACHINE:" ~ arch ~ " "; - string msvcrtlib = "msvcrt51.lib"; + string msvcrtlib = "msvcrt100.lib"; - // build msvcrt.lib for WinXP - runShell("cl /EP -D__MSVCRT_VERSION__=0x0501UL -D__DLLNAME__=msvcrt " ~ msvcdef ~ " >" ~ dir ~ "msvcrt.def"); + // build msvcrt.lib for VS2010 + runShell("cl /EP -D__MSVCRT_VERSION__=0x10000000UL -D__DLLNAME__=msvcr100 " ~ msvcdef ~ " >" ~ dir ~ "msvcrt.def"); runShell(lib ~ "/OUT:" ~ dir ~ msvcrtlib ~ " /DEF:" ~ dir ~ "msvcrt.def"); // no translation necessary runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_stub0.obj /D_APPTYPE=0 msvcrt_stub.c"); runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_stub1.obj /D_APPTYPE=1 msvcrt_stub.c"); runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_stub2.obj /D_APPTYPE=2 msvcrt_stub.c"); runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_data.obj msvcrt_data.c"); + runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_atexit.obj msvcrt_atexit.c"); runShell(ml ~ " /c /Fo" ~ dir ~ "msvcrt_abs.obj msvcrt_abs.asm"); - auto files = ["msvcrt_abs.obj", "msvcrt_stub0.obj", "msvcrt_stub1.obj", "msvcrt_stub2.obj", "msvcrt_data.obj" ]; + auto files = ["msvcrt_abs.obj", "msvcrt_stub0.obj", "msvcrt_stub1.obj", "msvcrt_stub2.obj", "msvcrt_data.obj", "msvcrt_atexit.obj" ]; auto objs = files.map!(a => dir ~ a).join(" "); runShell(lib ~ dir ~ msvcrtlib ~ " " ~ objs); - // create empty oldnames.lib (expected by dmd) - std.file.write(dir ~ "empty.c", ""); - runShell("cl /c /Zl /Fo" ~ dir ~ "oldnames.obj " ~ dir ~ "empty.c"); + // create oldnames.lib (expected by dmd) + runShell("cl /c /Zl /Fo" ~ dir ~ "oldnames.obj oldnames.c"); runShell(lib ~ "/OUT:" ~ dir ~ "oldnames.lib " ~ dir ~ "oldnames.obj"); // create empty uuid.lib (expected by dmd, but UUIDs already in druntime) + std.file.write(dir ~ "empty.c", ""); runShell("cl /c /Zl /Fo" ~ dir ~ "uuid.obj " ~ dir ~ "empty.c"); runShell(lib ~ "/OUT:" ~ dir ~ "uuid.lib " ~ dir ~ "uuid.obj"); diff --git a/winsdk/msvcrt_atexit.c b/winsdk/msvcrt_atexit.c new file mode 100644 index 0000000000..26c7c07cd6 --- /dev/null +++ b/winsdk/msvcrt_atexit.c @@ -0,0 +1,34 @@ +#include + +typedef void(*_PVFV)(void); + +typedef struct atexit_node +{ + struct atexit_node* next; + _PVFV pfn; +} atexit_node; + +static atexit_node* atexit_list; + +int atexit(_PVFV pfn) +{ + atexit_node* node = malloc(sizeof(atexit_node)); + if(!node) + return -1; + // TODO: not thread safe + node->pfn = pfn; + node->next = atexit_list; + atexit_list = node; + return 0; +} + +void term_atexit() +{ + while(atexit_list) + { + atexit_node* n = atexit_list; + atexit_list = n->next; + (*(n->pfn))(); + free(n); + } +} diff --git a/winsdk/msvcrt_data.c b/winsdk/msvcrt_data.c index e023f477fc..5fe00535db 100644 --- a/winsdk/msvcrt_data.c +++ b/winsdk/msvcrt_data.c @@ -1,4 +1,5 @@ #include +#include #define _CRTALLOC(x) __declspec(allocate(x)) @@ -38,7 +39,7 @@ _CRTALLOC(".rdata$T") const IMAGE_TLS_DIRECTORY _tls_used = (ULONG) 0 // Characteristics }; -typedef void(*_PVFV)(); +typedef void(*_PVFV)(void); // C init _CRTALLOC(".CRT$XIA") _PVFV __xi_a[] = { NULL }; @@ -57,3 +58,4 @@ char _fltused; int _argc = 0; char **_argv = NULL; + diff --git a/winsdk/msvcrt_stub.c b/winsdk/msvcrt_stub.c index 2e729e4191..152c9a0094 100644 --- a/winsdk/msvcrt_stub.c +++ b/winsdk/msvcrt_stub.c @@ -27,10 +27,14 @@ extern _PVFV __xt_z[]; extern int main (int, char **, char **); extern void _setargv (void); +extern void term_atexit(); extern IMAGE_DOS_HEADER __ImageBase; // linker generated +extern int __ref_oldnames; + #pragma comment(lib, "kernel32.lib") +#pragma comment(lib, "oldnames.lib") #if _APPTYPE == __UNKNOWN_APP BOOL WINAPI @@ -45,9 +49,10 @@ DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved) } bRet = DllMain (hDll, dwReason, lpReserved); - - if (dwReason == DLL_PROCESS_ATTACH || dwReason == DLL_PROCESS_ATTACH && !bRet) + + if (dwReason == DLL_PROCESS_DETACH || dwReason == DLL_PROCESS_ATTACH && !bRet) { + term_atexit(); _initterm(__xp_a, __xp_z); _initterm(__xt_a, __xt_z); } @@ -66,7 +71,7 @@ extern char **_argv; typedef struct _startupinfo { int mode; } _startupinfo; extern void __getmainargs( int *argc, char ***argv, char ***penv, int glob, _startupinfo *info ); -/* The function mainCRTStartup() is the entry point for all +/* The function mainCRTStartup() is the entry point for all * console/desktop programs. */ #if _APPTYPE == __CONSOLE_APP @@ -77,6 +82,7 @@ void WinMainCRTStartup(void) { int nRet, xRet; __set_app_type(_APPTYPE); + __ref_oldnames = 0; // drag in alternate definitions /* The MSVCRT.DLL start-up hook requires this invocation * protocol... @@ -101,6 +107,7 @@ void WinMainCRTStartup(void) } #endif + term_atexit(); _initterm(__xp_a, __xp_z); _initterm(__xt_a, __xt_z); diff --git a/winsdk/oldnames.c b/winsdk/oldnames.c new file mode 100644 index 0000000000..83e092b5a1 --- /dev/null +++ b/winsdk/oldnames.c @@ -0,0 +1,140 @@ + +#if defined _M_IX86 + #define C_PREFIX "_" +#elif defined _M_X64 || defined _M_ARM || defined _M_ARM64 + #define C_PREFIX "" +#else + #error Unsupported architecture +#endif + +#define DECLARE_ALTERNATE_NAME(name, alternate_name) \ + __pragma(comment(linker, "/alternatename:" C_PREFIX #name "=" C_PREFIX #alternate_name)) +#define DECLARE_ALTERNATE__(name) DECLARE_ALTERNATE_NAME(name, _##name) + +DECLARE_ALTERNATE_NAME(time, _time32); +DECLARE_ALTERNATE_NAME(ftime, _ftime32); +DECLARE_ALTERNATE_NAME(utime, _utime32); +DECLARE_ALTERNATE_NAME(stat, _stat32); +DECLARE_ALTERNATE_NAME(fstat, _fstat32); +DECLARE_ALTERNATE_NAME(strcmpi, _stricmp); +DECLARE_ALTERNATE_NAME(localtime, _localtime32); + +DECLARE_ALTERNATE__(fcloseall ); +DECLARE_ALTERNATE__(tzset ); +DECLARE_ALTERNATE__(execvpe ); +DECLARE_ALTERNATE__(execvp ); +DECLARE_ALTERNATE__(execve ); +DECLARE_ALTERNATE__(execv ); +DECLARE_ALTERNATE__(execlpe ); +DECLARE_ALTERNATE__(execlp ); +DECLARE_ALTERNATE__(execle ); +DECLARE_ALTERNATE__(execl ); +DECLARE_ALTERNATE__(control87); +DECLARE_ALTERNATE__(sys_errlist); +DECLARE_ALTERNATE__(filelength); +DECLARE_ALTERNATE__(control87 ); +DECLARE_ALTERNATE__(_wcsicoll ); +DECLARE_ALTERNATE__(_wcsupr ); +DECLARE_ALTERNATE__(_wcslwr ); +DECLARE_ALTERNATE__(_wcsset ); +DECLARE_ALTERNATE__(_wcsrev ); +DECLARE_ALTERNATE__(_wcsnset ); +DECLARE_ALTERNATE__(_wcsnicmp ); +DECLARE_ALTERNATE__(_wcsicmp ); +DECLARE_ALTERNATE__(_wcsdup ); +DECLARE_ALTERNATE__(_dup ); +DECLARE_ALTERNATE__(_tzset ); +DECLARE_ALTERNATE__(_tzname ); +DECLARE_ALTERNATE__(_timezone ); +DECLARE_ALTERNATE__(_strupr ); +DECLARE_ALTERNATE__(_strset ); +DECLARE_ALTERNATE__(_strrev ); +DECLARE_ALTERNATE__(_strnset ); +DECLARE_ALTERNATE__(_strnicmp ); +DECLARE_ALTERNATE__(_strlwr ); +DECLARE_ALTERNATE__(_strdup ); +DECLARE_ALTERNATE__(_stricmp ); +DECLARE_ALTERNATE__(_tempnam ); +DECLARE_ALTERNATE__(_rmtmp ); +DECLARE_ALTERNATE__(_putw ); +DECLARE_ALTERNATE__(_getw ); +DECLARE_ALTERNATE__(_fputchar ); +DECLARE_ALTERNATE__(_flushall ); +DECLARE_ALTERNATE__(_fileno ); +DECLARE_ALTERNATE__(_fgetchar ); +DECLARE_ALTERNATE__(_fdopen ); +DECLARE_ALTERNATE__(_ultoa ); +DECLARE_ALTERNATE__(_swab ); +DECLARE_ALTERNATE__(_putenv ); +DECLARE_ALTERNATE__(_onexit ); +DECLARE_ALTERNATE__(_ltoa ); +DECLARE_ALTERNATE__(_itoa ); +DECLARE_ALTERNATE__(_yn ); +DECLARE_ALTERNATE__(_y1 ); +DECLARE_ALTERNATE__(_y0 ); +DECLARE_ALTERNATE__(_jn ); +DECLARE_ALTERNATE__(_j1 ); +DECLARE_ALTERNATE__(_j0 ); +DECLARE_ALTERNATE__(_cabs ); +DECLARE_ALTERNATE__(_HUGE ); +DECLARE_ALTERNATE__(_gcvt ); +DECLARE_ALTERNATE__(_fcvt ); +DECLARE_ALTERNATE__(_ecvt ); +DECLARE_ALTERNATE__(_lsearch ); +DECLARE_ALTERNATE__(_lfind ); +DECLARE_ALTERNATE__(_spawnvpe ); +DECLARE_ALTERNATE__(_spawnvp ); +DECLARE_ALTERNATE__(_spawnve ); +DECLARE_ALTERNATE__(_spawnv ); +DECLARE_ALTERNATE__(_spawnlpe ); +DECLARE_ALTERNATE__(_spawnlp ); +DECLARE_ALTERNATE__(_spawnle ); +DECLARE_ALTERNATE__(_spawnl ); +DECLARE_ALTERNATE__(_getpid ); +DECLARE_ALTERNATE__(_cwait ); +DECLARE_ALTERNATE__(_memicmp ); +DECLARE_ALTERNATE__(_memccpy ); +DECLARE_ALTERNATE__(_write ); +DECLARE_ALTERNATE__(_unlink ); +DECLARE_ALTERNATE__(_umask ); +DECLARE_ALTERNATE__(_tell ); +DECLARE_ALTERNATE__(_sys_nerr ); +DECLARE_ALTERNATE__(_sopen ); +DECLARE_ALTERNATE__(_setmode ); +DECLARE_ALTERNATE__(_read ); +DECLARE_ALTERNATE__(_open ); +DECLARE_ALTERNATE__(_mktemp ); +DECLARE_ALTERNATE__(_lseek ); +DECLARE_ALTERNATE__(_locking ); +DECLARE_ALTERNATE__(_isatty ); +DECLARE_ALTERNATE__(_eof ); +DECLARE_ALTERNATE__(_dup2 ); +DECLARE_ALTERNATE__(_creat ); +DECLARE_ALTERNATE__(_close ); +DECLARE_ALTERNATE__(_chsize ); +DECLARE_ALTERNATE__(_chmod ); +DECLARE_ALTERNATE__(_access ); +DECLARE_ALTERNATE__(_rmdir ); +DECLARE_ALTERNATE__(_mkdir ); +DECLARE_ALTERNATE__(_getcwd ); +DECLARE_ALTERNATE__(_chdir ); +DECLARE_ALTERNATE__(_ungetch ); +DECLARE_ALTERNATE__(_putch ); +DECLARE_ALTERNATE__(_kbhit ); +DECLARE_ALTERNATE__(_getche ); +DECLARE_ALTERNATE__(_fpreset ); +DECLARE_ALTERNATE__(_getch ); +DECLARE_ALTERNATE__(_environ ); +DECLARE_ALTERNATE__(_daylight ); +DECLARE_ALTERNATE__(_cscanf ); +DECLARE_ALTERNATE__(_cputs ); +DECLARE_ALTERNATE__(_cprintf ); +DECLARE_ALTERNATE__(_cgets ); + +// access this symbol to drag in the generated linker directives +int __ref_oldnames; + +#if defined _M_X64 +int _isnan(double); +int _isnanf(float f) { return _isnan(f); } +#endif From 885841f130446b01b545cea60f28339c870f5813 Mon Sep 17 00:00:00 2001 From: Rainer Schuetze Date: Sun, 5 Nov 2017 14:18:38 +0100 Subject: [PATCH 4/4] asm only needed for x86, implement long divisions --- winsdk/buildsdk.d | 15 +- winsdk/msvcrt_abs.asm | 337 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 344 insertions(+), 8 deletions(-) diff --git a/winsdk/buildsdk.d b/winsdk/buildsdk.d index 59768ea909..ca7ffed865 100644 --- a/winsdk/buildsdk.d +++ b/winsdk/buildsdk.d @@ -121,17 +121,17 @@ void buildLibs(bool x64, string defdir, string dir) mkdirRecurse(dir); //goto LnoDef; - foreach(f; std.file.dirEntries("def", SpanMode.shallow)) + foreach(f; std.file.dirEntries(defdir, SpanMode.shallow)) if (extension(f).toLower == ".def") def2implib(x64, f, dir); - foreach(f; std.file.dirEntries("def/directx", SpanMode.shallow)) + foreach(f; std.file.dirEntries(defdir ~ "/directx", SpanMode.shallow)) if (extension(f).toLower == ".def") def2implib(x64, f, dir); version(DDK) // disable for now { mkdirRecurse(dir ~ ddk); - foreach(f; std.file.dirEntries("def/ddk", SpanMode.shallow)) + foreach(f; std.file.dirEntries(defdir ~ "/ddk", SpanMode.shallow)) if (extension(f).toLower == ".def") def2implib(x64, f, dir ~ "ddk/"); } @@ -140,7 +140,6 @@ void buildLibs(bool x64, string defdir, string dir) void buildMsvcrt(bool x64, string dir, string msvcdef) { string arch = x64 ? "x64" : "x86"; - string ml = x64 ? "ml64" : "ml"; string lib = "lib /MACHINE:" ~ arch ~ " "; string msvcrtlib = "msvcrt100.lib"; @@ -152,8 +151,12 @@ void buildMsvcrt(bool x64, string dir, string msvcdef) runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_stub2.obj /D_APPTYPE=2 msvcrt_stub.c"); runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_data.obj msvcrt_data.c"); runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_atexit.obj msvcrt_atexit.c"); - runShell(ml ~ " /c /Fo" ~ dir ~ "msvcrt_abs.obj msvcrt_abs.asm"); - auto files = ["msvcrt_abs.obj", "msvcrt_stub0.obj", "msvcrt_stub1.obj", "msvcrt_stub2.obj", "msvcrt_data.obj", "msvcrt_atexit.obj" ]; + auto files = ["msvcrt_stub0.obj", "msvcrt_stub1.obj", "msvcrt_stub2.obj", "msvcrt_data.obj", "msvcrt_atexit.obj" ]; + if (!x64) + { + runShell("ml /c /Fo" ~ dir ~ "msvcrt_abs.obj msvcrt_abs.asm"); + files ~= "msvcrt_abs.obj"; + } auto objs = files.map!(a => dir ~ a).join(" "); runShell(lib ~ dir ~ msvcrtlib ~ " " ~ objs); diff --git a/winsdk/msvcrt_abs.asm b/winsdk/msvcrt_abs.asm index edf5293901..0cf6acfac9 100644 --- a/winsdk/msvcrt_abs.asm +++ b/winsdk/msvcrt_abs.asm @@ -1,8 +1,341 @@ - +;; absolute symbols public __except_list public __tls_array +;; symbols not exported by the shared runtime +public __alldiv +public __allrem +public __aulldiv +public __aullrem + __except_list EQU 0 __tls_array EQU 02ch -end +;;/** +;; * Support for 64-bit longs. +;; * +;; * Copyright: Copyright Digital Mars 2000 - 2012. +;; * License: Distributed under the +;; * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). +;; * (See accompanying file LICENSE) +;; * Authors: Walter Bright, Sean Kelly +;; * Source: $(DRUNTIMESRC src/rt/_llmath.d) +;; */ +;; +;;copied from druntime module rt.llmath; + +_TEXT segment para use32 public 'CODE' + assume CS:_TEXT + +;;/*************************************** +;; * Unsigned long divide. +;; * Input: +;; * [EDX,EAX],[ECX,EBX] +;; * Output: +;; * [EDX,EAX] = [EDX,EAX] / [ECX,EBX] +;; * [ECX,EBX] = [EDX,EAX] % [ECX,EBX] +;; */ + +__ULDIV__ proc + + test ECX,ECX ; + jz uldiv ; + + ; if ECX > EDX, then quotient is 0 and remainder is [EDX,EAX] + cmp ECX,EDX ; + ja quo0 ; + + test ECX,ECX ; + js Lleft ; + + ;/* We have n>d, and know that n/d will fit in 32 bits. + ; * d will be left justified if we shift it left s bits. + ; * [d1,d0] <<= s + ; * [n2,n1,n0] = [n1,n0] << s + ; * + ; * Use one divide, by this reasoning: + ; * ([n2,n1]<<32 + n0)/(d1<<32 + d0) + ; * becomes: + ; * ([n2,n1]<<32)/(d1<<32 + d0) + n0/(d1<<32 + d0) + ; * The second divide is always 0. + ; * Ignore the d0 in the first divide, which will yield a quotient + ; * that might be too high by 1 (because d1 is left justified). + ; * We can tell if it's too big if: + ; * q*[d1,d0] > [n2,n1,n0] + ; * which is: + ; * q*[d1,d0] > [[q*[d1,0]+q%[d1,0],n1,n0] + ; * If we subtract q*[d1,0] from both sides, we get: + ; * q*d0 > [[n2,n1]%d1,n0] + ; * So if it is too big by one, reduce q by one to q'=q-one. + ; * Compute remainder as: + ; * r = ([n1,n0] - q'*[d1,d0]) >> s + ; * Again, we can subtract q*[d1,0]: + ; * r = ([n1,n0] - q*[d1,0] - (q'*[d1,d0] - q*[d1,0])) >> s + ; * r = ([[n2,n1]%d1,n0] + (q*[d1,0] - (q - one)*[d1,d0])) >> s + ; * r = ([[n2,n1]%d1,n0] + (q*[d1,0] - [d1 *(q-one),d0*(1-q)])) >> s + ; * r = ([[n2,n1]%d1,n0] + [d1 *one,d0*(one-q)])) >> s + ; */ + + push EBP ; + push ESI ; + push EDI ; + + mov ESI,EDX ; + mov EDI,EAX ; + mov EBP,ECX ; + + bsr EAX,ECX ; // EAX is now 30..0 + xor EAX,01Fh ; // EAX is now 1..31 + mov CH,AL ; + neg EAX ; + add EAX,32 ; + mov CL,AL ; + + mov EAX,EBX ; + shr EAX,CL ; + xchg CH,CL ; + shl EBP,CL ; + or EBP,EAX ; + shl EBX,CL ; + + mov EDX,ESI ; + xchg CH,CL ; + shr EDX,CL ; + + mov EAX,EDI ; + shr EAX,CL ; + xchg CH,CL ; + shl EDI,CL ; + shl ESI,CL ; + or EAX,ESI ; + + div EBP ; + push EBP ; + mov EBP,EAX ; + mov ESI,EDX ; + + mul EBX ; + cmp EDX,ESI ; + ja L1 ; + jb L2 ; + cmp EAX,EDI ; + jbe L2 ; +L1: dec EBP ; + sub EAX,EBX ; + sbb EDX,0[ESP] ; +L2: + add ESP,4 ; + sub EDI,EAX ; + sbb ESI,EDX ; + mov EAX,ESI ; + xchg CH,CL ; + shl EAX,CL ; + xchg CH,CL ; + shr EDI,CL ; + or EDI,EAX ; + shr ESI,CL ; + mov EBX,EDI ; + mov ECX,ESI ; + mov EAX,EBP ; + xor EDX,EDX ; + + pop EDI ; + pop ESI ; + pop EBP ; + ret ; + +uldiv: test EDX,EDX ; + jnz D3 ; + ; Both high words are 0, we can use the DIV instruction + div EBX ; + mov EBX,EDX ; + mov EDX,ECX ; // EDX = ECX = 0 + ret ; + + even ; +D3: ; Divide [EDX,EAX] by EBX + mov ECX,EAX ; + mov EAX,EDX ; + xor EDX,EDX ; + div EBX ; + xchg ECX,EAX ; + div EBX ; + ; ECX,EAX = result + ; EDX = remainder + mov EBX,EDX ; + mov EDX,ECX ; + xor ECX,ECX ; + ret ; + +quo0: ; Quotient is 0 + ; Remainder is [EDX,EAX] + mov EBX,EAX ; + mov ECX,EDX ; + xor EAX,EAX ; + xor EDX,EDX ; + ret ; + +Lleft: ; The quotient is 0 or 1 and EDX >= ECX + cmp EDX,ECX ; + ja quo1 ; // [EDX,EAX] > [ECX,EBX] + ; EDX == ECX + cmp EAX,EBX ; + jb quo0 ; + +quo1: ; Quotient is 1 + ; Remainder is [EDX,EAX] - [ECX,EBX] + sub EAX,EBX ; + sbb EDX,ECX ; + mov EBX,EAX ; + mov ECX,EDX ; + mov EAX,1 ; + xor EDX,EDX ; + ret ; + +__ULDIV__ endp + +;;/*************************************** +;; * Signed long divide. +;; * Input: +;; * [EDX,EAX],[ECX,EBX] +;; * Output: +;; * [EDX,EAX] = [EDX,EAX] / [ECX,EBX] +;; * [ECX,EBX] = [EDX,EAX] % [ECX,EBX] +;; */ +;; +__LDIV__ proc + + test EDX,EDX ; // [EDX,EAX] negative? + jns L10 ; // no + ; neg64 EDX,EAX ; // [EDX,EAX] = -[EDX,EAX] + neg EDX ; + neg EAX ; + sbb EDX,0 ; + test ECX,ECX ; // [ECX,EBX] negative? + jns L11 ; // no + ; neg64 ECX,EBX ; + neg ECX ; + neg EBX ; + sbb ECX,0 ; + call __ULDIV__ ; + ; neg64 ECX,EBX ; // remainder same sign as dividend + neg ECX ; + neg EBX ; + sbb ECX,0 ; + ret ; + +L11: call __ULDIV__ ; + ; neg64 ECX,EBX ; // remainder same sign as dividend + neg ECX ; + neg EBX ; + sbb ECX,0 ; + ; neg64 EDX,EAX ; // quotient is negative + neg EDX ; + neg EAX ; + sbb EDX,0 ; + ret ; + +L10: test ECX,ECX ; // [ECX,EBX] negative? + jns L12 ; // no (all is positive) + ; neg64 ECX,EBX ; + neg ECX ; + neg EBX ; + sbb ECX,0 ; + call __ULDIV__ ; + ; neg64 EDX,EAX ; // quotient is negative + neg EDX ; + neg EAX ; + sbb EDX,0 ; + ret ; + +L12: jmp __ULDIV__ ; + +__LDIV__ endp + +;; * Input +;; * [ESP+4] QWORD: dividend +;; * [ESP+12] QWORD: divisor +;; * Output +;; * [EDX,EAX] = quotient +__alldiv proc + + push EBX + mov EAX,[ESP+8] + mov EDX,[ESP+12] + mov EBX,[ESP+16] + mov ECX,[ESP+20] + + call __LDIV__ + pop EBX + + ret 16 + +__alldiv endp + +;; * Input +;; * [ESP+4] QWORD: dividend +;; * [ESP+12] QWORD: divisor +;; * Output +;; * [EDX,EAX] = remainder +__allrem proc + + push EBX + mov EAX,[ESP+8] + mov EDX,[ESP+12] + mov EBX,[ESP+16] + mov ECX,[ESP+20] + + call __LDIV__ + mov EAX, EBX + mov EDX, ECX + pop EBX + + ret 16 + +__allrem endp + +;; * Input +;; * [ESP+4] QWORD: dividend +;; * [ESP+12] QWORD: divisor +;; * Output +;; * [EDX,EAX] = quotient +__aulldiv proc + + push EBX + mov EAX,[ESP+8] + mov EDX,[ESP+12] + mov EBX,[ESP+16] + mov ECX,[ESP+20] + + call __ULDIV__ + pop EBX + + ret 16 + +__aulldiv endp + +;; * Input +;; * [ESP+4] QWORD: dividend +;; * [ESP+12] QWORD: divisor +;; * Output +;; * [EDX,EAX] = remainder +__aullrem proc + + push EBX + mov EAX,[ESP+8] + mov EDX,[ESP+12] + mov EBX,[ESP+16] + mov ECX,[ESP+20] + + call __ULDIV__ + mov EAX, EBX + mov EDX, ECX + pop EBX + + ret 16 + +__aullrem endp + +_TEXT ends + + end