Создание консольных приложений без заголовков CRT и default?

Я пытаюсь создать консольное приложение без использования CRT или любого другого импорта, кроме kernel32.во всяком случае, Либ. Я получаю свой код для компиляции, но не могу обернуть компоновщик вокруг нескольких проблем:

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 и GetProcAddress я ввел в программу явно, не используя 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 );

Я полагаю, что-то не так с моими прототипами. Тем не менее, большая проблема __security_check_cookie и _wmainCRTStartup, которые, очевидно, что-то это связано с ЭЛТ. Поэтому мне интересно, как я буду переопределять значение по умолчанию int wmain(int argc, wchar_t* argv[]) для entrypoint и как избавиться от любого файла cookie безопасности.

6 ответов


_wmainCRTStartup-это функция, которая вызывает wmain ()

IIRC он должен быть доступен в некоторых .o файл, с которым вы можете связаться, посмотрите в каталоге lib.

может быть, это тоже полезное чтение: уменьшить размер EXE и DLL с LIBCTINY.Либ!--6--> (и Matt Pietrek скалы :-)


Ну, отвечая себе здесь, чтобы подвести итог, в случае, если кто-то еще найдет эту страницу в поисках информации.

как советовал MSalters, код cookie безопасности может быть украден из источника CRT, но при этом я обнаружил, что /GS- флаг компилятора можно использовать, чтобы полностью избежать безопасности.

как сказал SoapBox, функции API должны быть __stdcall, а также точка входа не. Я исправил проблему точки входа с флагом командной строки компоновщика /entry:wmain.

и, наконец, как отметил Томек, функции API должны быть в extern C!

так:

#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;
}

более правильное объявление точки входа будет:

int __stdcall wmain(PVOID ThreadParam)

без точки входа CRT, вызываемой напрямую BaseThreadInitThunk. Его передает указатель на что-то, но не argc+argv.


вы можете посмотреть в Windows.h чтобы увидеть прототипы, необходимые для импорта kernel32. В общем случае функции windows определены WINAPI что на самом деле __stdcall, а не __cdecl. По крайней мере, это решит проблему.

Что касается вашей другой проблемы, вам нужно изучить аргументы командной строки компоновщика и посмотреть, есть ли способ заставить его не искать вещи из CRT. Я не знаю, есть ли способ сделать это или нет. Но тебе придется найти способ или определение. это функции вашего " Я " (которые вы, вероятно, не хотите делать).

Я бы рекомендовал просто использовать другой компилятор / компоновщик.


вам нужно объявить windows.h функционирует как extern "C".


правильная точка входа main(), а не wmain() (поскольку вы компилируете консольное приложение). Код cookie безопасности может быть взят из исходного кода CRT; нет необходимости связывать его.