* layout.cc (Layout::include_section): Refactored check for debug
authorCary Coutant <ccoutant@google.com>
Thu, 1 May 2008 01:23:21 +0000 (01:23 +0000)
committerCary Coutant <ccoutant@google.com>
Thu, 1 May 2008 01:23:21 +0000 (01:23 +0000)
info section.
(Layout::add_comdat): Add new parameters.  Change type
of signature parameter.  Add object and shndx to signatures table.
(Layout::find_kept_object): New function.
* layout.h: Include <cstring>.
(Layout::is_debug_info_section): New function.
(Layout::add_comdat): Add new parameters.
(Layout::find_kept_object): New function.
(Layout::Kept_section): New struct.
(Layout::Signatures): Change type of map range.
* object.cc (Relobj::output_section_address): New function.
(Sized_relobj::include_section_group): Add new parameters.  Change
calls to Layout::add_comdat.  Change to build table of kept comdat
groups and table mapping discarded sections to kept sections.
(Sized_relobj::include_linkonce_section): Likewise.  Add new parameter.
(Sized_relobj::do_layout): Change calls to include_section_group and
include_linkonce_section.
(Sized_relobj::do_finalize_local_symbols): Do not set local symbol
value to zero when section is discarded.
(Sized_relobj::map_to_kept_section): New function.
* object.h (Relobj::output_section_address): New function.
(Relobj::Comdat_group): New type.
(Relobj::find_comdat_group): New function.
(Relobj::Comdat_group_table): New type.
(Relobj::Kept_comdat_section): New type.
(Relobj::Kept_comdat_section_table): New type.
(Relobj::add_comdat_group): New function.
(Relobj::set_kept_comdat_section): New function.
(Relobj::get_kept_comdat_section): New function.
(Relobj::comdat_groups_): New field.
(Relobj::kept_comdat_sections_): New field.
(Symbol_value::input_value): Update comment.
(Sized_relobj::map_to_kept_section) New function.
(Sized_relobj::include_linkonce_section): Add new parameter.
* target-reloc.h (Comdat_behavior): New type.
(get_comdat_behavior): New function.
(relocate_section): Add code to map a discarded section to the
corresponding kept section when applying a relocation.

gold/ChangeLog
gold/layout.cc
gold/layout.h
gold/object.cc
gold/object.h
gold/target-reloc.h

index 10823b52136cd27ec764e7ec00660f5c4792301b..c0612930773559a5ec81d744709bb365e8076687 100644 (file)
@@ -1,3 +1,45 @@
+2008-04-30  Cary Coutant  <ccoutant@google.com>
+
+       * layout.cc (Layout::include_section): Refactored check for debug
+       info section.
+       (Layout::add_comdat): Add new parameters.  Change type
+       of signature parameter.  Add object and shndx to signatures table.
+       (Layout::find_kept_object): New function.
+       * layout.h: Include <cstring>.
+       (Layout::is_debug_info_section): New function.
+       (Layout::add_comdat): Add new parameters.
+       (Layout::find_kept_object): New function.
+       (Layout::Kept_section): New struct.
+       (Layout::Signatures): Change type of map range.
+       * object.cc (Relobj::output_section_address): New function.
+       (Sized_relobj::include_section_group): Add new parameters.  Change
+       calls to Layout::add_comdat.  Change to build table of kept comdat
+       groups and table mapping discarded sections to kept sections.
+       (Sized_relobj::include_linkonce_section): Likewise.  Add new parameter.
+       (Sized_relobj::do_layout): Change calls to include_section_group and
+       include_linkonce_section.
+       (Sized_relobj::do_finalize_local_symbols): Do not set local symbol
+       value to zero when section is discarded.
+       (Sized_relobj::map_to_kept_section): New function.
+       * object.h (Relobj::output_section_address): New function.
+       (Relobj::Comdat_group): New type.
+       (Relobj::find_comdat_group): New function.
+       (Relobj::Comdat_group_table): New type.
+       (Relobj::Kept_comdat_section): New type.
+       (Relobj::Kept_comdat_section_table): New type.
+       (Relobj::add_comdat_group): New function.
+       (Relobj::set_kept_comdat_section): New function.
+       (Relobj::get_kept_comdat_section): New function.
+       (Relobj::comdat_groups_): New field.
+       (Relobj::kept_comdat_sections_): New field.
+       (Symbol_value::input_value): Update comment.
+       (Sized_relobj::map_to_kept_section) New function.
+       (Sized_relobj::include_linkonce_section): Add new parameter.
+       * target-reloc.h (Comdat_behavior): New type.
+       (get_comdat_behavior): New function.
+       (relocate_section): Add code to map a discarded section to the
+       corresponding kept section when applying a relocation.
+
 2008-04-30  Craig Silverstein  <csilvers@google.com>
 
        * dwarf_reader.cc (next_generation_count): New static var.
index a3bcf2135698fa9f49c0f28354314ad9f819c42a..8d0d5f79e01554e109ad5c4d5478b3aeba0bca6c 100644 (file)
@@ -192,11 +192,7 @@ Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
       if (parameters->options().strip_debug()
          && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
        {
-         // Debugging sections can only be recognized by name.
-         if (is_prefix_of(".debug", name)
-             || is_prefix_of(".gnu.linkonce.wi.", name)
-             || is_prefix_of(".line", name)
-             || is_prefix_of(".stab", name))
+         if (is_debug_info_section(name))
            return false;
        }
       if (parameters->options().strip_debug_gdb()
@@ -2770,11 +2766,12 @@ Layout::output_section_name(const char* name, size_t* plen)
 // want a linkonce signature to block another linkonce signature.
 
 bool
-Layout::add_comdat(const char* signature, bool group)
+Layout::add_comdat(Relobj* object, unsigned int shndx,
+                   const std::string& signature, bool group)
 {
-  std::string sig(signature);
+  Kept_section kept(object, shndx, group);
   std::pair<Signatures::iterator, bool> ins(
-    this->signatures_.insert(std::make_pair(sig, group)));
+    this->signatures_.insert(std::make_pair(signature, kept)));
 
   if (ins.second)
     {
@@ -2782,7 +2779,7 @@ Layout::add_comdat(const char* signature, bool group)
       return true;
     }
 
-  if (ins.first->second)
+  if (ins.first->second.group_)
     {
       // We've already seen a real section group with this signature.
       return false;
@@ -2792,7 +2789,7 @@ Layout::add_comdat(const char* signature, bool group)
       // This is a real section group, and we've already seen a
       // linkonce section with this signature.  Record that we've seen
       // a section group, and don't include this section group.
-      ins.first->second = true;
+      ins.first->second.group_ = true;
       return false;
     }
   else
@@ -2804,6 +2801,20 @@ Layout::add_comdat(const char* signature, bool group)
     }
 }
 
+// Find the given comdat signature, and return the object and section
+// index of the kept group.
+Relobj*
+Layout::find_kept_object(const std::string& signature,
+                         unsigned int* pshndx) const
+{
+  Signatures::const_iterator p = this->signatures_.find(signature);
+  if (p == this->signatures_.end())
+    return NULL;
+  if (pshndx != NULL)
+    *pshndx = p->second.shndx_;
+  return p->second.object_;
+}
+
 // Store the allocated sections into the section list.
 
 void
index efa8b61d5aa3c03d32a9bb6c42db156648cb7429..8584a0cabf5e19a0ddea476c3d490beeb83cabd0 100644 (file)
@@ -23,6 +23,7 @@
 #ifndef GOLD_LAYOUT_H
 #define GOLD_LAYOUT_H
 
+#include <cstring>
 #include <list>
 #include <string>
 #include <utility>
@@ -212,12 +213,29 @@ class Layout
   is_linkonce(const char* name)
   { return strncmp(name, ".gnu.linkonce", sizeof(".gnu.linkonce") - 1) == 0; }
 
+  // Return true if a section is a debugging section.
+  static inline bool
+  is_debug_info_section(const char* name)
+  {
+    // Debugging sections can only be recognized by name.
+    return (strncmp(name, ".debug", sizeof(".debug") - 1) == 0
+            || strncmp(name, ".gnu.linkonce.wi.", 
+                       sizeof(".gnu.linkonce.wi.") - 1) == 0
+            || strncmp(name, ".line", sizeof(".line") - 1) == 0
+            || strncmp(name, ".stab", sizeof(".stab") - 1) == 0);
+  }
+
   // Record the signature of a comdat section, and return whether to
   // include it in the link.  The GROUP parameter is true for a
   // section group signature, false for a signature derived from a
   // .gnu.linkonce section.
   bool
-  add_comdat(const char*, bool group);
+  add_comdat(Relobj*, unsigned int, const std::string&, bool group);
+
+  // Find the given comdat signature, and return the object and section
+  // index of the kept group.
+  Relobj*
+  find_kept_object(const std::string&, unsigned int*) const;
 
   // Finalize the layout after all the input sections have been added.
   off_t
@@ -550,7 +568,19 @@ class Layout
   segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
 
   // A mapping used for group signatures.
-  typedef Unordered_map<std::string, bool> Signatures;
+  struct Kept_section
+    {
+      Kept_section()
+        : object_(NULL), shndx_(0), group_(false)
+      { }
+      Kept_section(Relobj* object, unsigned int shndx, bool group)
+        : object_(object), shndx_(shndx), group_(group)
+      { }
+      Relobj* object_;
+      unsigned int shndx_;
+      bool group_;
+    };
+  typedef Unordered_map<std::string, Kept_section> Signatures;
 
   // Mapping from input section name/type/flags to output section.  We
   // use canonicalized strings here.
index 1672225d0298c955fb5cd5c3276f380d524f8239..8f444113ee8aeaff144f7cbb1fa67a602411e677 100644 (file)
@@ -230,6 +230,18 @@ Object::handle_gnu_warning_section(const char* name, unsigned int shndx,
   return false;
 }
 
+// Class Relobj.
+
+// Return the output address of the input section SHNDX.
+uint64_t
+Relobj::output_section_address(unsigned int shndx) const
+{
+  section_offset_type offset;
+  Output_section* os = this->output_section(shndx, &offset);
+  gold_assert(os != NULL && offset != -1);
+  return os->address() + offset;
+}
+
 // Class Sized_relobj.
 
 template<int size, bool big_endian>
@@ -510,10 +522,13 @@ Sized_relobj<size, big_endian>::include_section_group(
     Layout* layout,
     unsigned int index,
     const char* name,
-    const elfcpp::Shdr<size, big_endian>& shdr,
+    const unsigned char* shdrs,
+    const char* section_names,
+    section_size_type section_names_size,
     std::vector<bool>* omit)
 {
   // Read the section contents.
+  typename This::Shdr shdr(shdrs + index * This::shdr_size);
   const unsigned char* pcon = this->get_view(shdr.get_sh_offset(),
                                             shdr.get_sh_size(), true, false);
   const elfcpp::Elf_Word* pword =
@@ -562,12 +577,11 @@ Sized_relobj<size, big_endian>::include_section_group(
       return false;
     }
 
-  const char* signature = psymnames + sym.get_st_name();
+  std::string signature(psymnames + sym.get_st_name());
 
   // It seems that some versions of gas will create a section group
   // associated with a section symbol, and then fail to give a name to
   // the section symbol.  In such a case, use the name of the section.
-  std::string secname;
   if (signature[0] == '\0' && sym.get_st_type() == elfcpp::STT_SECTION)
     {
       bool is_ordinary;
@@ -580,24 +594,40 @@ Sized_relobj<size, big_endian>::include_section_group(
                      symndx, sym_shndx);
          return false;
        }
-      secname = this->section_name(sym_shndx);
-      signature = secname.c_str();
+      typename This::Shdr member_shdr(shdrs + sym_shndx * This::shdr_size);
+      if (member_shdr.get_sh_name() < section_names_size)
+        signature = section_names + member_shdr.get_sh_name();
     }
 
-  // Record this section group, and see whether we've already seen one
-  // with the same signature.
+  // Record this section group in the layout, and see whether we've already
+  // seen one with the same signature.
+  bool include_group = ((flags & elfcpp::GRP_COMDAT) == 0
+                        || layout->add_comdat(this, index, signature, true));
+
+  if (include_group && parameters->options().relocatable())
+    layout->layout_group(symtab, this, index, name, signature.c_str(),
+                           shdr, pword);
+
+  Relobj* kept_object = NULL;
+  Comdat_group* kept_group = NULL;
 
-  if ((flags & elfcpp::GRP_COMDAT) == 0
-      || layout->add_comdat(signature, true))
+  if (!include_group)
     {
-      if (parameters->options().relocatable())
-       layout->layout_group(symtab, this, index, name, signature, shdr,
-                            pword);
-      return true;
+      // This group is being discarded.  Find the object and group
+      // that was kept in its place.
+      unsigned int kept_group_index = 0;
+      kept_object = layout->find_kept_object(signature, &kept_group_index);
+      if (kept_object != NULL)
+        kept_group = kept_object->find_comdat_group(kept_group_index);
+    }
+  else if (flags & elfcpp::GRP_COMDAT)
+    {
+      // This group is being kept.  Create the table to map section names
+      // to section indexes and add it to the table of groups.
+      kept_group = new Comdat_group();
+      this->add_comdat_group(index, kept_group);
     }
 
-  // This is a duplicate.  We want to discard the sections in this
-  // group.
   size_t count = shdr.get_sh_size() / sizeof(elfcpp::Elf_Word);
   for (size_t i = 1; i < count; ++i)
     {
@@ -616,10 +646,42 @@ Sized_relobj<size, big_endian>::include_section_group(
         this->error(_("invalid section group %u refers to earlier section %u"),
                     index, secnum);
 
-      (*omit)[secnum] = true;
+      // Get the name of the member section.
+      typename This::Shdr member_shdr(shdrs + secnum * This::shdr_size);
+      if (member_shdr.get_sh_name() >= section_names_size)
+        {
+          // This is an error, but it will be diagnosed eventually
+          // in do_layout, so we don't need to do anything here but
+          // ignore it.
+          continue;
+        }
+      std::string mname(section_names + member_shdr.get_sh_name());
+
+      if (!include_group)
+        {
+          (*omit)[secnum] = true;
+          if (kept_group != NULL)
+            {
+              // Find the corresponding kept section, and store that info
+              // in the discarded section table.
+              Comdat_group::const_iterator p = kept_group->find(mname);
+              if (p != kept_group->end())
+                {
+                  Kept_comdat_section* kept =
+                    new Kept_comdat_section(kept_object, p->second);
+                  this->set_kept_comdat_section(secnum, kept);
+                }
+            }
+        }
+      else if (flags & elfcpp::GRP_COMDAT)
+        {
+          // Add the section to the kept group table.
+          gold_assert(kept_group != NULL);
+          kept_group->insert(std::make_pair(mname, secnum));
+        }
     }
 
-  return false;
+  return include_group;
 }
 
 // Whether to include a linkonce section in the link.  NAME is the
@@ -641,6 +703,7 @@ template<int size, bool big_endian>
 bool
 Sized_relobj<size, big_endian>::include_linkonce_section(
     Layout* layout,
+    unsigned int index,
     const char* name,
     const elfcpp::Shdr<size, big_endian>&)
 {
@@ -658,8 +721,52 @@ Sized_relobj<size, big_endian>::include_linkonce_section(
     symname = name + strlen(linkonce_t);
   else
     symname = strrchr(name, '.') + 1;
-  bool include1 = layout->add_comdat(symname, false);
-  bool include2 = layout->add_comdat(name, true);
+  std::string sig1(symname);
+  std::string sig2(name);
+  bool include1 = layout->add_comdat(this, index, sig1, false);
+  bool include2 = layout->add_comdat(this, index, sig2, true);
+
+  if (!include2)
+    {
+      // The section is being discarded on the basis of its section
+      // name (i.e., the kept section was also a linkonce section).
+      // In this case, the section index stored with the layout object
+      // is the linkonce section that was kept.
+      unsigned int kept_group_index = 0;
+      Relobj* kept_object = layout->find_kept_object(sig2, &kept_group_index);
+      if (kept_object != NULL)
+        {
+          Kept_comdat_section* kept =
+            new Kept_comdat_section(kept_object, kept_group_index);
+          this->set_kept_comdat_section(index, kept);
+        }
+    }
+  else if (!include1)
+    {
+      // The section is being discarded on the basis of its symbol
+      // name.  This means that the corresponding kept section was
+      // part of a comdat group, and it will be difficult to identify
+      // the specific section within that group that corresponds to
+      // this linkonce section.  We'll handle the simple case where
+      // the group has only one member section.  Otherwise, it's not
+      // worth the effort.
+      unsigned int kept_group_index = 0;
+      Relobj* kept_object = layout->find_kept_object(sig1, &kept_group_index);
+      if (kept_object != NULL)
+        {
+          Comdat_group* kept_group =
+            kept_object->find_comdat_group(kept_group_index);
+          if (kept_group != NULL && kept_group->size() == 1)
+            {
+              Comdat_group::const_iterator p = kept_group->begin();
+              gold_assert(p != kept_group->end());
+              Kept_comdat_section* kept =
+                new Kept_comdat_section(kept_object, p->second);
+              this->set_kept_comdat_section(index, kept);
+            }
+        }
+    }
+
   return include1 && include2;
 }
 
@@ -679,7 +786,8 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
     return;
 
   // Get the section headers.
-  const unsigned char* pshdrs = sd->section_headers->data();
+  const unsigned char* shdrs = sd->section_headers->data();
+  const unsigned char* pshdrs;
 
   // Get the section names.
   const unsigned char* pnamesu = sd->section_names->data();
@@ -691,7 +799,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
   std::vector<unsigned int> reloc_shndx(shnum, 0);
   std::vector<unsigned int> reloc_type(shnum, elfcpp::SHT_NULL);
   // Skip the first, dummy, section.
-  pshdrs += This::shdr_size;
+  pshdrs = shdrs + This::shdr_size;
   for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
     {
       typename This::Shdr shdr(pshdrs);
@@ -749,7 +857,7 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
   std::vector<unsigned int> eh_frame_sections;
 
   // Skip the first, dummy, section.
-  pshdrs = sd->section_headers->data() + This::shdr_size;
+  pshdrs = shdrs + This::shdr_size;
   for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size)
     {
       typename This::Shdr shdr(pshdrs);
@@ -784,14 +892,15 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
        {
          if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
            {
-             if (!this->include_section_group(symtab, layout, i, name, shdr,
+             if (!this->include_section_group(symtab, layout, i, name, shdrs,
+                                              pnames, sd->section_names_size,
                                               &omit))
                discard = true;
            }
           else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0
                    && Layout::is_linkonce(name))
            {
-             if (!this->include_linkonce_section(layout, name, shdr))
+             if (!this->include_linkonce_section(layout, i, name, shdr))
                discard = true;
            }
        }
@@ -1124,7 +1233,10 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
 
          if (os == NULL)
            {
-             lv.set_output_value(0);
+              // This local symbol belongs to a section we are discarding.
+              // In some cases when applying relocations later, we will
+              // attempt to match it to the corresponding kept section,
+              // so we leave the input value unchanged here.
              continue;
            }
          else if (mo[shndx].offset == -1)
@@ -1417,6 +1529,28 @@ Sized_relobj<size, big_endian>::get_symbol_location_info(
   return false;
 }
 
+// Look for a kept section corresponding to the given discarded section,
+// and return its output address.  This is used only for relocations in
+// debugging sections.  If we can't find the kept section, return 0.
+
+template<int size, bool big_endian>
+typename Sized_relobj<size, big_endian>::Address
+Sized_relobj<size, big_endian>::map_to_kept_section(
+    unsigned int shndx,
+    bool* found) const
+{
+  Kept_comdat_section *kept = this->get_kept_comdat_section(shndx);
+  if (kept != NULL)
+    {
+      gold_assert(kept->object_ != NULL);
+      *found = true;
+      return (static_cast<Address>
+              (kept->object_->output_section_address(kept->shndx_)));
+    }
+  *found = false;
+  return 0;
+}
+
 // Input_objects methods.
 
 // Add a regular relocatable object to the list.  Return false if this
index aaaa48dc8b95169e3737dae15016856bd1964eb4..52359afa367d07112231d19019fb26bf8be1fbd2 100644 (file)
@@ -561,6 +561,8 @@ class Relobj : public Object
   Relobj(const std::string& name, Input_file* input_file, off_t offset = 0)
     : Object(name, input_file, false, offset),
       map_to_output_(),
+      comdat_groups_(),
+      kept_comdat_sections_(),
       map_to_relocatable_relocs_(NULL),
       object_merge_map_(NULL),
       relocs_must_follow_section_writes_(false)
@@ -647,6 +649,10 @@ class Relobj : public Object
     this->map_to_output_[shndx].offset = off;
   }
 
+  // Return the output address of the input section SHNDX.
+  uint64_t
+  output_section_address(unsigned int shndx) const;
+
   // Return true if we need to wait for output sections to be written
   // before we can apply relocations.  This is true if the object has
   // any relocations for sections which require special handling, such
@@ -684,6 +690,24 @@ class Relobj : public Object
     return (*this->map_to_relocatable_relocs_)[reloc_shndx];
   }
 
+  // Information needed to keep track of kept comdat groups.  This is
+  // simply a map from the section name to its section index.  This may
+  // not be a one-to-one mapping, but we ignore that possibility since
+  // this is used only to attempt to handle stray relocations from
+  // non-comdat debug sections that refer to comdat loadable sections.
+  typedef Unordered_map<std::string, unsigned int> Comdat_group;
+
+  // Find a comdat group table given its group section SHNDX.
+  Comdat_group*
+  find_comdat_group(unsigned int shndx) const
+  {
+    Comdat_group_table::const_iterator p =
+      this->comdat_groups_.find(shndx);
+    if (p != this->comdat_groups_.end())
+      return p->second;
+    return NULL;
+  }
+
  protected:
   // What we need to know to map an input section to an output
   // section.  We keep an array of these, one for each input section,
@@ -698,6 +722,23 @@ class Relobj : public Object
     section_offset_type offset;
   };
 
+  // A map from group section index to the table of group members.
+  typedef std::map<unsigned int, Comdat_group*> Comdat_group_table;
+
+  // To keep track of discarded comdat sections, we need to map a member
+  // section index to the object and section index of the corresponding
+  // kept section.
+  struct Kept_comdat_section
+  {
+    Kept_comdat_section(Relobj* object, unsigned int shndx)
+      : object_(object), shndx_(shndx)
+    { }
+    Relobj* object_;
+    unsigned int shndx_;
+  };
+  typedef std::map<unsigned int, Kept_comdat_section*>
+      Kept_comdat_section_table;
+
   // Read the relocs--implemented by child class.
   virtual void
   do_read_relocs(Read_relocs_data*) = 0;
@@ -745,6 +786,30 @@ class Relobj : public Object
   map_to_output() const
   { return this->map_to_output_; }
 
+  // Record a new comdat group whose group section index is SHNDX.
+  void
+  add_comdat_group(unsigned int shndx, Comdat_group* group)
+  { this->comdat_groups_[shndx] = group; }
+
+  // Record a mapping from discarded section SHNDX to the corresponding
+  // kept section.
+  void
+  set_kept_comdat_section(unsigned int shndx, Kept_comdat_section* kept)
+  {
+    this->kept_comdat_sections_[shndx] = kept;
+  }
+
+  // Find the kept section corresponding to the discarded section SHNDX.
+  Kept_comdat_section*
+  get_kept_comdat_section(unsigned int shndx) const
+  {
+    Kept_comdat_section_table::const_iterator p =
+      this->kept_comdat_sections_.find(shndx);
+    if (p == this->kept_comdat_sections_.end())
+      return NULL;
+    return p->second;
+  }
+
   // Set the size of the relocatable relocs array.
   void
   size_relocatable_relocs()
@@ -762,6 +827,10 @@ class Relobj : public Object
  private:
   // Mapping from input sections to output section.
   std::vector<Map_to_output> map_to_output_;
+  // Table of kept comdat groups.
+  Comdat_group_table comdat_groups_;
+  // Table mapping discarded comdat sections to corresponding kept sections.
+  Kept_comdat_section_table kept_comdat_sections_;
   // Mapping from input section index to the information recorded for
   // the relocations.  This is only used for a relocatable link.
   std::vector<Relocatable_relocs*>* map_to_relocatable_relocs_;
@@ -927,7 +996,7 @@ class Symbol_value
   { this->u_.value = value; }
 
   // Return the input value.  This is only called by
-  // finalize_local_symbols.
+  // finalize_local_symbols and (in special cases) relocate_section.
   Value
   input_value() const
   { return this->u_.value; }
@@ -1288,6 +1357,12 @@ class Sized_relobj : public Relobj
   get_symbol_location_info(unsigned int shndx, off_t offset,
                           Symbol_location_info* info);
 
+  // Look for a kept section corresponding to the given discarded section,
+  // and return its output address.  This is used only for relocations in
+  // debugging sections.
+  Address
+  map_to_kept_section(unsigned int shndx, bool* found) const;
+
  protected:
   // Read the symbols.
   void
@@ -1421,12 +1496,12 @@ class Sized_relobj : public Relobj
   // Whether to include a section group in the link.
   bool
   include_section_group(Symbol_table*, Layout*, unsigned int, const char*,
-                       const elfcpp::Shdr<size, big_endian>&,
+                       const unsigned char*, const char *, section_size_type,
                        std::vector<bool>*);
 
   // Whether to include a linkonce section in the link.
   bool
-  include_linkonce_section(Layout*, const char*,
+  include_linkonce_section(Layout*, unsigned int, const char*,
                           const elfcpp::Shdr<size, big_endian>&);
 
   // Views and sizes when relocating.
index b0d71f5cb6fe119247369a67706739ab0246b062..e1c3cc37b69892120bc26935a820919dadc9d922 100644 (file)
@@ -119,6 +119,31 @@ scan_relocs(
     }
 }
 
+// Behavior for relocations to discarded comdat sections.
+
+enum Comdat_behavior
+{
+  CB_UNDETERMINED,   // Not yet determined -- need to look at section name.
+  CB_PRETEND,        // Attempt to map to the corresponding kept section.
+  CB_IGNORE,         // Ignore the relocation.
+  CB_WARNING         // Print a warning.
+};
+
+// Decide what the linker should do for relocations that refer to discarded
+// comdat sections.  This decision is based on the name of the section being
+// relocated.
+
+inline Comdat_behavior
+get_comdat_behavior(const char* name)
+{
+  if (Layout::is_debug_info_section(name))
+    return CB_PRETEND;
+  if (strcmp(name, ".eh_frame") == 0
+      || strcmp(name, ".gcc_except_table") == 0)
+    return CB_IGNORE;
+  return CB_WARNING;
+}
+
 // This function implements the generic part of relocation processing.
 // The template parameter Relocate must be a class type which provides
 // a single function, relocate(), which implements the machine
@@ -159,6 +184,8 @@ relocate_section(
   Sized_relobj<size, big_endian>* object = relinfo->object;
   unsigned int local_count = object->local_symbol_count();
 
+  Comdat_behavior comdat_behavior = CB_UNDETERMINED;
+
   for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
     {
       Reltype reloc(prelocs);
@@ -187,6 +214,44 @@ relocate_section(
        {
          sym = NULL;
          psymval = object->local_symbol(r_sym);
+
+          // If the local symbol belongs to a section we are discarding,
+          // and that section is a debug section, try to find the
+          // corresponding kept section and map this symbol to its
+          // counterpart in the kept section.
+         bool is_ordinary;
+         unsigned int shndx = psymval->input_shndx(&is_ordinary);
+         if (is_ordinary
+             && shndx != elfcpp::SHN_UNDEF
+             && !object->is_section_included(shndx))
+           {
+             if (comdat_behavior == CB_UNDETERMINED)
+               {
+                 const char* name =
+                   object->section_name(relinfo->data_shndx).c_str();
+                 comdat_behavior = get_comdat_behavior(name);
+               }
+             if (comdat_behavior == CB_PRETEND)
+               {
+                  bool found;
+                 typename elfcpp::Elf_types<size>::Elf_Addr value =
+                   object->map_to_kept_section(shndx, &found);
+                 if (found)
+                   symval.set_output_value(value + psymval->input_value());
+                  else
+                    symval.set_output_value(0);
+               }
+             else
+               {
+                 if (comdat_behavior == CB_WARNING)
+                    gold_warning_at_location(relinfo, i, offset,
+                                             _("Relocation refers to discarded "
+                                               "comdat section"));
+                  symval.set_output_value(0);
+               }
+             symval.set_no_output_symtab_entry();
+             psymval = &symval;
+           }
        }
       else
        {