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;