Bug 19161 - GNU ld wrongly garbage collects section referenced via __start_SECTIONNAME
Summary: GNU ld wrongly garbage collects section referenced via __start_SECTIONNAME
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.26
: P2 normal
Target Milestone: 2.26
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on: 27495
Blocks:
  Show dependency treegraph
 
Reported: 2015-10-21 23:07 UTC by David Li
Modified: 2021-03-01 19:19 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
A patch (267 bytes, patch)
2015-10-22 18:04 UTC, H.J. Lu
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description David Li 2015-10-21 23:07:18 UTC
Here is a small reproducible:

// Failed with gnu ld

gcc -fuse-ld=bfd  -fdata-sections -Wl,--gc-sections gctest.c gctest2.c

/tmp/cc4jxArE.o: In function `dump':
gctest2.c:(.text+0xc): undefined reference to `__start_my_section'
collect2: error: ld returned 1 exit status


// Fine with Gold:

gcc -fuse-ld=gold -fdata-sections -Wl,--gc-sections gctest.c gctest2.c




// gctest.c

extern int variable;
int main()
{
  return variable;
}


// gctest2.c

typedef struct A {
   int i;
   int j;
} A;

extern int printf(const char*,...);
extern int atexit(void (*)(void));
A __attribute__((section("my_section"))) a[2] = {{1,2}, {3,4}};

extern A __start_my_section;
extern A __stop_my_section;

int variable = 0;


void dump()
{
   A* ap = &__start_my_section;
   printf("%d %d\n", ap->i, ap->j);
}

void __attribute__((constructor)) foo() {
   atexit(dump);
}
Comment 1 Sriraman Tallam 2015-10-22 17:53:14 UTC
(In reply to David Li from comment #0)
> Here is a small reproducible:
> 
> // Failed with gnu ld
> 
> gcc -fuse-ld=bfd  -fdata-sections -Wl,--gc-sections gctest.c gctest2.c
> 
> /tmp/cc4jxArE.o: In function `dump':
> gctest2.c:(.text+0xc): undefined reference to `__start_my_section'


gold linker has this check to prevent any named section 'XXX' from being garbage collected if it finds a symbol __start_XXX or __stop_XXX:

In gold/gc.h:

//If the symbol name matches '__start_XXX' then the section with
// the C identifier like name 'XXX' should not be garbage collected.
// A similar treatment to symbols with the name '__stop_XXX'.
if (is_prefix_of(cident_section_start_prefix, gsym->name()))
  { ...


GNU ld should also be doing this?


> collect2: error: ld returned 1 exit status
> 
> 
> // Fine with Gold:
> 
> gcc -fuse-ld=gold -fdata-sections -Wl,--gc-sections gctest.c gctest2.c
> 
> 
> 
> 
> // gctest.c
> 
> extern int variable;
> int main()
> {
>   return variable;
> }
> 
> 
> // gctest2.c
> 
> typedef struct A {
>    int i;
>    int j;
> } A;
> 
> extern int printf(const char*,...);
> extern int atexit(void (*)(void));
> A __attribute__((section("my_section"))) a[2] = {{1,2}, {3,4}};
> 
> extern A __start_my_section;
> extern A __stop_my_section;
> 
> int variable = 0;
> 
> 
> void dump()
> {
>    A* ap = &__start_my_section;
>    printf("%d %d\n", ap->i, ap->j);
> }
> 
> void __attribute__((constructor)) foo() {
>    atexit(dump);
> }
Comment 2 H.J. Lu 2015-10-22 18:04:26 UTC
Created attachment 8737 [details]
A patch

Try this.
Comment 3 David Li 2015-10-22 18:36:22 UTC
(In reply to H.J. Lu from comment #2)
> Created attachment 8737 [details]
> A patch
> 
> Try this.

Verified the fix works fine.
Comment 4 cvs-commit@gcc.gnu.org 2015-10-22 19:25:10 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=bba037e0aef1f3b17cc6cf6fd041ed6110cc375a

commit bba037e0aef1f3b17cc6cf6fd041ed6110cc375a
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Thu Oct 22 12:17:43 2015 -0700

    Always keep sections marked with SEC_KEEP
    
    SEC_KEEP check in elf_gc_sweep was missing in commit:
    
    commit bde6f3eb6dff94cea1d471e15c6154d55d49820f
    Author: H.J. Lu <hjl.tools@gmail.com>
    Date:   Fri Jan 8 01:43:23 2010 +0000
    
        Set SEC_KEEP on section XXX for undefined __start_XXX/__stop_XXX
    
        bfd/
    
        2010-01-07  H.J. Lu  <hongjiu.lu@intel.com>
    
          PR ld/11133
          * elflink.c (_bfd_elf_gc_mark_hook): Check section XXX for
          undefined __start_XXX/__stop_XXX in all input files and set
          SEC_KEEP.
    
    This patch adds SEC_KEEP check to elf_gc_sweep.
    
    bfd/
    
    	PR ld/19161
    	* elflink.c (elf_gc_sweep): Always keep sections marked with
    	SEC_KEEP.
    
    ld/testsuite/
    
    	PR ld/19161
    	* ld-gc/gc.exp: Run pr19161 test.
    	* ld-gc/pr19161-1.c: New file.
    	* ld-gc/pr19161-2.c: Likewise.
    	* ld-gc/pr19161.d: Likewise.
Comment 5 H.J. Lu 2015-10-22 19:25:55 UTC
Fixed for 2.26.
Comment 6 cvs-commit@gcc.gnu.org 2015-10-22 23:53:32 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1e7eae0dcc0e5473dda573b30107ffdd501b0d73

commit 1e7eae0dcc0e5473dda573b30107ffdd501b0d73
Author: Alan Modra <amodra@gmail.com>
Date:   Fri Oct 23 10:14:51 2015 +1030

    Re: Always keep sections marked with SEC_KEEP
    
    Revert bba037e0, it breaks the gc-sections model.  Instead fix the
    underlying problem which is that _bfd_elf_gc_mark_hook is too late to
    be setting SEC_KEEP.
    
    	PR ld/11133
    	PR ld/19161
    	* elflink.c (elf_gc_sweep): Revert last patch.
    	(_bfd_elf_gc_mark_hook): Don't set SEC_KEEP here.
Comment 7 cvs-commit@gcc.gnu.org 2015-10-23 11:57:34 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1cce69b9dc8c58884c3cc4a8928fb234294e6886

commit 1cce69b9dc8c58884c3cc4a8928fb234294e6886
Author: Alan Modra <amodra@gmail.com>
Date:   Fri Oct 23 22:23:05 2015 +1030

    Handle __start_* and __stop_* symbols in --gc-sections
    
    	PR ld/11133
    	PR ld/19161
    	PR ld/19167
    	* elflink.c (_bfd_elf_gc_mark_hook): Delete code handling __start_*
    	and __stop_* symbol refs.
    	(_bfd_elf_gc_mark_rsec): Add start_stop parameter.  Handle __start_*
    	and __stop_* symbol refs here..
    	(_bfd_elf_gc_mark_reloc): ..and here.
    	* elf-bfd.h (_bfd_elf_gc_mark_hook): Update prototype.
    	* elf-eh-frame.c (_bfd_elf_parse_eh_frame): Update
    	_bfd_elf_gc_mark_rsec call.