Valid HTML 4.01 Transitional Valid CSS Valid SVG 1.0

Me, myself & IT

Minimalist Runtime Library for Microsoft® C Compiler

Purpose

Create small(er) and fast(er) pure Win32 applications, console programs and DLLs with Microsoft’s Visual C compilers without the MSVCRT runtime libraries, using only functions of the Win32 API, for use on Windows XP and newer versions of Windows NT as well as Windows PE.

Note: NOMSVCRT is no C runtime library, it offers (almost) no POSIX functions like isascii(), printf() or qsort(), no objects like FILE or functions like ferror() which operate on them, and no global variables like errno or stderr, but just the compiler helper routines and intrinsics called from objects created with Microsoft’s Visual C compiler, and the startup routines called from Windows’ module loader.

Prerequisites

A platform or Windows® SDK for Windows 2000 and newer versions of Windows NT.

Preparation

Perform the following 8 (optionally 9) steps to build the minimalist Win32 runtime library NOMSVCRT from the sources and verify the build:
  1. Download the makefile NOMSVCRT.MAK into an arbitrary, preferable empty directory.

  2. Run the following command line to build the object library NOMSVCRT.LIB for the I386 alias x86 processor architecture:

    NMAKE.exe /R /F NOMSVCRT.MAK
  3. Download the include file NOMSVCRT.H and the ANSI C source file NOMSVCRT.C into the directory used in step 1. and step 2.

  4. Run the following command lines to build the sample Windows application NOMSVCRT.EXE, the sample DLL NOMSVCRT.DLL and the sample console program NOMSVCRT.COM:

    CL.exe /I. /Zl NOMSVCRT.C
    CL.exe /DUNICODE /I. /Zl NOMSVCRT.C
    CL.exe /DDLL /I. /LD /Zl NOMSVCRT.C
    CL.exe /DCONSOLE /FeNOMSVCRT.COM /I. /Zl NOMSVCRT.C
    CL.exe /DCONSOLE /DUNICODE /FeNOMSVCRT.COM /I. /Zl NOMSVCRT.C
    Each resulting portable executable file is about 4 kB to 5 kB small.
  5. [Screenshot of NOMSVCRT.EXE] Start the sample application NOMSVCRT.EXE built in step 4., either per double-click or on the command line, optionally with arbitrary arguments: it displays a message box like that shown on the right.

  6. Run the following command line to load the sample DLL NOMSVCRT.DLL built in step 4.:

    RUNDLL32.EXE "%CD%\NOMSVCRT.DLL",foobar
    Windows’ module loader executes its startup routine, which displays two message boxes like those shown below:

    [Screenshot of NOMSVCRT.DLL run via RUNDLL32.EXE] [Screenshot of NOMSVCRT.DLL run via RUNDLL32.EXE]

  7. Run the following command line to execute the console program NOMSVCRT.COM built in step 4.:

    NOMSVCRT.COM foobar\\baz
    It prints output like the following text:
    argc:		2
    argv[0]:	0x0046FB3C	NOMSVCRT.COM
    argv[1]:	0x0046FB58	foobar\\baz
    
    envp[0]:	0x008B0B18	ALLUSERSPROFILE=C:\ProgramData
    envp[1]:	0x008B0B56	APPDATA=C:\Users\Stefan\AppData\Roaming
    envp[2]:	0x008B0BA6	CommonProgramFiles=C:\Program Files (x86)\Common Files
    envp[3]:	0x008B0C14	CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
    envp[4]:	0x008B0C8C	CommonProgramW6432=C:\Program Files\Common Files
    envp[5]:	0x008B0CEE	COMPUTERNAME=H270
    envp[6]:	0x008B0D12	ComSpec=C:\Windows\system32\cmd.exe
    envp[7]:	0x008B0D5A	COPYCMD=/V /Z
    envp[8]:	0x008B0D76	DevMgr_Show_Details=*
    envp[9]:	0x008B0DA2	DevMgr_Show_NonPresent_Devices=*
    envp[10]:	0x008B0DE4	DIRCMD=/A /P /X
    envp[11]:	0x008B0E04	FP_NO_HOST_CHECK=NO
    envp[12]:	0x008B0E2C	HOMEDRIVE=C:
    envp[13]:	0x008B0E46	HOMEPATH=\Users\Stefan
    envp[14]:	0x008B0E74	LOCALAPPDATA=C:\Users\Stefan\AppData\Local
    envp[15]:	0x008B0ECA	LOGONSERVER=\\H270
    envp[16]:	0x008B0EF0	NUMBER_OF_PROCESSORS=2
    envp[17]:	0x008B0F1E	OS=Windows_NT
    envp[18]:	0x008B0F3A	Path=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\Commands;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Program Files\Microsoft SDKs\Windows\v7.0\bin
    envp[19]:	0x008B1094	PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
    envp[20]:	0x008B1110	PROCESSOR_ARCHITECTURE=x86
    envp[21]:	0x008B1146	PROCESSOR_ARCHITEW6432=AMD64
    envp[22]:	0x008B1180	PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 23 Stepping 10, GenuineIntel
    envp[23]:	0x008B1212	PROCESSOR_LEVEL=6
    envp[24]:	0x008B1236	PROCESSOR_REVISION=170a
    envp[25]:	0x008B1266	ProgramData=C:\ProgramData
    envp[26]:	0x008B129C	ProgramFiles=C:\Program Files (x86)
    envp[27]:	0x008B12E4	ProgramFiles(x86)=C:\Program Files (x86)
    envp[28]:	0x008B1336	ProgramW6432=C:\Program Files
    envp[29]:	0x008B1372	PROMPT=$P$G
    envp[30]:	0x008B138A	PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
    envp[31]:	0x008B140C	PUBLIC=C:\Users\Public
    envp[32]:	0x008B143A	SystemDrive=C:
    envp[33]:	0x008B1458	SystemRoot=C:\Windows
    envp[34]:	0x008B1484	TEMP=C:\Users\Stefan\AppData\Local\Temp
    envp[35]:	0x008B14CA	TMP=C:\Users\Stefan\AppData\Local\Temp
    envp[36]:	0x008B150E	USERDOMAIN=H270
    envp[37]:	0x008B152E	USERDOMAIN_ROAMINGPROFILE=H270
    envp[38]:	0x008B156C	USERNAME=Stefan
    envp[39]:	0x008B158C	USERPROFILE=C:\Users\Stefan
    envp[40]:	0x008B15C4	windir=C:\Windows
  8. Optionally download the icon file NOMSVCRT.ICO into the directory used in step 1. to step 3., then run the following command line to build the three sample executable files with (almost) all bells and whistles, i.e. with a resource containing the icon, an application manifest and version information, plus a custom DOS stub:

    NMAKE.exe /R /F NOMSVCRT.MAK samples
  9. Finally move the include file NOMSVCRT.H downloaded in step 3. into one of the include directories used by the Visual C compiler, and the object library NOMSVCRT.LIB built in step 2. into one of the lib directories for the I386 alias x86 appropriate processor architecture.

Dependencies

WINDOWS.H must be included before NOMSVCRT.H.

Note: the functions max() and min() are defined only when the corresponding macros are not defined; to disable their definition in WINDOWS.H define the macro NOMINMAX before including WINDOWS.H.

Usage

// Copyright © 2004-2017, Stefan Kanthak <‍skanthak‍@‍nexgo‍.‍de‍>

// Minimalist Win32 Runtime Library for Microsoft C Compiler 20xy

#define NOMINMAX
#define STRICT
#define WIN32_LEAN_AND_MEAN

#define WINVER		0x0500
#define _WIN32_WINNT	0x0500

#include <windows.h>
…
#define IEEE754		// for floating-point routines
#include <nomsvcrt.h>
…
#ifdef DLL
// see <https://msdn.microsoft.com/en-us/library/ms682583.aspx>
// and <https://msdn.microsoft.com/en-us/library/ms682596.aspx>

BOOL	WINAPI	DllMain(HANDLE hModule,
		        DWORD  dwReason,
		        LPVOID lpReserved)
{
	…
	return TRUE;
}
#else // DLL
#ifdef CONSOLE
#ifdef UNICODE
// see <https://msdn.microsoft.com/en-us/library/6wd819wh.aspx>

int	wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
	return PrintString(STDOUT, L"Hello world!\n");
}
#else // ANSI
// see <https://msdn.microsoft.com/en-us/library/3ze4ytsc.aspx>
// and <https://msdn.microsoft.com/en-us/library/6wd819wh.aspx>

int	main(int argc, char *argv[], char *envp[])
{
	return PrintString(STDOUT, "Hello world!\n");
}
#endif // UNICODE
#else // WINDOWS
#ifdef UNICODE
// see <https://msdn.microsoft.com/en-us/library/ms633559.aspx>
// and <https://msdn.microsoft.com/en-us/library/ff381406.aspx>

INT	WINAPI	wWinMain(HINSTANCE hInstance,
		         HINSTANCE hPrevInstance,
	                 LPWSTR    lpCmdLine,
	                 INT       nCmdShow)
{
	// see <https://msdn.microsoft.com/en-us/library/ms645507.aspx>

	return MessageBoxEx((HWND) NULL, L"Hello world!\n", L"NOMSVCRT", MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL));
}
#else // ANSI
// see <https://msdn.microsoft.com/en-us/library/ms633559.aspx>
// and <https://msdn.microsoft.com/en-us/library/ff381406.aspx>

INT	WINAPI	WinMain(HINSTANCE hInstance,
		        HINSTANCE hPrevInstance,
	                LPSTR     lpCmdLine,
	                INT       nCmdShow)
{
	// see <https://msdn.microsoft.com/en-us/library/ms645507.aspx>

	return MessageBoxEx((HWND) NULL, "Hello world!\n", "NOMSVCRT", MB_OK, MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL));
}
#endif // UNICODE
#endif // CONSOLE
#endif // DLL
CL.exe /GA /GF /Gy /Oi /Zl … ‹source›.c

Implementation

NOMSVCRT.LIB implements the following helper routines, internal functions and intrinsics supported and used by Microsoft’s Visual C compilers.

Startup routines

mainCRTStartup(), wmainCRTStartup(), WinMainCRTStartup(), wWinMainCRTStartup() and _DllMainCRTStartup().

Note: the startup routines compile for all processor architectures supported by Windows.

Stack allocation and runtime checks

_alloca(), _chkstk() and __security_check_cookie().

Note: the /GS runtime check routine raises an exception 0xC0000409 alias STATUS_STACK_BUFFER_OVERRUN; it compiles for all processor architectures supported by Windows.

Buffer manipulation

memchr(), memcmp(), memcpy(), memmove() and memset(), plus wmemchr(), wmemcmp(), wmemcpy(), wmemmove() and wmemset().

Note: for processor architectures other than I386 alias x86 only the memcpy(), memset(), wmemcpy() and wmemset() routines are implemented.

ASCII string handling

strcat(), strchr(), strcmp(), strcpy(), strlen(), strset() and _strset().

Note: the string handling routines are implemented only for the I386 alias x86 processor architecture.

Unicode string handling

wcscat(), wcschr(), wcscmp(), wcscpy(), wcslen(), wcsset() and _wcsset().

Note: the string handling routines are implemented only for the I386 alias x86 processor architecture.

Endian conversion

htonl(), htons(), ntohl() and ntohs().

Note: the conversion routines are implemented only for the I386 alias x86 processor architecture.

Signed 64-bit arithmetic

_alldiv(), _alldvrm(), _allmul(), _allrem(), _allshl() and _allshr(), plus _allrotl() and _allrotr().

Note: the multiplication routine is about 2× faster and the division routines are 4× to 6× faster than those supplied in Microsoft’s MSVCRT libraries; multiplication is about 10× slower than native 64-bit multiplication, while division and remainder are (on average) about 1.5× slower than native 64-bit signed division and remainder.

Unsigned 64-bit arithmetic

_aulldiv(), _aulldvrm(), _aullrem() and _aullshr(), plus _aullmul(), _aullrotl(), _aullrotr() and _aullshl().

Note: the division routines are 4× to 6× faster than those supplied in Microsoft’s MSVCRT libraries; they are (on average) only 1 to 3 processor cycles slower than native 64-bit unsigned division and remainder.

Floating point

_CIacos(), _CIasin(), _CIatan(), _CIatan2(), _CIcos(), _CIcosh(), _CIexp(), _CIfmod(), _CIlog(), _CIlog10(), _CIpow(), _CIsin(), _CIsinh(), _CIsqrt(), _CItan(), _CItanh(), _ftol(), _ftol2(), _ftol2_sse(), acos(), acosh(), asin(), asinh(), atan(), atan2(), atanh(), cos(), cosh(), exp(), exp2(), fabs(), fmod(), fremainder(), log(), log2(), log10(), pow(), sin(), sinh(), sqrt(), tan() and tanh(), plus acot(), acot2(), acoth(), cot(), coth() and exp10().

Note: the floating point routines are implemented only for the I386 alias x86 processor architecture; they use the algebraic, arithmetic, transcendental and trigonometric functions of the processor’s builtin IEEE–754 FPU.

POSIX functions

calloc(), free(), malloc() and realloc().

Limitation

NOMSVCRT does neither support runtime checks, i.e. the /RTC1, /RTCc, /RTCs and /RTCu compiler switches, nor global initializers.

Download

… the makefile NOMSVCRT.MAK to build the object library NOMSVCRT.LIB for the I386 alias x86 processor architecture, the optional icon file NOMSVCRT.ICO to build the resource file NOMSVCRT.RES, the include file NOMSVCRT.H, and the ANSI C source file NOMSVCRT.C to build the sample Windows application NOMSVCRT.EXE, the sample DLL NOMSVCRT.DLL, and the sample console program NOMSVCRT.COM, …

Contact

If you miss anything here, have additions, comments, corrections, criticism or questions, want to give feedback, hints or tipps, report broken links, bugs, errors, inaccuracies, omissions, vulnerabilities or weaknesses, …:
don’t hesitate to contact me and feel free to ask, comment, criticise, flame, notify or report!

Use the X.509 certificate to send S/MIME encrypted mail.

Notes: I dislike HTML (and even weirder formats too) in email, I prefer to receive plain text.
I also expect to see a full (real) name as sender, not a nickname!
Emails in weird formats and without a proper sender name are likely to be discarded.
I abhor top posts and expect inline quotes in replies.

Terms and conditions

By using this site, you signify your agreement to these terms and conditions. If you do not agree to these terms and conditions, do not use this site!
Copyright © 1995–2017 • Stefan Kanthak • <‍skanthak‍@‍nexgo‍.‍de‍>