【问题标题】:static linking breaks debug executable on windows (mingw)静态链接会破坏 Windows 上的调试可执行文件(mingw)
【发布时间】:2011-08-25 08:04:23
【问题描述】:

我们的 C++ 项目使用混合的动态 (Qt) 和静态 (ffmpeg、portaudio) 库。目前我正在尝试将其移植到 Windows 并且由 mingw(通过 QtCreator)生成的调试可执行文件拒绝启动(错误是某某不是有效的可执行文件)。具有相同链接的发布可执行文件启动(但有一些我想调试的问题)。

为了缩小问题的可能原因,我做了一个什么都不做的虚拟项目,只是链接到同一组库,它有完全相同的问题。只要我禁用链接到两个静态库的调试可执行文件,只要我启用其中任何一个,调试可执行文件就会损坏。

我还没有尝试构建 ffmpeg 和 portaudio 的 dll 版本,但我想了解这个案例的问题所在。

【问题讨论】:

    标签: windows debugging mingw qt-creator static-linking


    【解决方案1】:

    这是因为一些 Qt 下载中包含的 MinGW 包中的 ld 链接器中的一个严重错误。

    MinGW 4.4.0 包中包含的 ld 链接器在用于放置 .debug_pubtypes 部分的默认链接器脚本中有一个错误,该部分用于存储符号或一些调试信息。链接描述文件导致该部分被放置在加载程序不喜欢的虚拟地址(或类似的东西)。有时 - 如果图像中没有符号,或者符号足够小(或者可能有其他因素),问题就不会出现。

    你有几个选择:

    • 使用-T <scriptfile> 选项为ld 指定正确的链接描述文件
    • 升级到更新版本的 ld(MinGW 4.5.2 附带的 2.21 版本可以正常工作)。

    这是 ld 2.21 的默认链接器脚本,如果你将它传递给你拥有的版本,它应该可以工作(不幸的是,我的笔记没有说明有问题的 ld 的版本号是什么 - 如果你可以删除对此发表评论,以便我更新我的笔记,我将不胜感激)。

    /* Default linker script, for normal executables */
    OUTPUT_FORMAT(pei-i386)
    SEARCH_DIR("/c/temp/gcc/dest/i686-pc-mingw32/lib"); SEARCH_DIR("/c/temp/gcc/dest/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
    SECTIONS
    {
      /* Make the virtual address and file offset synced if the alignment is
         lower than the target page size. */
      . = SIZEOF_HEADERS;
      . = ALIGN(__section_alignment__);
      .text  __image_base__ + ( __section_alignment__ < 0x1000 ? . : __section_alignment__ ) :
      {
         *(.init)
        *(.text)
        *(SORT(.text$*))
         *(.text.*)
        *(.glue_7t)
        *(.glue_7)
         ___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
                LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*));  LONG (0);
         ___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
                LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*));  LONG (0);
         *(.fini)
        /* ??? Why is .gcc_exc here?  */
         *(.gcc_exc)
        PROVIDE (etext = .);
         *(.gcc_except_table)
      }
      /* The Cygwin32 library uses a section to avoid copying certain data
         on fork.  This used to be named ".data".  The linker used
         to include this between __data_start__ and __data_end__, but that
         breaks building the cygwin32 dll.  Instead, we name the section
         ".data_cygwin_nocopy" and explictly include it after __data_end__. */
      .data BLOCK(__section_alignment__) :
      {
        __data_start__ = . ;
        *(.data)
        *(.data2)
        *(SORT(.data$*))
        *(.jcr)
        __data_end__ = . ;
        *(.data_cygwin_nocopy)
      }
      .rdata BLOCK(__section_alignment__) :
      {
        *(.rdata)
                 *(SORT(.rdata$*))
        ___RUNTIME_PSEUDO_RELOC_LIST__ = .;
        __RUNTIME_PSEUDO_RELOC_LIST__ = .;
        *(.rdata_runtime_pseudo_reloc)
        ___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
        __RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
      }
      .eh_frame BLOCK(__section_alignment__) :
      {
        *(.eh_frame)
      }
      .pdata BLOCK(__section_alignment__) :
      {
        *(.pdata)
      }
      .bss BLOCK(__section_alignment__) :
      {
        __bss_start__ = . ;
        *(.bss)
        *(COMMON)
        __bss_end__ = . ;
      }
      .edata BLOCK(__section_alignment__) :
      {
        *(.edata)
      }
      /DISCARD/ :
      {
        *(.debug$S)
        *(.debug$T)
        *(.debug$F)
        *(.drectve)
         *(.note.GNU-stack)
         *(.gnu.lto_*)
      }
      .idata BLOCK(__section_alignment__) :
      {
        /* This cannot currently be handled with grouped sections.
        See pe.em:sort_sections.  */
        SORT(*)(.idata$2)
        SORT(*)(.idata$3)
        /* These zeroes mark the end of the import list.  */
        LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
        SORT(*)(.idata$4)
        __IAT_start__ = .;
        SORT(*)(.idata$5)
        __IAT_end__ = .;
        SORT(*)(.idata$6)
        SORT(*)(.idata$7)
      }
      .CRT BLOCK(__section_alignment__) :
      {
        ___crt_xc_start__ = . ;
        *(SORT(.CRT$XC*))  /* C initialization */
        ___crt_xc_end__ = . ;
        ___crt_xi_start__ = . ;
        *(SORT(.CRT$XI*))  /* C++ initialization */
        ___crt_xi_end__ = . ;
        ___crt_xl_start__ = . ;
        *(SORT(.CRT$XL*))  /* TLS callbacks */
        /* ___crt_xl_end__ is defined in the TLS Directory support code */
        ___crt_xp_start__ = . ;
        *(SORT(.CRT$XP*))  /* Pre-termination */
        ___crt_xp_end__ = . ;
        ___crt_xt_start__ = . ;
        *(SORT(.CRT$XT*))  /* Termination */
        ___crt_xt_end__ = . ;
      }
      .tls BLOCK(__section_alignment__) :
      {
        ___tls_start__ = . ;
        *(.tls)
        *(.tls$)
        *(SORT(.tls$*))
        ___tls_end__ = . ;
      }
      .endjunk BLOCK(__section_alignment__) :
      {
        /* end is deprecated, don't use it */
        PROVIDE (end = .);
        PROVIDE ( _end = .);
         __end__ = .;
      }
      .rsrc BLOCK(__section_alignment__) :
      {
        *(.rsrc)
        *(SORT(.rsrc$*))
      }
      .reloc BLOCK(__section_alignment__) :
      {
        *(.reloc)
      }
      .stab BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.stab)
      }
      .stabstr BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.stabstr)
      }
      /* DWARF debug sections.
         Symbols in the DWARF debugging sections are relative to the beginning
         of the section.  Unlike other targets that fake this by putting the
         section VMA at 0, the PE format will not allow it.  */
      /* DWARF 1.1 and DWARF 2.  */
      .debug_aranges BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_aranges)
      }
      .debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_pubnames)
      }
      .debug_pubtypes BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_pubtypes)
      }
      /* DWARF 2.  */
      .debug_info BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_info) *(.gnu.linkonce.wi.*)
      }
      .debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_abbrev)
      }
      .debug_line BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_line)
      }
      .debug_frame BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_frame)
      }
      .debug_str BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_str)
      }
      .debug_loc BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_loc)
      }
      .debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_macinfo)
      }
      /* SGI/MIPS DWARF 2 extensions.  */
      .debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_weaknames)
      }
      .debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_funcnames)
      }
      .debug_typenames BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_typenames)
      }
      .debug_varnames BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_varnames)
      }
      /* DWARF 3.  */
      .debug_ranges BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_ranges)
      }
      /* DWARF 4.  */
      .debug_types BLOCK(__section_alignment__) (NOLOAD) :
      {
        *(.debug_types) *(.gnu.linkonce.wt.*)
      }
    }
    

    我不介意告诉你,我必须经历大约一周的痛苦才能解决这个问题。对于它认为可执行文件无效的原因,Windows 根本没有提供任何真正的帮助,而且调试——即使使用“Windows 调试工具”中的 cdb 或 WinDBG——也没什么帮助。 Windows 似乎从 NT 内核的加载程序内部深处确定 PE 无效,并且没有提供任何我能找到的有关原因的信息(如果能在事件日志什么的)。

    我最终使用 Wine 的 (!!) 跟踪工具解决了这个问题。我想知道“已检查”版本的 Windows 是否会提供有关该问题的更多信息,但我在下载和安装它时遇到了麻烦。

    【讨论】:

    • 我有 QtCreator 2.2.1 和 mingw 4.4,其中包括 ld 2.19.1。
    • 嗯...虽然测试二进制文件现在在静态链接时运行,但项目本身仍然没有。
    • 以上评论是在从 MinGW 4.5.x 构建/链接到 ld 2.21 之后。如果我在您提供的脚本中添加QMAKE_LFLAGS_WINDOWS = -Wl,-T $$PWD/linker-script.txt,那么大型项目的问题似乎也得到了解决。
    • 我不明白为什么在使用 ld 2.21 时必须指定链接器脚本,因为它应该将该脚本绑定到它作为默认值。如果您使用ld --verbose &gt; somefilename 转储默认脚本,它是否与我发布的脚本相同(可能不同的 MinGW 发行版使用不同的脚本)?但如果你使用QMAKE_LFLAGS_WINDOWS 设置,我想这并不重要。
    • 啊,明白了,我的 PATH 中仍然有错误的 mingw,所以一些可执行文件在那里拾取。似乎工具链选择器在这方面略有破坏 - 从工具链指向编译器是不够的,我需要将其“bin”目录单独添加到 PATH。
    猜你喜欢
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-31
    • 2013-06-24
    • 1970-01-01
    • 2019-01-16
    相关资源
    最近更新 更多