From: Ulrich Eckhardt on 8 Sep 2009 04:32 Vincent Fatica wrote: > On Mon, 07 Sep 2009 09:26:25 +0200, Ulrich Eckhardt > <eckhardt(a)satorlaser.com> wrote: > > |How about this: > | > | char simem[sizeof (STARTUPINFO)] = {0}; > | STARTUPINFO si = (STARTUPINFO*)simem; > > Did you mean > > char simem[sizeof (STARTUPINFO)] = {0}; > STARTUPINFO *psi = (STARTUPINFO*)simem; Of course, yes. > That invokes memset, gives the LNK4210 warning, makes a .CRT section, and > increases the .text segment from 0x9F bytes to 0x9AA bytes (159 to 2474). > > SecureZeroMemory and __stosb avoid memset. So does > > STARTUPINFO si = {sizeof(si),0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; > > but that costs about 64 bytes later, moving 0 into each member. Honestly: I would ignore that and start getting some real work done. ;) *shrug* Good luck anyway! Uli -- C++ FAQ: http://parashift.com/c++-faq-lite Sator Laser GmbH Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
From: pm on 8 Sep 2009 07:37 http://social.msdn.microsoft.com/forums/en-US/Vsexpressvc/thread/a51fe950-cd74-4133-8d84-1bc07b353bc2/ http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/dd0ccf2c-ec28-4b1a-a609-bd962a17febf/ PM- Vincent Fatica wrote: > (VC9) I am trying to avoid the runtime library in a tiny app (something I do > regularly). When I try to zero-fill a STARTUPINFO struct with a for-loop, the > compiler turns my for-loop into a call to _memset. > > ; 13 : STARTUPINFO si; > ; 14 : si.cb = sizeof(si); > ; 15 : for (BYTE *p = (BYTE*) &si + sizeof(si.cb); p < (BYTE*) &si + > sizeof(si); p++) > ; 16 : *p=0; > > push 64 ; 00000040H > lea edx, DWORD PTR _si$[esp+104] > push 0 > push edx > add esi, 2 > mov DWORD PTR _si$[esp+108], 68 ; 00000044H > call _memset > add esp, 12 ; 0000000cH > > How do I avoid that (elegantly)? Is it some kind of optimization I can simply > turn off? I can trick the compiler with the likes of > > ; 16 : *p = p ? 0 : 1; // in the loop > > That avoids the _memset, but seems particularly kludgy. > > Thanks.
From: xiaosi on 8 Sep 2009 09:29 Mark Lucovsky remarked about BaseProcessStart(PPROCESS_START_ROUTINE lpStartAddress): "lpStartAddress - Supplies the starting address of the new thread. The address is logically a procedure that never returns." Yes, on my 32bit windows xp sp3, __tmainCRTStartupt (tmainCRTStartup or tWinMainCRTStartup) never returns to BaseProcessStart. Without any exception thrown, __tmainCRTStartup calls exit(), doexit(), __crtExitProcess(), ExitProcess(), _ExitProcess(), NtTerminateProcess(), and never returns. 00 ntdll!NtTerminateProcess 01 kernel32!_ExitProcess+0x37 02 kernel32!ExitProcess+0x14 03 MSVCR90!__crtExitProcess+0x17 [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0dat.c @ 731] 04 MSVCR90!doexit+0x10a [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0dat.c @ 644] 05 MSVCR90!exit+0x11 [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0dat.c @ 412] 06 winconsol!__tmainCRTStartup+0x125 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 597] 07 kernel32!BaseProcessStart+0x23 int __tmainCRTStartup( void ) #ifdef WPRFLAG mainret = wWinMain( #else /* WPRFLAG */ mainret = WinMain( #endif /* WPRFLAG */ (HINSTANCE)&__ImageBase, NULL, lpszCommandLine, StartupInfo.dwFlags & STARTF_USESHOWWINDOW ? StartupInfo.wShowWindow : SW_SHOWDEFAULT ); #else /* _WINMAIN_ */ #ifdef WPRFLAG __winitenv = envp; mainret = wmain(argc, argv, envp); #else /* WPRFLAG */ __initenv = envp; mainret = main(argc, argv, envp); #endif /* WPRFLAG */ #endif /* _WINMAIN_ */ /* * Note that if the exe is managed app, we don't really need to * call exit or _c_exit. .cctor should be able to take care of * this. */ if ( !managedapp ) exit(mainret); "Alex Blekhman" <tkfx.REMOVE(a)yahoo.com> wrote: > "xiaosi" wrote: >> Besides call convention, ExitProcess should be used instead of return, because both tmainCRTStartup and tWinMainCRTStartup call >> kernel32!ExitProcess(status) after tmain or tWinMain return status. > > This is incorrect. tmainCRTStartup and tWinMainCRTStartup call ExitProcess only if there is an exception thrown from main/WinMain. > Otherwise, both CRT startup routines just return. kernel32!BaseProcessStart routine calls ExitThread, which in its turn calls > ExitProcess. > > Alex
From: xiaosi on 8 Sep 2009 10:53 Yes, the msdn documentation is incorrect about /ENTRY, it had confused me long ago. EXE ENTRY should be int __cdecl(*)(void), or int __stdcall(*)(void). DLL ENTRY must be defined as DllMain. 00 hookdll!DllMain [j:\test\hookdll\hookdll.cpp @ 95] 01 hookdll!__DllMainCRTStartup+0x7a [f:\dd\vctools\crt_bld\self_x86\crt\src\crtdll.c @ 546] 02 hookdll!_DllMainCRTStartup+0x1e [f:\dd\vctools\crt_bld\self_x86\crt\src\crtdll.c @ 510] 03 ntdll!LdrpCallInitRoutine+0x14 04 ntdll!LdrpRunInitializeRoutines+0x344 05 ntdll!LdrpInitializeProcess+0x1131 06 ntdll!_LdrpInitialize+0x183 07 ntdll!KiUserApcDispatcher+0x7 BOOL WINAPI _DllMainCRTStartup( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ) "Alex Blekhman" <tkfx.REMOVE(a)yahoo.com> wrote: > I found the requirements here: > > "/ENTRY (Entry-Point Symbol)" > http://msdn.microsoft.com/en-us/library/f9t8842e.aspx > > <quote> > The function must be defined with the __stdcall calling > convention. The parameters and return value must be defined as > documented in the Win32 API for WinMain (for an .exe file) or > DllEntryPoint (for a DLL). > </quote> > > However, after reading your answer I looked into crtexe.c file I > discovered that CRT startup routines don't respect this > requirement, exactly as you noticed. Moreover, BaseProcessStart > routine from kernel32.dll doesn't care neither about parameters > nor calling convention. The call looks like this: > > call dword ptr [ebp+8] > push eax > call _ExitThread@4 > > Where "dword ptr [ebp+8]" is the address of the process entry > point. The process entry point address is passed as a parameter to > BaseProcessStart, as well. > > So, actually the linker documentation is incorrect and one must > use int __cdecl(*)(void) function as a custom entry point. It is > only by sheer luck BaseProcessStart and subsequent code don't > change anything on stack, so there is no access violation > exception. > > I would be very interested in hearing from MSFT people about the > issue. > > Alex
From: xiaosi on 8 Sep 2009 11:06
When I write: #pragma comment(lib, "F:\\WINDDK\\3790.1830\\lib\\wxp\\i386\\ntdll.lib") VC always import memset from ntdll.lib instead of CRT lib. To ensure not to import anything from CRT lib, I write: #pragma comment(linker, "/nodefaultlib") But this need to write every lib you will use: #pragma comment(lib, "kernel32") #pragma comment(lib, "user32") #pragma comment(lib, "gdi32") #pragma comment(lib, "comctl32") "Vincent Fatica" <vince(a)blackholespam.net> wrote: > > How do I ensure my app get them from ntdll.dll and not try to get them from the > CRT lib? > > On Tue, 8 Sep 2009 13:32:29 +0800, "xiaosi" <xiaosi(a)cn99.com> wrote: > > |One day I dumpbin /headers /exports ntdll.dll > exports_ntdll.txt, and find ntdll.dll has many "built-in" crt functions. When > system > |loads an app, it always firstly maps ntdll.dll to the app's process. This means every app has these "built-in" crt functions, so > why > |bother to import these functions from the crt lib (except using inline for speed). wcstoul/wcstol/strtoul/strtol are also > "built-in" > |in ntdll.dll. |