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]

[GOLD] powerpc opd reloc warnings


This silences "relocation refers to discarded section" warnings for
powerpc64 .opd section entries.  I note which entries are discarded
during Scan::local (and Scan::global, but .opd entries ought to be
using local syms), then use that info later during section
relocation.  The same info will be used to remove symbols defined on
discarded entries and in resizing .opd when I figure out how to do all
that..  OK?

	* target-reloc.h (scan_relocs): Call scan.local for relocs
	against symbols in discarded sections.  Pass is_discarded
	param.
	* arm.cc, * i386.cc, * sparc.cc, * x86_64.cc (Target_*::Scan::local):
	Add is_discarded param.
	* powerpc (Target_powerpc::Scan::local): Likewise.  Use
	is_discarded to flag opd entry as discarded.  Don't emit dyn
	relocs on such entries.
	(Target_powerpc::Scan::global): Similarly detect and handle
	such opd entries.
	(Powerpc_relobj): Replace opd_ent_shndx_ and opd_ent_off_ with
	opd_ent_.  Update all uses.
	(Powerpc_relobj::get_opd_discard, set_opd_discard): New functions.
	(Target_powerpc::relocate_section): Zero out discarded opd
	entry relocs.

Index: gold/target-reloc.h
===================================================================
RCS file: /cvs/src/src/gold/target-reloc.h,v
retrieving revision 1.53
diff -u -p -r1.53 target-reloc.h
--- gold/target-reloc.h	5 Sep 2012 00:34:20 -0000	1.53
+++ gold/target-reloc.h	12 Sep 2012 05:24:54 -0000
@@ -81,30 +81,25 @@ scan_relocs(
 	  unsigned int shndx = lsym.get_st_shndx();
 	  bool is_ordinary;
 	  shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
-	  if (is_ordinary
-	      && shndx != elfcpp::SHN_UNDEF
-	      && !object->is_section_included(shndx)
-              && !symtab->is_section_folded(object, shndx))
-	    {
-	      // RELOC is a relocation against a local symbol in a
-	      // section we are discarding.  We can ignore this
-	      // relocation.  It will eventually become a reloc
-	      // against the value zero.
-	      //
-	      // FIXME: We should issue a warning if this is an
-	      // allocated section; is this the best place to do it?
-	      // 
-	      // FIXME: The old GNU linker would in some cases look
-	      // for the linkonce section which caused this section to
-	      // be discarded, and, if the other section was the same
-	      // size, change the reloc to refer to the other section.
-	      // That seems risky and weird to me, and I don't know of
-	      // any case where it is actually required.
-
-	      continue;
-	    }
+	  // If RELOC is a relocation against a local symbol in a
+	  // section we are discarding then we can ignore it.  It will
+	  // eventually become a reloc against the value zero.
+	  //
+	  // FIXME: We should issue a warning if this is an
+	  // allocated section; is this the best place to do it?
+	  // 
+	  // FIXME: The old GNU linker would in some cases look
+	  // for the linkonce section which caused this section to
+	  // be discarded, and, if the other section was the same
+	  // size, change the reloc to refer to the other section.
+	  // That seems risky and weird to me, and I don't know of
+	  // any case where it is actually required.
+	  bool is_discarded = (is_ordinary
+			       && shndx != elfcpp::SHN_UNDEF
+			       && !object->is_section_included(shndx)
+			       && !symtab->is_section_folded(object, shndx));
 	  scan.local(symtab, layout, target, object, data_shndx,
-		     output_section, reloc, r_type, lsym);
+		     output_section, reloc, r_type, lsym, is_discarded);
 	}
       else
 	{
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.154
diff -u -p -r1.154 arm.cc
--- gold/arm.cc	10 Sep 2012 23:05:54 -0000	1.154
+++ gold/arm.cc	12 Sep 2012 02:45:44 -0000
@@ -2551,7 +2551,8 @@ class Target_arm : public Sized_target<3
 	  unsigned int data_shndx,
 	  Output_section* output_section,
 	  const elfcpp::Rel<32, big_endian>& reloc, unsigned int r_type,
-	  const elfcpp::Sym<32, big_endian>& lsym);
+	  const elfcpp::Sym<32, big_endian>& lsym,
+	  bool is_discarded);
 
     inline void
     global(Symbol_table* symtab, Layout* layout, Target_arm* target,
@@ -7857,8 +7858,12 @@ Target_arm<big_endian>::Scan::local(Symb
 				    Output_section* output_section,
 				    const elfcpp::Rel<32, big_endian>& reloc,
 				    unsigned int r_type,
-				    const elfcpp::Sym<32, big_endian>& lsym)
+				    const elfcpp::Sym<32, big_endian>& lsym,
+				    bool is_discarded)
 {
+  if (is_discarded)
+    return;
+
   r_type = get_real_reloc_type(r_type);
   switch (r_type)
     {
Index: gold/i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.147
diff -u -p -r1.147 i386.cc
--- gold/i386.cc	10 Sep 2012 23:05:54 -0000	1.147
+++ gold/i386.cc	12 Sep 2012 02:45:44 -0000
@@ -538,7 +538,8 @@ class Target_i386 : public Sized_target<
 	  unsigned int data_shndx,
 	  Output_section* output_section,
 	  const elfcpp::Rel<32, false>& reloc, unsigned int r_type,
-	  const elfcpp::Sym<32, false>& lsym);
+	  const elfcpp::Sym<32, false>& lsym,
+	  bool is_discarded);
 
     inline void
     global(Symbol_table* symtab, Layout* layout, Target_i386* target,
@@ -1702,15 +1703,19 @@ Target_i386::Scan::reloc_needs_plt_for_i
 
 inline void
 Target_i386::Scan::local(Symbol_table* symtab,
-				Layout* layout,
-				Target_i386* target,
-				Sized_relobj_file<32, false>* object,
-				unsigned int data_shndx,
-				Output_section* output_section,
-				const elfcpp::Rel<32, false>& reloc,
-				unsigned int r_type,
-				const elfcpp::Sym<32, false>& lsym)
+			 Layout* layout,
+			 Target_i386* target,
+			 Sized_relobj_file<32, false>* object,
+			 unsigned int data_shndx,
+			 Output_section* output_section,
+			 const elfcpp::Rel<32, false>& reloc,
+			 unsigned int r_type,
+			 const elfcpp::Sym<32, false>& lsym,
+			 bool is_discarded)
 {
+  if (is_discarded)
+    return;
+
   // A local STT_GNU_IFUNC symbol may require a PLT entry.
   if (lsym.get_st_type() == elfcpp::STT_GNU_IFUNC
       && this->reloc_needs_plt_for_ifunc(object, r_type))
Index: gold/sparc.cc
===================================================================
RCS file: /cvs/src/src/gold/sparc.cc,v
retrieving revision 1.60
diff -u -p -r1.60 sparc.cc
--- gold/sparc.cc	10 Sep 2012 23:05:54 -0000	1.60
+++ gold/sparc.cc	12 Sep 2012 02:45:45 -0000
@@ -237,7 +237,8 @@ class Target_sparc : public Sized_target
 	  unsigned int data_shndx,
 	  Output_section* output_section,
 	  const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
-	  const elfcpp::Sym<size, big_endian>& lsym);
+	  const elfcpp::Sym<size, big_endian>& lsym,
+	  bool is_discarded);
 
     inline void
     global(Symbol_table* symtab, Layout* layout, Target_sparc* target,
@@ -2240,8 +2241,12 @@ Target_sparc<size, big_endian>::Scan::lo
 			Output_section* output_section,
 			const elfcpp::Rela<size, big_endian>& reloc,
 			unsigned int r_type,
-			const elfcpp::Sym<size, big_endian>& lsym)
+			const elfcpp::Sym<size, big_endian>& lsym,
+			bool is_discarded)
 {
+  if (is_discarded)
+    return;
+
   bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
   unsigned int orig_r_type = r_type;
   r_type &= 0xff;
Index: gold/x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.156
diff -u -p -r1.156 x86_64.cc
--- gold/x86_64.cc	10 Sep 2012 23:05:54 -0000	1.156
+++ gold/x86_64.cc	12 Sep 2012 02:45:45 -0000
@@ -676,7 +676,8 @@ class Target_x86_64 : public Sized_targe
 	  unsigned int data_shndx,
 	  Output_section* output_section,
 	  const elfcpp::Rela<size, false>& reloc, unsigned int r_type,
-	  const elfcpp::Sym<size, false>& lsym);
+	  const elfcpp::Sym<size, false>& lsym,
+	  bool is_discarded);
 
     inline void
     global(Symbol_table* symtab, Layout* layout, Target_x86_64* target,
@@ -2270,8 +2271,12 @@ Target_x86_64<size>::Scan::local(Symbol_
 				 Output_section* output_section,
 				 const elfcpp::Rela<size, false>& reloc,
 				 unsigned int r_type,
-				 const elfcpp::Sym<size, false>& lsym)
+				 const elfcpp::Sym<size, false>& lsym,
+				 bool is_discarded)
 {
+  if (is_discarded)
+    return;
+
   // A local STT_GNU_IFUNC symbol may require a PLT entry.
   bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
   if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type))
Index: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.57
diff -u -p -r1.57 powerpc.cc
--- gold/powerpc.cc	10 Sep 2012 23:05:54 -0000	1.57
+++ gold/powerpc.cc	12 Sep 2012 05:22:58 -0000
@@ -65,8 +65,7 @@ public:
   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_(), access_from_map_(),
-      opd_valid_(false)
+      special_(0), opd_valid_(false), opd_ent_(), access_from_map_()
   { }
 
   ~Powerpc_relobj()
@@ -97,8 +96,7 @@ public:
   init_opd(size_t opd_size)
   {
     size_t count = this->opd_ent_ndx(opd_size);
-    this->opd_ent_shndx_.resize(count);
-    this->opd_ent_off_.reserve(count);
+    this->opd_ent_.resize(count);
   }
 
   // Return section and offset of function entry for .opd + R_OFF.
@@ -106,11 +104,11 @@ public:
   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);
+    gold_assert(ndx < this->opd_ent_.size());
+    gold_assert(this->opd_ent_[ndx].shndx != 0);
     if (value != NULL)
-      *value = this->opd_ent_off_[ndx];
-    return this->opd_ent_shndx_[ndx];
+      *value = this->opd_ent_[ndx].off;
+    return this->opd_ent_[ndx].shndx;
   }
 
   // Set section and offset of function entry for .opd + R_OFF.
@@ -118,9 +116,27 @@ public:
   set_opd_ent(Address r_off, unsigned int shndx, Address value)
   {
     size_t ndx = this->opd_ent_ndx(r_off);
-    gold_assert(ndx < this->opd_ent_shndx_.size());
-    this->opd_ent_shndx_[ndx] = shndx;
-    this->opd_ent_off_[ndx] = value;
+    gold_assert(ndx < this->opd_ent_.size());
+    this->opd_ent_[ndx].shndx = shndx;
+    this->opd_ent_[ndx].off = value;
+  }
+
+  // Return discard flag for .opd + R_OFF.
+  bool
+  get_opd_discard(Address r_off) const
+  {
+    size_t ndx = this->opd_ent_ndx(r_off);
+    gold_assert(ndx < this->opd_ent_.size());
+    return this->opd_ent_[ndx].discard;
+  }
+
+  // Set discard flag for .opd + R_OFF.
+  void
+  set_opd_discard(Address r_off)
+  {
+    size_t ndx = this->opd_ent_ndx(r_off);
+    gold_assert(ndx < this->opd_ent_.size());
+    this->opd_ent_[ndx].discard = true;
   }
 
   Access_from*
@@ -165,38 +181,47 @@ public:
   { return 0x8000; }
 
 private:
-  // Return index into opd_ent_shndx or opd_ent_off array for .opd entry
-  // at OFF.  .opd entries are 24 bytes long, but they can be spaced
-  // 16 bytes apart when the language doesn't use the last 8-byte
-  // word, the environment pointer.  Thus dividing the entry section
-  // offset by 16 will give an index into opd_ent_shndx_ and
-  // opd_ent_off_ that works for either layout of .opd.  (It leaves
-  // some elements of the vectors unused when .opd entries are spaced
-  // 24 bytes apart, but we don't know the spacing until relocations
-  // are processed, and in any case it is possible for an object to
-  // have some entries spaced 16 bytes apart and others 24 bytes apart.)
+  struct Opd_ent
+  {
+    unsigned int shndx;
+    bool discard;
+    Offset off;
+  };
+
+  // Return index into opd_ent_ array for .opd entry at OFF.
+  // .opd entries are 24 bytes long, but they can be spaced 16 bytes
+  // apart when the language doesn't use the last 8-byte word, the
+  // environment pointer.  Thus dividing the entry section offset by
+  // 16 will give an index into opd_ent_ that works for either layout
+  // of .opd.  (It leaves some elements of the vector unused when .opd
+  // entries are spaced 24 bytes apart, but we don't know the spacing
+  // until relocations are processed, and in any case it is possible
+  // for an object to have some entries spaced 16 bytes apart and
+  // others 24 bytes apart.)
   size_t
   opd_ent_ndx(size_t off) const
   { return off >> 4;}
 
   // For 32-bit the .got2 section shdnx, for 64-bit the .opd section shndx.
   unsigned int special_;
+
+  // Set at the start of gc_process_relocs, when we know opd_ent_
+  // vector is 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_;
+
   // The first 8-byte word of an OPD entry gives the address of the
   // entry point of the function.  Relocatable object files have a
-  // relocation on this word.  The following two vectors record the
+  // relocation on this word.  The following vector records the
   // section and offset specified by these relocations.
-  std::vector<unsigned int> opd_ent_shndx_;
-  std::vector<Offset> opd_ent_off_;
+  std::vector<Opd_ent> opd_ent_;
+
   // 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.
+  // gc_process_relocs for another object, before the opd_ent_ vector
+  // is 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>
@@ -413,6 +438,8 @@ class Target_powerpc : public Sized_targ
   class Scan
   {
   public:
+    typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
     Scan()
       : issued_non_pic_error_(false)
     { }
@@ -426,7 +453,8 @@ class Target_powerpc : public Sized_targ
 	  unsigned int data_shndx,
 	  Output_section* output_section,
 	  const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
-	  const elfcpp::Sym<size, big_endian>& lsym);
+	  const elfcpp::Sym<size, big_endian>& lsym,
+	  bool is_discarded);
 
     inline void
     global(Symbol_table* symtab, Layout* layout, Target_powerpc* target,
@@ -2361,11 +2389,21 @@ Target_powerpc<size, big_endian>::Scan::
     Output_section* output_section,
     const elfcpp::Rela<size, big_endian>& reloc,
     unsigned int r_type,
-    const elfcpp::Sym<size, big_endian>& /* lsym */)
+    const elfcpp::Sym<size, big_endian>& /* lsym */,
+    bool is_discarded)
 {
   Powerpc_relobj<size, big_endian>* ppc_object
     = static_cast<Powerpc_relobj<size, big_endian>*>(object);
 
+  if (is_discarded)
+    {
+      if (size == 64
+	  && data_shndx == ppc_object->opd_shndx()
+	  && r_type == elfcpp::R_PPC64_ADDR64)
+	ppc_object->set_opd_discard(reloc.get_r_offset());
+      return;
+    }
+
   switch (r_type)
     {
     case elfcpp::R_POWERPC_NONE:
@@ -2382,13 +2420,19 @@ Target_powerpc<size, big_endian>::Scan::
 	  = target->got_section(symtab, layout);
 	if (parameters->options().output_is_position_independent())
 	  {
+	    Address off = reloc.get_r_offset();
+	    if (size == 64
+		&& data_shndx == ppc_object->opd_shndx()
+		&& ppc_object->get_opd_discard(off - 8))
+	      break;
+
 	    Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+	    Powerpc_relobj<size, big_endian>* symobj = ppc_object;
 	    rela_dyn->add_output_section_relative(got->output_section(),
 						  elfcpp::R_POWERPC_RELATIVE,
 						  output_section,
-						  object, data_shndx,
-						  reloc.get_r_offset(),
-						  ppc_object->toc_base_offset());
+						  object, data_shndx, off,
+						  symobj->toc_base_offset());
 	  }
       }
       break;
@@ -2658,6 +2702,12 @@ Target_powerpc<size, big_endian>::Scan::
 	  = target->got_section(symtab, layout);
 	if (parameters->options().output_is_position_independent())
 	  {
+	    Address off = reloc.get_r_offset();
+	    if (size == 64
+		&& data_shndx == ppc_object->opd_shndx()
+		&& ppc_object->get_opd_discard(off - 8))
+	      break;
+
 	    Reloc_section* rela_dyn = target->rela_dyn_section(layout);
 	    Powerpc_relobj<size, big_endian>* symobj = ppc_object;
 	    if (data_shndx != ppc_object->opd_shndx())
@@ -2666,14 +2716,22 @@ Target_powerpc<size, big_endian>::Scan::
 	    rela_dyn->add_output_section_relative(got->output_section(),
 						  elfcpp::R_POWERPC_RELATIVE,
 						  output_section,
-						  object, data_shndx,
-						  reloc.get_r_offset(),
+						  object, data_shndx, off,
 						  symobj->toc_base_offset());
 	  }
       }
       break;
 
     case elfcpp::R_PPC64_ADDR64:
+      if (size == 64
+	  && data_shndx == ppc_object->opd_shndx()
+	  && (gsym->is_defined_in_discarded_section()
+	      || gsym->object() != object))
+	{
+	  ppc_object->set_opd_discard(reloc.get_r_offset());
+	  break;
+	}
+      // Fall thru
     case elfcpp::R_PPC64_UADDR64:
     case elfcpp::R_POWERPC_ADDR32:
     case elfcpp::R_POWERPC_UADDR32:
@@ -4038,6 +4096,43 @@ Target_powerpc<size, big_endian>::reloca
 
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
+  unsigned char *opd_rel = NULL;
+  Powerpc_relobj<size, big_endian>* const object
+    = static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
+  if (size == 64
+      && relinfo->data_shndx == object->opd_shndx())
+    {
+      // Rewrite opd relocs, omitting those for discarded sections
+      // to silence gold::relocate_section errors.
+      const int reloc_size
+	= Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+      opd_rel = new unsigned char[reloc_count * reloc_size];
+      const unsigned char* rrel = prelocs;
+      unsigned char* wrel = opd_rel;
+
+      for (size_t i = 0;
+	   i < reloc_count;
+	   ++i, rrel += reloc_size, wrel += reloc_size)
+	{
+	  typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+	    reloc(rrel);
+	  typename elfcpp::Elf_types<size>::Elf_WXword r_info
+	    = reloc.get_r_info();
+	  unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+	  Address r_off = reloc.get_r_offset();
+	  if (r_type == elfcpp::R_PPC64_TOC)
+	    r_off -= 8;
+	  bool is_discarded = object->get_opd_discard(r_off);
+
+	  // Reloc number is reported in some errors, so keep all relocs.
+	  if (is_discarded)
+	    memset(wrel, 0, reloc_size);
+	  else
+	    memcpy(wrel, rrel, reloc_size);
+	}
+      prelocs = opd_rel;
+    }
+
   gold::relocate_section<size, big_endian, Powerpc, elfcpp::SHT_RELA,
 			 Powerpc_relocate>(
     relinfo,
@@ -4050,6 +4145,9 @@ Target_powerpc<size, big_endian>::reloca
     address,
     view_size,
     reloc_symbol_changes);
+
+  if (opd_rel != NULL)
+    delete[] opd_rel;
 }
 
 class Powerpc_scan_relocatable_reloc

-- 
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]