public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [GOLD] advice on powerpc64 .opd handling
@ 2012-08-15  4:04 Alan Modra
  2012-08-16  9:24 ` Ian Lance Taylor
  0 siblings, 1 reply; 9+ messages in thread
From: Alan Modra @ 2012-08-15  4:04 UTC (permalink / raw)
  To: Ian Lance Taylor, Cary Coutant; +Cc: binutils, David Edelsohn

Hi Ian, Cary,
  I'd like some guidance on how I should implement .opd entry lookup
for PowerPC64.  The problem is this:

- A PowerPC64 function symbol points at a function descriptor in the
  .opd section.
- Relocations on branch and call insns reference the function symbol.
  For functions that resolve locally, we want to branch to the
  function code entry point, necessitating a read of the function
  descriptor in the .opd section.
- .opd section contents are useless until after relocation.  (.opd
  could be nobits in most relocatable object files.)

gold will need to evaluate .opd entries during --gc-sections
processing (to find the code section to mark), when creating call
stubs (for analysis of code section relocs to determinde whether a toc
adjusting stub is needed), and when performing final relocation.
This of course will happen for any section that might contain a direct
function call, ie. all code sections, but the .opd section involved
will always be the one in the same object file as the code section.
Another twist is that in the future I'd like to relax .opd for
--gc-sections, removing entries for functions in discarded sections.

In BFD, elf64-ppc.c:opd_entry_value I implement OPD entry lookup by
doing a binary search over .opd relocs to find the one on the
particular OPD entry of interest, then use that reloc symbol/addend to
find the code section and offset.

Should I do the same in gold or would some other approach be better?
(I'm still discovering when and where various things happen in gold,
but I'm thinking a better approach might be to build up .opd entry
info in a vector during reloc scan.  And somehow ensure .opd relocs
are scanned before any other section..)

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [GOLD] advice on powerpc64 .opd handling
  2012-08-15  4:04 [GOLD] advice on powerpc64 .opd handling Alan Modra
@ 2012-08-16  9:24 ` Ian Lance Taylor
  2012-08-16 13:53   ` Alan Modra
  0 siblings, 1 reply; 9+ messages in thread
From: Ian Lance Taylor @ 2012-08-16  9:24 UTC (permalink / raw)
  To: Ian Lance Taylor, Cary Coutant, binutils, David Edelsohn

On Tue, Aug 14, 2012 at 7:46 PM, Alan Modra <amodra@gmail.com> wrote:
> Hi Ian, Cary,
>   I'd like some guidance on how I should implement .opd entry lookup
> for PowerPC64.  The problem is this:
>
> - A PowerPC64 function symbol points at a function descriptor in the
>   .opd section.
> - Relocations on branch and call insns reference the function symbol.
>   For functions that resolve locally, we want to branch to the
>   function code entry point, necessitating a read of the function
>   descriptor in the .opd section.
> - .opd section contents are useless until after relocation.  (.opd
>   could be nobits in most relocatable object files.)
>
> gold will need to evaluate .opd entries during --gc-sections
> processing (to find the code section to mark), when creating call
> stubs (for analysis of code section relocs to determinde whether a toc
> adjusting stub is needed), and when performing final relocation.
> This of course will happen for any section that might contain a direct
> function call, ie. all code sections, but the .opd section involved
> will always be the one in the same object file as the code section.
> Another twist is that in the future I'd like to relax .opd for
> --gc-sections, removing entries for functions in discarded sections.
>
> In BFD, elf64-ppc.c:opd_entry_value I implement OPD entry lookup by
> doing a binary search over .opd relocs to find the one on the
> particular OPD entry of interest, then use that reloc symbol/addend to
> find the code section and offset.
>
> Should I do the same in gold or would some other approach be better?
> (I'm still discovering when and where various things happen in gold,
> but I'm thinking a better approach might be to build up .opd entry
> info in a vector during reloc scan.  And somehow ensure .opd relocs
> are scanned before any other section..)

I don't really know the answer here.  It sounds like what you need are
not the contents of the .opd section itself, but the contents of the
.rela.opd section.  gold will read all the relocs before it does
anything with them.  Perhaps you can define a do_read_relocs function
in your Powerpc_relobj class that calls the Sized_relobj_file
do_read_relocs routine, then looks through the Section_relocs to find
the .opd relocs, then builds whatever data structure you need out of
that.

Ian

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [GOLD] advice on powerpc64 .opd handling
  2012-08-16  9:24 ` Ian Lance Taylor
@ 2012-08-16 13:53   ` Alan Modra
  2012-08-17  5:28     ` Ian Lance Taylor
  0 siblings, 1 reply; 9+ messages in thread
From: Alan Modra @ 2012-08-16 13:53 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Cary Coutant, binutils, David Edelsohn

On Wed, Aug 15, 2012 at 03:39:20PM -0700, Ian Lance Taylor wrote:
> I don't really know the answer here.  It sounds like what you need are
> not the contents of the .opd section itself, but the contents of the
> .rela.opd section.  gold will read all the relocs before it does
> anything with them.  Perhaps you can define a do_read_relocs function
> in your Powerpc_relobj class that calls the Sized_relobj_file
> do_read_relocs routine, then looks through the Section_relocs to find
> the .opd relocs, then builds whatever data structure you need out of
> that.

Yes, that's what I've done after a few false starts.  (My first
attempt built up opd entry info in Scan::local and Scan::global.  That
was a bad idea since I'll need opd entry info available for garbage
collection when I get around to tackling that problem.)

Anyway, I'm reasonably happy with the following as now gold generates
a dynamically linked ppc64 "Hello world" that actually runs..  I would
appreciate you reviewing though.

	* powerpc.cc: Formatting and white space.
	(Powerpc_relobj): Rename got2_section_ to special_.
	Add opd_ent_count_, opd_ent_shndx_, opd_ent_off_.
	(Powerpc_relobj::opd_shndx, init_opd, get_opd_ent, set_opd_ent,
	do_read_relocs, opd_ent_ndx): New functions.
	(Target_powerpc::is_branch_reloc): New function.
	(Powerpc_relobj::do_find_special_sections): Find .opd for 64-bit.
	(ld_2_1, cror_15_15_15, cror_31_31_31): New insn constants.
	(Output_data_glink): Rename pltresolve_size to pltresolve_size_.
	(Output_data_glink::pltresolve_size): New function.
	(Output_data_glink::do_write): Correct toc base.  Don't try to use
	uint16_t for 24-bit offset.
	(Target_powerpc::Scan::local): Handle more relocs.
	(Target_powerpc::do_finalize_sections): Set up DT_PPC64_GLINK.
	(Target_powerpc::Relocate::relocate): Correct toc base calculation.
	Plug in toc restoring insn after plt calls.  Translate branches
	to function descriptor symbols to corresponding entry point.
	* symtab.h: Comment typo.

Index: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.49
diff -u -p -r1.49 powerpc.cc
--- gold/powerpc.cc	14 Aug 2012 03:39:03 -0000	1.49
+++ gold/powerpc.cc	16 Aug 2012 12:11:52 -0000
@@ -60,26 +60,93 @@ 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),
-      got2_section_(0)
+      special_(0)
   { }
 
   ~Powerpc_relobj()
   { }
 
+  // The .got2 section shndx.
   unsigned int
   got2_shndx() const
   {
     if (size == 32)
-      return this->got2_section_;
+      return this->special_;
     else
       return 0;
   }
 
+  // The .opd section shndx.
+  unsigned int
+  opd_shndx() const
+  {
+    if (size == 32)
+      return 0;
+    else
+      return this->special_;
+  }
+
+  // Init OPD entry arrays.
+  void
+  init_opd(size_t opd_size)
+  {
+    size_t count = this->opd_ent_ndx(opd_size);
+    this->opd_ent_count_ = count;
+    this->opd_ent_shndx_ = new unsigned int[count];
+    this->opd_ent_off_ = new typename elfcpp::Elf_types<size>::Elf_Off[count];
+    memset(this->opd_ent_shndx_, 0, sizeof(this->opd_ent_shndx_[0]) * count);
+  }
+
+  // Return section and offset of function entry for .opd + R_OFF.
+  void
+  get_opd_ent(typename elfcpp::Elf_types<size>::Elf_Addr r_off,
+	      unsigned int* shndx,
+	      typename elfcpp::Elf_types<size>::Elf_Addr* value)
+  {
+    size_t ndx = this->opd_ent_ndx(r_off);
+    gold_assert(ndx < this->opd_ent_count_);
+    *shndx = this->opd_ent_shndx_[ndx];
+    *value = this->opd_ent_off_[ndx];
+  }
+
+  // Set section and offset of function entry for .opd + R_OFF.
+  void
+  set_opd_ent(typename elfcpp::Elf_types<size>::Elf_Addr r_off,
+	      unsigned int shndx,
+	      typename elfcpp::Elf_types<size>::Elf_Addr value)
+  {
+    size_t ndx = this->opd_ent_ndx(r_off);
+    gold_assert(ndx < this->opd_ent_count_);
+    this->opd_ent_shndx_[ndx] = shndx;
+    this->opd_ent_off_[ndx] = value;
+  }
+
+  // Examine .rela.opd to build info about function entry points.
+  void
+  scan_opd_relocs(size_t reloc_count,
+		  const unsigned char* prelocs,
+		  const unsigned char* plocal_syms);
+
+  void
+  do_read_relocs(Read_relocs_data*);
+
   bool
   do_find_special_sections(Read_symbols_data* sd);
 
 private:
-  unsigned int got2_section_;
+  // 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 environment pointer
+  // word.  Thus dividing the entry section offset by 16 will give a
+  // unique index.
+  size_t
+  opd_ent_ndx(size_t off) const
+  { return off >> 4;}
+
+  unsigned int special_;
+  size_t opd_ent_count_;
+  unsigned int* opd_ent_shndx_;
+  typename elfcpp::Elf_types<size>::Elf_Off* opd_ent_off_;
 };
 
 template<int size, bool big_endian>
@@ -342,6 +409,19 @@ class Target_powerpc : public Sized_targ
 	     typename elfcpp::Elf_types<size>::Elf_Addr,
 	     section_size_type);
 
+    inline bool
+    is_branch_reloc(unsigned int r_type) const
+    {
+      return (r_type == elfcpp::R_POWERPC_REL24
+	      || r_type == elfcpp::R_POWERPC_REL14
+	      || r_type == elfcpp::R_POWERPC_REL14_BRTAKEN
+	      || r_type == elfcpp::R_POWERPC_REL14_BRNTAKEN
+	      || r_type == elfcpp::R_POWERPC_ADDR24
+	      || r_type == elfcpp::R_POWERPC_ADDR14
+	      || r_type == elfcpp::R_POWERPC_ADDR14_BRTAKEN
+	      || r_type == elfcpp::R_POWERPC_ADDR14_BRNTAKEN);
+    }
+
    private:
     // Do a TLS relocation.
     inline void
@@ -460,8 +540,8 @@ Target::Target_info Target_powerpc<32, t
   0x10000000,		// default_text_segment_address
   64 * 1024,		// abi_pagesize (overridable by -z max-page-size)
   4 * 1024,		// common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,		// isolate_execinstr
+  0,			// rosegment_gap
   elfcpp::SHN_UNDEF,	// small_common_shndx
   elfcpp::SHN_UNDEF,	// large_common_shndx
   0,			// small_common_section_flags
@@ -486,8 +566,8 @@ Target::Target_info Target_powerpc<32, f
   0x10000000,		// default_text_segment_address
   64 * 1024,		// abi_pagesize (overridable by -z max-page-size)
   4 * 1024,		// common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,		// isolate_execinstr
+  0,			// rosegment_gap
   elfcpp::SHN_UNDEF,	// small_common_shndx
   elfcpp::SHN_UNDEF,	// large_common_shndx
   0,			// small_common_section_flags
@@ -512,8 +592,8 @@ Target::Target_info Target_powerpc<64, t
   0x10000000,		// default_text_segment_address
   64 * 1024,		// abi_pagesize (overridable by -z max-page-size)
   8 * 1024,		// common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,		// isolate_execinstr
+  0,			// rosegment_gap
   elfcpp::SHN_UNDEF,	// small_common_shndx
   elfcpp::SHN_UNDEF,	// large_common_shndx
   0,			// small_common_section_flags
@@ -538,8 +618,8 @@ Target::Target_info Target_powerpc<64, f
   0x10000000,		// default_text_segment_address
   64 * 1024,		// abi_pagesize (overridable by -z max-page-size)
   8 * 1024,		// common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,		// isolate_execinstr
+  0,			// rosegment_gap
   elfcpp::SHN_UNDEF,	// small_common_shndx
   elfcpp::SHN_UNDEF,	// large_common_shndx
   0,			// small_common_section_flags
@@ -656,9 +736,7 @@ public:
     This::template rela<16>(view, 16, 0xffff, value, addend);
   }
 
-  // R_POWERPC_ADDR16_HA: Same as R_POWERPC_ADDR16_HI except that if the
-  //                      final value of the low 16 bits of the
-  //                      relocation is negative, add one.
+  // R_POWERPC_ADDR16_HA: ((Symbol + Addend + 0x8000) >> 16) & 0xffff
   static inline void
   addr16_ha(unsigned char* view,
 	    typename elfcpp::Elf_types<size>::Elf_Addr value,
@@ -693,9 +771,7 @@ public:
     This::template rela<16>(view, 16, 0xffff, value - address, addend);
   }
 
-  // R_POWERPC_REL16_HA: Same as R_POWERPC_REL16_HI except that if the
-  //                 final value of the low 16 bits of the
-  //                 relocation is negative, add one.
+  // R_POWERPC_REL16_HA: ((Symbol + Addend + 0x8000 - Address) >> 16) & 0xffff
   static inline void
   rel16_ha(unsigned char* view,
 	   typename elfcpp::Elf_types<size>::Elf_Addr value,
@@ -706,30 +782,95 @@ public:
   }
 };
 
-// Stash away the index of .got2 in a relocatable object, if such
-// a section exists.
+// Stash away the index of .got2 or .opd in a relocatable object, if
+// such a section exists.
 
 template<int size, bool big_endian>
 bool
 Powerpc_relobj<size, big_endian>::do_find_special_sections(
     Read_symbols_data* sd)
 {
-  if (size == 32)
+  const unsigned char* const pshdrs = sd->section_headers->data();
+  const unsigned char* namesu = sd->section_names->data();
+  const char* names = reinterpret_cast<const char*>(namesu);
+  section_size_type names_size = sd->section_names_size;
+  const unsigned char* s;
+
+  s = this->find_shdr(pshdrs, size == 32 ? ".got2" : ".opd",
+		      names, names_size, NULL);
+  if (s != NULL)
     {
-      const unsigned char* const pshdrs = sd->section_headers->data();
-      const unsigned char* namesu = sd->section_names->data();
-      const char* names = reinterpret_cast<const char*>(namesu);
-      section_size_type names_size = sd->section_names_size;
-      const unsigned char* s;
+      unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
+      this->special_ = ndx;
+    }
+  return Sized_relobj_file<size, big_endian>::do_find_special_sections(sd);
+}
 
-      s = this->find_shdr(pshdrs, ".got2", names, names_size, NULL);
-      if (s != NULL)
-	{
-	  unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
-	  this->got2_section_ = ndx;
+// Examine .rela.opd to build info about function entry points.
+
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::scan_opd_relocs(
+    size_t reloc_count,
+    const unsigned char* prelocs,
+    const unsigned char* plocal_syms)
+{
+  if (size == 64)
+    {
+      typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+	Reltype;
+      const int reloc_size
+	= Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+      const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+      for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+	{
+	  Reltype reloc(prelocs);
+	  typename elfcpp::Elf_types<size>::Elf_WXword r_info
+	    = reloc.get_r_info();
+	  unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+	  if (r_type == elfcpp::R_PPC64_ADDR64)
+	    {
+	      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+	      typename elfcpp::Elf_types<size>::Elf_Addr value;
+	      bool is_ordinary;
+	      unsigned int shndx;
+	      if (r_sym < this->local_symbol_count())
+		{
+		  typename elfcpp::Sym<size, big_endian>
+		    lsym(plocal_syms + r_sym * sym_size);
+		  shndx = lsym.get_st_shndx();
+		  shndx = this->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+		  value = lsym.get_st_value();
+		}
+	      else
+		shndx = this->symbol_section_and_value(r_sym, &value,
+						       &is_ordinary);
+	      this->set_opd_ent(reloc.get_r_offset(), shndx,
+				value + reloc.get_r_addend());
+	    }
 	}
     }
-  return Sized_relobj_file<size, big_endian>::do_find_special_sections(sd);
+}
+
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
+{
+  Sized_relobj_file<size, big_endian>::do_read_relocs(rd);
+  if (size == 64)
+    {
+      for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
+	   p != rd->relocs.end();
+	   ++p)
+	if (p->data_shndx == this->opd_shndx())
+	  {
+	    this->init_opd(this->section_size(this->opd_shndx()));
+	    this->scan_opd_relocs(p->reloc_count, p->contents->data(),
+				  rd->local_symbols->data());
+	    break;
+	  }
+    }
 }
 
 // Set up PowerPC target specific relobj.
@@ -745,21 +886,20 @@ Target_powerpc<size, big_endian>::do_mak
   if (et == elfcpp::ET_REL)
     {
       Powerpc_relobj<size, big_endian>* obj =
-        new Powerpc_relobj<size, big_endian>(name, input_file, offset, ehdr);
+	new Powerpc_relobj<size, big_endian>(name, input_file, offset, ehdr);
       obj->setup();
       return obj;
     }
   else if (et == elfcpp::ET_DYN)
     {
       Sized_dynobj<size, big_endian>* obj =
-        new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
+	new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
       obj->setup();
       return obj;
     }
   else
     {
-      gold_error(_("%s: unsupported ELF file type %d"),
-                 name.c_str(), et);
+      gold_error(_("%s: unsupported ELF file type %d"), name.c_str(), et);
       return NULL;
     }
 }
@@ -1013,45 +1153,48 @@ Output_data_plt_powerpc<size, big_endian
     }
 }
 
-static const uint32_t addis_11_11       = 0x3d6b0000;
-static const uint32_t addis_11_30       = 0x3d7e0000;
-static const uint32_t addis_12_12       = 0x3d8c0000;
-static const uint32_t addi_11_11        = 0x396b0000;
-static const uint32_t add_0_11_11       = 0x7c0b5a14;
-static const uint32_t add_11_0_11       = 0x7d605a14;
-static const uint32_t b                 = 0x48000000;
-static const uint32_t bcl_20_31         = 0x429f0005;
-static const uint32_t bctr              = 0x4e800420;
-static const uint32_t blrl              = 0x4e800021;
-static const uint32_t lis_11            = 0x3d600000;
-static const uint32_t lis_12            = 0x3d800000;
-static const uint32_t lwzu_0_12         = 0x840c0000;
-static const uint32_t lwz_0_12          = 0x800c0000;
-static const uint32_t lwz_11_11         = 0x816b0000;
-static const uint32_t lwz_11_30         = 0x817e0000;
-static const uint32_t lwz_12_12         = 0x818c0000;
-static const uint32_t mflr_0            = 0x7c0802a6;
-static const uint32_t mflr_12           = 0x7d8802a6;
-static const uint32_t mtctr_0           = 0x7c0903a6;
-static const uint32_t mtctr_11          = 0x7d6903a6;
-static const uint32_t mtlr_0            = 0x7c0803a6;
-static const uint32_t nop               = 0x60000000;
-static const uint32_t sub_11_11_12      = 0x7d6c5850;
-static const uint32_t addis_12_2        = 0x3d820000;
-static const uint32_t std_2_1           = 0xf8410000;
-static const uint32_t ld_11_12          = 0xe96c0000;
-static const uint32_t ld_2_12           = 0xe84c0000;
-static const uint32_t addi_12_12        = 0x398c0000;
-static const uint32_t ld_11_2           = 0xe9620000;
-static const uint32_t addi_2_2          = 0x38420000;
-static const uint32_t ld_2_2            = 0xe8420000;
-static const uint32_t mflr_11           = 0x7d6802a6;
-static const uint32_t ld_2_11           = 0xe84b0000;
-static const uint32_t mtlr_12           = 0x7d8803a6;
-static const uint32_t add_12_2_11       = 0x7d825a14;
-static const uint32_t li_0_0            = 0x38000000;
-static const uint32_t lis_0_0           = 0x3c000000;
-static const uint32_t ori_0_0_0         = 0x60000000;
+static const uint32_t addis_11_11	= 0x3d6b0000;
+static const uint32_t addis_11_30	= 0x3d7e0000;
+static const uint32_t addis_12_12	= 0x3d8c0000;
+static const uint32_t addi_11_11	= 0x396b0000;
+static const uint32_t add_0_11_11	= 0x7c0b5a14;
+static const uint32_t add_11_0_11	= 0x7d605a14;
+static const uint32_t b			= 0x48000000;
+static const uint32_t bcl_20_31		= 0x429f0005;
+static const uint32_t bctr		= 0x4e800420;
+static const uint32_t blrl		= 0x4e800021;
+static const uint32_t lis_11		= 0x3d600000;
+static const uint32_t lis_12		= 0x3d800000;
+static const uint32_t lwzu_0_12		= 0x840c0000;
+static const uint32_t lwz_0_12		= 0x800c0000;
+static const uint32_t lwz_11_11		= 0x816b0000;
+static const uint32_t lwz_11_30		= 0x817e0000;
+static const uint32_t lwz_12_12		= 0x818c0000;
+static const uint32_t mflr_0		= 0x7c0802a6;
+static const uint32_t mflr_12		= 0x7d8802a6;
+static const uint32_t mtctr_0		= 0x7c0903a6;
+static const uint32_t mtctr_11		= 0x7d6903a6;
+static const uint32_t mtlr_0		= 0x7c0803a6;
+static const uint32_t nop		= 0x60000000;
+static const uint32_t sub_11_11_12	= 0x7d6c5850;
+static const uint32_t addis_12_2	= 0x3d820000;
+static const uint32_t std_2_1		= 0xf8410000;
+static const uint32_t ld_2_1		= 0xe8410000;
+static const uint32_t ld_11_12		= 0xe96c0000;
+static const uint32_t ld_2_12		= 0xe84c0000;
+static const uint32_t addi_12_12	= 0x398c0000;
+static const uint32_t ld_11_2		= 0xe9620000;
+static const uint32_t addi_2_2		= 0x38420000;
+static const uint32_t ld_2_2		= 0xe8420000;
+static const uint32_t mflr_11		= 0x7d6802a6;
+static const uint32_t ld_2_11		= 0xe84b0000;
+static const uint32_t mtlr_12		= 0x7d8803a6;
+static const uint32_t add_12_2_11	= 0x7d825a14;
+static const uint32_t li_0_0		= 0x38000000;
+static const uint32_t lis_0_0		= 0x3c000000;
+static const uint32_t ori_0_0_0		= 0x60000000;
+static const uint32_t cror_15_15_15	= 0x4def7b82;
+static const uint32_t cror_31_31_31	= 0x4ffffb82;
 
 // Write out the PLT.
 
@@ -1149,6 +1292,12 @@ class Output_data_glink : public Output_
     return this->pltresolve_;
   }
 
+  int
+  pltresolve_size() const
+  {
+    return this->pltresolve_size_;
+  }
+
  protected:
   // Write to a map file.
   void
@@ -1156,7 +1305,7 @@ class Output_data_glink : public Output_
   { mapfile->print_output_data(this, _("** glink")); }
 
  private:
-  static const int pltresolve_size = 16*4;
+  static const int pltresolve_size_ = 16*4;
 
   void
   set_final_data_size();
@@ -1171,7 +1320,7 @@ class Output_data_glink : public Output_
     Glink_sym_ent(const Symbol* sym,
 		  const elfcpp::Rela<size, big_endian>& reloc,
 		  const Sized_relobj<size, big_endian>* object)
-      : sym_(sym), object_(0), addend_(0)
+      : sym_(sym), addend_(0), object_(0)
     {
       if (size != 32)
 	this->addend_ = reloc.get_r_addend();
@@ -1185,16 +1334,16 @@ class Output_data_glink : public Output_
 	}
     }
 
-    const Symbol* sym_;
-    const Sized_relobj<size, big_endian>* object_;
-    unsigned int addend_;
-
     bool operator==(const Glink_sym_ent& that) const
     {
       return (this->sym_ == that.sym_
 	      && this->object_ == that.object_
 	      && this->addend_ == that.addend_);
     }
+
+    const Symbol* sym_;
+    unsigned int addend_;
+    const Sized_relobj<size, big_endian>* object_;
   };
 
   class Glink_sym_ent_hash
@@ -1276,13 +1425,13 @@ Output_data_glink<size, big_endian>::set
 	  total += 4 * (count - 1);
 
 	  total += -total & 15;
-	  total += this->pltresolve_size;
+	  total += this->pltresolve_size_;
 	}
       else
 	{
 	  total *= 32;
 	  this->pltresolve_ = total;
-	  total += this->pltresolve_size;
+	  total += this->pltresolve_size_;
 
 	  // space for branch table
 	  total += 8 * count;
@@ -1314,7 +1463,7 @@ ha(uint32_t a)
 
 template<bool big_endian>
 static inline void
-write_insn(unsigned char *p, uint32_t v)
+write_insn(unsigned char* p, uint32_t v)
 {
   elfcpp::Swap<32, big_endian>::writeval(p, v);
 }
@@ -1329,19 +1478,21 @@ Output_data_glink<size, big_endian>::do_
   const section_size_type oview_size =
     convert_to_section_size_type(this->data_size());
   unsigned char* const oview = of->get_output_view(off, oview_size);
-  unsigned char *p;
+  unsigned char* p;
 
   // The base address of the .plt section.
   uint32_t plt_base = this->targ_->plt_section()->address();
 
   // The address of _GLOBAL_OFFSET_TABLE_.
-  const Output_data_got_powerpc<size, big_endian> *got;
+  const Output_data_got_powerpc<size, big_endian>* got;
   typename elfcpp::Elf_types<size>::Elf_Addr g_o_t;
   got = this->targ_->got_section();
-  g_o_t = got->address() + got->g_o_t();
 
   if (size == 64)
     {
+      const unsigned int toc_base_offset = 0x8000;
+      g_o_t = got->output_section()->address() + toc_base_offset;
+
       // Write out call stubs.
       typename Glink_entries::const_iterator g;
       for (g = this->glink_entries_.begin();
@@ -1407,7 +1558,7 @@ Output_data_glink<size, big_endian>::do_
       write_insn<big_endian>(p, mtctr_11),			p += 4;
       write_insn<big_endian>(p, ld_11_12 + 16),			p += 4;
       write_insn<big_endian>(p, bctr),				p += 4;
-      while (p < oview + this->pltresolve_ + this->pltresolve_size)
+      while (p < oview + this->pltresolve_ + this->pltresolve_size_)
 	write_insn<big_endian>(p, nop), p += 4;
 
       // Write lazy link call stubs.
@@ -1423,13 +1574,15 @@ Output_data_glink<size, big_endian>::do_
 	      write_insn<big_endian>(p, lis_0_0 + hi(indx)),		p += 4;
 	      write_insn<big_endian>(p, ori_0_0_0 + l(indx)),		p += 4;
 	    }
-	  uint16_t branch_off = this->pltresolve_ + 8 - (p - oview);
+	  uint32_t branch_off = this->pltresolve_ + 8 - (p - oview);
 	  write_insn<big_endian>(p, b + (branch_off & 0x3fffffc)),	p += 4;
 	  indx++;
 	}
     }
   else
     {
+      g_o_t = got->address() + got->g_o_t();
+
       // Write out call stubs.
       typename Glink_entries::const_iterator g;
       for (g = this->glink_entries_.begin();
@@ -1480,8 +1633,8 @@ Output_data_glink<size, big_endian>::do_
 
       // Write out pltresolve branch table.
       p = oview + this->pltresolve_;
-      unsigned int the_end = oview_size - this->pltresolve_size;
-      unsigned char *end_p = oview + the_end;
+      unsigned int the_end = oview_size - this->pltresolve_size_;
+      unsigned char* end_p = oview + the_end;
       while (p < end_p - 8 * 4)
 	write_insn<big_endian>(p, b + end_p - p), p += 4;
       while (p < end_p)
@@ -1852,8 +2005,10 @@ Target_powerpc<size, big_endian>::Scan::
 
     case elfcpp::R_PPC64_ADDR64:
     case elfcpp::R_POWERPC_ADDR32:
-    case elfcpp::R_POWERPC_ADDR16_HA:
+    case elfcpp::R_POWERPC_ADDR16:
     case elfcpp::R_POWERPC_ADDR16_LO:
+    case elfcpp::R_POWERPC_ADDR16_HI:
+    case elfcpp::R_POWERPC_ADDR16_HA:
       // If building a shared library (or a position-independent
       // executable), we need to create a dynamic relocation for
       // this location.
@@ -1893,8 +2048,8 @@ Target_powerpc<size, big_endian>::Scan::
     case elfcpp::R_POWERPC_GOT16_HI:
     case elfcpp::R_POWERPC_GOT16_HA:
       {
-        // The symbol requires a GOT entry.
-        Output_data_got_powerpc<size, big_endian>* got;
+	// The symbol requires a GOT entry.
+	Output_data_got_powerpc<size, big_endian>* got;
 	unsigned int r_sym;
 
 	got = target->got_section(symtab, layout);
@@ -1985,16 +2140,16 @@ Target_powerpc<size, big_endian>::Scan::
     case elfcpp::R_PPC_LOCAL24PC:
       break;
 
+    case elfcpp::R_PPC64_ADDR64:
+    case elfcpp::R_POWERPC_ADDR32:
     case elfcpp::R_POWERPC_ADDR16:
     case elfcpp::R_POWERPC_ADDR16_LO:
     case elfcpp::R_POWERPC_ADDR16_HI:
     case elfcpp::R_POWERPC_ADDR16_HA:
-    case elfcpp::R_POWERPC_ADDR32:
-    case elfcpp::R_PPC64_ADDR64:
       {
-        // Make a PLT entry if necessary.
-        if (gsym->needs_plt_entry())
-          {
+	// Make a PLT entry if necessary.
+	if (gsym->needs_plt_entry())
+	  {
 	    target->make_plt_entry(layout, gsym, reloc, 0);
 	    // Since this is not a PC-relative relocation, we may be
 	    // taking the address of a function. In that case we need to
@@ -2003,16 +2158,16 @@ Target_powerpc<size, big_endian>::Scan::
 	    if (size == 32
 		&& gsym->is_from_dynobj() && !parameters->options().shared())
 	      gsym->set_needs_dynsym_value();
-          }
-        // Make a dynamic relocation if necessary.
-        if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
-          {
-            if (gsym->may_need_copy_reloc())
-              {
-	        target->copy_reloc(symtab, layout, object,
-	                           data_shndx, output_section, gsym, reloc);
-              }
-            else if ((r_type == elfcpp::R_POWERPC_ADDR32
+	  }
+	// Make a dynamic relocation if necessary.
+	if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+	  {
+	    if (gsym->may_need_copy_reloc())
+	      {
+		target->copy_reloc(symtab, layout, object,
+				   data_shndx, output_section, gsym, reloc);
+	      }
+	    else if ((r_type == elfcpp::R_POWERPC_ADDR32
 		      || r_type == elfcpp::R_PPC64_ADDR64)
 		     && gsym->can_use_relative_reloc(false))
 	      {
@@ -2086,8 +2241,8 @@ Target_powerpc<size, big_endian>::Scan::
     case elfcpp::R_POWERPC_GOT16_HI:
     case elfcpp::R_POWERPC_GOT16_HA:
       {
-        // The symbol requires a GOT entry.
-        Output_data_got_powerpc<size, big_endian>* got;
+	// The symbol requires a GOT entry.
+	Output_data_got_powerpc<size, big_endian>* got;
 
 	got = target->got_section(symtab, layout);
 	if (gsym->final_value_is_known())
@@ -2261,13 +2416,21 @@ Target_powerpc<size, big_endian>::do_fin
   layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
 				  this->rela_dyn_, true, size == 32);
 
+  Output_data_dynamic* odyn = layout->dynamic_data();
   if (size == 32)
     {
       this->got_->finalize_data_size();
-      Output_data_dynamic* odyn = layout->dynamic_data();
       odyn->add_section_plus_offset(elfcpp::DT_PPC_GOT,
 				    this->got_, this->got_->g_o_t());
     }
+  else
+    {
+      this->glink_->finalize_data_size();
+      odyn->add_section_plus_offset(elfcpp::DT_PPC64_GLINK,
+				    this->glink_,
+				    (this->glink_->pltresolve()
+				     + this->glink_->pltresolve_size() - 32));
+    }
 
   // Emit any relocs we saved in an attempt to avoid generating COPY
   // relocs.
@@ -2290,13 +2453,13 @@ Target_powerpc<size, big_endian>::Reloca
     const Symbol_value<size>* psymval,
     unsigned char* view,
     typename elfcpp::Elf_types<size>::Elf_Addr address,
-    section_size_type /* view_size */)
+    section_size_type view_size)
 {
   const unsigned int toc_base_offset = 0x8000;
   typedef Powerpc_relocate_functions<size, big_endian> Reloc;
   const Powerpc_relobj<size, big_endian>* const object
     = static_cast<const Powerpc_relobj<size, big_endian>*>(relinfo->object);
-  elfcpp::Elf_Xword value;
+  typename elfcpp::Elf_types<size>::Elf_Addr value;
 
   if (r_type == elfcpp::R_POWERPC_GOT16
       || r_type == elfcpp::R_POWERPC_GOT16_LO
@@ -2320,7 +2483,8 @@ Target_powerpc<size, big_endian>::Reloca
     }
   else if (r_type == elfcpp::R_PPC64_TOC)
     {
-      value = target->got_section()->address() + toc_base_offset;
+      value = (target->got_section()->output_section()->address()
+	       + toc_base_offset);
     }
   else if (gsym != NULL
 	   && (r_type == elfcpp::R_POWERPC_REL24
@@ -2332,6 +2496,36 @@ Target_powerpc<size, big_endian>::Reloca
       glink = target->glink_section();
       unsigned int glink_index = glink->find_entry(gsym, rela, object);
       value = glink->address() + glink_index * glink->glink_entry_size();
+      if (size == 64)
+	{
+	  typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+	  Valtype* wv = reinterpret_cast<Valtype*>(view);
+	  bool can_plt_call = false;
+	  if (rela.get_r_offset() + 8 <= view_size)
+	    {
+	      Valtype insn2 = elfcpp::Swap<32, big_endian>::readval(wv + 1);
+	      if (insn2 == nop
+		  || insn2 == cror_15_15_15 || insn2 == cror_31_31_31)
+		{
+		  elfcpp::Swap<32, big_endian>::writeval(wv + 1, ld_2_1 + 40);
+		  can_plt_call = true;
+		}
+	    }
+	  if (!can_plt_call)
+	    {
+	      if (parameters->options().output_is_executable())
+		{
+		  Valtype insn = elfcpp::Swap<32, big_endian>::readval(wv);
+		  if ((insn & 1) == 0)
+		    can_plt_call = true;
+		}
+	      else if (strcmp(gsym->name(), ".__libc_start_main") == 0)
+		can_plt_call = true;
+	    }
+	  if (!can_plt_call)
+	    gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+				   _("call lacks nop, can't restore toc"));
+	}
     }
   else
     {
@@ -2339,6 +2533,25 @@ Target_powerpc<size, big_endian>::Reloca
       if (r_type != elfcpp::R_PPC_PLTREL24)
 	addend = rela.get_r_addend();
       value = psymval->value(object, addend);
+      if (size == 64 && this->is_branch_reloc(r_type))
+	{
+	  Powerpc_relobj<size, big_endian>* symobj = const_cast
+	    <Powerpc_relobj<size, big_endian>*>(object);
+	  if (gsym != NULL)
+	    symobj = static_cast
+	      <Powerpc_relobj<size, big_endian>*>(gsym->object());
+	  unsigned int shndx = symobj->opd_shndx();
+	  typename elfcpp::Elf_types<size>::Elf_Addr opd_addr
+	    = (symobj->output_section(shndx)->address()
+	       + symobj->output_section_offset(shndx));
+	  if (value >= opd_addr
+	      && value < opd_addr + symobj->section_size(shndx))
+	    {
+	      symobj->get_opd_ent(value - opd_addr, &shndx, &value);
+	      value += (symobj->output_section(shndx)->address()
+			+ symobj->output_section_offset(shndx));
+	    }
+	}
     }
 
   switch (r_type)
@@ -2350,7 +2563,8 @@ Target_powerpc<size, big_endian>::Reloca
     case elfcpp::R_PPC64_TOC16_DS:
     case elfcpp::R_PPC64_TOC16_LO_DS:
       // Subtract the TOC base address.
-      value -= target->got_section()->address() + toc_base_offset;
+      value -= (target->got_section()->output_section()->address()
+		+ toc_base_offset);
       break;
 
     case elfcpp::R_POWERPC_SECTOFF:
@@ -2716,13 +2930,13 @@ Target_powerpc<size, big_endian>::reloca
 	new_offset = offset + offset_in_output_section;
       else
 	{
-          section_offset_type sot_offset =
-              convert_types<section_offset_type, Address>(offset);
+	  section_offset_type sot_offset =
+	    convert_types<section_offset_type, Address>(offset);
 	  section_offset_type new_sot_offset =
-              output_section->output_offset(object, relinfo->data_shndx,
-                                            sot_offset);
+	    output_section->output_offset(object, relinfo->data_shndx,
+					  sot_offset);
 	  gold_assert(new_sot_offset != -1);
-          new_offset = new_sot_offset;
+	  new_offset = new_sot_offset;
 	}
 
       reloc_write.put_r_offset(new_offset);
Index: gold/symtab.h
===================================================================
RCS file: /cvs/src/src/gold/symtab.h,v
retrieving revision 1.127
diff -u -p -r1.127 symtab.h
--- gold/symtab.h	31 Oct 2011 21:36:54 -0000	1.127
+++ gold/symtab.h	16 Aug 2012 12:03:01 -0000
@@ -62,7 +62,7 @@ class Garbage_collection;
 class Icf;
 
 // The base class of an entry in the symbol table.  The symbol table
-// can have a lot of entries, so we don't want this class to big.
+// can have a lot of entries, so we don't want this class too big.
 // Size dependent fields can be found in the template class
 // Sized_symbol.  Targets may support their own derived classes.
 


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [GOLD] advice on powerpc64 .opd handling
  2012-08-16 13:53   ` Alan Modra
@ 2012-08-17  5:28     ` Ian Lance Taylor
  2012-08-17  8:11       ` Alan Modra
  0 siblings, 1 reply; 9+ messages in thread
From: Ian Lance Taylor @ 2012-08-17  5:28 UTC (permalink / raw)
  To: Ian Lance Taylor, Cary Coutant, binutils, David Edelsohn

On Thu, Aug 16, 2012 at 6:43 AM, Alan Modra <amodra@gmail.com> wrote:
>
>         * powerpc.cc: Formatting and white space.
>         (Powerpc_relobj): Rename got2_section_ to special_.
>         Add opd_ent_count_, opd_ent_shndx_, opd_ent_off_.
>         (Powerpc_relobj::opd_shndx, init_opd, get_opd_ent, set_opd_ent,
>         do_read_relocs, opd_ent_ndx): New functions.
>         (Target_powerpc::is_branch_reloc): New function.
>         (Powerpc_relobj::do_find_special_sections): Find .opd for 64-bit.
>         (ld_2_1, cror_15_15_15, cror_31_31_31): New insn constants.
>         (Output_data_glink): Rename pltresolve_size to pltresolve_size_.
>         (Output_data_glink::pltresolve_size): New function.
>         (Output_data_glink::do_write): Correct toc base.  Don't try to use
>         uint16_t for 24-bit offset.
>         (Target_powerpc::Scan::local): Handle more relocs.
>         (Target_powerpc::do_finalize_sections): Set up DT_PPC64_GLINK.
>         (Target_powerpc::Relocate::relocate): Correct toc base calculation.
>         Plug in toc restoring insn after plt calls.  Translate branches
>         to function descriptor symbols to corresponding entry point.
>         * symtab.h: Comment typo.
>
>    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),
> -      got2_section_(0)
> +      special_(0)
>    { }

You should initialize all the new fields in the constructor, even if
you just initialize them to 0.


> +  unsigned int special_;
> +  size_t opd_ent_count_;
> +  unsigned int* opd_ent_shndx_;
> +  typename elfcpp::Elf_types<size>::Elf_Off* opd_ent_off_;

Please add comments for each describing the values they hold,
especially for special_.

Normally a C array should be std::vector in C++.  This should probably be

  std::vector<unsigned int> ent_shndx_;
  std::vector<typename elfcpp::Elf_Types<size>::Elf_Off> opd_ent_off_;

You may want to add a typedef for Elf_Off in the class, e.g., Address
in Sized_relobj in object.h.


> +         unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
> +         if (r_type == elfcpp::R_PPC64_ADDR64)
> +           {
> +             unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
> +             typename elfcpp::Elf_types<size>::Elf_Addr value;
> +             bool is_ordinary;
> +             unsigned int shndx;
> +             if (r_sym < this->local_symbol_count())
> +               {
> +                 typename elfcpp::Sym<size, big_endian>
> +                   lsym(plocal_syms + r_sym * sym_size);
> +                 shndx = lsym.get_st_shndx();
> +                 shndx = this->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
> +                 value = lsym.get_st_value();
> +               }
> +             else
> +               shndx = this->symbol_section_and_value(r_sym, &value,
> +                                                      &is_ordinary);

This isn't necessarily something to worry about right now, but
symbol_section_and_value is kind of a slow function.  If there are a
lot of global symbols in .opd sections, it will be better to get a
view of the global symbols once.

> +  if (size == 64)
> +    {
> +      for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
> +          p != rd->relocs.end();
> +          ++p)
> +       if (p->data_shndx == this->opd_shndx())
> +         {
> +           this->init_opd(this->section_size(this->opd_shndx()));
> +           this->scan_opd_relocs(p->reloc_count, p->contents->data(),
> +                                 rd->local_symbols->data());
> +           break;
> +         }
> +    }

When there is more than a single line in a for body, I prefer to see
curly braces.


>   private:
> -  static const int pltresolve_size = 16*4;
> +  static const int pltresolve_size_ = 16*4;

Although data member names always end in underscore, it's not
necessary for the name of a constant to end in underscore.

> +         if (!can_plt_call)
> +           {
> +             if (parameters->options().output_is_executable())

What should happen for a shared library here?  Should this be
!relocatable() instead?

> +         if (value >= opd_addr
> +             && value < opd_addr + symobj->section_size(shndx))
> +           {
> +             symobj->get_opd_ent(value - opd_addr, &shndx, &value);
> +             value += (symobj->output_section(shndx)->address()
> +                       + symobj->output_section_offset(shndx));

Should get_opd_ent double-check that it is not returning an undefined symbol?

Will this work correctly if the symbol is defined in a SHT_GROUP
section that is discarded?  Code like this usually calls
get_output_section_offset, not output_section_offset, and checks for a
return == invalid_address.  In that case it needs to call
output_section->output_address.  See examples in output.cc.

Ian

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [GOLD] advice on powerpc64 .opd handling
  2012-08-17  5:28     ` Ian Lance Taylor
@ 2012-08-17  8:11       ` Alan Modra
  2012-08-17 14:36         ` Ian Lance Taylor
  0 siblings, 1 reply; 9+ messages in thread
From: Alan Modra @ 2012-08-17  8:11 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Cary Coutant, binutils, David Edelsohn

On Thu, Aug 16, 2012 at 10:08:13PM -0700, Ian Lance Taylor wrote:
> Normally a C array should be std::vector in C++.  This should probably be
> 
>   std::vector<unsigned int> ent_shndx_;
>   std::vector<typename elfcpp::Elf_Types<size>::Elf_Off> opd_ent_off_;

Even when no resizing will be needed?

> > +               shndx = this->symbol_section_and_value(r_sym, &value,
> > +                                                      &is_ordinary);
> 
> This isn't necessarily something to worry about right now, but
> symbol_section_and_value is kind of a slow function.

Yes, I noticed that.  Gloabl symbols here are a rarity.

> > +         if (!can_plt_call)
> > +           {
> > +             if (parameters->options().output_is_executable())
> 
> What should happen for a shared library here?  Should this be
> !relocatable() instead?

This was copied from bfd/elf64-ppc.c without much thought.  Now that
you mention it, I'm not sure that the bfd code is correct.
Investigating.

> 
> > +         if (value >= opd_addr
> > +             && value < opd_addr + symobj->section_size(shndx))
> > +           {
> > +             symobj->get_opd_ent(value - opd_addr, &shndx, &value);
> > +             value += (symobj->output_section(shndx)->address()
> > +                       + symobj->output_section_offset(shndx));
> 
> Should get_opd_ent double-check that it is not returning an undefined symbol?

I suppose that could be caused by an invalid object file.  Valid OPD
entries point at locally defined functions.

> Will this work correctly if the symbol is defined in a SHT_GROUP
> section that is discarded?

Hasn't something gone horribly if we're trying to call such a
function?

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [GOLD] advice on powerpc64 .opd handling
  2012-08-17  8:11       ` Alan Modra
@ 2012-08-17 14:36         ` Ian Lance Taylor
  2012-08-18  1:45           ` Alan Modra
  0 siblings, 1 reply; 9+ messages in thread
From: Ian Lance Taylor @ 2012-08-17 14:36 UTC (permalink / raw)
  To: Ian Lance Taylor, Cary Coutant, binutils, David Edelsohn

On Fri, Aug 17, 2012 at 12:23 AM, Alan Modra <amodra@gmail.com> wrote:
> On Thu, Aug 16, 2012 at 10:08:13PM -0700, Ian Lance Taylor wrote:
>> Normally a C array should be std::vector in C++.  This should probably be
>>
>>   std::vector<unsigned int> ent_shndx_;
>>   std::vector<typename elfcpp::Elf_Types<size>::Elf_Off> opd_ent_off_;
>
> Even when no resizing will be needed?

Yes.  The overhead is small.

>> Will this work correctly if the symbol is defined in a SHT_GROUP
>> section that is discarded?
>
> Hasn't something gone horribly if we're trying to call such a
> function?

Seems to me that it's normal for a C++ template instantiation.  Maybe
I'm missing something.

Ian

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [GOLD] advice on powerpc64 .opd handling
  2012-08-17 14:36         ` Ian Lance Taylor
@ 2012-08-18  1:45           ` Alan Modra
  2012-08-18 11:13             ` Ian Lance Taylor
  0 siblings, 1 reply; 9+ messages in thread
From: Alan Modra @ 2012-08-18  1:45 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Cary Coutant, binutils, David Edelsohn

On Fri, Aug 17, 2012 at 06:59:57AM -0700, Ian Lance Taylor wrote:
> On Fri, Aug 17, 2012 at 12:23 AM, Alan Modra <amodra@gmail.com> wrote:
> > On Thu, Aug 16, 2012 at 10:08:13PM -0700, Ian Lance Taylor wrote:
> >> Normally a C array should be std::vector in C++.  This should probably be
> >>
> >>   std::vector<unsigned int> ent_shndx_;
> >>   std::vector<typename elfcpp::Elf_Types<size>::Elf_Off> opd_ent_off_;
> >
> > Even when no resizing will be needed?
> 
> Yes.  The overhead is small.

OK.

> >> Will this work correctly if the symbol is defined in a SHT_GROUP
> >> section that is discarded?
> >
> > Hasn't something gone horribly if we're trying to call such a
> > function?
> 
> Seems to me that it's normal for a C++ template instantiation.  Maybe
> I'm missing something.

I meant function as in a symbol in the object file, not a language
feature.  In other words, if gold is relocating a function call then
(a) the section we're relocating is a kept section, and
(b) the function symbol referenced in the reloc will have its code
section kept too, unless something has gone wrong with --gc-sections.
As far as I'm aware, the only way (b) might fail is if the function
symbol is STB_LOCAL, but I thought gcc no longer used local symbols in
comdat groups or linkonce sections.  Or is there something I'm missing
about gold symbol resolution?

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [GOLD] advice on powerpc64 .opd handling
  2012-08-18  1:45           ` Alan Modra
@ 2012-08-18 11:13             ` Ian Lance Taylor
  2012-08-18 12:49               ` Alan Modra
  0 siblings, 1 reply; 9+ messages in thread
From: Ian Lance Taylor @ 2012-08-18 11:13 UTC (permalink / raw)
  To: Ian Lance Taylor, Cary Coutant, binutils, David Edelsohn

On Fri, Aug 17, 2012 at 6:13 PM, Alan Modra <amodra@gmail.com> wrote:
>
>> >> Will this work correctly if the symbol is defined in a SHT_GROUP
>> >> section that is discarded?
>> >
>> > Hasn't something gone horribly if we're trying to call such a
>> > function?
>>
>> Seems to me that it's normal for a C++ template instantiation.  Maybe
>> I'm missing something.
>
> I meant function as in a symbol in the object file, not a language
> feature.  In other words, if gold is relocating a function call then
> (a) the section we're relocating is a kept section, and
> (b) the function symbol referenced in the reloc will have its code
> section kept too, unless something has gone wrong with --gc-sections.
> As far as I'm aware, the only way (b) might fail is if the function
> symbol is STB_LOCAL, but I thought gcc no longer used local symbols in
> comdat groups or linkonce sections.  Or is there something I'm missing
> about gold symbol resolution?

It's possible that the case I'm thinking of can not occur (although in
that case you should call get_output_section_offset and assert that it
does not return invalid_address).  I'm thinking about a call to an
instantiated template function, which will be a STB_WEAK symbol in a
section that is in a SHT_GROUP.  The same SHT_GROUP may be defined in
some other object file, in which case that is the symbol definition
that will be used, not the one in the current object file.

Ian

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [GOLD] advice on powerpc64 .opd handling
  2012-08-18 11:13             ` Ian Lance Taylor
@ 2012-08-18 12:49               ` Alan Modra
  0 siblings, 0 replies; 9+ messages in thread
From: Alan Modra @ 2012-08-18 12:49 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: Cary Coutant, binutils, David Edelsohn

On Fri, Aug 17, 2012 at 09:37:17PM -0700, Ian Lance Taylor wrote:
> It's possible that the case I'm thinking of can not occur (although in
> that case you should call get_output_section_offset and assert that it
> does not return invalid_address).  I'm thinking about a call to an
> instantiated template function, which will be a STB_WEAK symbol in a
> section that is in a SHT_GROUP.  The same SHT_GROUP may be defined in
> some other object file, in which case that is the symbol definition
> that will be used, not the one in the current object file.

OK, so we are talking about the same thing.  Given multiple weak
symbols, whichever symbol wins determines the kept section (and
object).  We'll use the .opd section entry from that object too.  I've
changed to code to call get_output_section_offset and assert, and in
another place I used output_section_offset directly too.
Committed.

	* powerpc.cc: Formatting and white space.
	(Powerpc_relobj): Rename got2_section_ to special_.
	Add opd_ent_shndx_ and opd_ent_off_ vectors.
	(Powerpc_relobj::opd_shndx, init_opd, get_opd_ent, set_opd_ent,
	scan_opd_relocs, do_read_relocs, opd_ent_ndx): New functions.
	(Target_powerpc): Add Address typedef and invalid_address.  Use
	throughout.
	(Target_powerpc::is_branch_reloc): New function.
	(Powerpc_relocate_functions): Add Address typedef, use throughout.
	(Powerpc_relocate_functions:rela, rela_ua): Correct type used
	for dst_mask, value and addend.
	(Powerpc_relobj::do_find_special_sections): Find .opd for 64-bit.
	(ld_2_1, cror_15_15_15, cror_31_31_31): New insn constants.
	(Output_data_glink::do_write): Correct toc base.  Don't try to use
	uint16_t for 24-bit offset.  Use get_output_section_offset and
	check return.
	(Target_powerpc::Scan::local): Handle more relocs.
	(Target_powerpc::do_finalize_sections): Set up DT_PPC64_GLINK.
	(Target_powerpc::Relocate::relocate): Correct toc base calculation.
	Plug in toc restoring insn after plt calls.  Translate branches
	to function descriptor symbols to corresponding entry point.
	(Target_powerpc::relocate_for_relocatable): Check return from
	get_output_section_offset.
	* symtab.h: Comment typo.

Index: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.49
diff -u -p -r1.49 powerpc.cc
--- gold/powerpc.cc	14 Aug 2012 03:39:03 -0000	1.49
+++ gold/powerpc.cc	18 Aug 2012 09:53:20 -0000
@@ -57,29 +57,106 @@ template<int size, bool big_endian>
 class Powerpc_relobj : public Sized_relobj_file<size, big_endian>
 {
 public:
+  typedef typename elfcpp::Elf_types<size>::Elf_Off Offset;
+
   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),
-      got2_section_(0)
+      special_(0), opd_ent_shndx_(), opd_ent_off_()
   { }
 
   ~Powerpc_relobj()
   { }
 
+  // The .got2 section shndx.
   unsigned int
   got2_shndx() const
   {
     if (size == 32)
-      return this->got2_section_;
+      return this->special_;
     else
       return 0;
   }
 
+  // The .opd section shndx.
+  unsigned int
+  opd_shndx() const
+  {
+    if (size == 32)
+      return 0;
+    else
+      return this->special_;
+  }
+
+  // Init OPD entry arrays.
+  void
+  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);
+  }
+
+  // Return section and offset of function entry for .opd + R_OFF.
+  void
+  get_opd_ent(typename elfcpp::Elf_types<size>::Elf_Addr r_off,
+	      unsigned int* shndx,
+	      typename elfcpp::Elf_types<size>::Elf_Addr* value)
+  {
+    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];
+  }
+
+  // Set section and offset of function entry for .opd + R_OFF.
+  void
+  set_opd_ent(typename elfcpp::Elf_types<size>::Elf_Addr r_off,
+	      unsigned int shndx,
+	      typename elfcpp::Elf_types<size>::Elf_Addr 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;
+  }
+
+  // Examine .rela.opd to build info about function entry points.
+  void
+  scan_opd_relocs(size_t reloc_count,
+		  const unsigned char* prelocs,
+		  const unsigned char* plocal_syms);
+
+  void
+  do_read_relocs(Read_relocs_data*);
+
   bool
   do_find_special_sections(Read_symbols_data* sd);
 
 private:
-  unsigned int got2_section_;
+  // 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.)
+  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_;
+  // 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
+  // section and offset specified by these relocations.
+  std::vector<unsigned int> opd_ent_shndx_;
+  std::vector<Offset> opd_ent_off_;
 };
 
 template<int size, bool big_endian>
@@ -88,6 +165,8 @@ class Target_powerpc : public Sized_targ
  public:
   typedef
     Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian> Reloc_section;
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+  static const Address invalid_address = static_cast<Address>(0) - 1;
 
   Target_powerpc()
     : Sized_target<size, big_endian>(&powerpc_info),
@@ -156,7 +235,7 @@ class Target_powerpc : public Sized_targ
 		   Output_section* output_section,
 		   bool needs_special_offset_handling,
 		   unsigned char* view,
-		   typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+		   Address view_address,
 		   section_size_type view_size,
 		   const Reloc_symbol_changes*);
 
@@ -185,7 +264,7 @@ class Target_powerpc : public Sized_targ
 			   off_t offset_in_output_section,
 			   const Relocatable_relocs*,
 			   unsigned char*,
-			   typename elfcpp::Elf_types<size>::Elf_Addr,
+			   Address,
 			   section_size_type,
 			   unsigned char* reloc_view,
 			   section_size_type reloc_view_size);
@@ -342,6 +421,19 @@ class Target_powerpc : public Sized_targ
 	     typename elfcpp::Elf_types<size>::Elf_Addr,
 	     section_size_type);
 
+    inline bool
+    is_branch_reloc(unsigned int r_type) const
+    {
+      return (r_type == elfcpp::R_POWERPC_REL24
+	      || r_type == elfcpp::R_POWERPC_REL14
+	      || r_type == elfcpp::R_POWERPC_REL14_BRTAKEN
+	      || r_type == elfcpp::R_POWERPC_REL14_BRNTAKEN
+	      || r_type == elfcpp::R_POWERPC_ADDR24
+	      || r_type == elfcpp::R_POWERPC_ADDR14
+	      || r_type == elfcpp::R_POWERPC_ADDR14_BRTAKEN
+	      || r_type == elfcpp::R_POWERPC_ADDR14_BRNTAKEN);
+    }
+
    private:
     // Do a TLS relocation.
     inline void
@@ -460,8 +552,8 @@ Target::Target_info Target_powerpc<32, t
   0x10000000,		// default_text_segment_address
   64 * 1024,		// abi_pagesize (overridable by -z max-page-size)
   4 * 1024,		// common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,		// isolate_execinstr
+  0,			// rosegment_gap
   elfcpp::SHN_UNDEF,	// small_common_shndx
   elfcpp::SHN_UNDEF,	// large_common_shndx
   0,			// small_common_section_flags
@@ -486,8 +578,8 @@ Target::Target_info Target_powerpc<32, f
   0x10000000,		// default_text_segment_address
   64 * 1024,		// abi_pagesize (overridable by -z max-page-size)
   4 * 1024,		// common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,		// isolate_execinstr
+  0,			// rosegment_gap
   elfcpp::SHN_UNDEF,	// small_common_shndx
   elfcpp::SHN_UNDEF,	// large_common_shndx
   0,			// small_common_section_flags
@@ -512,8 +604,8 @@ Target::Target_info Target_powerpc<64, t
   0x10000000,		// default_text_segment_address
   64 * 1024,		// abi_pagesize (overridable by -z max-page-size)
   8 * 1024,		// common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,		// isolate_execinstr
+  0,			// rosegment_gap
   elfcpp::SHN_UNDEF,	// small_common_shndx
   elfcpp::SHN_UNDEF,	// large_common_shndx
   0,			// small_common_section_flags
@@ -538,8 +630,8 @@ Target::Target_info Target_powerpc<64, f
   0x10000000,		// default_text_segment_address
   64 * 1024,		// abi_pagesize (overridable by -z max-page-size)
   8 * 1024,		// common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,		// isolate_execinstr
+  0,			// rosegment_gap
   elfcpp::SHN_UNDEF,	// small_common_shndx
   elfcpp::SHN_UNDEF,	// large_common_shndx
   0,			// small_common_section_flags
@@ -552,23 +644,25 @@ template<int size, bool big_endian>
 class Powerpc_relocate_functions
 {
 private:
+  typedef Powerpc_relocate_functions<size, big_endian> This;
+  typedef Relocate_functions<size, big_endian> This_reloc;
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
   // Do a simple RELA relocation
   template<int valsize>
   static inline void
   rela(unsigned char* view,
        unsigned int right_shift,
-       elfcpp::Elf_Xword dst_mask,
-       typename elfcpp::Swap<size, big_endian>::Valtype value,
-       typename elfcpp::Swap<size, big_endian>::Valtype addend)
+       typename elfcpp::Valtype_base<valsize>::Valtype dst_mask,
+       Address value,
+       Address addend)
   {
     typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
     Valtype* wv = reinterpret_cast<Valtype*>(view);
     Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
     Valtype reloc = (value + addend) >> right_shift;
-
     val &= ~dst_mask;
     reloc &= dst_mask;
-
     elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
   }
 
@@ -577,159 +671,173 @@ private:
   static inline void
   rela_ua(unsigned char* view,
 	  unsigned int right_shift,
-	  elfcpp::Elf_Xword dst_mask,
-	  typename elfcpp::Swap<size, big_endian>::Valtype value,
-	  typename elfcpp::Swap<size, big_endian>::Valtype addend)
+	  typename elfcpp::Valtype_base<valsize>::Valtype dst_mask,
+	  Address value,
+	  Address addend)
   {
-    typedef typename elfcpp::Swap_unaligned<valsize,
-					    big_endian>::Valtype Valtype;
+    typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
+      Valtype;
     Valtype* wv = reinterpret_cast<Valtype*>(view);
     Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
     Valtype reloc = (value + addend) >> right_shift;
-
     val &= ~dst_mask;
     reloc &= dst_mask;
-
     elfcpp::Swap_unaligned<valsize, big_endian>::writeval(wv, val | reloc);
   }
 
-  typedef Powerpc_relocate_functions<size, big_endian> This;
-  typedef Relocate_functions<size, big_endian> This_reloc;
 public:
   // R_POWERPC_REL32: (Symbol + Addend - Address)
   static inline void
-  rel32(unsigned char* view,
-	typename elfcpp::Elf_types<size>::Elf_Addr value,
-	typename elfcpp::Elf_types<size>::Elf_Addr addend,
-	typename elfcpp::Elf_types<size>::Elf_Addr address)
+  rel32(unsigned char* view, Address value, Address addend, Address address)
   { This_reloc::pcrela32(view, value, addend, address); }
 
   // R_POWERPC_REL24: (Symbol + Addend - Address) & 0x3fffffc
   static inline void
-  rel24(unsigned char* view,
-	typename elfcpp::Elf_types<size>::Elf_Addr value,
-	typename elfcpp::Elf_types<size>::Elf_Addr addend,
-	typename elfcpp::Elf_types<size>::Elf_Addr address)
-  {
-    This::template rela<32>(view, 0, 0x03fffffc, value - address, addend);
-  }
+  rel24(unsigned char* view, Address value, Address addend, Address address)
+  { This::template rela<32>(view, 0, 0x03fffffc, value - address, addend); }
 
   // R_POWERPC_REL14: (Symbol + Addend - Address) & 0xfffc
   static inline void
-  rel14(unsigned char* view,
-	typename elfcpp::Elf_types<size>::Elf_Addr value,
-	typename elfcpp::Elf_types<size>::Elf_Addr addend,
-	typename elfcpp::Elf_types<size>::Elf_Addr address)
-  {
-    This::template rela<32>(view, 0, 0xfffc, value - address, addend);
-  }
+  rel14(unsigned char* view, Address value, Address addend, Address address)
+  { This::template rela<32>(view, 0, 0xfffc, value - address, addend); }
 
   // R_POWERPC_ADDR16: (Symbol + Addend) & 0xffff
   static inline void
-  addr16(unsigned char* view,
-	 typename elfcpp::Elf_types<size>::Elf_Addr value,
-	 typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  addr16(unsigned char* view, Address value, Address addend)
   { This_reloc::rela16(view, value, addend); }
 
   // R_POWERPC_ADDR16_DS: (Symbol + Addend) & 0xfffc
   static inline void
-  addr16_ds(unsigned char* view,
-	    typename elfcpp::Elf_types<size>::Elf_Addr value,
-	    typename elfcpp::Elf_types<size>::Elf_Addr addend)
-  {
-    This::template rela<16>(view, 0, 0xfffc, value, addend);
-  }
+  addr16_ds(unsigned char* view, Address value, Address addend)
+  { This::template rela<16>(view, 0, 0xfffc, value, addend); }
 
   // R_POWERPC_ADDR16_LO: (Symbol + Addend) & 0xffff
   static inline void
-  addr16_lo(unsigned char* view,
-	 typename elfcpp::Elf_types<size>::Elf_Addr value,
-	 typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  addr16_lo(unsigned char* view, Address value, Address addend)
   { This_reloc::rela16(view, value, addend); }
 
   // R_POWERPC_ADDR16_HI: ((Symbol + Addend) >> 16) & 0xffff
   static inline void
-  addr16_hi(unsigned char* view,
-	    typename elfcpp::Elf_types<size>::Elf_Addr value,
-	    typename elfcpp::Elf_types<size>::Elf_Addr addend)
-  {
-    This::template rela<16>(view, 16, 0xffff, value, addend);
-  }
+  addr16_hi(unsigned char* view, Address value, Address addend)
+  { This::template rela<16>(view, 16, 0xffff, value, addend); }
 
-  // R_POWERPC_ADDR16_HA: Same as R_POWERPC_ADDR16_HI except that if the
-  //                      final value of the low 16 bits of the
-  //                      relocation is negative, add one.
+  // R_POWERPC_ADDR16_HA: ((Symbol + Addend + 0x8000) >> 16) & 0xffff
   static inline void
-  addr16_ha(unsigned char* view,
-	    typename elfcpp::Elf_types<size>::Elf_Addr value,
-	    typename elfcpp::Elf_types<size>::Elf_Addr addend)
-  {
-    This::addr16_hi(view, value + 0x8000, addend);
-  }
+  addr16_ha(unsigned char* view, Address value, Address addend)
+  { This::addr16_hi(view, value + 0x8000, addend); }
 
   // R_POWERPC_REL16: (Symbol + Addend - Address) & 0xffff
   static inline void
-  rel16(unsigned char* view,
-	typename elfcpp::Elf_types<size>::Elf_Addr value,
-	typename elfcpp::Elf_types<size>::Elf_Addr addend,
-	typename elfcpp::Elf_types<size>::Elf_Addr address)
+  rel16(unsigned char* view, Address value, Address addend, Address address)
   { This_reloc::pcrela16(view, value, addend, address); }
 
   // R_POWERPC_REL16_LO: (Symbol + Addend - Address) & 0xffff
   static inline void
-  rel16_lo(unsigned char* view,
-	   typename elfcpp::Elf_types<size>::Elf_Addr value,
-	   typename elfcpp::Elf_types<size>::Elf_Addr addend,
-	   typename elfcpp::Elf_types<size>::Elf_Addr address)
+  rel16_lo(unsigned char* view, Address value, Address addend, Address address)
   { This_reloc::pcrela16(view, value, addend, address); }
 
   // R_POWERPC_REL16_HI: ((Symbol + Addend - Address) >> 16) & 0xffff
   static inline void
-  rel16_hi(unsigned char* view,
-	   typename elfcpp::Elf_types<size>::Elf_Addr value,
-	   typename elfcpp::Elf_types<size>::Elf_Addr addend,
-	   typename elfcpp::Elf_types<size>::Elf_Addr address)
-  {
-    This::template rela<16>(view, 16, 0xffff, value - address, addend);
-  }
+  rel16_hi(unsigned char* view, Address value, Address addend, Address address)
+  { This::template rela<16>(view, 16, 0xffff, value - address, addend); }
 
-  // R_POWERPC_REL16_HA: Same as R_POWERPC_REL16_HI except that if the
-  //                 final value of the low 16 bits of the
-  //                 relocation is negative, add one.
+  // R_POWERPC_REL16_HA: ((Symbol + Addend + 0x8000 - Address) >> 16) & 0xffff
   static inline void
-  rel16_ha(unsigned char* view,
-	   typename elfcpp::Elf_types<size>::Elf_Addr value,
-	   typename elfcpp::Elf_types<size>::Elf_Addr addend,
-	   typename elfcpp::Elf_types<size>::Elf_Addr address)
-  {
-    This::rel16_hi(view, value + 0x8000, addend, address);
-  }
+  rel16_ha(unsigned char* view, Address value, Address addend, Address address)
+  { This::rel16_hi(view, value + 0x8000, addend, address); }
 };
 
-// Stash away the index of .got2 in a relocatable object, if such
-// a section exists.
+// Stash away the index of .got2 or .opd in a relocatable object, if
+// such a section exists.
 
 template<int size, bool big_endian>
 bool
 Powerpc_relobj<size, big_endian>::do_find_special_sections(
     Read_symbols_data* sd)
 {
-  if (size == 32)
+  const unsigned char* const pshdrs = sd->section_headers->data();
+  const unsigned char* namesu = sd->section_names->data();
+  const char* names = reinterpret_cast<const char*>(namesu);
+  section_size_type names_size = sd->section_names_size;
+  const unsigned char* s;
+
+  s = this->find_shdr(pshdrs, size == 32 ? ".got2" : ".opd",
+		      names, names_size, NULL);
+  if (s != NULL)
+    {
+      unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
+      this->special_ = ndx;
+    }
+  return Sized_relobj_file<size, big_endian>::do_find_special_sections(sd);
+}
+
+// Examine .rela.opd to build info about function entry points.
+
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::scan_opd_relocs(
+    size_t reloc_count,
+    const unsigned char* prelocs,
+    const unsigned char* plocal_syms)
+{
+  if (size == 64)
     {
-      const unsigned char* const pshdrs = sd->section_headers->data();
-      const unsigned char* namesu = sd->section_names->data();
-      const char* names = reinterpret_cast<const char*>(namesu);
-      section_size_type names_size = sd->section_names_size;
-      const unsigned char* s;
+      typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+	Reltype;
+      const int reloc_size
+	= Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+      const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+      for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+	{
+	  Reltype reloc(prelocs);
+	  typename elfcpp::Elf_types<size>::Elf_WXword r_info
+	    = reloc.get_r_info();
+	  unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+	  if (r_type == elfcpp::R_PPC64_ADDR64)
+	    {
+	      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+	      typename elfcpp::Elf_types<size>::Elf_Addr value;
+	      bool is_ordinary;
+	      unsigned int shndx;
+	      if (r_sym < this->local_symbol_count())
+		{
+		  typename elfcpp::Sym<size, big_endian>
+		    lsym(plocal_syms + r_sym * sym_size);
+		  shndx = lsym.get_st_shndx();
+		  shndx = this->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+		  value = lsym.get_st_value();
+		}
+	      else
+		shndx = this->symbol_section_and_value(r_sym, &value,
+						       &is_ordinary);
+	      this->set_opd_ent(reloc.get_r_offset(), shndx,
+				value + reloc.get_r_addend());
+	    }
+	}
+    }
+}
 
-      s = this->find_shdr(pshdrs, ".got2", names, names_size, NULL);
-      if (s != NULL)
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
+{
+  Sized_relobj_file<size, big_endian>::do_read_relocs(rd);
+  if (size == 64)
+    {
+      for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
+	   p != rd->relocs.end();
+	   ++p)
 	{
-	  unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
-	  this->got2_section_ = ndx;
+	  if (p->data_shndx == this->opd_shndx())
+	    {
+	      this->init_opd(this->section_size(this->opd_shndx()));
+	      this->scan_opd_relocs(p->reloc_count, p->contents->data(),
+				    rd->local_symbols->data());
+	      break;
+	    }
 	}
     }
-  return Sized_relobj_file<size, big_endian>::do_find_special_sections(sd);
 }
 
 // Set up PowerPC target specific relobj.
@@ -745,21 +853,20 @@ Target_powerpc<size, big_endian>::do_mak
   if (et == elfcpp::ET_REL)
     {
       Powerpc_relobj<size, big_endian>* obj =
-        new Powerpc_relobj<size, big_endian>(name, input_file, offset, ehdr);
+	new Powerpc_relobj<size, big_endian>(name, input_file, offset, ehdr);
       obj->setup();
       return obj;
     }
   else if (et == elfcpp::ET_DYN)
     {
       Sized_dynobj<size, big_endian>* obj =
-        new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
+	new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
       obj->setup();
       return obj;
     }
   else
     {
-      gold_error(_("%s: unsupported ELF file type %d"),
-                 name.c_str(), et);
+      gold_error(_("%s: unsupported ELF file type %d"), name.c_str(), et);
       return NULL;
     }
 }
@@ -1013,45 +1120,48 @@ Output_data_plt_powerpc<size, big_endian
     }
 }
 
-static const uint32_t addis_11_11       = 0x3d6b0000;
-static const uint32_t addis_11_30       = 0x3d7e0000;
-static const uint32_t addis_12_12       = 0x3d8c0000;
-static const uint32_t addi_11_11        = 0x396b0000;
-static const uint32_t add_0_11_11       = 0x7c0b5a14;
-static const uint32_t add_11_0_11       = 0x7d605a14;
-static const uint32_t b                 = 0x48000000;
-static const uint32_t bcl_20_31         = 0x429f0005;
-static const uint32_t bctr              = 0x4e800420;
-static const uint32_t blrl              = 0x4e800021;
-static const uint32_t lis_11            = 0x3d600000;
-static const uint32_t lis_12            = 0x3d800000;
-static const uint32_t lwzu_0_12         = 0x840c0000;
-static const uint32_t lwz_0_12          = 0x800c0000;
-static const uint32_t lwz_11_11         = 0x816b0000;
-static const uint32_t lwz_11_30         = 0x817e0000;
-static const uint32_t lwz_12_12         = 0x818c0000;
-static const uint32_t mflr_0            = 0x7c0802a6;
-static const uint32_t mflr_12           = 0x7d8802a6;
-static const uint32_t mtctr_0           = 0x7c0903a6;
-static const uint32_t mtctr_11          = 0x7d6903a6;
-static const uint32_t mtlr_0            = 0x7c0803a6;
-static const uint32_t nop               = 0x60000000;
-static const uint32_t sub_11_11_12      = 0x7d6c5850;
-static const uint32_t addis_12_2        = 0x3d820000;
-static const uint32_t std_2_1           = 0xf8410000;
-static const uint32_t ld_11_12          = 0xe96c0000;
-static const uint32_t ld_2_12           = 0xe84c0000;
-static const uint32_t addi_12_12        = 0x398c0000;
-static const uint32_t ld_11_2           = 0xe9620000;
-static const uint32_t addi_2_2          = 0x38420000;
-static const uint32_t ld_2_2            = 0xe8420000;
-static const uint32_t mflr_11           = 0x7d6802a6;
-static const uint32_t ld_2_11           = 0xe84b0000;
-static const uint32_t mtlr_12           = 0x7d8803a6;
-static const uint32_t add_12_2_11       = 0x7d825a14;
-static const uint32_t li_0_0            = 0x38000000;
-static const uint32_t lis_0_0           = 0x3c000000;
-static const uint32_t ori_0_0_0         = 0x60000000;
+static const uint32_t addis_11_11	= 0x3d6b0000;
+static const uint32_t addis_11_30	= 0x3d7e0000;
+static const uint32_t addis_12_12	= 0x3d8c0000;
+static const uint32_t addi_11_11	= 0x396b0000;
+static const uint32_t add_0_11_11	= 0x7c0b5a14;
+static const uint32_t add_11_0_11	= 0x7d605a14;
+static const uint32_t b			= 0x48000000;
+static const uint32_t bcl_20_31		= 0x429f0005;
+static const uint32_t bctr		= 0x4e800420;
+static const uint32_t blrl		= 0x4e800021;
+static const uint32_t lis_11		= 0x3d600000;
+static const uint32_t lis_12		= 0x3d800000;
+static const uint32_t lwzu_0_12		= 0x840c0000;
+static const uint32_t lwz_0_12		= 0x800c0000;
+static const uint32_t lwz_11_11		= 0x816b0000;
+static const uint32_t lwz_11_30		= 0x817e0000;
+static const uint32_t lwz_12_12		= 0x818c0000;
+static const uint32_t mflr_0		= 0x7c0802a6;
+static const uint32_t mflr_12		= 0x7d8802a6;
+static const uint32_t mtctr_0		= 0x7c0903a6;
+static const uint32_t mtctr_11		= 0x7d6903a6;
+static const uint32_t mtlr_0		= 0x7c0803a6;
+static const uint32_t nop		= 0x60000000;
+static const uint32_t sub_11_11_12	= 0x7d6c5850;
+static const uint32_t addis_12_2	= 0x3d820000;
+static const uint32_t std_2_1		= 0xf8410000;
+static const uint32_t ld_2_1		= 0xe8410000;
+static const uint32_t ld_11_12		= 0xe96c0000;
+static const uint32_t ld_2_12		= 0xe84c0000;
+static const uint32_t addi_12_12	= 0x398c0000;
+static const uint32_t ld_11_2		= 0xe9620000;
+static const uint32_t addi_2_2		= 0x38420000;
+static const uint32_t ld_2_2		= 0xe8420000;
+static const uint32_t mflr_11		= 0x7d6802a6;
+static const uint32_t ld_2_11		= 0xe84b0000;
+static const uint32_t mtlr_12		= 0x7d8803a6;
+static const uint32_t add_12_2_11	= 0x7d825a14;
+static const uint32_t li_0_0		= 0x38000000;
+static const uint32_t lis_0_0		= 0x3c000000;
+static const uint32_t ori_0_0_0		= 0x60000000;
+static const uint32_t cror_15_15_15	= 0x4def7b82;
+static const uint32_t cror_31_31_31	= 0x4ffffb82;
 
 // Write out the PLT.
 
@@ -1121,6 +1231,8 @@ template<int size, bool big_endian>
 class Output_data_glink : public Output_section_data
 {
  public:
+  static const int pltresolve_size = 16*4;
+
   Output_data_glink(Target_powerpc<size, big_endian>*);
 
   // Add an entry
@@ -1156,8 +1268,6 @@ class Output_data_glink : public Output_
   { mapfile->print_output_data(this, _("** glink")); }
 
  private:
-  static const int pltresolve_size = 16*4;
-
   void
   set_final_data_size();
 
@@ -1171,7 +1281,7 @@ class Output_data_glink : public Output_
     Glink_sym_ent(const Symbol* sym,
 		  const elfcpp::Rela<size, big_endian>& reloc,
 		  const Sized_relobj<size, big_endian>* object)
-      : sym_(sym), object_(0), addend_(0)
+      : sym_(sym), addend_(0), object_(0)
     {
       if (size != 32)
 	this->addend_ = reloc.get_r_addend();
@@ -1185,16 +1295,16 @@ class Output_data_glink : public Output_
 	}
     }
 
-    const Symbol* sym_;
-    const Sized_relobj<size, big_endian>* object_;
-    unsigned int addend_;
-
     bool operator==(const Glink_sym_ent& that) const
     {
       return (this->sym_ == that.sym_
 	      && this->object_ == that.object_
 	      && this->addend_ == that.addend_);
     }
+
+    const Symbol* sym_;
+    unsigned int addend_;
+    const Sized_relobj<size, big_endian>* object_;
   };
 
   class Glink_sym_ent_hash
@@ -1314,7 +1424,7 @@ ha(uint32_t a)
 
 template<bool big_endian>
 static inline void
-write_insn(unsigned char *p, uint32_t v)
+write_insn(unsigned char* p, uint32_t v)
 {
   elfcpp::Swap<32, big_endian>::writeval(p, v);
 }
@@ -1329,19 +1439,21 @@ Output_data_glink<size, big_endian>::do_
   const section_size_type oview_size =
     convert_to_section_size_type(this->data_size());
   unsigned char* const oview = of->get_output_view(off, oview_size);
-  unsigned char *p;
+  unsigned char* p;
 
   // The base address of the .plt section.
   uint32_t plt_base = this->targ_->plt_section()->address();
 
   // The address of _GLOBAL_OFFSET_TABLE_.
-  const Output_data_got_powerpc<size, big_endian> *got;
+  const Output_data_got_powerpc<size, big_endian>* got;
   typename elfcpp::Elf_types<size>::Elf_Addr g_o_t;
   got = this->targ_->got_section();
-  g_o_t = got->address() + got->g_o_t();
 
   if (size == 64)
     {
+      const unsigned int toc_base_offset = 0x8000;
+      g_o_t = got->output_section()->address() + toc_base_offset;
+
       // Write out call stubs.
       typename Glink_entries::const_iterator g;
       for (g = this->glink_entries_.begin();
@@ -1423,13 +1535,15 @@ Output_data_glink<size, big_endian>::do_
 	      write_insn<big_endian>(p, lis_0_0 + hi(indx)),		p += 4;
 	      write_insn<big_endian>(p, ori_0_0_0 + l(indx)),		p += 4;
 	    }
-	  uint16_t branch_off = this->pltresolve_ + 8 - (p - oview);
+	  uint32_t branch_off = this->pltresolve_ + 8 - (p - oview);
 	  write_insn<big_endian>(p, b + (branch_off & 0x3fffffc)),	p += 4;
 	  indx++;
 	}
     }
   else
     {
+      g_o_t = got->address() + got->g_o_t();
+
       // Write out call stubs.
       typename Glink_entries::const_iterator g;
       for (g = this->glink_entries_.begin();
@@ -1438,6 +1552,7 @@ Output_data_glink<size, big_endian>::do_
 	{
 	  uint32_t plt_addr = plt_base + g->first.sym_->plt_offset();
 	  uint32_t got_addr;
+	  const uint32_t invalid_address = static_cast<uint32_t>(-1);
 
 	  p = oview + g->second * this->glink_entry_size();
 	  if (parameters->options().output_is_position_independent())
@@ -1447,9 +1562,10 @@ Output_data_glink<size, big_endian>::do_
 	      if (object != NULL)
 		{
 		  unsigned int got2 = object->got2_shndx();
-		  got_addr = (g->first.object_->output_section(got2)->address()
-			      + g->first.object_->output_section_offset(got2)
-			      + g->first.addend_);
+		  got_addr = g->first.object_->get_output_section_offset(got2);
+		  gold_assert(got_addr != invalid_address);
+		  got_addr += (g->first.object_->output_section(got2)->address()
+			       + g->first.addend_);
 		}
 	      else
 		got_addr = g_o_t;
@@ -1481,7 +1597,7 @@ Output_data_glink<size, big_endian>::do_
       // Write out pltresolve branch table.
       p = oview + this->pltresolve_;
       unsigned int the_end = oview_size - this->pltresolve_size;
-      unsigned char *end_p = oview + the_end;
+      unsigned char* end_p = oview + the_end;
       while (p < end_p - 8 * 4)
 	write_insn<big_endian>(p, b + end_p - p), p += 4;
       while (p < end_p)
@@ -1852,8 +1968,10 @@ Target_powerpc<size, big_endian>::Scan::
 
     case elfcpp::R_PPC64_ADDR64:
     case elfcpp::R_POWERPC_ADDR32:
-    case elfcpp::R_POWERPC_ADDR16_HA:
+    case elfcpp::R_POWERPC_ADDR16:
     case elfcpp::R_POWERPC_ADDR16_LO:
+    case elfcpp::R_POWERPC_ADDR16_HI:
+    case elfcpp::R_POWERPC_ADDR16_HA:
       // If building a shared library (or a position-independent
       // executable), we need to create a dynamic relocation for
       // this location.
@@ -1893,8 +2011,8 @@ Target_powerpc<size, big_endian>::Scan::
     case elfcpp::R_POWERPC_GOT16_HI:
     case elfcpp::R_POWERPC_GOT16_HA:
       {
-        // The symbol requires a GOT entry.
-        Output_data_got_powerpc<size, big_endian>* got;
+	// The symbol requires a GOT entry.
+	Output_data_got_powerpc<size, big_endian>* got;
 	unsigned int r_sym;
 
 	got = target->got_section(symtab, layout);
@@ -1985,16 +2103,16 @@ Target_powerpc<size, big_endian>::Scan::
     case elfcpp::R_PPC_LOCAL24PC:
       break;
 
+    case elfcpp::R_PPC64_ADDR64:
+    case elfcpp::R_POWERPC_ADDR32:
     case elfcpp::R_POWERPC_ADDR16:
     case elfcpp::R_POWERPC_ADDR16_LO:
     case elfcpp::R_POWERPC_ADDR16_HI:
     case elfcpp::R_POWERPC_ADDR16_HA:
-    case elfcpp::R_POWERPC_ADDR32:
-    case elfcpp::R_PPC64_ADDR64:
       {
-        // Make a PLT entry if necessary.
-        if (gsym->needs_plt_entry())
-          {
+	// Make a PLT entry if necessary.
+	if (gsym->needs_plt_entry())
+	  {
 	    target->make_plt_entry(layout, gsym, reloc, 0);
 	    // Since this is not a PC-relative relocation, we may be
 	    // taking the address of a function. In that case we need to
@@ -2003,16 +2121,16 @@ Target_powerpc<size, big_endian>::Scan::
 	    if (size == 32
 		&& gsym->is_from_dynobj() && !parameters->options().shared())
 	      gsym->set_needs_dynsym_value();
-          }
-        // Make a dynamic relocation if necessary.
-        if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
-          {
-            if (gsym->may_need_copy_reloc())
-              {
-	        target->copy_reloc(symtab, layout, object,
-	                           data_shndx, output_section, gsym, reloc);
-              }
-            else if ((r_type == elfcpp::R_POWERPC_ADDR32
+	  }
+	// Make a dynamic relocation if necessary.
+	if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+	  {
+	    if (gsym->may_need_copy_reloc())
+	      {
+		target->copy_reloc(symtab, layout, object,
+				   data_shndx, output_section, gsym, reloc);
+	      }
+	    else if ((r_type == elfcpp::R_POWERPC_ADDR32
 		      || r_type == elfcpp::R_PPC64_ADDR64)
 		     && gsym->can_use_relative_reloc(false))
 	      {
@@ -2086,8 +2204,8 @@ Target_powerpc<size, big_endian>::Scan::
     case elfcpp::R_POWERPC_GOT16_HI:
     case elfcpp::R_POWERPC_GOT16_HA:
       {
-        // The symbol requires a GOT entry.
-        Output_data_got_powerpc<size, big_endian>* got;
+	// The symbol requires a GOT entry.
+	Output_data_got_powerpc<size, big_endian>* got;
 
 	got = target->got_section(symtab, layout);
 	if (gsym->final_value_is_known())
@@ -2261,13 +2379,21 @@ Target_powerpc<size, big_endian>::do_fin
   layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
 				  this->rela_dyn_, true, size == 32);
 
+  Output_data_dynamic* odyn = layout->dynamic_data();
   if (size == 32)
     {
       this->got_->finalize_data_size();
-      Output_data_dynamic* odyn = layout->dynamic_data();
       odyn->add_section_plus_offset(elfcpp::DT_PPC_GOT,
 				    this->got_, this->got_->g_o_t());
     }
+  else
+    {
+      this->glink_->finalize_data_size();
+      odyn->add_section_plus_offset(elfcpp::DT_PPC64_GLINK,
+				    this->glink_,
+				    (this->glink_->pltresolve()
+				     + this->glink_->pltresolve_size - 32));
+    }
 
   // Emit any relocs we saved in an attempt to avoid generating COPY
   // relocs.
@@ -2289,14 +2415,14 @@ Target_powerpc<size, big_endian>::Reloca
     const Sized_symbol<size>* gsym,
     const Symbol_value<size>* psymval,
     unsigned char* view,
-    typename elfcpp::Elf_types<size>::Elf_Addr address,
-    section_size_type /* view_size */)
+    Address address,
+    section_size_type view_size)
 {
   const unsigned int toc_base_offset = 0x8000;
   typedef Powerpc_relocate_functions<size, big_endian> Reloc;
   const Powerpc_relobj<size, big_endian>* const object
     = static_cast<const Powerpc_relobj<size, big_endian>*>(relinfo->object);
-  elfcpp::Elf_Xword value;
+  Address value;
 
   if (r_type == elfcpp::R_POWERPC_GOT16
       || r_type == elfcpp::R_POWERPC_GOT16_LO
@@ -2320,7 +2446,8 @@ Target_powerpc<size, big_endian>::Reloca
     }
   else if (r_type == elfcpp::R_PPC64_TOC)
     {
-      value = target->got_section()->address() + toc_base_offset;
+      value = (target->got_section()->output_section()->address()
+	       + toc_base_offset);
     }
   else if (gsym != NULL
 	   && (r_type == elfcpp::R_POWERPC_REL24
@@ -2332,13 +2459,54 @@ Target_powerpc<size, big_endian>::Reloca
       glink = target->glink_section();
       unsigned int glink_index = glink->find_entry(gsym, rela, object);
       value = glink->address() + glink_index * glink->glink_entry_size();
+      if (size == 64)
+	{
+	  typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+	  Valtype* wv = reinterpret_cast<Valtype*>(view);
+	  bool can_plt_call = false;
+	  if (rela.get_r_offset() + 8 <= view_size)
+	    {
+	      Valtype insn2 = elfcpp::Swap<32, big_endian>::readval(wv + 1);
+	      if (insn2 == nop
+		  || insn2 == cror_15_15_15 || insn2 == cror_31_31_31)
+		{
+		  elfcpp::Swap<32, big_endian>::writeval(wv + 1, ld_2_1 + 40);
+		  can_plt_call = true;
+		}
+	    }
+	  if (!can_plt_call)
+	    gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+				   _("call lacks nop, can't restore toc"));
+	}
     }
   else
     {
-      elfcpp::Elf_Xword addend = 0;
+      typename elfcpp::Elf_types<size>::Elf_Swxword addend = 0;
       if (r_type != elfcpp::R_PPC_PLTREL24)
 	addend = rela.get_r_addend();
       value = psymval->value(object, addend);
+      if (size == 64 && this->is_branch_reloc(r_type))
+	{
+	  Powerpc_relobj<size, big_endian>* symobj = const_cast
+	    <Powerpc_relobj<size, big_endian>*>(object);
+	  if (gsym != NULL)
+	    symobj = static_cast
+	      <Powerpc_relobj<size, big_endian>*>(gsym->object());
+	  unsigned int shndx = symobj->opd_shndx();
+	  Address opd_addr = symobj->get_output_section_offset(shndx);
+	  gold_assert(opd_addr != invalid_address);
+	  opd_addr += symobj->output_section(shndx)->address();
+	  if (value >= opd_addr
+	      && value < opd_addr + symobj->section_size(shndx))
+	    {
+	      Address sec_off;
+	      symobj->get_opd_ent(value - opd_addr, &shndx, &sec_off);
+	      Address sec_addr = symobj->get_output_section_offset(shndx);
+	      gold_assert(sec_addr != invalid_address);
+	      sec_addr += symobj->output_section(shndx)->address();
+	      value = sec_addr + sec_off;
+	    }
+	}
     }
 
   switch (r_type)
@@ -2350,7 +2518,8 @@ Target_powerpc<size, big_endian>::Reloca
     case elfcpp::R_PPC64_TOC16_DS:
     case elfcpp::R_PPC64_TOC16_LO_DS:
       // Subtract the TOC base address.
-      value -= target->got_section()->address() + toc_base_offset;
+      value -= (target->got_section()->output_section()->address()
+		+ toc_base_offset);
       break;
 
     case elfcpp::R_POWERPC_SECTOFF:
@@ -2487,14 +2656,14 @@ Target_powerpc<size, big_endian>::Reloca
     const Sized_symbol<size>* gsym,
     const Symbol_value<size>* psymval,
     unsigned char* view,
-    typename elfcpp::Elf_types<size>::Elf_Addr address,
+    Address address,
     section_size_type)
 {
   Output_segment* tls_segment = relinfo->layout->tls_segment();
   const Sized_relobj_file<size, big_endian>* object = relinfo->object;
 
-  const elfcpp::Elf_Xword addend = rela.get_r_addend();
-  typename elfcpp::Elf_types<size>::Elf_Addr value = psymval->value(object, 0);
+  const Address addend = rela.get_r_addend();
+  Address value = psymval->value(object, 0);
 
   const bool is_final =
     (gsym == NULL
@@ -2519,7 +2688,7 @@ Target_powerpc<size, big_endian>::reloca
     Output_section* output_section,
     bool needs_special_offset_handling,
     unsigned char* view,
-    typename elfcpp::Elf_types<size>::Elf_Addr address,
+    Address address,
     section_size_type view_size,
     const Reloc_symbol_changes* reloc_symbol_changes)
 {
@@ -2622,29 +2791,30 @@ Target_powerpc<size, big_endian>::reloca
     off_t offset_in_output_section,
     const Relocatable_relocs* rr,
     unsigned char*,
-    typename elfcpp::Elf_types<size>::Elf_Addr,
+    Address,
     section_size_type,
     unsigned char* reloc_view,
     section_size_type reloc_view_size)
 {
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
   typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
     Reltype;
   typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc_write
     Reltype_write;
   const int reloc_size
     = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
-  const Address invalid_address = static_cast<Address>(0) - 1;
 
   Powerpc_relobj<size, big_endian>* const object
     = static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
   const unsigned int local_count = object->local_symbol_count();
   unsigned int got2_shndx = object->got2_shndx();
-  typename elfcpp::Elf_types<size>::Elf_Swxword got2_addend = 0;
+  Address got2_addend = 0;
   if (got2_shndx != 0)
-    got2_addend = object->get_output_section_offset(got2_shndx);
+    {
+      got2_addend = object->get_output_section_offset(got2_shndx);
+      gold_assert(got2_addend != invalid_address);
+    }
 
   unsigned char* pwrite = reloc_view;
 
@@ -2716,13 +2886,13 @@ Target_powerpc<size, big_endian>::reloca
 	new_offset = offset + offset_in_output_section;
       else
 	{
-          section_offset_type sot_offset =
-              convert_types<section_offset_type, Address>(offset);
+	  section_offset_type sot_offset =
+	    convert_types<section_offset_type, Address>(offset);
 	  section_offset_type new_sot_offset =
-              output_section->output_offset(object, relinfo->data_shndx,
-                                            sot_offset);
+	    output_section->output_offset(object, relinfo->data_shndx,
+					  sot_offset);
 	  gold_assert(new_sot_offset != -1);
-          new_offset = new_sot_offset;
+	  new_offset = new_sot_offset;
 	}
 
       reloc_write.put_r_offset(new_offset);
Index: gold/symtab.h
===================================================================
RCS file: /cvs/src/src/gold/symtab.h,v
retrieving revision 1.127
diff -u -p -r1.127 symtab.h
--- gold/symtab.h	31 Oct 2011 21:36:54 -0000	1.127
+++ gold/symtab.h	16 Aug 2012 12:03:01 -0000
@@ -62,7 +62,7 @@ class Garbage_collection;
 class Icf;
 
 // The base class of an entry in the symbol table.  The symbol table
-// can have a lot of entries, so we don't want this class to big.
+// can have a lot of entries, so we don't want this class too big.
 // Size dependent fields can be found in the template class
 // Sized_symbol.  Targets may support their own derived classes.
 


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-08-18 11:13 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-15  4:04 [GOLD] advice on powerpc64 .opd handling Alan Modra
2012-08-16  9:24 ` Ian Lance Taylor
2012-08-16 13:53   ` Alan Modra
2012-08-17  5:28     ` Ian Lance Taylor
2012-08-17  8:11       ` Alan Modra
2012-08-17 14:36         ` Ian Lance Taylor
2012-08-18  1:45           ` Alan Modra
2012-08-18 11:13             ` Ian Lance Taylor
2012-08-18 12:49               ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).