Fix corrupted .eh_frame section with LTO and --gc-sections.
authorCary Coutant <ccoutant@google.com>
Tue, 25 Nov 2014 21:55:42 +0000 (13:55 -0800)
committerCary Coutant <ccoutant@google.com>
Wed, 26 Nov 2014 00:14:15 +0000 (16:14 -0800)
Backport from trunk:

When --gc-sections is turned on during an LTO link, the .eh_frame sections
from deferred files are processed before those from the replacement files.
As a result, the section end-cap from crtendS.o is placed ahead of
the .eh_frame data from the replacement files. This patch fixes the bug
by skipping the layout of the deferred sections during GC pass 2.

gold/
PR gold/17639
* object.cc (Sized_relobj_file): Initialize is_deferred_layout_.
(Sized_relobj_file::do_layout): Handle deferred sections properly
during GC pass 1. Don't add reloc sections to deferred list twice.
* object.h (Sized_relobj_file::is_deferred_layout): New function.
(Sized_relobj_file::is_deferred_layout_): New data member.

gold/ChangeLog
gold/object.cc
gold/object.h

index ff5d5af..141a465 100644 (file)
@@ -1,3 +1,12 @@
+2014-11-25  Cary Coutant  <ccoutant@google.com>
+
+       PR gold/17639
+       * object.cc (Sized_relobj_file): Initialize is_deferred_layout_.
+       (Sized_relobj_file::do_layout): Handle deferred sections properly
+       during GC pass 1. Don't add reloc sections to deferred list twice.
+       * object.h (Sized_relobj_file::is_deferred_layout): New function.
+       (Sized_relobj_file::is_deferred_layout_): New data member.
+
 2014-11-21  Alan Modra  <amodra@gmail.com>
 
        * powerpc.cc (Target_powerpc::Relocate::relocate): Correct test
index 6ab84ce..e357ddf 100644 (file)
@@ -430,6 +430,7 @@ Sized_relobj_file<size, big_endian>::Sized_relobj_file(
     kept_comdat_sections_(),
     has_eh_frame_(false),
     discarded_eh_frame_shndx_(-1U),
+    is_deferred_layout_(false),
     deferred_layout_(),
     deferred_layout_relocs_(),
     compressed_sections_()
@@ -1430,6 +1431,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
     {
       parameters->options().plugins()->add_deferred_layout_object(this);
       this->deferred_layout_.reserve(num_sections_to_defer);
+      this->is_deferred_layout_ = true;
     }
 
   // Whether we've seen a .note.GNU-stack section.
@@ -1590,10 +1592,13 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
        {
          if (is_pass_one)
            {
-             out_sections[i] = reinterpret_cast<Output_section*>(1);
+             if (this->is_deferred_layout())
+               out_sections[i] = reinterpret_cast<Output_section*>(2);
+             else
+               out_sections[i] = reinterpret_cast<Output_section*>(1);
              out_section_offsets[i] = invalid_address;
            }
-         else if (should_defer_layout)
+         else if (this->is_deferred_layout())
            this->deferred_layout_.push_back(Deferred_layout(i, name,
                                                             pshdrs,
                                                             reloc_shndx[i],
@@ -1658,11 +1663,12 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
        }
 
       // Defer layout here if input files are claimed by plugins.  When gc
-      // is turned on this function is called twice.  For the second call
-      // should_defer_layout should be false.
-      if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
+      // is turned on this function is called twice; we only want to do this
+      // on the first pass.
+      if (!is_pass_two
+          && this->is_deferred_layout()
+          && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
        {
-         gold_assert(!is_pass_two);
          this->deferred_layout_.push_back(Deferred_layout(i, name,
                                                           pshdrs,
                                                           reloc_shndx[i],
@@ -1764,6 +1770,8 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab,
       Output_section* data_section = out_sections[data_shndx];
       if (data_section == reinterpret_cast<Output_section*>(2))
        {
+         if (is_pass_two)
+           continue;
          // The layout for the data section was deferred, so we need
          // to defer the relocation section, too.
          const char* name = pnames + shdr.get_sh_name();
index 754b1d2..cf45ec5 100644 (file)
@@ -2202,6 +2202,10 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
                            Symbol_value<size>* lv_out,
                            const Symbol_table* symtab);
 
+  // Return true if the layout for this object was deferred.
+  bool is_deferred_layout() const
+  { return this->is_deferred_layout_; }
+
  protected:
   typedef typename Sized_relobj<size, big_endian>::Output_sections
       Output_sections;
@@ -2740,6 +2744,9 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   // If this object has a GNU style .eh_frame section that is discarded in
   // output, record the index here.  Otherwise it is -1U.
   unsigned int discarded_eh_frame_shndx_;
+  // True if the layout of this object was deferred, waiting for plugin
+  // replacement files.
+  bool is_deferred_layout_;
   // The list of sections whose layout was deferred.
   std::vector<Deferred_layout> deferred_layout_;
   // The list of relocation sections whose layout was deferred.