【问题标题】:Building console apps without CRT & default headers?构建没有 CRT 和默认标题的控制台应用程序?
【发布时间】:2008-11-20 11:59:00
【问题描述】:

我正在尝试在不使用 CRT 或任何其他导入而不是 kernel32.lib 的情况下构建控制台应用程序。我可以编译我的代码,但无法将链接器封装在一些问题上:

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,这显然与CRT 有关。 所以我想知道如何覆盖入口点的默认int wmain(int argc, wchar_t* argv[]),以及如何摆脱安全cookie。

【问题讨论】:

    标签: c++ windows visual-studio-2008 visual-c++


    【解决方案1】:

    _wmainCRTStartup是调用wmain()的函数

    IIRC 它应该在您可以链接的某个 .o 文件中可用,请查看您的 lib 目录。

    也许这也是有用的阅读:Reduce EXE and DLL Size with LIBCTINY.LIB (和 Matt Pietrek 摇滚 :-)

    【讨论】:

      【解决方案2】:

      好吧,在这里回答我自己总结一下,以防其他人发现此页面寻找信息。

      正如 MSalters 所建议的,可以从 CRT 源中窃取安全 cookie 代码,但这样做我发现/GS- 编译器标志可用于完全避免安全问题。

      正如 SoapBox 所说,API 函数必须是 __stdcall,入口点也是如此。 我用链接器命令行标志/entry:wmain修复了入口点问题。

      最后,正如 Tomek 所指出的,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;
      }
      

      【讨论】:

      • 我刚刚写了一个包含/entry 选项的答案,当我注意到您的自我答案几乎包含以下所有内容时: 1. 包含windows.h 不会影响您的可执行文件的大小少量。如果您想确定,请使用#define WIN32_LEAN_AND_MEAN#define WIN32_EXTRA_LEAN。 Win32 标头不包括 CRT 标头,因此这里不会有问题。 2. 您可能已经这样做了,但是将/NODEFAULTLIB 传递给链接器并手动链接到kernel32.lib 等。这确实大大降低了生成的可执行文件大小。
      【解决方案3】:

      更正确的入口点声明将是:

      int __stdcall wmain(PVOID ThreadParam)
      

      没有由 BaseThreadInitThunk 直接调用的 CRT 入口点。它传递指向某个东西的指针,但不是 argc+argv。

      【讨论】:

        【解决方案4】:

        您可以在 Windows.h 中查看您的 kernel32 导入所需的原型。一般来说,windows函数定义为WINAPI,实际上是__stdcall而不是__cdecl。这至少可以解决这个问题。

        至于您的其他问题,您需要探索链接器命令行参数,看看是否有办法让它不从 CRT 中查找内容。我不知道是否有办法做到这一点。但是您必须自己找到一种方法或定义这些功能(您可能不想这样做)。

        我建议只使用不同的编译器/链接器。

        【讨论】:

        • 其实我已经尝试将它们作为标准调用,但并没有解决问题。
        【解决方案5】:

        您需要将 windows.h 函数声明为 extern "C"。

        【讨论】:

          【解决方案6】:

          正确的入口点是main(),而不是wmain()(因为您正在编译控制台应用程序)。 可以从 CRT 源代码中截取安全 cookie 代码;无需链接。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-03-25
            • 2019-03-12
            • 2012-11-02
            • 2010-09-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多