views:

780

answers:

5

I'm trying to build a console application without using the CRT, or any other imports than kernel32.lib in any case. I get my code to compile, but can't wrap the linker around a few problems:

unresolved external symbol @__security_check_cookie@4
unresolved external symbol "int __cdecl FreeLibrary(void *)" (?FreeLibrary@@YAHPAX@Z)
unresolved external symbol "void * __cdecl LoadLibraryW(wchar_t *)" (?LoadLibraryW@@YAPAXPA_W@Z)
unresolved external symbol "int (__cdecl*__cdecl GetProcAddress(void *,char *))(void)" (?GetProcAddress@@YAP6AHXZPAXPAD@Z)
unresolved external symbol _wmainCRTStartup

FreeLibrary, LoadLibraryW and GetProcAddress I've brought in to program explicitly, not using windows.h:

#pragma comment(lib, "kernel32.lib")

typedef int(*FARPROC)();

void* LoadLibraryW( wchar_t* lpLibFileName );
FARPROC GetProcAddress( void* hModule, char* lpProcName );
int FreeLibrary( void* hLibModule );

I suppose something is wrong with my prototypes. However, the bigger problem are __security_check_cookie and _wmainCRTStartup, which obviously have something to do with the CRT. So I'm wondering how I'd go about overriding the default int wmain(int argc, wchar_t* argv[]) for entrypoint, and how to get rid of whatever the security cookie is.

+1  A: 

You can look in Windows.h to see the prototypes you need for your kernel32 imports. In general, windows functions are defined WINAPI which is actually __stdcall and not __cdecl. That will fix that problem at least.

As for your other problem, you need to explore the linker commandline arguments and see if there is a way to get it to not look for things from CRT. I don't know if there is a way to do that or not. But you're going to have to find a way or define those functions your self (which you probably don't want to do).

I'd recommend just using a different compiler/linker.

SoapBox
Actually I tried them as stdcalls already, and it didn't solve the problem.
psoul
+1  A: 

The proper entry point is main(), not wmain() (since you're compiling a console app). The security cookie code can be nicked from the CRT source code; no need to link it in.

MSalters
wmain is the console entry point for unicode.
psoul
+3  A: 

_wmainCRTStartup is the function that calls wmain()

IIRC it should be available in some .o file that you can link with, look in your lib directory.

Maybe this is useful reading too: Reduce EXE and DLL Size with LIBCTINY.LIB (and Matt Pietrek rocks :-)

divideandconquer.se
+1  A: 

You need to declare windows.h functions as extern "C".

Tomek
Thank you! This solved it.
psoul
A: 

Well, answering myself here to sum up, in case someone else finds this page looking for info.

As MSalters advised, the security cookie code can be stolen from the CRT source, but doing that I found that the /GS- compiler flag can be used to avoid the security stuff altogether.

As SoapBox said, the API functions need to be __stdcall, as well as the entry point does. I fixed the entry point issue with linker command line flag /entry:wmain.

And finally, as Tomek pointed out, the API functions gotta be in extern C!

So:

#pragma comment(lib, "kernel32.lib")

typedef int(*FARPROC)();

extern "C" {
  void* __stdcall LoadLibraryW( wchar_t* lpLibFileName );
  FARPROC __stdcall GetProcAddress( void* hModule, char* lpProcName );
  int __stdcall FreeLibrary( void* hLibModule );
  typedef int (__stdcall *f_MessageBoxW_t)( unsigned long hWnd, wchar_t* lpText, wchar_t* lpCaption, unsigned long uType);
  f_MessageBoxW_t fnMsg;
  void* hUser;
};

int __stdcall wmain(int argc, wchar_t* argv[])
{
  hUser = LoadLibraryW( L"user32.dll" );
  fnMsg = (f_MessageBoxW_t)GetProcAddress( hUser, "MessageBoxW" );
  fnMsg( 0, L"foo", L"bar", 0 );
  FreeLibrary( hUser );
  return 0;
}
psoul