【问题标题】:Static linking libgcc on Windows DLLWindows DLL 上的静态链接 libgcc
【发布时间】:2017-06-28 19:31:21
【问题描述】:

我正在用 C++ 编写一个 Windows DLL。这个库只有 C 接口,并且只使用也有 C 接口的标准 Windows 库。因此,将所有 C++ 库静态链接到库中似乎是安全的,因为仅使用 C 接口时我不依赖于 C++ ABI 版本。

不幸的是,当我使用 -static-stdc++ -static-libgcc 编译我的库时,我的库停止处理异常,当抛出一些异常时,DLL 调用其静态链接的 _Unwind_RaiseException 函数,这会中止整个应用程序。

我认为它可能是一个损坏的libgtcc.a,所以我尝试更新我的编译器。但是 MinGW 4.8 和 MinGW 6.3 的结果是一样的。

请问有人能解释一下这里到底发生了什么吗?

Klasyc

【问题讨论】:

  • 使用 TDM-GCC。看简要说明here
  • 或者支持SEH的MinGW。
  • @RustyX OP 已经尝试过 MinGW,正如你所说,它支持 SEH,但如果库是静态链接的并且异常被抛出跨 DLL 边界,则不支持。这是 TDM-GCC 解决的问题之一。如果运行时库是动态链接的(即进程中只有一个版本),MinGW 就很好。
  • @RustyX:为什么我需要支持 SEH 的编译器?我认为 SEH 允许我捕获 Windows 异常,例如访问冲突等,但即使是基本的 C++ 异常,我也有问题。
  • @Dan:我通常使用 QtCreator 和 MinGW 随附的 C++/Qt。我对这个组合很满意。因此,我也将它用于我的 DLL。

标签: c++ windows dll exception-handling


【解决方案1】:

您是否正在处理 DLL 中的所有异常?如果任何异常“泄漏”到具有 C 调用约定的函数之外,则会导致应用程序崩溃。

我在 MinGW x86_64-5.3.0-win32-seh-rt_v4-rev0mingw32 4.8.1 dwarf2 下使用静态 libstdc++ 没有遇到 C++ 异常问题/libgcc。

DLL 源(dll.cpp):

#include <windows.h>
#include <exception>
#include <iostream>

extern "C" {
__declspec(dllexport) int __stdcall test() {
    try {
        new int[-1];
        return 123;
    } catch (const std::exception& ex) {
        std::cerr << "Exception:" << ex.what() << std::endl;
        return 456;
    }
}
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD     fdwReason, LPVOID    lpvReserved)
{
    return TRUE;
}

应用源(app.c):

#include <stdio.h>

#ifdef __cplusplus
extern "C"
#endif
__declspec(dllimport) int __stdcall test();

int main() {
  printf("result: %d\n", test());
  return 0;
}

编译:

g++ -O2 -static-libgcc -static-libstdc++ -shared -Wl,--out-implib=dtest.lib -s -o dtest.dll dll.cpp

g++ -O2 -static-libgcc -static-libstdc++ -L. -s -o app app.c -ldtest

输出:

Exception:std::bad_alloc
result: 456

回答您的评论“为什么我需要支持 SEH 的编译器?我认为 SEH 允许我捕获 Windows 异常” - 在 Windows 上,SEH 是 all 的事实上的标准异常,包括 C++ 异常(使用 Visual C++ 编译时)。 MinGW 对 C++ 异常(SEH、SJLJ 和 DWARF)有不同的实现,但是 SEH 是唯一零开销的机制,所以如果它可用,你真的应该更喜欢它而不是 SJLJ 和 DWARF。

【讨论】:

    【解决方案2】:

    感谢 RastyX 在他的回答中提供了这个简单的例子。经过一番研究,我发现当我使用-static-libgcc 编译 DLL 部分和没有此开关的应用程序部分(这两个部分使用相同的 g++ 编译)时,应用程序崩溃了。

    还要感谢 Ripi2 对 TDM-GCC 的建议。我尝试了 SJLJ 和 DWARF-2 异常处理,两者都有效。

    总而言之,MinGW 的 libgcc 似乎不喜欢每个进程多次实例化它。在我的情况下,我在 DLL 中使用了一份副本(静态链接),在应用程序中使用了一份副本,这可能会破坏异常处理。

    另一方面,TDM-GCC 专注于基本库的静态链接,正如其网页所说,因此即使没有-static-stdc++ -static-libgcc 命令行开关(这就是我想要的),它也会生成仅依赖于 Windows 库的二进制文件。异常处理也在这里工作,所以改变工具链对我来说是正确的方式。

    【讨论】:

      猜你喜欢
      • 2010-12-02
      • 2020-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-06
      • 1970-01-01
      相关资源
      最近更新 更多