Bug 11539

Summary: ld --gc-sections should work for PE-COFF on MinGW
Product: binutils Reporter: Andrea Gray <andrea.e.gray>
Component: ldAssignee: unassigned
Status: NEW ---    
Severity: normal CC: ard.biesheuvel, asmwarrior, bug-binutils, damian, daniel.f.starke, eduardo.marcovecchio, gillou.ray, hjl.tools, ktietz70, nickc, patrick.hanevold, puetzk, realnc, rodger.combs, ssbssa, steve, vanboxem.ruben, xunxun1982
Priority: P2    
Version: unspecified   
Target Milestone: ---   
Host: *-*-mingw32 Target: *-*-mingw32
Build: Last reconfirmed:
Attachments: implement --gc-sections for coff (first shot)
Add KEEPs to the linker script template

Description Andrea Gray 2010-04-26 04:36:01 UTC
ld --gc-sections should work for PE-COFF on MinGW.

MSVC has supported this feature (under the name of /OPT:REF) since time began. 
As a result, GCC generates significantly larger executables than MSVC.
Comment 1 sourceware 2011-03-12 14:21:54 UTC
Created attachment 5301 [details]
implement --gc-sections for coff (first shot)

- Mostly a copy and paste from elflink.c to cofflink.c
- This is only a first try; however, it reduces the size of a statically compiled wxWidgets app from 5.1 MB to 3.8 MB, so it does something useful for me; YMMV
- I’m by far no COFF export; some linker guru will need to review the patch and comment on all the "FIXME" comments
- I have not yet tried to generate a DLL with gc enabled
- Somehow the entry symbol does not get into _bfd_coff_gc_keep so no gc mark root is available; as a workaround, "-Wl,--undefined=_WinMainCRTStartup" should be used
Comment 2 vanboxem.ruben 2011-05-14 10:45:47 UTC
I changed the Host/Target/Build to include x86_64 and removed the Build specification, because it's not relevant.
Comment 3 Nikos Chantziaras 2011-06-16 00:08:17 UTC
This is very useful. A static Qt binary gets from 12MB to 8MB with this.
Comment 4 Nikos Chantziaras 2011-07-01 00:31:11 UTC
I found problem with the patch: it will remove the .rsrc section too.  This section should be kept, as it contains the application icon, version information, etc.
Comment 5 Shinji Igarashi 2011-10-05 03:42:15 UTC
Created attachment 5960 [details]
Add KEEPs to the linker script template

Very nice. The patch saves me from some boring works splitting source files per function.

- entry symbol
I think "-Wl,-e" works and is better than "-Wl,--undefined" in this case.

For PE-COFF targets, the default entry symbol is used according to the subsystem,
unless explicitly specified by a command-line or a linker script.
And the code setting the gc root (search gc_sym_list in ldlang.c) ignores the linker's default.
MinGW-GCC's default specs file gives -e option to the linker only if the
generating file is a DLL, so for now the linker's default is used for EXE
unless you specify the explicit one.

I don't know whether ignoring the default entry symbol makes sense.
Anyway the current manual says --gc-sections requires -Wl,-e or -Wl,-u
or using KEEPs in a linker script to keep sections.

- .rsrc section
Default linker scripts(generated from pe.sc) lack KEEP commands.
The attached patch may fix it.
Comment 6 xunxun 2011-10-24 09:28:59 UTC
It seems to dll build can't use the patches, even if using -Wl,--undefined=_DllMainCRTStartup. Though the dll is generated successfully, we can't use other exes to link the dll (running the exe can't show anything). 
How do we make the patches generate the dll correctly?
Comment 7 xunxun 2011-10-31 21:02:31 UTC
I try to keep eh_frame section, then the dll build can work (I test it in wxWidgets 2.8.12 Release Mono Unicode Dll).
So we should find some methods to keep some sections of eh_frame.
Comment 8 Nick Clifton 2012-08-14 15:45:09 UTC
Comment 9 Damian Kaczmarek 2013-08-19 18:43:07 UTC
I was dissatisfied with my DLL size being an order of magnitude bigger than it should be and the search lead me to this bug report. I have just tried the provided patch with binutils-2.23.2 and the initial builds of my statically linked DLL failed with a section named "COMMON" missing. I have changed the cofflink.c to exclude this section from removal and it finally built. However, the functions from my DLL crash so probably something got badly removed. After debugging the removal process by -Wl,--print-gc-sections I also prevented .eh_frame from removal but my application still crashed. At this point I feel only despair as COFF is basically black magic to me. Does anybody work on this feature or have more up to date patches? I would happily do some testing and/or help in other ways.
Comment 10 Kevin Puetz 2013-10-17 19:52:40 UTC
Found several discussions linking to this page, but none mentioning a somewhat newer patch posted at https://sourceware.org/ml/binutils/2012-08/msg00386.html. Adding that link here for any future readers...
Comment 11 Jackie Rosen 2014-02-16 18:29:51 UTC Comment hidden (spam)
Comment 12 Eduardo Luis Marcovecchio 2015-07-02 15:18:41 UTC
Please, no news on this subject yet? I'm sure this is a very important feature for us Windows GCC users (MingW / TDM), and I would help if I had the knowledge. 

We have tons of people on the internet talking about how GCC ports to Windows generate bloated code in comparison to MSVC, and this single implementation would help a lot, mainly on projects linked against big libs, like wxWidgets, QT and others.
Comment 13 cvs-commit@gcc.gnu.org 2015-07-03 14:51:52 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:


commit 0f088b2a9417b1d4ed597849ffa671eba25f5051
Author: Kai Tietz <ktietz@redhat.com>
Date:   Fri Jul 3 15:50:29 2015 +0100

    Add experimental support for --gc-sections with COFF and PE based targets.
    	PR ld/11539
    bfd	* coffcode.h (coff_bfd_gc_sections): Define default
    	to bfd_coff_gc_sections function.
    	* cofflink.c (init_reloc_cookie): Copy and adjust coff
    	related code about gc-sections from elflink.c to here.
    	(fini_reloc_cookie): Likewise.
    	(init_reloc_cookie_rels): Likewise.
    	(fini_reloc_cookie_rels): Likewise.
    	(init_reloc_cookie_for_section): Likewise.
    	(fini_reloc_cookie_for_section): Likewise.
    	(_bfd_coff_gc_mark_hook): Likewise.
    	(_bfd_coff_gc_mark_rsec): Likewise.
    	(_bfd_coff_gc_mark_reloc): Likewise.
    	(_bfd_coff_gc_mark): Likewise.
    	(_bfd_coff_gc_mark_extra_sections): Likewise.
    	(coff_gc_sweep_symbol_info): Likewise.
    	(coff_gc_sweep_symbol): Likewise.
    	(gc_sweep_hook_fn): Likewise.
    	(coff_gc_sweep): Likewise.
    	(bfd_coff_gc_sections): Likewise.
    	(_bfd_coff_gc_keep): Likewise.
    	* libcoff.h (coff_reloc_cookie): New struct.
    	(bfd_coff_gc_sections): New prototype.
    	(coff_gc_mark_hook_fn): New type.
    ld	* scripttempl/pep.sc: Mark .idata*, .CRT*, .tls*,
    	.rsrc*, .init, .ctor*, .dtor*, .fini, .jcr,
    	.eh_frame, .pdata. .xdata, and .gcc_except_table sections
    	as KEEP.
    	* scripttempl/pe.sc: Likewise.
Comment 14 Nick Clifton 2015-07-03 14:55:21 UTC
Hi Eduardo,

(In reply to Eduardo Luis Marcovecchio from comment #12)
> Please, no news on this subject yet?  

Sorry for dropping the ball on this one.

Unfortunately I do not have an easy way of testing COFF/PE binaries at the moment, so I am going to ask for your help.  I have checked in Kai's patch to the mainline binutils sources on an experimental basis.  Please could you try it out and if/when you encounter problems, please could you file them here.  A testcase to reproduce the problem would be very helpful, as would the output from the linkers --print-gc-sections option.

Comment 15 Eduardo Luis Marcovecchio 2015-07-03 15:08:06 UTC
Thanks a lot, Nick!

I will do that as soon as possible, probably recompiling wxWidgets with -ffunction-sections and -fdata-sections, then linking a simple app with -Wl and --gc-sections enabled.

If anyone has suggestions on other libs to test, I will be glad to test with them too.

Comment 16 vanboxem.ruben 2015-07-03 15:10:07 UTC
I would say Qt and Boost could also be used as a testbed. Qt doesn't have a test suite though, but I guess compiling the examples might be a first indication. Boost has a test suite.
Comment 17 Nick Clifton 2015-07-03 15:22:17 UTC
(Just FYI - I am going to be on vacation next week, so I will not be able to respond to bug reports until the week after ...)
Comment 18 Ard Biesheuvel 2015-08-19 07:49:43 UTC
I have given this a spin with building the OVMF firmware (EDK2/Tianocore)


In my case, I need to pass -fno-asynchrounous-unwind-tables to actually get some noticeable improvement, since the unwind info seems to hold some live references to code that is otherwise unused. But with that added, it works beautifully.

(using GCC 4.9.3 + binutils-gdb 7.10 branch)
Comment 19 Hannes Domani 2016-02-06 13:13:05 UTC
I tried this now with gcc 5.3.0 and binutils 2.26.

For x64 I needed -fno-asynchrounous-unwind-tables as described in the last comment (but not for x86).

Additionally I had to use --require-defined=XXX for at least one of my exported functions, otherwise the generated dll is almost empty (both x86 and x64).
Comment 20 rcombs 2016-02-19 02:28:28 UTC
The core issue here seems to be resolved in 2.26, but --gc-sections still isn't taking symbols exported by --version-script into account.