static link with gold + gc-sections does not flush stdout buffer to file.

Sriraman Tallam tmsriram@google.com
Thu Jan 7 00:53:00 GMT 2010


Hi,

     I have re-done this patch for gold. Please take a look and let me
know what you think. Basically, I detect references to __start_XXX and
__stop_XXX symbols from sections that will be kept and then do not
discard any section with name XXX.

2010-01-06  Sriraman Tallam  <tmsriram@google.com>

	* gc.cc (Garbage_collection::do_transitive_closure): Add referenced
	orphan sections to the worklist.
	(Garbage_collection::track_orphan_section): New function.
	* gc.h (Garbage_collection::Tracked_orphan_section_map): New typedef.
	(Garbage_collection::Tracked_orphan_section_range): New typedef.
	(Garbage_collection::Orphan_section_map): New typedef.
	(Garbage_collection::track_orphan_section): New function.
	(Garbage_collection::tracked_orphan_sections): New function.
	(Garbage_collection::orphan_sections): New function.
	(Garbage_collection::tracked_orphan_sections_): New member.
	(Garbage_collection::orphan_sections_): New member.
	(gc_process_relocs): Track orphan section references.
	* symtab.cc (Symbol_table::gc_update_orphan_sections): New function.
	* symtab.h (Symbol_table::gc_update_orphan_sections): New function.
	* testsuite/Makefile.am: Add gc_orphan_section_test.
	* testsuite/Makefile.in: Regenerate.
	* testsuite/gc_orphan_section_test.cc: New file.
	* testsuite/gc_orphan_section_test.sh: New file.

Thanks,
-Sri.

On Tue, Jan 5, 2010 at 7:49 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Mon, Jan 4, 2010 at 5:02 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>> Hi,
>>
>> Here is how to reproduce the bug :
>>
>> $ cat hello.cc
>> #include <stdio.h>
>> int main()
>> {
>>  printf("Hello World\n");
>> }
>>
>> $ gcc hello.cc -static -Wl,--gc-sections
>> $ ./a.out > tt.out
>> $ wc tt.out
>> 0 0 0 tt.out
>>
>>
>> Also, this bug is present in GNU ld. Will file a bug for this.
>>
>> Looking at the sections discarded shows the following :
>>
>> ld: removing unused section from '__libc_atexit' in file
>> '/usr/grte/v1/lib/../lib64/libc.a(genops.o)'
>> ld: removing unused section from '__libc_freeres_fn' in file
>> '/usr/grte/v1/lib/../lib64/libc.a(register-atfork.o)'
>> ld: removing unused section from '__libc_subfreeres' in file
>> '/usr/grte/v1/lib/../lib64/libc.a(register-atfork.o)'
>> ld: removing unused section from '__libc_freeres_fn' in file
>> '/usr/grte/v1/lib/../lib64/libc.a(dcigettext.o)'
>>
>> Out of these, removing __libc_atexit is responsible for this behaviour
>> as it registers __IO_cleanup which flushes the buffer. Also, to me, it
>> looks like the other symbols with __libc prefix are also important.
>>
>> Here is a patch to make gc-sections not delete sections prefixed with
>> __libc and this fixes the problem.
>>
>>
>> 2010-01-04  Sriraman Tallam  <tmsriram@google.com>
>>
>>        * object.cc (Relobj::is_section_name_included): Keep sections whose
>>        names begin with "__libc" from being discarded by gc-sections.
>>
>
> The fix is wrong. Please see my comments at
>
> http://sourceware.org/bugzilla/show_bug.cgi?id=11133
>
> --
> H.J.
>
-------------- next part --------------
Index: gc.cc
===================================================================
RCS file: /cvs/src/src/gold/gc.cc,v
retrieving revision 1.1
diff -u -u -p -r1.1 gc.cc
--- gc.cc	28 Jan 2009 02:25:33 -0000	1.1
+++ gc.cc	7 Jan 2010 00:46:50 -0000
@@ -1,6 +1,6 @@
 // gc.cc -- garbage collection of unused sections
 
-// Copyright 2009 Free Software Foundation, Inc.
+// Copyright 2009, 2010 Free Software Foundation, Inc.
 // Written by Sriraman Tallam <tmsriram@google.com>.
 
 // This file is part of gold.
@@ -66,9 +66,40 @@ Garbage_collection::do_transitive_closur
               this->worklist().push(*it_v);   
             }
         }
+      // Add the orphan sections referenced by this section.
+      Garbage_collection::Tracked_orphan_section_range key_range =
+        this->tracked_orphan_sections_.equal_range(entry);
+      Garbage_collection::Tracked_orphan_section_map::iterator it;
+      for (it = key_range.first; it != key_range.second; ++it)
+        {
+          std::string orphan_section_name = it->second;
+          Garbage_collection::Orphan_section_map::iterator ele =
+            this->orphan_sections_.find(orphan_section_name);
+          gold_assert (ele != this->orphan_sections_.end());
+          Garbage_collection::Sections_reachable v = ele->second;
+          for (Garbage_collection::Sections_reachable::iterator it_v
+               = v.begin();
+               it_v != v.end();
+               ++it_v)
+            {
+              if (it_v->first == NULL)
+                continue;
+              this->worklist().push(*it_v);
+            }
+        }
     }
   this->worklist_ready();
 }
 
+void
+Garbage_collection::track_orphan_section(Section_id secn,
+                                         std::string section_name)
+{
+  this->tracked_orphan_sections_.insert(std::make_pair(secn, section_name));
+  if (this->orphan_sections_.find(section_name)
+      == this->orphan_sections_.end())
+    this->orphan_sections_[section_name].insert(Section_id(NULL, 0));
+}
+
 } // End namespace gold.
 
Index: gc.h
===================================================================
RCS file: /cvs/src/src/gold/gc.h,v
retrieving revision 1.6
diff -u -u -p -r1.6 gc.h
--- gc.h	4 Jan 2010 19:08:39 -0000	1.6
+++ gc.h	7 Jan 2010 00:46:50 -0000
@@ -60,6 +60,17 @@ class Garbage_collection
   typedef Unordered_set<Section_id, Section_id_hash> Sections_reachable;
   typedef std::map<Section_id, Sections_reachable> Section_ref;
   typedef std::queue<Section_id> Worklist_type;
+  // This maps a section to the name of the orphan section it references.
+  // A section can reference more than one orphan section.
+  typedef Unordered_multimap<Section_id, std::string, Section_id_hash>
+    Tracked_orphan_section_map;
+  typedef std::pair<Tracked_orphan_section_map::iterator,
+                    Tracked_orphan_section_map::iterator>
+    Tracked_orphan_section_range;
+  // This maps the name of the orphan section to the list of sections that
+  // have that name.  Different object files can have orphan sections with
+  // the same name.
+  typedef std::map<std::string, Sections_reachable> Orphan_section_map;
 
   Garbage_collection()
   : is_worklist_ready_(false)
@@ -94,12 +105,26 @@ class Garbage_collection
   is_section_garbage(Object* obj, unsigned int shndx)
   { return (this->referenced_list().find(Section_id(obj, shndx))
             == this->referenced_list().end()); }
+
+  void
+  track_orphan_section(Section_id secn, std::string section_name);
+
+  Tracked_orphan_section_map&
+  tracked_orphan_sections()
+  { return tracked_orphan_sections_; }
+
+  Orphan_section_map&
+  orphan_sections()
+  { return orphan_sections_; }
+
  private:
 
   Worklist_type work_list_;
   bool is_worklist_ready_;
   Section_ref section_reloc_map_;
   Sections_reachable referenced_list_;
+  Tracked_orphan_section_map tracked_orphan_sections_;
+  Orphan_section_map orphan_sections_;
 };
 
 // Data to pass between successive invocations of do_layout
@@ -217,7 +242,23 @@ gc_process_relocs(
           dst_indx = gsym->shndx(&is_ordinary);
           if (!is_ordinary)
             continue;
+          Section_id src_id(src_obj, src_indx);
           Section_id dst_id(dst_obj, dst_indx);
+          // If the symbol name matches '__start_XXX' then the orphan
+          // section with the name 'XXX' should not be garbage collected.
+          // A similar treatment to symbols with the name '__stop_XXX'.
+          if (is_prefix_of("__start_", gsym->name()))
+            {
+              symtab->gc()->track_orphan_section(src_id,
+                                                 std::string(gsym->name()
+                                                 + strlen("__start_")));
+            }
+          else if (is_prefix_of("__stop_", gsym->name()))
+            {
+              symtab->gc()->track_orphan_section(src_id,
+                                                 std::string(gsym->name()
+                                                 + strlen("__stop_")));
+            }
           if (is_icf_tracked)
             {
               (*secvec).push_back(dst_id);
Index: gold.cc
===================================================================
RCS file: /cvs/src/src/gold/gold.cc,v
retrieving revision 1.76
diff -u -u -p -r1.76 gold.cc
--- gold.cc	6 Jan 2010 05:30:24 -0000	1.76
+++ gold.cc	7 Jan 2010 00:46:50 -0000
@@ -326,6 +326,7 @@ queue_middle_tasks(const General_options
         }
       // Symbols named with -u should not be considered garbage.
       symtab->gc_mark_undef_symbols();
+      symtab->gc_update_orphan_sections(input_objects);
       gold_assert(symtab->gc() != NULL);
       // Do a transitive closure on all references to determine the worklist.
       symtab->gc()->do_transitive_closure();
Index: symtab.cc
===================================================================
RCS file: /cvs/src/src/gold/symtab.cc,v
retrieving revision 1.136
diff -u -u -p -r1.136 symtab.cc
--- symtab.cc	5 Jan 2010 19:29:15 -0000	1.136
+++ symtab.cc	7 Jan 2010 00:46:50 -0000
@@ -524,6 +524,28 @@ Symbol_table::is_section_folded(Object* 
           && this->icf_->is_section_folded(obj, shndx));
 }
 
+// Find the orphan sections that are tracked.
+
+void
+Symbol_table::gc_update_orphan_sections(const Input_objects* input_objects)
+{
+  for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+       p != input_objects->relobj_end();
+       ++p)
+    {
+      for (unsigned int i = 0;i < (*p)->shnum(); ++i)
+        {
+          std::string section_name = (*p)->section_name(i);
+          Garbage_collection::Orphan_section_map::iterator it =
+            this->gc_->orphan_sections().find(section_name);
+          if (it == this->gc_->orphan_sections().end())
+            continue;
+          Garbage_collection::Sections_reachable& v(it->second);
+          v.insert(Section_id(*p, i));
+        }
+    }
+}
+
 // For symbols that have been listed with -u option, add them to the
 // work list to avoid gc'ing them.
 
Index: symtab.h
===================================================================
RCS file: /cvs/src/src/gold/symtab.h,v
retrieving revision 1.103
diff -u -u -p -r1.103 symtab.h
--- symtab.h	31 Dec 2009 05:07:21 -0000	1.103
+++ symtab.h	7 Jan 2010 00:46:50 -0000
@@ -1,6 +1,6 @@
 // symtab.h -- the gold symbol table   -*- C++ -*-
 
-// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -1230,6 +1230,9 @@ class Symbol_table
   gc() const
   { return this->gc_; }
 
+  void
+  gc_update_orphan_sections(const Input_objects* input_objects);
+
   // During garbage collection, this keeps undefined symbols.
   void
   gc_mark_undef_symbols(); 
cvs diff: Diffing po
cvs diff: Diffing testsuite
Index: testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.115
diff -u -u -p -r1.115 Makefile.am
--- testsuite/Makefile.am	31 Dec 2009 05:07:22 -0000	1.115
+++ testsuite/Makefile.am	7 Jan 2010 00:46:51 -0000
@@ -139,6 +139,16 @@ gc_tls_test:gc_tls_test.o gcctestdir/ld
 gc_tls_test.stdout: gc_tls_test
 	$(TEST_NM) -C gc_tls_test > gc_tls_test.stdout
 
+check_SCRIPTS += gc_orphan_section_test.sh
+check_DATA += gc_orphan_section_test.stdout
+MOSTLYCLEANFILES += gc_orphan_section_test
+gc_orphan_section_test.o: gc_orphan_section_test.cc
+	$(CXXCOMPILE) -O0 -c -g -o $@ $<
+gc_orphan_section_test:gc_orphan_section_test.o gcctestdir/ld
+	$(CXXLINK) -Bgcctestdir/ -Wl,--gc-sections gc_orphan_section_test.o
+gc_orphan_section_test.stdout: gc_orphan_section_test
+	$(TEST_NM) gc_orphan_section_test > gc_orphan_section_test.stdout
+
 check_SCRIPTS += icf_test.sh
 check_DATA += icf_test.stdout
 MOSTLYCLEANFILES += icf_test
Index: testsuite/gc_orphan_section_test.cc
===================================================================
RCS file: testsuite/gc_orphan_section_test.cc
diff -N testsuite/gc_orphan_section_test.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gc_orphan_section_test.cc	7 Jan 2010 00:46:51 -0000
@@ -0,0 +1,36 @@
+// gc_orphan_section_test.cc -- a test case for gold
+
+// Copyright 2010 Free Software Foundation, Inc.
+// Written by Sriraman Tallam <tmsriram@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// The goal of this program is to verify if garbage collection does not
+// discard orphan sections when references to them through __start_XXX
+// and __stop_XXX are present.  Here section _foo must not be gc'ed but
+// _boo should be gc'ed.
+
+extern const int *__start__foo;
+int foo __attribute__((__section__("_foo"))) = 1;
+int boo __attribute__((__section__("_boo"))) = 1;
+
+int main()
+{
+  return *__start__foo;
+}
+
Index: testsuite/gc_orphan_section_test.sh
===================================================================
RCS file: testsuite/gc_orphan_section_test.sh
diff -N testsuite/gc_orphan_section_test.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gc_orphan_section_test.sh	7 Jan 2010 00:46:51 -0000
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# gc_orphan_section_test.sh -- test --gc-sections
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# The goal of this program is to verify if gc-sections works as expected
+# with orphan sections.
+# File gc_orphan_sections_test.cc is in this test. This program checks if
+# the orphan sections are retained when they are referenced through
+# __start_XXX and __stop_XXX symbols.
+
+check()
+{
+    if grep -q " boo" "$1"
+    then
+        echo "Garbage collection failed to collect boo"
+	exit 1
+    fi
+    grep_foo=`grep -q " foo" $1`
+    if [ $? != 0 ];
+    then
+        echo "Garbage collection should not discard foo"
+	exit 1
+    fi
+}
+
+check gc_orphan_section_test.stdout


More information about the Binutils mailing list