* target.h (Target::gc_mark_symbol, do_gc_mark_symbol): New functions.
authorAlan Modra <amodra@gmail.com>
Sun, 9 Sep 2012 03:43:51 +0000 (03:43 +0000)
committerAlan Modra <amodra@gmail.com>
Sun, 9 Sep 2012 03:43:51 +0000 (03:43 +0000)
(Sized_target::gc_add_reference, do_gc_add_reference): New functions.
* gc.h (gc_process_relocs): Call target gc_add_reference.
* gold.cc (queue_middle_tasks): Use gc_mark_symbol on start sym.
* symtab.cc (Symbol_table::gc_mark_undef_symbols): Use gc_mark_symbol.
(Symbol_table::gc_mark_symbol): Call target gc_mark_symbol. Remove
unnecessary cast.
* powerpc.cc (Powerpc_relobj::get_opd_ent): Rearrange parameters
to cater for when we don't need code offset.  Update use.
(Powerpc_relobj::access_from_map_, opd_valid_): New vars.
(Powerpc_relobj::access_from_map, add_reference, opd_valid,
set_opd_valid): New functions.
(Target_powerpc::do_gc_add_reference): New function.
(Target_powerpc::gc_process_relocs): Call gc()->add_reference on
stashed refs.
(Target_powerpc::do_gc_mark_symbol): New function.

gold/ChangeLog
gold/gc.h
gold/gold.cc
gold/powerpc.cc
gold/symtab.cc
gold/target.h

index ce00f17..7c16d7b 100644 (file)
@@ -1,3 +1,22 @@
+2012-09-09  Alan Modra  <amodra@gmail.com>
+
+       * target.h (Target::gc_mark_symbol, do_gc_mark_symbol): New functions.
+       (Sized_target::gc_add_reference, do_gc_add_reference): New functions.
+       * gc.h (gc_process_relocs): Call target gc_add_reference.
+       * gold.cc (queue_middle_tasks): Use gc_mark_symbol on start sym.
+       * symtab.cc (Symbol_table::gc_mark_undef_symbols): Use gc_mark_symbol.
+       (Symbol_table::gc_mark_symbol): Call target gc_mark_symbol. Remove
+       unnecessary cast.
+       * powerpc.cc (Powerpc_relobj::get_opd_ent): Rearrange parameters
+       to cater for when we don't need code offset.  Update use.
+       (Powerpc_relobj::access_from_map_, opd_valid_): New vars.
+       (Powerpc_relobj::access_from_map, add_reference, opd_valid,
+       set_opd_valid): New functions.
+       (Target_powerpc::do_gc_add_reference): New function.
+       (Target_powerpc::gc_process_relocs): Call gc()->add_reference on
+       stashed refs.
+       (Target_powerpc::do_gc_mark_symbol): New function.
+
 2012-09-06  Cary Coutant  <ccoutant@google.com>
 
        * dwarf_reader.cc (Dwarf_die::read_attributes): Add
index 56b5e74..a169151 100644 (file)
--- a/gold/gc.h
+++ b/gold/gc.h
@@ -187,8 +187,6 @@ gc_process_relocs(
     size_t local_count,
     const unsigned char* plocal_syms)
 {
-  Object* dst_obj;
-  unsigned int dst_indx;
   Scan scan;
 
   typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
@@ -235,6 +233,9 @@ gc_process_relocs(
       unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
       typename elfcpp::Elf_types<size>::Elf_Swxword addend =
       Reloc_types<sh_type, size, big_endian>::get_reloc_addend_noerror(&reloc);
+      Object* dst_obj;
+      unsigned int dst_indx;
+      typename elfcpp::Elf_types<size>::Elf_Addr dst_off;
 
       if (r_sym < local_count)
         {
@@ -246,6 +247,8 @@ gc_process_relocs(
           shndx = src_obj->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
           dst_obj = src_obj;
           dst_indx = shndx;
+         dst_off = lsym.get_st_value();
+
           if (is_icf_tracked)
             {
              if (is_ordinary) 
@@ -288,11 +291,13 @@ gc_process_relocs(
 
           dst_obj = NULL;
           dst_indx = 0;
+         dst_off = 0;
           bool is_ordinary = false;
           if (gsym->source() == Symbol::FROM_OBJECT)
             {
               dst_obj = gsym->object();
               dst_indx = gsym->shndx(&is_ordinary);
+             dst_off = static_cast<const Sized_symbol<size>*>(gsym)->value();
             }
 
          // When doing safe folding, check to see if this relocation is that
@@ -348,6 +353,10 @@ gc_process_relocs(
       if (parameters->options().gc_sections())
         {
          symtab->gc()->add_reference(src_obj, src_indx, dst_obj, dst_indx);
+         dst_off += addend;
+         parameters->sized_target<size, big_endian>()
+           ->gc_add_reference(symtab, src_obj, src_indx,
+                              dst_obj, dst_indx, dst_off);
           if (cident_section_name != NULL)
             {
               Garbage_collection::Cident_section_map::iterator ele =
index 1b4badc..0f9a228 100644 (file)
@@ -504,15 +504,7 @@ queue_middle_tasks(const General_options& options,
       // Find the start symbol if any.
       Symbol* start_sym = symtab->lookup(parameters->entry());
       if (start_sym != NULL)
-       {
-         bool is_ordinary;
-         unsigned int shndx = start_sym->shndx(&is_ordinary);
-         if (is_ordinary)
-           {
-             symtab->gc()->worklist().push(
-               Section_id(start_sym->object(), shndx));
-           }
-       }
+       symtab->gc_mark_symbol(start_sym);
       // Symbols named with -u should not be considered garbage.
       symtab->gc_mark_undef_symbols(layout);
       gold_assert(symtab->gc() != NULL);
index 9ac81a1..f9a14ce 100644 (file)
@@ -59,11 +59,14 @@ class Powerpc_relobj : public Sized_relobj_file<size, big_endian>
 public:
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
   typedef typename elfcpp::Elf_types<size>::Elf_Off Offset;
+  typedef Unordered_set<Section_id, Section_id_hash> Section_refs;
+  typedef Unordered_map<Address, Section_refs> Access_from;
 
   Powerpc_relobj(const std::string& name, Input_file* input_file, off_t offset,
                 const typename elfcpp::Ehdr<size, big_endian>& ehdr)
     : Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr),
-      special_(0), opd_ent_shndx_(), opd_ent_off_()
+      special_(0), opd_ent_shndx_(), opd_ent_off_(), access_from_map_(),
+      opd_valid_(false)
   { }
 
   ~Powerpc_relobj()
@@ -99,14 +102,15 @@ public:
   }
 
   // Return section and offset of function entry for .opd + R_OFF.
-  void
-  get_opd_ent(Address r_off, unsigned int* shndx, Address* value) const
+  unsigned int
+  get_opd_ent(Address r_off, Address* value = NULL) const
   {
     size_t ndx = this->opd_ent_ndx(r_off);
     gold_assert(ndx < this->opd_ent_shndx_.size());
     gold_assert(this->opd_ent_shndx_[ndx] != 0);
-    *shndx = this->opd_ent_shndx_[ndx];
-    *value = this->opd_ent_off_[ndx];
+    if (value != NULL)
+      *value = this->opd_ent_off_[ndx];
+    return this->opd_ent_shndx_[ndx];
   }
 
   // Set section and offset of function entry for .opd + R_OFF.
@@ -119,6 +123,29 @@ public:
     this->opd_ent_off_[ndx] = value;
   }
 
+  Access_from*
+  access_from_map()
+  { return &this->access_from_map_; }
+
+  // Add a reference from SRC_OBJ, SRC_INDX to this object's .opd
+  // section at DST_OFF.
+  void
+  add_reference(Object* src_obj,
+               unsigned int src_indx,
+               typename elfcpp::Elf_types<size>::Elf_Addr dst_off)
+  {
+    Section_id src_id(src_obj, src_indx);
+    this->access_from_map_[dst_off].insert(src_id);
+  }
+
+  bool
+  opd_valid() const
+  { return this->opd_valid_; }
+
+  void
+  set_opd_valid()
+  { this->opd_valid_ = true; }
+
   // Examine .rela.opd to build info about function entry points.
   void
   scan_opd_relocs(size_t reloc_count,
@@ -160,6 +187,16 @@ private:
   // section and offset specified by these relocations.
   std::vector<unsigned int> opd_ent_shndx_;
   std::vector<Offset> opd_ent_off_;
+  // References made to this object's .opd section when running
+  // gc_process_relocs for another object, before the opd_ent vectors
+  // are valid for this object.
+  Access_from access_from_map_;
+  // Set at the start of gc_process_relocs, when we know opd_ent
+  // vectors are valid.  The flag could be made atomic and set in
+  // do_read_relocs with memory_order_release and then tested with
+  // memory_order_acquire, potentially resulting in fewer entries in
+  // access_from_map_.
+  bool opd_valid_;
 };
 
 template<int size, bool big_endian>
@@ -340,6 +377,24 @@ class Target_powerpc : public Sized_target<size, big_endian>
   unsigned int
   plt_entry_size() const;
 
+  // Add any special sections for this symbol to the gc work list.
+  // For powerpc64, this adds the code section of a function
+  // descriptor.
+  void
+  do_gc_mark_symbol(Symbol_table* symtab, Symbol* sym) const;
+
+  // Handle target specific gc actions when adding a gc reference from
+  // SRC_OBJ, SRC_SHNDX to a location specified by DST_OBJ, DST_SHNDX
+  // and DST_OFF.  For powerpc64, this adds a referenc to the code
+  // section of a function descriptor.
+  void
+  do_gc_add_reference(Symbol_table* symtab,
+                     Object* src_obj,
+                     unsigned int src_shndx,
+                     Object* dst_obj,
+                     unsigned int dst_shndx,
+                     Address dst_off) const;
+
  private:
 
   // The class which scans relocations.
@@ -2913,6 +2968,33 @@ Target_powerpc<size, big_endian>::gc_process_relocs(
 {
   typedef Target_powerpc<size, big_endian> Powerpc;
   typedef typename Target_powerpc<size, big_endian>::Scan Scan;
+  Powerpc_relobj<size, big_endian>* ppc_object
+    = static_cast<Powerpc_relobj<size, big_endian>*>(object);
+  if (size == 64)
+    ppc_object->set_opd_valid();
+  if (size == 64 && data_shndx == ppc_object->opd_shndx())
+    {
+      typename Powerpc_relobj<size, big_endian>::Access_from::iterator p;
+      for (p = ppc_object->access_from_map()->begin();
+          p != ppc_object->access_from_map()->end();
+          ++p)
+       {
+         Address dst_off = p->first;
+         unsigned int dst_indx = ppc_object->get_opd_ent(dst_off);
+         typename Powerpc_relobj<size, big_endian>::Section_refs::iterator s;
+         for (s = p->second.begin(); s != p->second.end(); ++s)
+           {
+             Object* src_obj = s->first;
+             unsigned int src_indx = s->second;
+             symtab->gc()->add_reference(src_obj, src_indx,
+                                         ppc_object, dst_indx);
+           }
+         p->second.clear();
+       }
+      ppc_object->access_from_map()->clear();
+      // Don't look at .opd relocs as .opd will reference everything.
+      return;
+    }
 
   gold::gc_process_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan,
                          typename Target_powerpc::Relocatable_size_for_reloc>(
@@ -2929,6 +3011,65 @@ Target_powerpc<size, big_endian>::gc_process_relocs(
     plocal_symbols);
 }
 
+// Handle target specific gc actions when adding a gc reference from
+// SRC_OBJ, SRC_SHNDX to a location specified by DST_OBJ, DST_SHNDX
+// and DST_OFF.  For powerpc64, this adds a referenc to the code
+// section of a function descriptor.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::do_gc_add_reference(
+    Symbol_table* symtab,
+    Object* src_obj,
+    unsigned int src_shndx,
+    Object* dst_obj,
+    unsigned int dst_shndx,
+    Address dst_off) const
+{
+  Powerpc_relobj<size, big_endian>* ppc_object
+    = static_cast<Powerpc_relobj<size, big_endian>*>(dst_obj);
+  if (size == 64 && dst_shndx == ppc_object->opd_shndx())
+    {
+      if (ppc_object->opd_valid())
+       {
+         dst_shndx = ppc_object->get_opd_ent(dst_off);
+         symtab->gc()->add_reference(src_obj, src_shndx, dst_obj, dst_shndx);
+       }
+      else
+       {
+         // If we haven't run scan_opd_relocs, we must delay
+         // processing this function descriptor reference.
+         ppc_object->add_reference(src_obj, src_shndx, dst_off);
+       }
+    }
+}
+
+// Add any special sections for this symbol to the gc work list.
+// For powerpc64, this adds the code section of a function
+// descriptor.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::do_gc_mark_symbol(
+    Symbol_table* symtab,
+    Symbol* sym) const
+{
+  if (size == 64)
+    {
+      Powerpc_relobj<size, big_endian>* ppc_object
+       = static_cast<Powerpc_relobj<size, big_endian>*>(sym->object());
+      bool is_ordinary;
+      unsigned int shndx = sym->shndx(&is_ordinary);
+      if (is_ordinary && shndx == ppc_object->opd_shndx())
+       {
+         Sized_symbol<size>* gsym = symtab->get_sized_symbol<size>(sym);
+         Address dst_off = gsym->value();
+         unsigned int dst_indx = ppc_object->get_opd_ent(dst_off);
+         symtab->gc()->worklist().push(Section_id(ppc_object, dst_indx));
+       }
+    }
+}
+
 // Scan relocations for a section.
 
 template<int size, bool big_endian>
@@ -3064,7 +3205,7 @@ Target_powerpc<size, big_endian>::symval_for_branch(
   if (value >= opd_addr && value < opd_addr + symobj->section_size(shndx))
     {
       Address sec_off;
-      symobj->get_opd_ent(value - opd_addr, dest_shndx, &sec_off);
+      *dest_shndx = symobj->get_opd_ent(value - opd_addr, &sec_off);
       Address sec_addr = symobj->get_output_section_offset(*dest_shndx);
       gold_assert(sec_addr != invalid_address);
       sec_addr += symobj->output_section(*dest_shndx)->address();
index e97f642..8fadd1d 100644 (file)
@@ -577,14 +577,7 @@ Symbol_table::gc_mark_undef_symbols(Layout* layout)
       if (sym->source() == Symbol::FROM_OBJECT 
           && !sym->object()->is_dynamic())
         {
-          Relobj* obj = static_cast<Relobj*>(sym->object());
-          bool is_ordinary;
-          unsigned int shndx = sym->shndx(&is_ordinary);
-          if (is_ordinary)
-            {
-              gold_assert(this->gc_ != NULL);
-              this->gc_->worklist().push(Section_id(obj, shndx));
-            }
+         this->gc_mark_symbol(sym);
         }
     }
 
@@ -601,14 +594,7 @@ Symbol_table::gc_mark_undef_symbols(Layout* layout)
          && sym->source() == Symbol::FROM_OBJECT 
           && !sym->object()->is_dynamic())
         {
-          Relobj* obj = static_cast<Relobj*>(sym->object());
-          bool is_ordinary;
-          unsigned int shndx = sym->shndx(&is_ordinary);
-          if (is_ordinary)
-            {
-              gold_assert(this->gc_ != NULL);
-              this->gc_->worklist().push(Section_id(obj, shndx));
-            }
+         this->gc_mark_symbol(sym);
         }
     }
 
@@ -622,14 +608,7 @@ Symbol_table::gc_mark_undef_symbols(Layout* layout)
       if (sym->source() == Symbol::FROM_OBJECT
          && !sym->object()->is_dynamic())
        {
-         Relobj* obj = static_cast<Relobj*>(sym->object());
-         bool is_ordinary;
-         unsigned int shndx = sym->shndx(&is_ordinary);
-         if (is_ordinary)
-           {
-             gold_assert(this->gc_ != NULL);
-             this->gc_->worklist().push(Section_id(obj, shndx));
-           }
+         this->gc_mark_symbol(sym);
        }
     }
 }
@@ -638,14 +617,14 @@ void
 Symbol_table::gc_mark_symbol(Symbol* sym)
 {
   // Add the object and section to the work list.
-  Relobj* obj = static_cast<Relobj*>(sym->object());
   bool is_ordinary;
   unsigned int shndx = sym->shndx(&is_ordinary);
   if (is_ordinary && shndx != elfcpp::SHN_UNDEF)
     {
       gold_assert(this->gc_!= NULL);
-      this->gc_->worklist().push(Section_id(obj, shndx));
+      this->gc_->worklist().push(Section_id(sym->object(), shndx));
     }
+  parameters->target().gc_mark_symbol(this, sym);
 }
 
 // When doing garbage collection, keep symbols that have been seen in
index 25ac96b..effde15 100644 (file)
@@ -421,6 +421,11 @@ class Target
                      size_t* plen) const
   { return this->do_output_section_name(relobj, name, plen); }
 
+  // Add any special sections for this symbol to the gc work list.
+  void
+  gc_mark_symbol(Symbol_table* symtab, Symbol* sym) const
+  { this->do_gc_mark_symbol(symtab, sym); }
+
  protected:
   // This struct holds the constant information for a child class.  We
   // use a struct to avoid the overhead of virtual function calls for
@@ -669,6 +674,11 @@ class Target
   do_output_section_name(const Relobj*, const char*, size_t*) const
   { return NULL; }
 
+  // This may be overridden by the child class.
+  virtual void
+  do_gc_mark_symbol(Symbol_table*, Symbol*) const
+  { }
+
  private:
   // The implementations of the four do_make_elf_object virtual functions are
   // almost identical except for their sizes and endianness.  We use a template.
@@ -935,6 +945,21 @@ class Sized_target : public Target
                   section_size_type /* view_size */)
   { gold_unreachable(); }
 
+  // Handle target specific gc actions when adding a gc reference from
+  // SRC_OBJ, SRC_SHNDX to a location specified by DST_OBJ, DST_SHNDX
+  // and DST_OFF.
+  void
+  gc_add_reference(Symbol_table* symtab,
+                  Object* src_obj,
+                  unsigned int src_shndx,
+                  Object* dst_obj,
+                  unsigned int dst_shndx,
+                  typename elfcpp::Elf_types<size>::Elf_Addr dst_off) const
+  {
+    this->do_gc_add_reference(symtab, src_obj, src_shndx,
+                             dst_obj, dst_shndx, dst_off);
+  }
+
  protected:
   Sized_target(const Target::Target_info* pti)
     : Target(pti)
@@ -946,6 +971,13 @@ class Sized_target : public Target
   // Set the EI_OSABI field if requested.
   virtual void
   do_adjust_elf_header(unsigned char*, int) const;
+
+  // Handle target specific gc actions when adding a gc reference.
+  virtual void
+  do_gc_add_reference(Symbol_table*, Object*, unsigned int,
+                     Object*, unsigned int,
+                     typename elfcpp::Elf_types<size>::Elf_Addr) const
+  { }
 };
 
 } // End namespace gold.