Figure 1

Figure 1 Hello World .MAP File

  Address         Publics by Value              Rva+Base     Lib:Object
 0001:00000000   _main                      00401000 f   hello.obj
 0001:0000000c   _printf                    0040100c f   LIBC:printf.obj
 0001:0000003d   _mainCRTStartup            0040103d f   LIBC:crt0.obj
 0001:0000011c   __amsg_exit                0040111c f   LIBC:crt0.obj
 0001:00000165   __stbuf                    00401165 f   LIBC:_sftbuf.obj
 0001:000001f2   __ftbuf                    004011f2 f   LIBC:_sftbuf.obj
 0001:0000022f   __output                   0040122f f   LIBC:output.obj
 0001:00000a39   ___initstdio               00401a39 f   LIBC:_file.obj
 0001:00000ade   ___endstdio                00401ade f   LIBC:_file.obj
 0001:00000af2   __cinit                    00401af2 f   LIBC:crt0dat.obj
 0001:00000b1f   _exit                      00401b1f f   LIBC:crt0dat.obj
 0001:00000b30   __exit                     00401b30 f   LIBC:crt0dat.obj
 0001:00000bf4   __XcptFilter               00401bf4 f   LIBC:winxfltr.obj
 0001:00000d78   __setenvp                  00401d78 f   LIBC:stdenvp.obj
 0001:00000e31   __setargv                  00401e31 f   LIBC:stdargv.obj
 0001:0000107e   ___crtGetEnvironmentStringsA 0040207e f   LIBC:a_env.obj
 0001:000011b0   __ioinit                   004021b0 f   LIBC:ioinit.obj
 0001:0000135b   __heap_init                0040235b f   LIBC:heapinit.obj
 0001:00001398   __global_unwind2           00402398 f   LIBC:exsup.obj
 0001:000013da   __local_unwind2            004023da f   LIBC:exsup.obj
 0001:00001432   __NLG_Return2              00402432 f   LIBC:exsup.obj
 0001:00001442   __abnormal_termination     00402442 f   LIBC:exsup.obj
 0001:00001465   __NLG_Notify1              00402465 f   LIBC:exsup.obj
 0001:0000146e   __NLG_Notify               0040246e f   LIBC:exsup.obj
 0001:00001481   __NLG_Dispatch             00402481 f   LIBC:exsup.obj
 0001:00001490   __except_handler3          00402490 f   LIBC:exsup3.obj
 0001:0000154d   __seh_longjmp_unwind@4     0040254d f   LIBC:exsup3.obj
 0001:00001568   __FF_MSGBANNER             00402568 f   LIBC:crt0msg.obj
 0001:000015a1   __NMSG_WRITE               004025a1 f   LIBC:crt0msg.obj
 0001:000016f4   _malloc                    004026f4 f   LIBC:malloc.obj
 0001:00001706   __nh_malloc                00402706 f   LIBC:malloc.obj
 0001:00001732   __heap_alloc               00402732 f   LIBC:malloc.obj
 0001:00001768   __isatty                   00402768 f   LIBC:isatty.obj
 0001:0000178e   _fflush                    0040278e f   LIBC:fflush.obj
 0001:000017c9   __flush                    004027c9 f   LIBC:fflush.obj
 0001:00001825   __flushall                 00402825 f   LIBC:fflush.obj
 0001:000018a0   _strlen                    004028a0 f   LIBC:strlen.obj
 0001:0000191b   _wctomb                    0040291b f   LIBC:wctomb.obj
 0001:00001990   __aulldiv                  00402990 f   LIBC:ulldiv.obj
 0001:00001a00   __aullrem                  00402a00 f   LIBC:ullrem.obj
 0001:00001a75   __flsbuf                   00402a75 f   LIBC:_flsbuf.obj
 0001:00001b8a   _calloc                    00402b8a f   LIBC:calloc.obj
 0001:00001c07   __fcloseall                00402c07 f   LIBC:closeall.obj
 0001:00001c5f   _free                      00402c5f f   LIBC:free.obj
 0001:00001c90   _strcpy                    00402c90 f   LIBC:strcat.obj
 0001:00001ca0   _strcat                    00402ca0 f   LIBC:strcat.obj
 0001:00001d80   __setmbcp                  00402d80 f   LIBC:mbctype.obj
 0001:00002144   ___initmbctable            00403144 f   LIBC:mbctype.obj
 0001:00002160   _memcpy                    00403160 f   LIBC:memcpy.obj
 0001:00002495   ___sbh_heap_init           00403495 f   LIBC:sbheap.obj
 0001:000024d3   ___sbh_find_block          004034d3 f   LIBC:sbheap.obj
 0001:000024fe   ___sbh_free_block          004034fe f   LIBC:sbheap.obj
 0001:00002829   ___sbh_alloc_block         00403829 f   LIBC:sbheap.obj
 0001:00002b32   ___sbh_alloc_new_region    00403b32 f   LIBC:sbheap.obj
 0001:00002be3   ___sbh_alloc_new_group     00403be3 f   LIBC:sbheap.obj
 0001:00002cde   ___crtMessageBoxA          00403cde f   LIBC:crtmbox.obj
 0001:00002d70   _strncpy                   00403d70 f   LIBC:strncpy.obj
 0001:00002e6e   __callnewh                 00403e6e f   LIBC:handler.obj
 0001:00002e89   __commit                   00403e89 f   LIBC:commit.obj
 0001:00002ee0   __write                    00403ee0 f   LIBC:write.obj
 0001:0000308d   __fptrap                   0040408d f   LIBC:crt0fp.obj
 0001:00003096   __lseek                    00404096 f   LIBC:lseek.obj
 0001:00003130   __getbuf                   00404130 f   LIBC:_getbuf.obj
 0001:00003180   _memset                    00404180 f   LIBC:memset.obj
 0001:000031d8   _fclose                    004041d8 f   LIBC:fclose.obj
 0001:0000322e   ___crtLCMapStringA         0040422e f   LIBC:a_map.obj
 0001:0000347d   ___crtGetStringTypeA       0040447d f   LIBC:a_str.obj
 0001:000035d0   _memmove                   004045d0 f   LIBC:memmove.obj
 0001:00003905   __free_osfhnd              00404905 f   LIBC:osfinfo.obj
 0001:0000397f   __get_osfhandle            0040497f f   LIBC:osfinfo.obj
 0001:000039bc   __dosmaperr                004049bc f   LIBC:dosmap.obj
 0001:00003a23   __close                    00404a23 f   LIBC:close.obj
 0001:00003ad6   __freebuf                  00404ad6 f   LIBC:_freebuf.obj
 0001:00003b10   __alloca_probe             00404b10 f   LIBC:chkstk.obj
 0001:00003b10   __chkstk                   00404b10 f   LIBC:chkstk.obj

Figure 2 printf.cpp

  //==========================================
// LIBCTINY - Matt Pietrek 2001
// MSDN Magazine, January 2001
//==========================================
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>

// Force the linker to include USER32.LIB
#pragma comment(linker, "/defaultlib:user32.lib")

extern "C" int __cdecl printf(const char * format, ...)
{
    char szBuff[1024];
    int retValue;
    DWORD cbWritten;
    va_list argptr;
          
    va_start( argptr, format );
    retValue = wvsprintf( szBuff, format, argptr );
    va_end( argptr );

    WriteFile(  GetStdHandle(STD_OUTPUT_HANDLE), szBuff, retValue,
                &cbWritten, 0 );

    return retValue;
}

Figure 3 initterm

  //==========================================
// LIBCTINY - Matt Pietrek 2001
// MSDN Magazine, January 2001
//==========================================
#include <windows.h>
#include <malloc.h>
#include "initterm.h"

#pragma data_seg(".CRT$XCA")
_PVFV __xc_a[] = { NULL };


#pragma data_seg(".CRT$XCZ")
_PVFV __xc_z[] = { NULL };

#pragma data_seg()  /* reset */

#pragma comment(linker, "/merge:.CRT=.data")

typedef void (__cdecl *_PVFV)(void);

void __cdecl _initterm (
        _PVFV * pfbegin,
        _PVFV * pfend
        )
{
    /*
     * walk the table of function pointers from the bottom up, until
     * the end is encountered.  Do not skip the first entry.  The initial
     * value of pfbegin points to the first valid entry.  Do not try to
     * execute what pfend points to.  Only entries before pfend are 
     * valid.
     */
    while ( pfbegin < pfend )
    {
        // if current table entry is non-NULL, call thru it.
        if ( *pfbegin != NULL )
            (**pfbegin)();
        ++pfbegin;
    }
}

static _PVFV * pf_atexitlist = 0;
static unsigned max_atexitlist_entries = 0;
static unsigned cur_atexitlist_entries = 0;

void __cdecl _atexit_init(void)
{
    max_atexitlist_entries = 32;
    pf_atexitlist = (_PVFV *)calloc( max_atexitlist_entries,
                                     sizeof(_PVFV*) );
}

int __cdecl atexit (_PVFV func )
{
    if ( cur_atexitlist_entries < max_atexitlist_entries )
    {
        pf_atexitlist[cur_atexitlist_entries++] = func; 
        return 0;
    }

    return -1;
}

void __cdecl _DoExit( void )
{
    if ( cur_atexitlist_entries )
    {
        _initterm(  pf_atexitlist,
                    // Use ptr math to find the end of the array
                    pf_atexitlist + cur_atexitlist_entries );
    }
}

Figure 4 DLLCRTO.CPP

  //==========================================
// LIBCTINY - Matt Pietrek 2001
// MSDN Magazine, January 2001
// FILE: DLLCRT0.CPP
//==========================================
#include <windows.h>
#include "initterm.h"

// Force the linker to include KERNEL32.LIB
#pragma comment(linker, "/defaultlib:kernel32.lib")

// Force 512 byte section alignment in the PE file
#pragma comment(linker, "/OPT:NOWIN98")

// #pragma comment(linker, "/nodefaultlib:libc.lib")
// #pragma comment(linker, "/nodefaultlib:libcmt.lib")

// User routine DllMain is called on all notifications

extern BOOL WINAPI DllMain(
                           HANDLE  hDllHandle,
                           DWORD   dwReason,
                           LPVOID  lpreserved
                           ) ;

//
// Modified version of the Visual C++ startup code.  Simplified to
// make it easier to read.  Only supports ANSI programs.
//
extern "C"
BOOL WINAPI _DllMainCRTStartup(
                               HANDLE  hDllHandle,
                               DWORD   dwReason,
                               LPVOID  lpreserved
                               )
{
    if ( dwReason == DLL_PROCESS_ATTACH )
    {
        // set up our minimal cheezy atexit table
        _atexit_init();

        // Call C++ constructors
        _initterm( __xc_a, __xc_z );
    }

    BOOL retcode = DllMain(hDllHandle, dwReason, lpreserved);

    if ( dwReason == DLL_PROCESS_DETACH )
    {
        _DoExit();
    }

    return retcode ;
}

Figure 5 TEST.CPP

  // Small test program to exercise TINYCRT.  Does nothing useful
//
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main( int argc, char *argv[] )
{
    int i;

    for ( i = 0; i < argc; i++ )
    {
        printf( "argc: %u \'%s\'\n", i, argv[i] );
    }

    char * p = new char[10];

    lstrcpy( p, "Hello" );

    delete p;

    printf( "%s\n", strlwr( "MyLowerCaseString" ) );

    printf ( "strcmpi: %u\n", strcmpi( "Abc", "abc" ) );

    strrchr( "foo", 'o' );

    return 0;
}

// Declare a simple C++ class with a constructor
class TestClass
{
public:
    TestClass(void)
    {
        printf( "In TestClass constructor\n" );
    }
    ~TestClass(void)
    {
        printf( "In TestClass destructor\n" );
    }
};

// Create a global instance of the class
TestClass g_TestClassInstance;