This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [GOLD] powerpc64 --gc-sections RFC


Ian, here's a tidier version of the powerpc --gc-sections support.
I went back to stashing opd refs per object, because stashing all the
refs means we need another hook to process them.  Also, this means on
average we stash half the refs we would when saving them all, and
naturally allows memory to be freed as each object is processed.  The
locking problem turns out to be a non-event, since gc_process_relocs
is serialized, simply set a flag there.  OK to apply?

	* 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.

Index: gold/target.h
===================================================================
RCS file: /cvs/src/src/gold/target.h,v
retrieving revision 1.68
diff -u -p -r1.68 target.h
--- gold/target.h	5 Sep 2012 00:34:20 -0000	1.68
+++ gold/target.h	8 Sep 2012 02:31:03 -0000
@@ -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.
Index: gold/gc.h
===================================================================
RCS file: /cvs/src/src/gold/gc.h,v
retrieving revision 1.16
diff -u -p -r1.16 gc.h
--- gold/gc.h	26 Apr 2012 00:07:17 -0000	1.16
+++ gold/gc.h	8 Sep 2012 02:31:02 -0000
@@ -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: gold/gold.cc
===================================================================
RCS file: /cvs/src/src/gold/gold.cc,v
retrieving revision 1.101
diff -u -p -r1.101 gold.cc
--- gold/gold.cc	24 Aug 2012 18:35:34 -0000	1.101
+++ gold/gold.cc	8 Sep 2012 02:31:02 -0000
@@ -504,15 +504,7 @@ queue_middle_tasks(const General_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: gold/symtab.cc
===================================================================
RCS file: /cvs/src/src/gold/symtab.cc,v
retrieving revision 1.167
diff -u -p -r1.167 symtab.cc
--- gold/symtab.cc	21 Aug 2012 21:41:04 -0000	1.167
+++ gold/symtab.cc	8 Sep 2012 02:31:03 -0000
@@ -577,14 +577,7 @@ Symbol_table::gc_mark_undef_symbols(Layo
       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(Layo
 	  && 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(Layo
       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: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.55
diff -u -p -r1.55 powerpc.cc
--- gold/powerpc.cc	5 Sep 2012 11:27:14 -0000	1.55
+++ gold/powerpc.cc	8 Sep 2012 04:37:04 -0000
@@ -59,11 +59,14 @@ class Powerpc_relobj : public Sized_relo
 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 = 0) 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)
+      *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_targ
   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_pro
 {
   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_pro
     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
   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();

-- 
Alan Modra
Australia Development Lab, IBM


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]