This is the mail archive of the binutils-cvs@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]

[binutils-gdb] Refactor gold to enable support for MIPS-64 relocation format.


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4d625b70fc3fb7facc7159feb8d49b78ac6641f9

commit 4d625b70fc3fb7facc7159feb8d49b78ac6641f9
Author: Cary Coutant <ccoutant@gmail.com>
Date:   Fri Dec 11 07:43:59 2015 -0800

    Refactor gold to enable support for MIPS-64 relocation format.
    
    For MIPS-64, the r_info field in the relocation format is
    replaced by several individual fields, including r_sym and
    r_type. To enable support for this format, I've refactored
    target-independent code to remove almost all uses of the r_info
    field. (I've left alone a couple of routines used only for
    incremental linking, which I can update if/when the MIPS target
    adds support for incremental linking.)
    
    For routines that are already templated on a Classify_reloc class
    (namely, gc_process_relocs, relocate_section, and
    relocate_relocs), I've extended the Classify_reloc interface to
    include sh_type (which no longer needs to be a separate template
    parameter) as well as get_r_sym() and get_r_type() methods for
    extracting the r_sym and r_type fields. For
    scan_relocatable_relocs, I've extended the
    Default_scan_relocatable_relocs class by converting it to a class
    template with Classify_reloc as a template parameter. For the
    remaining routines that need to access r_sym, I've added a
    virtual Target::get_r_sym() method with an override for the MIPS
    target.
    
    In elfcpp, I've added Mips64_rel, etc., accessor classes and
    corresponding internal data structures. The MIPS target uses
    these new classes within its own Mips_classify_reloc class.
    The Mips64_ accessor classes also expose the r_ssym, r_type2,
    and r_type3 fields from the relocation.
    
    These changes should be functionally the same for all but the
    MIPS target.
    
    elfcpp/
    	* elfcpp.h (Mips64_rel, Mips64_rel_write): New classes.
    	(Mips64_rela, Mips64_rela_write): New classes.
    	* elfcpp_internal.h (Mips64_rel_data, Mips64_rela_data): New structs.
    
    gold/
    	* gc.h (get_embedded_addend_size): Remove sh_type parameter.
    	(gc_process_relocs): Remove sh_type template parameter.
    	Use Classify_reloc to access r_sym, r_type, and r_addend fields.
    	* object.h (Sized_relobj_file::split_stack_adjust): Add target
    	parameter.
    	(Sized_relobj_file::split_stack_adjust_reltype): Likewise.
    	* reloc-types.h (Reloc_types::copy_reloc_addend): (SHT_REL and SHT_RELA
    	specializations) Remove.
    	* reloc.cc (Emit_relocs_strategy): Rename and move to target-reloc.h.
    	(Sized_relobj_file::emit_relocs_scan): Call Target::emit_relocs_scan().
    	(Sized_relobj_file::emit_relocs_scan_reltype): Remove.
    	(Sized_relobj_file::split_stack_adjust): Add target parameter.
    	Adjust all callers.
    	(Sized_relobj_file::split_stack_adjust_reltype): Likewise. Call
    	Target::get_r_sym() to get r_sym field from relocations.
    	(Track_relocs::next_symndx): Call Target::get_r_sym().
    	* target-reloc.h (scan_relocs): Remove sh_type template parameter;
    	add Classify_reloc template parameter.  Use for accessing r_sym and
    	r_type.
    	(relocate_section): Likewise.
    	(Default_classify_reloc): New class (renamed and moved from reloc.cc).
    	(Default_scan_relocatable_relocs): Remove sh_type template parameter.
    	(Default_scan_relocatable_relocs::Reltype): New typedef.
    	(Default_scan_relocatable_relocs::reloc_size): New const.
    	(Default_scan_relocatable_relocs::sh_type): New const.
    	(Default_scan_relocatable_relocs::get_r_sym): New method.
    	(Default_scan_relocatable_relocs::get_r_type): New method.
    	(Default_emit_relocs_strategy): New class.
    	(scan_relocatable_relocs): Replace sh_type template parameter with
    	Scan_relocatable_relocs class.  Use it to access r_sym and r_type
    	fields.
    	(relocate_relocs): Replace sh_type template parameter with
    	Classify_reloc class.  Use it to access r_sym and r_type fields.
    	* target.h (Target::is_call_to_non_split): Replace r_type parameter
    	with pointer to relocation. Adjust all callers.
    	(Target::do_is_call_to_non_split): Likewise.
    	(Target::emit_relocs_scan): New virtual method.
    	(Sized_target::get_r_sym): New virtual method.
    	* target.cc (Target::do_is_call_to_non_split): Replace r_type parameter
    	with pointer to relocation.
    
    	* aarch64.cc (Target_aarch64::emit_relocs_scan): New method.
    	(Target_aarch64::Relocatable_size_for_reloc): Remove.
    	(Target_aarch64::gc_process_relocs): Use Default_classify_reloc.
    	(Target_aarch64::scan_relocs): Likewise.
    	(Target_aarch64::relocate_section): Likewise.
    	(Target_aarch64::Relocatable_size_for_reloc::get_size_for_reloc):
    	Remove.
    	(Target_aarch64::scan_relocatable_relocs): Use Default_classify_reloc.
    	(Target_aarch64::relocate_relocs): Use Default_classify_reloc.
    	* arm.cc (Target_arm::Arm_scan_relocatable_relocs): Remove sh_type
    	template parameter.
    	(Target_arm::emit_relocs_scan): New method.
    	(Target_arm::Relocatable_size_for_reloc): Replace with...
    	(Target_arm::Classify_reloc): ...this.
    	(Target_arm::gc_process_relocs): Use Classify_reloc.
    	(Target_arm::scan_relocs): Likewise.
    	(Target_arm::relocate_section): Likewise.
    	(Target_arm::scan_relocatable_relocs): Likewise.
    	(Target_arm::relocate_relocs): Likewise.
    	* i386.cc (Target_i386::emit_relocs_scan): New method.
    	(Target_i386::Relocatable_size_for_reloc): Replace with...
    	(Target_i386::Classify_reloc): ...this.
    	(Target_i386::gc_process_relocs): Use Classify_reloc.
    	(Target_i386::scan_relocs): Likewise.
    	(Target_i386::relocate_section): Likewise.
    	(Target_i386::scan_relocatable_relocs): Likewise.
    	(Target_i386::relocate_relocs): Likewise.
    	* mips.cc (Mips_scan_relocatable_relocs): Remove sh_type template
    	parameter.
    	(Mips_reloc_types): New class template.
    	(Mips_classify_reloc): New class template.
    	(Target_mips::Reltype): New typedef.
    	(Target_mips::Relatype): New typedef.
    	(Target_mips::emit_relocs_scan): New method.
    	(Target_mips::get_r_sym): New method.
    	(Target_mips::Relocatable_size_for_reloc): Replace with
    	Mips_classify_reloc.
    	(Target_mips::copy_reloc): Use Mips_classify_reloc.
    	(Target_mips::gc_process_relocs): Likewise.
    	(Target_mips::scan_relocs): Likewise.
    	(Target_mips::relocate_section): Likewise.
    	(Target_mips::scan_relocatable_relocs): Likewise.
    	(Target_mips::relocate_relocs): Likewise.
    	(mips_get_size_for_reloc): New function, factored out from
    	Relocatable_size_for_reloc::get_size_for_reloc.
    	(Target_mips::Scan::local): Use Mips_classify_reloc.
    	(Target_mips::Scan::global): Likewise.
    	(Target_mips::Relocate::relocate): Likewise.
    	* powerpc.cc (Target_powerpc::emit_relocs_scan): New method.
    	(Target_powerpc::Relocatable_size_for_reloc): Remove.
    	(Target_powerpc::gc_process_relocs): Use Default_classify_reloc.
    	(Target_powerpc::scan_relocs): Likewise.
    	(Target_powerpc::relocate_section): Likewise.
    	(Powerpc_scan_relocatable_reloc): Convert to class template.
    	(Powerpc_scan_relocatable_reloc::Reltype): New typedef.
    	(Powerpc_scan_relocatable_reloc::reloc_size): New const.
    	(Powerpc_scan_relocatable_reloc::sh_type): New const.
    	(Powerpc_scan_relocatable_reloc::get_r_sym): New method.
    	(Powerpc_scan_relocatable_reloc::get_r_type): New method.
    	(Target_powerpc::scan_relocatable_relocs): Use
    	Powerpc_scan_relocatable_reloc.
    	(Target_powerpc::relocate_relocs): Use Default_classify_reloc.
    	* s390.cc (Target_s390::emit_relocs_scan): New method.
    	(Target_s390::Relocatable_size_for_reloc): Remove.
    	(Target_s390::gc_process_relocs): Use Default_classify_reloc.
    	(Target_s390::scan_relocs): Likewise.
    	(Target_s390::relocate_section): Likewise.
    	(Target_s390::Relocatable_size_for_reloc::get_size_for_reloc):
    	Remove.
    	(Target_s390::scan_relocatable_relocs): Use Default_classify_reloc.
    	(Target_s390::relocate_relocs): Use Default_classify_reloc.
    	* sparc.cc (Target_sparc::emit_relocs_scan): New method.
    	(Target_sparc::Relocatable_size_for_reloc): Remove.
    	(Target_sparc::gc_process_relocs): Use Default_classify_reloc.
    	(Target_sparc::scan_relocs): Likewise.
    	(Target_sparc::relocate_section): Likewise.
    	(Target_sparc::Relocatable_size_for_reloc::get_size_for_reloc):
    	Remove.
    	(Target_sparc::scan_relocatable_relocs): Use Default_classify_reloc.
    	(Target_sparc::relocate_relocs): Use Default_classify_reloc.
    	* tilegx.cc (Target_tilegx::emit_relocs_scan): New method.
    	(Target_tilegx::Relocatable_size_for_reloc): Remove.
    	(Target_tilegx::gc_process_relocs): Use Default_classify_reloc.
    	(Target_tilegx::scan_relocs): Likewise.
    	(Target_tilegx::relocate_section): Likewise.
    	(Target_tilegx::Relocatable_size_for_reloc::get_size_for_reloc):
    	Remove.
    	(Target_tilegx::scan_relocatable_relocs): Use Default_classify_reloc.
    	(Target_tilegx::relocate_relocs): Use Default_classify_reloc.
    	* x86_64.cc (Target_x86_64::emit_relocs_scan): New method.
    	(Target_x86_64::Relocatable_size_for_reloc): Remove.
    	(Target_x86_64::gc_process_relocs): Use Default_classify_reloc.
    	(Target_x86_64::scan_relocs): Likewise.
    	(Target_x86_64::relocate_section): Likewise.
    	(Target_x86_64::Relocatable_size_for_reloc::get_size_for_reloc):
    	Remove.
    	(Target_x86_64::scan_relocatable_relocs): Use Default_classify_reloc.
    	(Target_x86_64::relocate_relocs): Use Default_classify_reloc.
    
    	* testsuite/testfile.cc (Target_test::emit_relocs_scan): New method.

Diff:
---
 elfcpp/ChangeLog           |   6 +
 elfcpp/elfcpp.h            | 166 +++++++++++++++
 elfcpp/elfcpp_internal.h   |  23 +++
 gold/ChangeLog             | 146 +++++++++++++
 gold/aarch64.cc            | 123 +++++++----
 gold/arm.cc                |  93 +++++++--
 gold/gc.h                  |  31 ++-
 gold/i386.cc               |  92 +++++++--
 gold/mips.cc               | 504 ++++++++++++++++++++++++++++++++++-----------
 gold/object.h              |   6 +-
 gold/powerpc.cc            | 107 ++++++++--
 gold/reloc-types.h         |   8 -
 gold/reloc.cc              | 112 +++-------
 gold/s390.cc               | 195 +++++++-----------
 gold/sparc.cc              | 109 ++++++----
 gold/target-reloc.h        | 216 ++++++++++++++-----
 gold/target.cc             |   2 +-
 gold/target.h              |  37 +++-
 gold/testsuite/testfile.cc |   8 +
 gold/tilegx.cc             | 128 ++++++++----
 gold/x86_64.cc             | 169 +++++++--------
 21 files changed, 1591 insertions(+), 690 deletions(-)

diff --git a/elfcpp/ChangeLog b/elfcpp/ChangeLog
index e48be00..198eb92 100644
--- a/elfcpp/ChangeLog
+++ b/elfcpp/ChangeLog
@@ -1,3 +1,9 @@
+2016-01-11  Cary Coutant  <ccoutant@gmail.com>
+
+	* elfcpp.h (Mips64_rel, Mips64_rel_write): New classes.
+	(Mips64_rela, Mips64_rela_write): New classes.
+	* elfcpp_internal.h (Mips64_rel_data, Mips64_rela_data): New structs.
+
 2016-01-01  Alan Modra  <amodra@gmail.com>
 
 	Update year range in copyright notice of all files.
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index e0eae42..3d7039a 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -1661,6 +1661,172 @@ class Rela_write
   internal::Rela_data<size>* p_;
 };
 
+// MIPS-64 has a non-standard relocation layout.
+
+template<bool big_endian>
+class Mips64_rel
+{
+ public:
+  Mips64_rel(const unsigned char* p)
+    : p_(reinterpret_cast<const internal::Mips64_rel_data*>(p))
+  { }
+
+  template<typename File>
+  Mips64_rel(File* file, typename File::Location loc)
+    : p_(reinterpret_cast<const internal::Mips64_rel_data*>(
+	   file->view(loc.file_offset, loc.data_size).data()))
+  { }
+
+  typename Elf_types<64>::Elf_Addr
+  get_r_offset() const
+  { return Convert<64, big_endian>::convert_host(this->p_->r_offset); }
+
+  Elf_Word
+  get_r_sym() const
+  { return Convert<32, big_endian>::convert_host(this->p_->r_sym); }
+
+  unsigned char
+  get_r_ssym() const
+  { return this->p_->r_ssym; }
+
+  unsigned char
+  get_r_type() const
+  { return this->p_->r_type; }
+
+  unsigned char
+  get_r_type2() const
+  { return this->p_->r_type2; }
+
+  unsigned char
+  get_r_type3() const
+  { return this->p_->r_type3; }
+
+ private:
+  const internal::Mips64_rel_data* p_;
+};
+
+template<bool big_endian>
+class Mips64_rel_write
+{
+ public:
+  Mips64_rel_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Mips64_rel_data*>(p))
+  { }
+
+  void
+  put_r_offset(typename Elf_types<64>::Elf_Addr v)
+  { this->p_->r_offset = Convert<64, big_endian>::convert_host(v); }
+
+  void
+  put_r_sym(Elf_Word v)
+  { this->p_->r_sym = Convert<32, big_endian>::convert_host(v); }
+
+  void
+  put_r_ssym(unsigned char v)
+  { this->p_->r_ssym = v; }
+
+  void
+  put_r_type(unsigned char v)
+  { this->p_->r_type = v; }
+
+  void
+  put_r_type2(unsigned char v)
+  { this->p_->r_type2 = v; }
+
+  void
+  put_r_type3(unsigned char v)
+  { this->p_->r_type3 = v; }
+
+ private:
+  internal::Mips64_rel_data* p_;
+};
+
+template<bool big_endian>
+class Mips64_rela
+{
+ public:
+  Mips64_rela(const unsigned char* p)
+    : p_(reinterpret_cast<const internal::Mips64_rela_data*>(p))
+  { }
+
+  template<typename File>
+  Mips64_rela(File* file, typename File::Location loc)
+    : p_(reinterpret_cast<const internal::Mips64_rela_data*>(
+	   file->view(loc.file_offset, loc.data_size).data()))
+  { }
+
+  typename Elf_types<64>::Elf_Addr
+  get_r_offset() const
+  { return Convert<64, big_endian>::convert_host(this->p_->r_offset); }
+
+  Elf_Word
+  get_r_sym() const
+  { return Convert<32, big_endian>::convert_host(this->p_->r_sym); }
+
+  unsigned char
+  get_r_ssym() const
+  { return this->p_->r_ssym; }
+
+  unsigned char
+  get_r_type() const
+  { return this->p_->r_type; }
+
+  unsigned char
+  get_r_type2() const
+  { return this->p_->r_type2; }
+
+  unsigned char
+  get_r_type3() const
+  { return this->p_->r_type3; }
+
+  typename Elf_types<64>::Elf_Swxword
+  get_r_addend() const
+  { return Convert<64, big_endian>::convert_host(this->p_->r_addend); }
+
+ private:
+  const internal::Mips64_rela_data* p_;
+};
+
+template<bool big_endian>
+class Mips64_rela_write
+{
+ public:
+  Mips64_rela_write(unsigned char* p)
+    : p_(reinterpret_cast<internal::Mips64_rela_data*>(p))
+  { }
+
+  void
+  put_r_offset(typename Elf_types<64>::Elf_Addr v)
+  { this->p_->r_offset = Convert<64, big_endian>::convert_host(v); }
+
+  void
+  put_r_sym(Elf_Word v)
+  { this->p_->r_sym = Convert<32, big_endian>::convert_host(v); }
+
+  void
+  put_r_ssym(unsigned char v)
+  { this->p_->r_ssym = v; }
+
+  void
+  put_r_type(unsigned char v)
+  { this->p_->r_type = v; }
+
+  void
+  put_r_type2(unsigned char v)
+  { this->p_->r_type2 = v; }
+
+  void
+  put_r_type3(unsigned char v)
+  { this->p_->r_type3 = v; }
+
+  void
+  put_r_addend(typename Elf_types<64>::Elf_Swxword v)
+  { this->p_->r_addend = Convert<64, big_endian>::convert_host(v); }
+
+ private:
+  internal::Mips64_rela_data* p_;
+};
+
 // Accessor classes for entries in the ELF SHT_DYNAMIC section aka
 // PT_DYNAMIC segment.
 
diff --git a/elfcpp/elfcpp_internal.h b/elfcpp/elfcpp_internal.h
index 7080a2d..edca55f 100644
--- a/elfcpp/elfcpp_internal.h
+++ b/elfcpp/elfcpp_internal.h
@@ -180,6 +180,29 @@ struct Rela_data
   typename Elf_types<size>::Elf_Swxword r_addend;
 };
 
+// MIPS-64 has a non-standard layout for relocations.
+
+struct Mips64_rel_data
+{
+  typename Elf_types<64>::Elf_Addr r_offset;
+  Elf_Word r_sym;
+  unsigned char r_ssym;
+  unsigned char r_type3;
+  unsigned char r_type2;
+  unsigned char r_type;
+};
+
+struct Mips64_rela_data
+{
+  typename Elf_types<64>::Elf_Addr r_offset;
+  Elf_Word r_sym;
+  unsigned char r_ssym;
+  unsigned char r_type3;
+  unsigned char r_type2;
+  unsigned char r_type;
+  typename Elf_types<64>::Elf_Swxword r_addend;
+};
+
 // An entry in the ELF SHT_DYNAMIC section aka PT_DYNAMIC segment.
 
 template<int size>
diff --git a/gold/ChangeLog b/gold/ChangeLog
index e48be00..42c428b 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,149 @@
+2016-01-11  Cary Coutant  <ccoutant@gmail.com>
+
+	Refactor gold to enable support for MIPS-64 relocation format.
+
+	* gc.h (get_embedded_addend_size): Remove sh_type parameter.
+	(gc_process_relocs): Remove sh_type template parameter.
+	Use Classify_reloc to access r_sym, r_type, and r_addend fields.
+	* object.h (Sized_relobj_file::split_stack_adjust): Add target
+	parameter.
+	(Sized_relobj_file::split_stack_adjust_reltype): Likewise.
+	* reloc-types.h (Reloc_types::copy_reloc_addend): (SHT_REL and SHT_RELA
+	specializations) Remove.
+	* reloc.cc (Emit_relocs_strategy): Rename and move to target-reloc.h.
+	(Sized_relobj_file::emit_relocs_scan): Call Target::emit_relocs_scan().
+	(Sized_relobj_file::emit_relocs_scan_reltype): Remove.
+	(Sized_relobj_file::split_stack_adjust): Add target parameter.
+	Adjust all callers.
+	(Sized_relobj_file::split_stack_adjust_reltype): Likewise. Call
+	Target::get_r_sym() to get r_sym field from relocations.
+	(Track_relocs::next_symndx): Call Target::get_r_sym().
+	* target-reloc.h (scan_relocs): Remove sh_type template parameter;
+	add Classify_reloc template parameter.  Use for accessing r_sym and
+	r_type.
+	(relocate_section): Likewise.
+	(Default_classify_reloc): New class (renamed and moved from reloc.cc).
+	(Default_scan_relocatable_relocs): Remove sh_type template parameter.
+	(Default_scan_relocatable_relocs::Reltype): New typedef.
+	(Default_scan_relocatable_relocs::reloc_size): New const.
+	(Default_scan_relocatable_relocs::sh_type): New const.
+	(Default_scan_relocatable_relocs::get_r_sym): New method.
+	(Default_scan_relocatable_relocs::get_r_type): New method.
+	(Default_emit_relocs_strategy): New class.
+	(scan_relocatable_relocs): Replace sh_type template parameter with
+	Scan_relocatable_relocs class.  Use it to access r_sym and r_type
+	fields.
+	(relocate_relocs): Replace sh_type template parameter with
+	Classify_reloc class.  Use it to access r_sym and r_type fields.
+	* target.h (Target::is_call_to_non_split): Replace r_type parameter
+	with pointer to relocation. Adjust all callers.
+	(Target::do_is_call_to_non_split): Likewise.
+	(Target::emit_relocs_scan): New virtual method.
+	(Sized_target::get_r_sym): New virtual method.
+	* target.cc (Target::do_is_call_to_non_split): Replace r_type parameter
+	with pointer to relocation.
+
+	* aarch64.cc (Target_aarch64::emit_relocs_scan): New method.
+	(Target_aarch64::Relocatable_size_for_reloc): Remove.
+	(Target_aarch64::gc_process_relocs): Use Default_classify_reloc.
+	(Target_aarch64::scan_relocs): Likewise.
+	(Target_aarch64::relocate_section): Likewise.
+	(Target_aarch64::Relocatable_size_for_reloc::get_size_for_reloc):
+	Remove.
+	(Target_aarch64::scan_relocatable_relocs): Use Default_classify_reloc.
+	(Target_aarch64::relocate_relocs): Use Default_classify_reloc.
+	* arm.cc (Target_arm::Arm_scan_relocatable_relocs): Remove sh_type
+	template parameter.
+	(Target_arm::emit_relocs_scan): New method.
+	(Target_arm::Relocatable_size_for_reloc): Replace with...
+	(Target_arm::Classify_reloc): ...this.
+	(Target_arm::gc_process_relocs): Use Classify_reloc.
+	(Target_arm::scan_relocs): Likewise.
+	(Target_arm::relocate_section): Likewise.
+	(Target_arm::scan_relocatable_relocs): Likewise.
+	(Target_arm::relocate_relocs): Likewise.
+	* i386.cc (Target_i386::emit_relocs_scan): New method.
+	(Target_i386::Relocatable_size_for_reloc): Replace with...
+	(Target_i386::Classify_reloc): ...this.
+	(Target_i386::gc_process_relocs): Use Classify_reloc.
+	(Target_i386::scan_relocs): Likewise.
+	(Target_i386::relocate_section): Likewise.
+	(Target_i386::scan_relocatable_relocs): Likewise.
+	(Target_i386::relocate_relocs): Likewise.
+	* mips.cc (Mips_scan_relocatable_relocs): Remove sh_type template
+	parameter.
+	(Mips_reloc_types): New class template.
+	(Mips_classify_reloc): New class template.
+	(Target_mips::Reltype): New typedef.
+	(Target_mips::Relatype): New typedef.
+	(Target_mips::emit_relocs_scan): New method.
+	(Target_mips::get_r_sym): New method.
+	(Target_mips::Relocatable_size_for_reloc): Replace with
+	Mips_classify_reloc.
+	(Target_mips::copy_reloc): Use Mips_classify_reloc.
+	(Target_mips::gc_process_relocs): Likewise.
+	(Target_mips::scan_relocs): Likewise.
+	(Target_mips::relocate_section): Likewise.
+	(Target_mips::scan_relocatable_relocs): Likewise.
+	(Target_mips::relocate_relocs): Likewise.
+	(mips_get_size_for_reloc): New function, factored out from
+	Relocatable_size_for_reloc::get_size_for_reloc.
+	(Target_mips::Scan::local): Use Mips_classify_reloc.
+	(Target_mips::Scan::global): Likewise.
+	(Target_mips::Relocate::relocate): Likewise.
+	* powerpc.cc (Target_powerpc::emit_relocs_scan): New method.
+	(Target_powerpc::Relocatable_size_for_reloc): Remove.
+	(Target_powerpc::gc_process_relocs): Use Default_classify_reloc.
+	(Target_powerpc::scan_relocs): Likewise.
+	(Target_powerpc::relocate_section): Likewise.
+	(Powerpc_scan_relocatable_reloc): Convert to class template.
+	(Powerpc_scan_relocatable_reloc::Reltype): New typedef.
+	(Powerpc_scan_relocatable_reloc::reloc_size): New const.
+	(Powerpc_scan_relocatable_reloc::sh_type): New const.
+	(Powerpc_scan_relocatable_reloc::get_r_sym): New method.
+	(Powerpc_scan_relocatable_reloc::get_r_type): New method.
+	(Target_powerpc::scan_relocatable_relocs): Use
+	Powerpc_scan_relocatable_reloc.
+	(Target_powerpc::relocate_relocs): Use Default_classify_reloc.
+	* s390.cc (Target_s390::emit_relocs_scan): New method.
+	(Target_s390::Relocatable_size_for_reloc): Remove.
+	(Target_s390::gc_process_relocs): Use Default_classify_reloc.
+	(Target_s390::scan_relocs): Likewise.
+	(Target_s390::relocate_section): Likewise.
+	(Target_s390::Relocatable_size_for_reloc::get_size_for_reloc):
+	Remove.
+	(Target_s390::scan_relocatable_relocs): Use Default_classify_reloc.
+	(Target_s390::relocate_relocs): Use Default_classify_reloc.
+	* sparc.cc (Target_sparc::emit_relocs_scan): New method.
+	(Target_sparc::Relocatable_size_for_reloc): Remove.
+	(Target_sparc::gc_process_relocs): Use Default_classify_reloc.
+	(Target_sparc::scan_relocs): Likewise.
+	(Target_sparc::relocate_section): Likewise.
+	(Target_sparc::Relocatable_size_for_reloc::get_size_for_reloc):
+	Remove.
+	(Target_sparc::scan_relocatable_relocs): Use Default_classify_reloc.
+	(Target_sparc::relocate_relocs): Use Default_classify_reloc.
+	* tilegx.cc (Target_tilegx::emit_relocs_scan): New method.
+	(Target_tilegx::Relocatable_size_for_reloc): Remove.
+	(Target_tilegx::gc_process_relocs): Use Default_classify_reloc.
+	(Target_tilegx::scan_relocs): Likewise.
+	(Target_tilegx::relocate_section): Likewise.
+	(Target_tilegx::Relocatable_size_for_reloc::get_size_for_reloc):
+	Remove.
+	(Target_tilegx::scan_relocatable_relocs): Use Default_classify_reloc.
+	(Target_tilegx::relocate_relocs): Use Default_classify_reloc.
+	* x86_64.cc (Target_x86_64::emit_relocs_scan): New method.
+	(Target_x86_64::Relocatable_size_for_reloc): Remove.
+	(Target_x86_64::gc_process_relocs): Use Default_classify_reloc.
+	(Target_x86_64::scan_relocs): Likewise.
+	(Target_x86_64::relocate_section): Likewise.
+	(Target_x86_64::Relocatable_size_for_reloc::get_size_for_reloc):
+	Remove.
+	(Target_x86_64::scan_relocatable_relocs): Use Default_classify_reloc.
+	(Target_x86_64::relocate_relocs): Use Default_classify_reloc.
+
+	* testsuite/testfile.cc (Target_test::emit_relocs_scan): New method.
+
 2016-01-01  Alan Modra  <amodra@gmail.com>
 
 	Update year range in copyright notice of all files.
diff --git a/gold/aarch64.cc b/gold/aarch64.cc
index 715936b..20f2f4f 100644
--- a/gold/aarch64.cc
+++ b/gold/aarch64.cc
@@ -2869,6 +2869,21 @@ class Target_aarch64 : public Sized_target<size, big_endian>
 			  const unsigned char* plocal_symbols,
 			  Relocatable_relocs*);
 
+  // Scan the relocs for --emit-relocs.
+  void
+  emit_relocs_scan(Symbol_table* symtab,
+		   Layout* layout,
+		   Sized_relobj_file<size, big_endian>* object,
+		   unsigned int data_shndx,
+		   unsigned int sh_type,
+		   const unsigned char* prelocs,
+		   size_t reloc_count,
+		   Output_section* output_section,
+		   bool needs_special_offset_handling,
+		   size_t local_symbol_count,
+		   const unsigned char* plocal_syms,
+		   Relocatable_relocs* rr);
+
   // Relocate a section during a relocatable link.
   void
   relocate_relocs(
@@ -3224,15 +3239,6 @@ class Target_aarch64 : public Sized_target<size, big_endian>
 
   };  // End of class Relocate
 
-  // A class which returns the size required for a relocation type,
-  // used while scanning relocs during a relocatable link.
-  class Relocatable_size_for_reloc
-  {
-   public:
-    unsigned int
-    get_size_for_reloc(unsigned int, Relobj*);
-  };
-
   // Adjust TLS relocation type based on the options and whether this
   // is a local symbol.
   static tls::Tls_optimization
@@ -6630,17 +6636,16 @@ Target_aarch64<size, big_endian>::gc_process_relocs(
     size_t local_symbol_count,
     const unsigned char* plocal_symbols)
 {
+  typedef Target_aarch64<size, big_endian> Aarch64;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+
   if (sh_type == elfcpp::SHT_REL)
     {
       return;
     }
 
-  gold::gc_process_relocs<
-    size, big_endian,
-    Target_aarch64<size, big_endian>,
-    elfcpp::SHT_RELA,
-    typename Target_aarch64<size, big_endian>::Scan,
-    typename Target_aarch64<size, big_endian>::Relocatable_size_for_reloc>(
+  gold::gc_process_relocs<size, big_endian, Aarch64, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -6671,13 +6676,18 @@ Target_aarch64<size, big_endian>::scan_relocs(
     size_t local_symbol_count,
     const unsigned char* plocal_symbols)
 {
+  typedef Target_aarch64<size, big_endian> Aarch64;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+
   if (sh_type == elfcpp::SHT_REL)
     {
       gold_error(_("%s: unsupported REL reloc section"),
 		 object->name().c_str());
       return;
     }
-  gold::scan_relocs<size, big_endian, Target_aarch64, elfcpp::SHT_RELA, Scan>(
+
+  gold::scan_relocs<size, big_endian, Aarch64, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -7868,10 +7878,15 @@ Target_aarch64<size, big_endian>::relocate_section(
     section_size_type view_size,
     const Reloc_symbol_changes* reloc_symbol_changes)
 {
-  gold_assert(sh_type == elfcpp::SHT_RELA);
+  typedef Target_aarch64<size, big_endian> Aarch64;
   typedef typename Target_aarch64<size, big_endian>::Relocate AArch64_relocate;
-  gold::relocate_section<size, big_endian, Target_aarch64, elfcpp::SHT_RELA,
-			 AArch64_relocate, gold::Default_comdat_behavior>(
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::relocate_section<size, big_endian, Aarch64, AArch64_relocate,
+			 gold::Default_comdat_behavior, Classify_reloc>(
     relinfo,
     this,
     prelocs,
@@ -7884,21 +7899,6 @@ Target_aarch64<size, big_endian>::relocate_section(
     reloc_symbol_changes);
 }
 
-// Return the size of a relocation while scanning during a relocatable
-// link.
-
-template<int size, bool big_endian>
-unsigned int
-Target_aarch64<size, big_endian>::Relocatable_size_for_reloc::
-get_size_for_reloc(
-    unsigned int ,
-    Relobj* )
-{
-  // We will never support SHT_REL relocations.
-  gold_unreachable();
-  return 0;
-}
-
 // Scan the relocs during a relocatable link.
 
 template<int size, bool big_endian>
@@ -7917,13 +7917,14 @@ Target_aarch64<size, big_endian>::scan_relocatable_relocs(
     const unsigned char* plocal_symbols,
     Relocatable_relocs* rr)
 {
-  gold_assert(sh_type == elfcpp::SHT_RELA);
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_scan_relocatable_relocs<Classify_reloc>
+      Scan_relocatable_relocs;
 
-  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
-    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+  gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
-      Scan_relocatable_relocs>(
+  gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
     symtab,
     layout,
     object,
@@ -7937,6 +7938,45 @@ Target_aarch64<size, big_endian>::scan_relocatable_relocs(
     rr);
 }
 
+// Scan the relocs for --emit-relocs.
+
+template<int size, bool big_endian>
+void
+Target_aarch64<size, big_endian>::emit_relocs_scan(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* object,
+    unsigned int data_shndx,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    size_t local_symbol_count,
+    const unsigned char* plocal_syms,
+    Relocatable_relocs* rr)
+{
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+      Emit_relocs_strategy;
+
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_syms,
+    rr);
+}
+
 // Relocate a section during a relocatable link.
 
 template<int size, bool big_endian>
@@ -7954,9 +7994,12 @@ Target_aarch64<size, big_endian>::relocate_relocs(
     unsigned char* reloc_view,
     section_size_type reloc_view_size)
 {
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::relocate_relocs<size, big_endian, elfcpp::SHT_RELA>(
+  gold::relocate_relocs<size, big_endian, Classify_reloc>(
     relinfo,
     prelocs,
     reloc_count,
diff --git a/gold/arm.cc b/gold/arm.cc
index c20eb6d..4cd0b91 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -2040,9 +2040,9 @@ class Arm_output_data_got : public Output_data_got<32, big_endian>
 // bits.  The default handling of relocatable relocation cannot process these
 // relocations.  So we have to extend the default code.
 
-template<bool big_endian, int sh_type, typename Classify_reloc>
+template<bool big_endian, typename Classify_reloc>
 class Arm_scan_relocatable_relocs :
-  public Default_scan_relocatable_relocs<sh_type, Classify_reloc>
+  public Default_scan_relocatable_relocs<Classify_reloc>
 {
  public:
   // Return the strategy to use for a local symbol which is a section
@@ -2050,7 +2050,7 @@ class Arm_scan_relocatable_relocs :
   inline Relocatable_relocs::Reloc_strategy
   local_section_strategy(unsigned int r_type, Relobj*)
   {
-    if (sh_type == elfcpp::SHT_RELA)
+    if (Classify_reloc::sh_type == elfcpp::SHT_RELA)
       return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
     else
       {
@@ -2301,6 +2301,21 @@ class Target_arm : public Sized_target<32, big_endian>
 			  const unsigned char* plocal_symbols,
 			  Relocatable_relocs*);
 
+  // Scan the relocs for --emit-relocs.
+  void
+  emit_relocs_scan(Symbol_table* symtab,
+		   Layout* layout,
+		   Sized_relobj_file<32, big_endian>* object,
+		   unsigned int data_shndx,
+		   unsigned int sh_type,
+		   const unsigned char* prelocs,
+		   size_t reloc_count,
+		   Output_section* output_section,
+		   bool needs_special_offset_handling,
+		   size_t local_symbol_count,
+		   const unsigned char* plocal_syms,
+		   Relocatable_relocs* rr);
+
   // Emit relocations for a section.
   void
   relocate_relocs(const Relocate_info<32, big_endian>*,
@@ -2727,12 +2742,15 @@ class Target_arm : public Sized_target<32, big_endian>
 
   };
 
-  // A class which returns the size required for a relocation type,
-  // used while scanning relocs during a relocatable link.
-  class Relocatable_size_for_reloc
+  // A class for inquiring about properties of a relocation,
+  // used while scanning relocs during a relocatable link and
+  // garbage collection.
+  class Classify_reloc :
+      public gold::Default_classify_reloc<elfcpp::SHT_REL, 32, big_endian>
   {
    public:
-    unsigned int
+    // Return the size of the addend of the relocation (only used for SHT_REL).
+    static unsigned int
     get_size_for_reloc(unsigned int, Relobj*);
   };
 
@@ -9170,8 +9188,7 @@ Target_arm<big_endian>::gc_process_relocs(
   typedef Target_arm<big_endian> Arm;
   typedef typename Target_arm<big_endian>::Scan Scan;
 
-  gold::gc_process_relocs<32, big_endian, Arm, elfcpp::SHT_REL, Scan,
-			  typename Target_arm::Relocatable_size_for_reloc>(
+  gold::gc_process_relocs<32, big_endian, Arm, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -9201,7 +9218,6 @@ Target_arm<big_endian>::scan_relocs(Symbol_table* symtab,
 				    size_t local_symbol_count,
 				    const unsigned char* plocal_symbols)
 {
-  typedef typename Target_arm<big_endian>::Scan Scan;
   if (sh_type == elfcpp::SHT_RELA)
     {
       gold_error(_("%s: unsupported RELA reloc section"),
@@ -9209,7 +9225,7 @@ Target_arm<big_endian>::scan_relocs(Symbol_table* symtab,
       return;
     }
 
-  gold::scan_relocs<32, big_endian, Target_arm, elfcpp::SHT_REL, Scan>(
+  gold::scan_relocs<32, big_endian, Target_arm, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -10109,8 +10125,8 @@ Target_arm<big_endian>::relocate_section(
 	}
     }
 
-  gold::relocate_section<32, big_endian, Target_arm, elfcpp::SHT_REL,
-			 Arm_relocate, gold::Default_comdat_behavior>(
+  gold::relocate_section<32, big_endian, Target_arm, Arm_relocate,
+			 gold::Default_comdat_behavior, Classify_reloc>(
     relinfo,
     this,
     prelocs,
@@ -10128,7 +10144,7 @@ Target_arm<big_endian>::relocate_section(
 
 template<bool big_endian>
 unsigned int
-Target_arm<big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
+Target_arm<big_endian>::Classify_reloc::get_size_for_reloc(
     unsigned int r_type,
     Relobj* object)
 {
@@ -10165,13 +10181,12 @@ Target_arm<big_endian>::scan_relocatable_relocs(
     const unsigned char* plocal_symbols,
     Relocatable_relocs* rr)
 {
-  gold_assert(sh_type == elfcpp::SHT_REL);
+  typedef Arm_scan_relocatable_relocs<big_endian, Classify_reloc>
+      Scan_relocatable_relocs;
 
-  typedef Arm_scan_relocatable_relocs<big_endian, elfcpp::SHT_REL,
-    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+  gold_assert(sh_type == elfcpp::SHT_REL);
 
-  gold::scan_relocatable_relocs<32, big_endian, elfcpp::SHT_REL,
-      Scan_relocatable_relocs>(
+  gold::scan_relocatable_relocs<32, big_endian, Scan_relocatable_relocs>(
     symtab,
     layout,
     object,
@@ -10185,6 +10200,44 @@ Target_arm<big_endian>::scan_relocatable_relocs(
     rr);
 }
 
+// Scan the relocs for --emit-relocs.
+
+template<bool big_endian>
+void
+Target_arm<big_endian>::emit_relocs_scan(Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<32, big_endian>* object,
+    unsigned int data_shndx,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    size_t local_symbol_count,
+    const unsigned char* plocal_syms,
+    Relocatable_relocs* rr)
+{
+  typedef gold::Default_classify_reloc<elfcpp::SHT_REL, 32, big_endian>
+      Classify_reloc;
+  typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+      Emit_relocs_strategy;
+
+  gold_assert(sh_type == elfcpp::SHT_REL);
+
+  gold::scan_relocatable_relocs<32, big_endian, Emit_relocs_strategy>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_syms,
+    rr);
+}
+
 // Emit relocations for a section.
 
 template<bool big_endian>
@@ -10204,7 +10257,7 @@ Target_arm<big_endian>::relocate_relocs(
 {
   gold_assert(sh_type == elfcpp::SHT_REL);
 
-  gold::relocate_relocs<32, big_endian, elfcpp::SHT_REL>(
+  gold::relocate_relocs<32, big_endian, Classify_reloc>(
     relinfo,
     prelocs,
     reloc_count,
diff --git a/gold/gc.h b/gold/gc.h
index 2dcf61a..d0b16b2 100644
--- a/gold/gc.h
+++ b/gold/gc.h
@@ -38,9 +38,6 @@ class Object;
 template<int size, bool big_endian>
 class Sized_relobj_file;
 
-template<int sh_type, int size, bool big_endian>
-struct Reloc_types;
-
 class Output_section;
 class General_options;
 class Layout;
@@ -153,12 +150,11 @@ struct Symbols_data
 
 template<typename Classify_reloc>
 inline unsigned int
-get_embedded_addend_size(int sh_type, int r_type, Relobj* obj)
+get_embedded_addend_size(int r_type, Relobj* obj)
 {
-  if (sh_type != elfcpp::SHT_REL)
-    return 0;
-  Classify_reloc classify_reloc;
-  return classify_reloc.get_size_for_reloc(r_type, obj);
+  if (Classify_reloc::sh_type == elfcpp::SHT_REL)
+    return Classify_reloc::get_size_for_reloc(r_type, obj);
+  return 0;
 }
 
 // This function implements the generic part of reloc
@@ -167,7 +163,7 @@ get_embedded_addend_size(int sh_type, int r_type, Relobj* obj)
 // garbage collection (--gc-sections) and identical code
 // folding (--icf).
 
-template<int size, bool big_endian, typename Target_type, int sh_type,
+template<int size, bool big_endian, typename Target_type,
 	 typename Scan, typename Classify_reloc>
 inline void
 gc_process_relocs(
@@ -185,8 +181,8 @@ gc_process_relocs(
 {
   Scan scan;
 
-  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
-  const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+  typedef typename Classify_reloc::Reltype Reltype;
+  const int reloc_size = Classify_reloc::reloc_size;
   const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
 
   Icf::Sections_reachable_info* secvec = NULL;
@@ -224,11 +220,10 @@ gc_process_relocs(
   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_sym = elfcpp::elf_r_sym<size>(r_info);
-      unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+      unsigned int r_sym = Classify_reloc::get_r_sym(&reloc);
+      unsigned int r_type = Classify_reloc::get_r_type(&reloc);
       typename elfcpp::Elf_types<size>::Elf_Swxword addend =
-      Reloc_types<sh_type, size, big_endian>::get_reloc_addend_noerror(&reloc);
+	  Classify_reloc::get_r_addend(&reloc);
       Relobj* dst_obj;
       unsigned int dst_indx;
       typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
@@ -260,8 +255,7 @@ gc_process_relocs(
                 convert_to_section_size_type(reloc.get_r_offset());
 	      (*offsetvec).push_back(reloc_offset);
               (*reloc_addend_size_vec).push_back(
-                get_embedded_addend_size<Classify_reloc>(sh_type, r_type,
-                                                         src_obj));
+                get_embedded_addend_size<Classify_reloc>(r_type, src_obj));
             }
 
 	  // When doing safe folding, check to see if this relocation is that
@@ -337,8 +331,7 @@ gc_process_relocs(
                 convert_to_section_size_type(reloc.get_r_offset());
 	      (*offsetvec).push_back(reloc_offset);
               (*reloc_addend_size_vec).push_back(
-                get_embedded_addend_size<Classify_reloc>(sh_type, r_type,
-                                                         src_obj));
+                get_embedded_addend_size<Classify_reloc>(r_type, src_obj));
 	    }
 
           if (dst_obj == NULL)
diff --git a/gold/i386.cc b/gold/i386.cc
index 57e5542..82886d4 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -429,6 +429,21 @@ class Target_i386 : public Sized_target<32, false>
 			  const unsigned char* plocal_symbols,
 			  Relocatable_relocs*);
 
+  // Scan the relocs for --emit-relocs.
+  void
+  emit_relocs_scan(Symbol_table* symtab,
+		   Layout* layout,
+		   Sized_relobj_file<32, false>* object,
+		   unsigned int data_shndx,
+		   unsigned int sh_type,
+		   const unsigned char* prelocs,
+		   size_t reloc_count,
+		   Output_section* output_section,
+		   bool needs_special_offset_handling,
+		   size_t local_symbol_count,
+		   const unsigned char* plocal_syms,
+		   Relocatable_relocs* rr);
+
   // Emit relocations for a section.
   void
   relocate_relocs(const Relocate_info<32, false>*,
@@ -485,7 +500,7 @@ class Target_i386 : public Sized_target<32, false>
 
   // Return whether SYM is call to a non-split function.
   bool
-  do_is_call_to_non_split(const Symbol* sym, unsigned int) const;
+  do_is_call_to_non_split(const Symbol* sym, const unsigned char*) const;
 
   // Adjust -fsplit-stack code which calls non-split-stack code.
   void
@@ -723,12 +738,15 @@ class Target_i386 : public Sized_target<32, false>
     Local_dynamic_type local_dynamic_type_;
   };
 
-  // A class which returns the size required for a relocation type,
-  // used while scanning relocs during a relocatable link.
-  class Relocatable_size_for_reloc
+  // A class for inquiring about properties of a relocation,
+  // used while scanning relocs during a relocatable link and
+  // garbage collection.
+  class Classify_reloc :
+      public gold::Default_classify_reloc<elfcpp::SHT_REL, 32, false>
   {
    public:
-    unsigned int
+    // Return the size of the addend of the relocation (only used for SHT_REL).
+    static unsigned int
     get_size_for_reloc(unsigned int, Relobj*);
   };
 
@@ -2564,9 +2582,7 @@ Target_i386::gc_process_relocs(Symbol_table* symtab,
 				      size_t local_symbol_count,
 				      const unsigned char* plocal_symbols)
 {
-  gold::gc_process_relocs<32, false, Target_i386, elfcpp::SHT_REL,
-			  Target_i386::Scan,
-			  Target_i386::Relocatable_size_for_reloc>(
+  gold::gc_process_relocs<32, false, Target_i386, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -2602,8 +2618,7 @@ Target_i386::scan_relocs(Symbol_table* symtab,
       return;
     }
 
-  gold::scan_relocs<32, false, Target_i386, elfcpp::SHT_REL,
-		    Target_i386::Scan>(
+  gold::scan_relocs<32, false, Target_i386, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -3609,8 +3624,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
 {
   gold_assert(sh_type == elfcpp::SHT_REL);
 
-  gold::relocate_section<32, false, Target_i386, elfcpp::SHT_REL,
-			 Target_i386::Relocate, gold::Default_comdat_behavior>(
+  gold::relocate_section<32, false, Target_i386, Relocate,
+			 gold::Default_comdat_behavior, Classify_reloc>(
     relinfo,
     this,
     prelocs,
@@ -3627,7 +3642,7 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
 // link.
 
 unsigned int
-Target_i386::Relocatable_size_for_reloc::get_size_for_reloc(
+Target_i386::Classify_reloc::get_size_for_reloc(
     unsigned int r_type,
     Relobj* object)
 {
@@ -3712,13 +3727,12 @@ Target_i386::scan_relocatable_relocs(Symbol_table* symtab,
 				     const unsigned char* plocal_symbols,
 				     Relocatable_relocs* rr)
 {
-  gold_assert(sh_type == elfcpp::SHT_REL);
+  typedef gold::Default_scan_relocatable_relocs<Classify_reloc>
+      Scan_relocatable_relocs;
 
-  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_REL,
-    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+  gold_assert(sh_type == elfcpp::SHT_REL);
 
-  gold::scan_relocatable_relocs<32, false, elfcpp::SHT_REL,
-      Scan_relocatable_relocs>(
+  gold::scan_relocatable_relocs<32, false, Scan_relocatable_relocs>(
     symtab,
     layout,
     object,
@@ -3732,6 +3746,43 @@ Target_i386::scan_relocatable_relocs(Symbol_table* symtab,
     rr);
 }
 
+// Scan the relocs for --emit-relocs.
+
+void
+Target_i386::emit_relocs_scan(Symbol_table* symtab,
+			      Layout* layout,
+			      Sized_relobj_file<32, false>* object,
+			      unsigned int data_shndx,
+			      unsigned int sh_type,
+			      const unsigned char* prelocs,
+			      size_t reloc_count,
+			      Output_section* output_section,
+			      bool needs_special_offset_handling,
+			      size_t local_symbol_count,
+			      const unsigned char* plocal_syms,
+			      Relocatable_relocs* rr)
+{
+  typedef gold::Default_classify_reloc<elfcpp::SHT_REL, 32, false>
+      Classify_reloc;
+  typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+      Emit_relocs_strategy;
+
+  gold_assert(sh_type == elfcpp::SHT_REL);
+
+  gold::scan_relocatable_relocs<32, false, Emit_relocs_strategy>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_syms,
+    rr);
+}
+
 // Emit relocations for a section.
 
 void
@@ -3750,7 +3801,7 @@ Target_i386::relocate_relocs(
 {
   gold_assert(sh_type == elfcpp::SHT_REL);
 
-  gold::relocate_relocs<32, false, elfcpp::SHT_REL>(
+  gold::relocate_relocs<32, false, Classify_reloc>(
     relinfo,
     prelocs,
     reloc_count,
@@ -3867,7 +3918,8 @@ Target_i386::do_ehframe_datarel_base() const
 // get_pc_thunk function.
 
 bool
-Target_i386::do_is_call_to_non_split(const Symbol* sym, unsigned int) const
+Target_i386::do_is_call_to_non_split(const Symbol* sym,
+				     const unsigned char*) const
 {
   return (sym->type() == elfcpp::STT_FUNC
 	  && !is_prefix_of("__i686.get_pc_thunk.", sym->name()));
diff --git a/gold/mips.cc b/gold/mips.cc
index 3d513ff..c57ef4f 100644
--- a/gold/mips.cc
+++ b/gold/mips.cc
@@ -2642,9 +2642,9 @@ class Mips_output_section_reginfo : public Output_section
 // The MIPS target has relocation types which default handling of relocatable
 // relocation cannot process.  So we have to extend the default code.
 
-template<bool big_endian, int sh_type, typename Classify_reloc>
+template<bool big_endian, typename Classify_reloc>
 class Mips_scan_relocatable_relocs :
-  public Default_scan_relocatable_relocs<sh_type, Classify_reloc>
+  public Default_scan_relocatable_relocs<Classify_reloc>
 {
  public:
   // Return the strategy to use for a local symbol which is a section
@@ -2652,7 +2652,7 @@ class Mips_scan_relocatable_relocs :
   inline Relocatable_relocs::Reloc_strategy
   local_section_strategy(unsigned int r_type, Relobj* object)
   {
-    if (sh_type == elfcpp::SHT_RELA)
+    if (Classify_reloc::sh_type == elfcpp::SHT_RELA)
       return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
     else
       {
@@ -2662,7 +2662,7 @@ class Mips_scan_relocatable_relocs :
             return Relocatable_relocs::RELOC_SPECIAL;
 
           default:
-            return Default_scan_relocatable_relocs<sh_type, Classify_reloc>::
+            return Default_scan_relocatable_relocs<Classify_reloc>::
                 local_section_strategy(r_type, object);
           }
       }
@@ -2860,6 +2860,182 @@ class Symbol_visitor_check_symbols
   Symbol_table* symtab_;
 };
 
+// Relocation types, parameterized by SHT_REL vs. SHT_RELA, size,
+// and endianness. The relocation format for MIPS-64 is non-standard.
+
+template<int sh_type, int size, bool big_endian>
+struct Mips_reloc_types;
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_REL, 32, big_endian>
+{
+  typedef typename elfcpp::Rel<32, big_endian> Reloc;
+  typedef typename elfcpp::Rel_write<32, big_endian> Reloc_write;
+
+  static unsigned typename elfcpp::Elf_types<32>::Elf_Swxword
+  get_r_addend(const Reloc*)
+  { return 0; }
+
+  static inline void
+  set_reloc_addend(Reloc_write*,
+		   typename elfcpp::Elf_types<32>::Elf_Swxword)
+  { gold_unreachable(); }
+};
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_RELA, 32, big_endian>
+{
+  typedef typename elfcpp::Rela<32, big_endian> Reloc;
+  typedef typename elfcpp::Rela_write<32, big_endian> Reloc_write;
+
+  static unsigned typename elfcpp::Elf_types<32>::Elf_Swxword
+  get_r_addend(const Reloc* reloc)
+  { return reloc->get_r_addend(); }
+
+  static inline void
+  set_reloc_addend(Reloc_write* p,
+		   typename elfcpp::Elf_types<32>::Elf_Swxword val)
+  { p->put_r_addend(val); }
+};
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_REL, 64, big_endian>
+{
+  typedef typename elfcpp::Mips64_rel<big_endian> Reloc;
+  typedef typename elfcpp::Mips64_rel_write<big_endian> Reloc_write;
+
+  static unsigned typename elfcpp::Elf_types<64>::Elf_Swxword
+  get_r_addend(const Reloc*)
+  { return 0; }
+
+  static inline void
+  set_reloc_addend(Reloc_write*,
+		   typename elfcpp::Elf_types<64>::Elf_Swxword)
+  { gold_unreachable(); }
+};
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_RELA, 64, big_endian>
+{
+  typedef typename elfcpp::Mips64_rela<big_endian> Reloc;
+  typedef typename elfcpp::Mips64_rela_write<big_endian> Reloc_write;
+
+  static unsigned typename elfcpp::Elf_types<64>::Elf_Swxword
+  get_r_addend(const Reloc* reloc)
+  { return reloc->get_r_addend(); }
+
+  static inline void
+  set_reloc_addend(Reloc_write* p,
+		   typename elfcpp::Elf_types<64>::Elf_Swxword val)
+  { p->put_r_addend(val); }
+};
+
+// Forward declaration.
+static unsigned int
+mips_get_size_for_reloc(unsigned int, Relobj*);
+
+// A class for inquiring about properties of a relocation,
+// used while scanning relocs during a relocatable link and
+// garbage collection.
+
+template<int sh_type_, int size, bool big_endian>
+class Mips_classify_reloc;
+
+template<int sh_type_, bool big_endian>
+class Mips_classify_reloc<sh_type_, 32, big_endian> :
+    public gold::Default_classify_reloc<sh_type_, 32, big_endian>
+{
+ public:
+  typedef typename Mips_reloc_types<sh_type_, 32, big_endian>::Reloc
+      Reltype;
+  typedef typename Mips_reloc_types<sh_type_, 32, big_endian>::Reloc_write
+      Reltype_write;
+
+  // Return the symbol referred to by the relocation.
+  static inline unsigned int
+  get_r_sym(const Reltype* reloc)
+  { return elfcpp::elf_r_sym<32>(reloc->get_r_info()); }
+
+  // Return the type of the relocation.
+  static inline unsigned int
+  get_r_type(const Reltype* reloc)
+  { return elfcpp::elf_r_type<32>(reloc->get_r_info()); }
+
+  // Return the explicit addend of the relocation (return 0 for SHT_REL).
+  static inline unsigned int
+  get_r_addend(const Reltype* reloc)
+  { return Mips_reloc_types<sh_type_, 32, big_endian>::get_r_addend(reloc); }
+
+  // Write the r_info field to a new reloc, using the r_info field from
+  // the original reloc, replacing the r_sym field with R_SYM.
+  static inline void
+  put_r_info(Reltype_write* new_reloc, Reltype* reloc, unsigned int r_sym)
+  {
+    unsigned int r_type = elfcpp::elf_r_type<32>(reloc->get_r_info());
+    new_reloc->put_r_info(elfcpp::elf_r_info<64>(r_sym, r_type));
+  }
+
+  // Write the r_addend field to a new reloc.
+  static inline void
+  put_r_addend(Reltype_write* to,
+	       typename elfcpp::Elf_types<32>::Elf_Swxword addend)
+  { Mips_reloc_types<sh_type_, 32, big_endian>::set_reloc_addend(to, addend); }
+
+  // Return the size of the addend of the relocation (only used for SHT_REL).
+  static unsigned int
+  get_size_for_reloc(unsigned int r_type, Relobj* obj)
+  { return mips_get_size_for_reloc(r_type, obj); }
+};
+
+template<int sh_type_, bool big_endian>
+class Mips_classify_reloc<sh_type_, 64, big_endian> :
+    public gold::Default_classify_reloc<sh_type_, 64, big_endian>
+{
+ public:
+  typedef typename Mips_reloc_types<sh_type_, 64, big_endian>::Reloc
+      Reltype;
+  typedef typename Mips_reloc_types<sh_type_, 64, big_endian>::Reloc_write
+      Reltype_write;
+
+  // Return the symbol referred to by the relocation.
+  static inline unsigned int
+  get_r_sym(const Reltype* reloc)
+  { return reloc->get_r_sym(); }
+
+  // Return the type of the relocation.
+  static inline unsigned int
+  get_r_type(const Reltype* reloc)
+  { return reloc->get_r_type(); }
+
+  // Return the explicit addend of the relocation (return 0 for SHT_REL).
+  static inline typename elfcpp::Elf_types<64>::Elf_Swxword
+  get_r_addend(const Reltype* reloc)
+  { return Mips_reloc_types<sh_type_, 64, big_endian>::get_r_addend(reloc); }
+
+  // Write the r_info field to a new reloc, using the r_info field from
+  // the original reloc, replacing the r_sym field with R_SYM.
+  static inline void
+  put_r_info(Reltype_write* new_reloc, Reltype* reloc, unsigned int r_sym)
+  {
+    new_reloc->put_r_sym(r_sym);
+    new_reloc->put_r_ssym(reloc->get_r_ssym());
+    new_reloc->put_r_type3(reloc->get_r_type3());
+    new_reloc->put_r_type2(reloc->get_r_type2());
+    new_reloc->put_r_type(reloc->get_r_type());
+  }
+
+  // Write the r_addend field to a new reloc.
+  static inline void
+  put_r_addend(Reltype_write* to,
+	       typename elfcpp::Elf_types<64>::Elf_Swxword addend)
+  { Mips_reloc_types<sh_type_, 64, big_endian>::set_reloc_addend(to, addend); }
+
+  // Return the size of the addend of the relocation (only used for SHT_REL).
+  static unsigned int
+  get_size_for_reloc(unsigned int r_type, Relobj* obj)
+  { return mips_get_size_for_reloc(r_type, obj); }
+};
+
 template<int size, bool big_endian>
 class Target_mips : public Sized_target<size, big_endian>
 {
@@ -2870,6 +3046,10 @@ class Target_mips : public Sized_target<size, big_endian>
     Reloca_section;
   typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype32;
   typedef typename elfcpp::Swap<size, big_endian>::Valtype Valtype;
+  typedef typename Mips_reloc_types<elfcpp::SHT_REL, size, big_endian>::Reloc
+      Reltype;
+  typedef typename Mips_reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+      Relatype;
 
  public:
   Target_mips(const Target::Target_info* info = &mips_info)
@@ -2955,6 +3135,21 @@ class Target_mips : public Sized_target<size, big_endian>
                           const unsigned char* plocal_symbols,
                           Relocatable_relocs*);
 
+  // Scan the relocs for --emit-relocs.
+  void
+  emit_relocs_scan(Symbol_table* symtab,
+		   Layout* layout,
+		   Sized_relobj_file<size, big_endian>* object,
+		   unsigned int data_shndx,
+		   unsigned int sh_type,
+		   const unsigned char* prelocs,
+		   size_t reloc_count,
+		   Output_section* output_section,
+		   bool needs_special_offset_handling,
+		   size_t local_symbol_count,
+		   const unsigned char* plocal_syms,
+		   Relocatable_relocs* rr);
+
   // Emit relocations for a section.
   void
   relocate_relocs(const Relocate_info<size, big_endian>*,
@@ -3164,6 +3359,17 @@ class Target_mips : public Sized_target<size, big_endian>
   use_32bit_micromips_instructions() const
   { return this->insn32_; }
 
+  // Return the r_sym field from a relocation.
+  unsigned int
+  get_r_sym(const unsigned char* preloc) const
+  {
+    // Since REL and RELA relocs share the same structure through
+    // the r_info field, we can just use REL here.
+    Reltype rel(preloc);
+    return Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+	get_r_sym(&rel);
+  }
+
  protected:
   // Return the value to use for a dynamic symbol which requires special
   // treatment.  This is how we support equality comparisons of function
@@ -3268,7 +3474,7 @@ class Target_mips : public Sized_target<size, big_endian>
           Sized_relobj_file<size, big_endian>* object,
           unsigned int data_shndx,
           Output_section* output_section,
-          const elfcpp::Rel<size, big_endian>& reloc, unsigned int r_type,
+          const Reltype& reloc, unsigned int r_type,
           const elfcpp::Sym<size, big_endian>& lsym,
           bool is_discarded);
 
@@ -3277,7 +3483,7 @@ class Target_mips : public Sized_target<size, big_endian>
           Sized_relobj_file<size, big_endian>* object,
           unsigned int data_shndx,
           Output_section* output_section,
-          const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+          const Relatype& reloc, unsigned int r_type,
           const elfcpp::Sym<size, big_endian>& lsym,
           bool is_discarded);
 
@@ -3286,8 +3492,8 @@ class Target_mips : public Sized_target<size, big_endian>
           Sized_relobj_file<size, big_endian>* object,
           unsigned int data_shndx,
           Output_section* output_section,
-          const elfcpp::Rela<size, big_endian>* rela,
-          const elfcpp::Rel<size, big_endian>* rel,
+          const Relatype* rela,
+          const Reltype* rel,
           unsigned int rel_type,
           unsigned int r_type,
           const elfcpp::Sym<size, big_endian>& lsym,
@@ -3298,7 +3504,7 @@ class Target_mips : public Sized_target<size, big_endian>
            Sized_relobj_file<size, big_endian>* object,
            unsigned int data_shndx,
            Output_section* output_section,
-           const elfcpp::Rel<size, big_endian>& reloc, unsigned int r_type,
+           const Reltype& reloc, unsigned int r_type,
            Symbol* gsym);
 
     inline void
@@ -3306,7 +3512,7 @@ class Target_mips : public Sized_target<size, big_endian>
            Sized_relobj_file<size, big_endian>* object,
            unsigned int data_shndx,
            Output_section* output_section,
-           const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+           const Relatype& reloc, unsigned int r_type,
            Symbol* gsym);
 
     inline void
@@ -3314,8 +3520,8 @@ class Target_mips : public Sized_target<size, big_endian>
            Sized_relobj_file<size, big_endian>* object,
            unsigned int data_shndx,
            Output_section* output_section,
-           const elfcpp::Rela<size, big_endian>* rela,
-           const elfcpp::Rel<size, big_endian>* rel,
+           const Relatype* rela,
+           const Reltype* rel,
            unsigned int rel_type,
            unsigned int r_type,
            Symbol* gsym);
@@ -3326,7 +3532,7 @@ class Target_mips : public Sized_target<size, big_endian>
                                         Sized_relobj_file<size, big_endian>*,
                                         unsigned int,
                                         Output_section*,
-                                        const elfcpp::Rel<size, big_endian>&,
+                                        const Reltype&,
                                         unsigned int,
                                         const elfcpp::Sym<size, big_endian>&)
     { return false; }
@@ -3337,7 +3543,7 @@ class Target_mips : public Sized_target<size, big_endian>
                                          Sized_relobj_file<size, big_endian>*,
                                          unsigned int,
                                          Output_section*,
-                                         const elfcpp::Rel<size, big_endian>&,
+                                         const Reltype&,
                                          unsigned int, Symbol*)
     { return false; }
 
@@ -3347,7 +3553,7 @@ class Target_mips : public Sized_target<size, big_endian>
                                         Sized_relobj_file<size, big_endian>*,
                                         unsigned int,
                                         Output_section*,
-                                        const elfcpp::Rela<size, big_endian>&,
+                                        const Relatype&,
                                         unsigned int,
                                         const elfcpp::Sym<size, big_endian>&)
     { return false; }
@@ -3358,7 +3564,7 @@ class Target_mips : public Sized_target<size, big_endian>
                                          Sized_relobj_file<size, big_endian>*,
                                          unsigned int,
                                          Output_section*,
-                                         const elfcpp::Rela<size, big_endian>&,
+                                         const Relatype&,
                                          unsigned int, Symbol*)
     { return false; }
    private:
@@ -3397,15 +3603,6 @@ class Target_mips : public Sized_target<size, big_endian>
 	     unsigned char*, Mips_address, section_size_type);
   };
 
-  // A class which returns the size required for a relocation type,
-  // used while scanning relocs during a relocatable link.
-  class Relocatable_size_for_reloc
-  {
-   public:
-    unsigned int
-    get_size_for_reloc(unsigned int, Relobj*);
-  };
-
   // This POD class holds the dynamic relocations that should be emitted instead
   // of R_MIPS_32, R_MIPS_REL32 and R_MIPS_64 relocations.  We will emit these
   // relocations if it turns out that the symbol does not have static
@@ -3573,9 +3770,11 @@ class Target_mips : public Sized_target<size, big_endian>
   copy_reloc(Symbol_table* symtab, Layout* layout,
              Sized_relobj_file<size, big_endian>* object,
              unsigned int shndx, Output_section* output_section,
-             Symbol* sym, const elfcpp::Rel<size, big_endian>& reloc)
+             Symbol* sym, const Reltype& reloc)
   {
-    unsigned int r_type = elfcpp::elf_r_type<size>(reloc.get_r_info());
+    unsigned int r_type =
+	Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+	  get_r_type(&reloc);
     this->copy_relocs_.copy_reloc(symtab, layout,
                                   symtab->get_sized_symbol<size>(sym),
                                   object, shndx, output_section,
@@ -3725,7 +3924,6 @@ class Target_mips : public Sized_target<size, big_endian>
   bool insn32_;
 };
 
-
 // Helper structure for R_MIPS*_HI16/LO16 and R_MIPS*_GOT16/LO16 relocations.
 // It records high part of the relocation pair.
 
@@ -7510,10 +7708,10 @@ Target_mips<size, big_endian>::gc_process_relocs(
                         const unsigned char* plocal_symbols)
 {
   typedef Target_mips<size, big_endian> Mips;
-  typedef typename Target_mips<size, big_endian>::Scan Scan;
+  typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+      Classify_reloc;
 
-  gold::gc_process_relocs<size, big_endian, Mips, elfcpp::SHT_REL, Scan,
-                          typename Target_mips::Relocatable_size_for_reloc>(
+  gold::gc_process_relocs<size, big_endian, Mips, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -7545,34 +7743,43 @@ Target_mips<size, big_endian>::scan_relocs(
                         const unsigned char* plocal_symbols)
 {
   typedef Target_mips<size, big_endian> Mips;
-  typedef typename Target_mips<size, big_endian>::Scan Scan;
 
   if (sh_type == elfcpp::SHT_REL)
-    gold::scan_relocs<size, big_endian, Mips, elfcpp::SHT_REL, Scan>(
-      symtab,
-      layout,
-      this,
-      object,
-      data_shndx,
-      prelocs,
-      reloc_count,
-      output_section,
-      needs_special_offset_handling,
-      local_symbol_count,
-      plocal_symbols);
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+	  Classify_reloc;
+
+      gold::scan_relocs<size, big_endian, Mips, Scan, Classify_reloc>(
+	symtab,
+	layout,
+	this,
+	object,
+	data_shndx,
+	prelocs,
+	reloc_count,
+	output_section,
+	needs_special_offset_handling,
+	local_symbol_count,
+	plocal_symbols);
+    }
   else if (sh_type == elfcpp::SHT_RELA)
-    gold::scan_relocs<size, big_endian, Mips, elfcpp::SHT_RELA, Scan>(
-      symtab,
-      layout,
-      this,
-      object,
-      data_shndx,
-      prelocs,
-      reloc_count,
-      output_section,
-      needs_special_offset_handling,
-      local_symbol_count,
-      plocal_symbols);
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+	  Classify_reloc;
+
+      gold::scan_relocs<size, big_endian, Mips, Scan, Classify_reloc>(
+	symtab,
+	layout,
+	this,
+	object,
+	data_shndx,
+	prelocs,
+	reloc_count,
+	output_section,
+	needs_special_offset_handling,
+	local_symbol_count,
+	plocal_symbols);
+    }
 }
 
 template<int size, bool big_endian>
@@ -8227,41 +8434,48 @@ Target_mips<size, big_endian>::relocate_section(
   typedef typename Target_mips<size, big_endian>::Relocate Mips_relocate;
 
   if (sh_type == elfcpp::SHT_REL)
-    gold::relocate_section<size, big_endian, Mips, elfcpp::SHT_REL,
-      Mips_relocate, gold::Default_comdat_behavior>(
-      relinfo,
-      this,
-      prelocs,
-      reloc_count,
-      output_section,
-      needs_special_offset_handling,
-      view,
-      address,
-      view_size,
-      reloc_symbol_changes);
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+	  Classify_reloc;
+
+      gold::relocate_section<size, big_endian, Mips, Mips_relocate,
+			     gold::Default_comdat_behavior, Classify_reloc>(
+	relinfo,
+	this,
+	prelocs,
+	reloc_count,
+	output_section,
+	needs_special_offset_handling,
+	view,
+	address,
+	view_size,
+	reloc_symbol_changes);
+    }
   else if (sh_type == elfcpp::SHT_RELA)
-    gold::relocate_section<size, big_endian, Mips, elfcpp::SHT_RELA,
-      Mips_relocate, gold::Default_comdat_behavior>(
-      relinfo,
-      this,
-      prelocs,
-      reloc_count,
-      output_section,
-      needs_special_offset_handling,
-      view,
-      address,
-      view_size,
-      reloc_symbol_changes);
+    {
+      typedef Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+	  Classify_reloc;
+
+      gold::relocate_section<size, big_endian, Mips, Mips_relocate,
+			     gold::Default_comdat_behavior, Classify_reloc>(
+	relinfo,
+	this,
+	prelocs,
+	reloc_count,
+	output_section,
+	needs_special_offset_handling,
+	view,
+	address,
+	view_size,
+	reloc_symbol_changes);
+    }
 }
 
 // Return the size of a relocation while scanning during a relocatable
 // link.
 
-template<int size, bool big_endian>
 unsigned int
-Target_mips<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
-    unsigned int r_type,
-    Relobj* object)
+mips_get_size_for_reloc(unsigned int r_type, Relobj* object)
 {
   switch (r_type)
     {
@@ -8344,13 +8558,14 @@ Target_mips<size, big_endian>::scan_relocatable_relocs(
                         const unsigned char* plocal_symbols,
                         Relocatable_relocs* rr)
 {
-  gold_assert(sh_type == elfcpp::SHT_REL);
+  typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+      Classify_reloc;
+  typedef Mips_scan_relocatable_relocs<big_endian, Classify_reloc>
+      Scan_relocatable_relocs;
 
-  typedef Mips_scan_relocatable_relocs<big_endian, elfcpp::SHT_REL,
-    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+  gold_assert(sh_type == elfcpp::SHT_REL);
 
-  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_REL,
-    Scan_relocatable_relocs>(
+  gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
     symtab,
     layout,
     object,
@@ -8364,6 +8579,45 @@ Target_mips<size, big_endian>::scan_relocatable_relocs(
     rr);
 }
 
+// Scan the relocs for --emit-relocs.
+
+template<int size, bool big_endian>
+void
+Target_mips<size, big_endian>::emit_relocs_scan(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* object,
+    unsigned int data_shndx,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    size_t local_symbol_count,
+    const unsigned char* plocal_syms,
+    Relocatable_relocs* rr)
+{
+  typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+      Emit_relocs_strategy;
+
+  gold_assert(sh_type == elfcpp::SHT_REL);
+
+  gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_syms,
+    rr);
+}
+
 // Emit relocations for a section.
 
 template<int size, bool big_endian>
@@ -8382,9 +8636,12 @@ Target_mips<size, big_endian>::relocate_relocs(
                         unsigned char* reloc_view,
                         section_size_type reloc_view_size)
 {
+  typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+      Classify_reloc;
+
   gold_assert(sh_type == elfcpp::SHT_REL);
 
-  gold::relocate_relocs<size, big_endian, elfcpp::SHT_REL>(
+  gold::relocate_relocs<size, big_endian, Classify_reloc>(
     relinfo,
     prelocs,
     reloc_count,
@@ -8550,8 +8807,8 @@ Target_mips<size, big_endian>::Scan::local(
                         Sized_relobj_file<size, big_endian>* object,
                         unsigned int data_shndx,
                         Output_section* output_section,
-                        const elfcpp::Rela<size, big_endian>* rela,
-                        const elfcpp::Rel<size, big_endian>* rel,
+                        const Relatype* rela,
+                        const Reltype* rel,
                         unsigned int rel_type,
                         unsigned int r_type,
                         const elfcpp::Sym<size, big_endian>& lsym,
@@ -8561,23 +8818,24 @@ Target_mips<size, big_endian>::Scan::local(
     return;
 
   Mips_address r_offset;
-  typename elfcpp::Elf_types<size>::Elf_WXword r_info;
+  unsigned int r_sym;
   typename elfcpp::Elf_types<size>::Elf_Swxword r_addend;
 
   if (rel_type == elfcpp::SHT_RELA)
     {
       r_offset = rela->get_r_offset();
-      r_info = rela->get_r_info();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+	  get_r_sym(rela);
       r_addend = rela->get_r_addend();
     }
   else
     {
       r_offset = rel->get_r_offset();
-      r_info = rel->get_r_info();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+	  get_r_sym(rel);
       r_addend = 0;
     }
 
-  unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
   Mips_relobj<size, big_endian>* mips_obj =
     Mips_relobj<size, big_endian>::as_mips_relobj(object);
 
@@ -8655,7 +8913,6 @@ Target_mips<size, big_endian>::Scan::local(
       // R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.
       Mips_output_data_got<size, big_endian>* got =
         target->got_section(symtab, layout);
-      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
       got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type, -1U);
     }
 
@@ -8790,7 +9047,6 @@ Target_mips<size, big_endian>::Scan::local(
             // executable), we need to create a dynamic relocation for
             // this location.
             Reloc_section* rel_dyn = target->rel_dyn_section(layout);
-            unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
             rel_dyn->add_symbolless_local_addend(object, r_sym,
                                                  elfcpp::R_MIPS_REL32,
                                                  output_section, data_shndx,
@@ -8809,7 +9065,6 @@ Target_mips<size, big_endian>::Scan::local(
     case elfcpp::R_MIPS16_TLS_GD:
     case elfcpp::R_MICROMIPS_TLS_GD:
       {
-        unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
         bool output_is_shared = parameters->options().shared();
         const tls::Tls_optimization optimized_type
             = Target_mips<size, big_endian>::optimize_tls_reloc(
@@ -8929,7 +9184,7 @@ Target_mips<size, big_endian>::Scan::local(
                         Sized_relobj_file<size, big_endian>* object,
                         unsigned int data_shndx,
                         Output_section* output_section,
-                        const elfcpp::Rel<size, big_endian>& reloc,
+                        const Reltype& reloc,
                         unsigned int r_type,
                         const elfcpp::Sym<size, big_endian>& lsym,
                         bool is_discarded)
@@ -8944,7 +9199,7 @@ Target_mips<size, big_endian>::Scan::local(
     object,
     data_shndx,
     output_section,
-    (const elfcpp::Rela<size, big_endian>*) NULL,
+    (const Relatype*) NULL,
     &reloc,
     elfcpp::SHT_REL,
     r_type,
@@ -8961,7 +9216,7 @@ Target_mips<size, big_endian>::Scan::local(
                         Sized_relobj_file<size, big_endian>* object,
                         unsigned int data_shndx,
                         Output_section* output_section,
-                        const elfcpp::Rela<size, big_endian>& reloc,
+                        const Relatype& reloc,
                         unsigned int r_type,
                         const elfcpp::Sym<size, big_endian>& lsym,
                         bool is_discarded)
@@ -8977,7 +9232,7 @@ Target_mips<size, big_endian>::Scan::local(
     data_shndx,
     output_section,
     &reloc,
-    (const elfcpp::Rel<size, big_endian>*) NULL,
+    (const Reltype*) NULL,
     elfcpp::SHT_RELA,
     r_type,
     lsym, is_discarded);
@@ -8994,30 +9249,31 @@ Target_mips<size, big_endian>::Scan::global(
                                 Sized_relobj_file<size, big_endian>* object,
                                 unsigned int data_shndx,
                                 Output_section* output_section,
-                                const elfcpp::Rela<size, big_endian>* rela,
-                                const elfcpp::Rel<size, big_endian>* rel,
+                                const Relatype* rela,
+                                const Reltype* rel,
                                 unsigned int rel_type,
                                 unsigned int r_type,
                                 Symbol* gsym)
 {
   Mips_address r_offset;
-  typename elfcpp::Elf_types<size>::Elf_WXword r_info;
+  unsigned int r_sym;
   typename elfcpp::Elf_types<size>::Elf_Swxword r_addend;
 
   if (rel_type == elfcpp::SHT_RELA)
     {
       r_offset = rela->get_r_offset();
-      r_info = rela->get_r_info();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+	  get_r_sym(rela);
       r_addend = rela->get_r_addend();
     }
   else
     {
       r_offset = rel->get_r_offset();
-      r_info = rel->get_r_info();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+	  get_r_sym(rel);
       r_addend = 0;
     }
 
-  unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
   Mips_relobj<size, big_endian>* mips_obj =
     Mips_relobj<size, big_endian>::as_mips_relobj(object);
   Mips_symbol<size>* mips_sym = Mips_symbol<size>::as_mips_sym(gsym);
@@ -9434,7 +9690,7 @@ Target_mips<size, big_endian>::Scan::global(
                                 Sized_relobj_file<size, big_endian>* object,
                                 unsigned int data_shndx,
                                 Output_section* output_section,
-                                const elfcpp::Rela<size, big_endian>& reloc,
+                                const Relatype& reloc,
                                 unsigned int r_type,
                                 Symbol* gsym)
 {
@@ -9446,7 +9702,7 @@ Target_mips<size, big_endian>::Scan::global(
     data_shndx,
     output_section,
     &reloc,
-    (const elfcpp::Rel<size, big_endian>*) NULL,
+    (const Reltype*) NULL,
     elfcpp::SHT_RELA,
     r_type,
     gsym);
@@ -9461,7 +9717,7 @@ Target_mips<size, big_endian>::Scan::global(
                                 Sized_relobj_file<size, big_endian>* object,
                                 unsigned int data_shndx,
                                 Output_section* output_section,
-                                const elfcpp::Rel<size, big_endian>& reloc,
+                                const Reltype& reloc,
                                 unsigned int r_type,
                                 Symbol* gsym)
 {
@@ -9472,7 +9728,7 @@ Target_mips<size, big_endian>::Scan::global(
     object,
     data_shndx,
     output_section,
-    (const elfcpp::Rela<size, big_endian>*) NULL,
+    (const Relatype*) NULL,
     &reloc,
     elfcpp::SHT_REL,
     r_type,
@@ -9546,32 +9802,38 @@ Target_mips<size, big_endian>::Relocate::relocate(
                         section_size_type)
 {
   Mips_address r_offset;
-  typename elfcpp::Elf_types<size>::Elf_WXword r_info;
+  unsigned int r_sym;
+  unsigned int r_type;
   typename elfcpp::Elf_types<size>::Elf_Swxword r_addend;
 
   if (rel_type == elfcpp::SHT_RELA)
     {
-      const elfcpp::Rela<size, big_endian> rela(preloc);
+      const Relatype rela(preloc);
       r_offset = rela.get_r_offset();
-      r_info = rela.get_r_info();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+	  get_r_sym(&rela);
+      r_type = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+	  get_r_type(&rela);
       r_addend = rela.get_r_addend();
     }
   else
     {
-      const elfcpp::Rel<size, big_endian> rel(preloc);
+
+      const Reltype rel(preloc);
       r_offset = rel.get_r_offset();
-      r_info = rel.get_r_info();
+      r_sym = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+	  get_r_sym(&rel);
+      r_type = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+	  get_r_type(&rel);
       r_addend = 0;
     }
-  unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
 
   typedef Mips_relocate_functions<size, big_endian> Reloc_funcs;
   typename Reloc_funcs::Status reloc_status = Reloc_funcs::STATUS_OKAY;
 
   Mips_relobj<size, big_endian>* object =
-    Mips_relobj<size, big_endian>::as_mips_relobj(relinfo->object);
+      Mips_relobj<size, big_endian>::as_mips_relobj(relinfo->object);
 
-  unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
   bool target_is_16_bit_code = false;
   bool target_is_micromips_code = false;
   bool cross_mode_jump;
diff --git a/gold/object.h b/gold/object.h
index 25af341..95f6d56 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -2710,7 +2710,8 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
 		     unsigned int sh_type, unsigned int shndx,
 		     const unsigned char* prelocs, size_t reloc_count,
 		     unsigned char* view, section_size_type view_size,
-		     Reloc_symbol_changes** reloc_map);
+		     Reloc_symbol_changes** reloc_map,
+		     const Sized_target<size, big_endian>* target);
 
   template<int sh_type>
   void
@@ -2718,7 +2719,8 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
 			     unsigned int shndx, const unsigned char* prelocs,
 			     size_t reloc_count, unsigned char* view,
 			     section_size_type view_size,
-			     Reloc_symbol_changes** reloc_map);
+			     Reloc_symbol_changes** reloc_map,
+			     const Sized_target<size, big_endian>* target);
 
   // Find all functions in a section.
   void
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index b1c5aea..e26a198 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -663,6 +663,21 @@ class Target_powerpc : public Sized_target<size, big_endian>
 			  const unsigned char* plocal_symbols,
 			  Relocatable_relocs*);
 
+  // Scan the relocs for --emit-relocs.
+  void
+  emit_relocs_scan(Symbol_table* symtab,
+		   Layout* layout,
+		   Sized_relobj_file<size, big_endian>* object,
+		   unsigned int data_shndx,
+		   unsigned int sh_type,
+		   const unsigned char* prelocs,
+		   size_t reloc_count,
+		   Output_section* output_section,
+		   bool needs_special_offset_handling,
+		   size_t local_symbol_count,
+		   const unsigned char* plocal_syms,
+		   Relocatable_relocs* rr);
+
   // Emit relocations for a section.
   void
   relocate_relocs(const Relocate_info<size, big_endian>*,
@@ -1105,19 +1120,6 @@ class Target_powerpc : public Sized_target<size, big_endian>
     }
   };
 
-  // A class which returns the size required for a relocation type,
-  // used while scanning relocs during a relocatable link.
-  class Relocatable_size_for_reloc
-  {
-   public:
-    unsigned int
-    get_size_for_reloc(unsigned int, Relobj*)
-    {
-      gold_unreachable();
-      return 0;
-    }
-  };
-
   // Optimize the TLS relocation type based on what we know about the
   // symbol.  IS_FINAL is true if the final address of this symbol is
   // known at link time.
@@ -6430,7 +6432,9 @@ Target_powerpc<size, big_endian>::gc_process_relocs(
     const unsigned char* plocal_symbols)
 {
   typedef Target_powerpc<size, big_endian> Powerpc;
-  typedef typename Target_powerpc<size, big_endian>::Scan Scan;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+
   Powerpc_relobj<size, big_endian>* ppc_object
     = static_cast<Powerpc_relobj<size, big_endian>*>(object);
   if (size == 64)
@@ -6460,8 +6464,7 @@ Target_powerpc<size, big_endian>::gc_process_relocs(
       return;
     }
 
-  gold::gc_process_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan,
-			  typename Target_powerpc::Relocatable_size_for_reloc>(
+  gold::gc_process_relocs<size, big_endian, Powerpc, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -6707,7 +6710,8 @@ Target_powerpc<size, big_endian>::scan_relocs(
     const unsigned char* plocal_symbols)
 {
   typedef Target_powerpc<size, big_endian> Powerpc;
-  typedef typename Target_powerpc<size, big_endian>::Scan Scan;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
 
   if (sh_type == elfcpp::SHT_REL)
     {
@@ -6716,7 +6720,7 @@ Target_powerpc<size, big_endian>::scan_relocs(
       return;
     }
 
-  gold::scan_relocs<size, big_endian, Powerpc, elfcpp::SHT_RELA, Scan>(
+  gold::scan_relocs<size, big_endian, Powerpc, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -8177,11 +8181,13 @@ Target_powerpc<size, big_endian>::relocate_section(
   typedef typename Target_powerpc<size, big_endian>::Relocate Powerpc_relocate;
   typedef typename Target_powerpc<size, big_endian>::Relocate_comdat_behavior
     Powerpc_comdat_behavior;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
 
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::relocate_section<size, big_endian, Powerpc, elfcpp::SHT_RELA,
-			 Powerpc_relocate, Powerpc_comdat_behavior>(
+  gold::relocate_section<size, big_endian, Powerpc, Powerpc_relocate,
+			 Powerpc_comdat_behavior, Classify_reloc>(
     relinfo,
     this,
     prelocs,
@@ -8194,9 +8200,26 @@ Target_powerpc<size, big_endian>::relocate_section(
     reloc_symbol_changes);
 }
 
+template<int size, bool big_endian>
 class Powerpc_scan_relocatable_reloc
 {
 public:
+  typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+      Reltype;
+  static const int reloc_size =
+      Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+  static const int sh_type = elfcpp::SHT_RELA;
+
+  // Return the symbol referred to by the relocation.
+  static inline unsigned int
+  get_r_sym(const Reltype* reloc)
+  { return elfcpp::elf_r_sym<size>(reloc->get_r_info()); }
+
+  // Return the type of the relocation.
+  static inline unsigned int
+  get_r_type(const Reltype* reloc)
+  { return elfcpp::elf_r_type<size>(reloc->get_r_info()); }
+
   // Return the strategy to use for a local symbol which is not a
   // section symbol, given the relocation type.
   inline Relocatable_relocs::Reloc_strategy
@@ -8244,10 +8267,11 @@ Target_powerpc<size, big_endian>::scan_relocatable_relocs(
     const unsigned char* plocal_symbols,
     Relocatable_relocs* rr)
 {
+  typedef Powerpc_scan_relocatable_reloc<size, big_endian> Scan_strategy;
+
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
-				Powerpc_scan_relocatable_reloc>(
+  gold::scan_relocatable_relocs<size, big_endian, Scan_strategy>(
     symtab,
     layout,
     object,
@@ -8261,6 +8285,45 @@ Target_powerpc<size, big_endian>::scan_relocatable_relocs(
     rr);
 }
 
+// Scan the relocs for --emit-relocs.
+
+template<int size, bool big_endian>
+void
+Target_powerpc<size, big_endian>::emit_relocs_scan(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* object,
+    unsigned int data_shndx,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    size_t local_symbol_count,
+    const unsigned char* plocal_syms,
+    Relocatable_relocs* rr)
+{
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+      Emit_relocs_strategy;
+
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_syms,
+    rr);
+}
+
 // Emit relocations for a section.
 // This is a modified version of the function by the same name in
 // target-reloc.h.  Using relocate_special_relocatable for
diff --git a/gold/reloc-types.h b/gold/reloc-types.h
index b42be59..7334b9f 100644
--- a/gold/reloc-types.h
+++ b/gold/reloc-types.h
@@ -56,10 +56,6 @@ struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
   set_reloc_addend(Reloc_write*,
 		   typename elfcpp::Elf_types<size>::Elf_Swxword)
   { gold_unreachable(); }
-
-  static inline void
-  copy_reloc_addend(Reloc_write*, const Reloc*)
-  { gold_unreachable(); }
 };
 
 template<int size, bool big_endian>
@@ -81,10 +77,6 @@ struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
   set_reloc_addend(Reloc_write* p,
 		   typename elfcpp::Elf_types<size>::Elf_Swxword val)
   { p->put_r_addend(val); }
-
-  static inline void
-  copy_reloc_addend(Reloc_write* to, const Reloc* from)
-  { to->put_r_addend(from->get_r_addend()); }
 };
 
 }; // End namespace gold.
diff --git a/gold/reloc.cc b/gold/reloc.cc
index 3354019..b1a50e6 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -424,8 +424,8 @@ Sized_relobj_file<size, big_endian>::do_gc_process_relocs(Symbol_table* symtab,
 template<int size, bool big_endian>
 void
 Sized_relobj_file<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
-					       Layout* layout,
-					       Read_relocs_data* rd)
+						    Layout* layout,
+						    Read_relocs_data* rd)
 {
   Sized_target<size, big_endian>* target =
     parameters->sized_target<size, big_endian>();
@@ -501,41 +501,6 @@ Sized_relobj_file<size, big_endian>::do_scan_relocs(Symbol_table* symtab,
     }
 }
 
-// This is a strategy class we use when scanning for --emit-relocs.
-
-template<int sh_type>
-class Emit_relocs_strategy
-{
- public:
-  // A local non-section symbol.
-  inline Relocatable_relocs::Reloc_strategy
-  local_non_section_strategy(unsigned int, Relobj*, unsigned int)
-  { return Relocatable_relocs::RELOC_COPY; }
-
-  // A local section symbol.
-  inline Relocatable_relocs::Reloc_strategy
-  local_section_strategy(unsigned int, Relobj*)
-  {
-    if (sh_type == elfcpp::SHT_RELA)
-      return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
-    else
-      {
-	// The addend is stored in the section contents.  Since this
-	// is not a relocatable link, we are going to apply the
-	// relocation contents to the section as usual.  This means
-	// that we have no way to record the original addend.  If the
-	// original addend is not zero, there is basically no way for
-	// the user to handle this correctly.  Caveat emptor.
-	return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0;
-      }
-  }
-
-  // A global symbol.
-  inline Relocatable_relocs::Reloc_strategy
-  global_strategy(unsigned int, Relobj*, unsigned int)
-  { return Relocatable_relocs::RELOC_COPY; }
-};
-
 // Scan the input relocations for --emit-relocs.
 
 template<int size, bool big_endian>
@@ -546,40 +511,18 @@ Sized_relobj_file<size, big_endian>::emit_relocs_scan(
     const unsigned char* plocal_syms,
     const Read_relocs_data::Relocs_list::iterator& p)
 {
+  Sized_target<size, big_endian>* target =
+      parameters->sized_target<size, big_endian>();
+
   Relocatable_relocs* rr = this->relocatable_relocs(p->reloc_shndx);
   gold_assert(rr != NULL);
   rr->set_reloc_count(p->reloc_count);
-
-  if (p->sh_type == elfcpp::SHT_REL)
-    this->emit_relocs_scan_reltype<elfcpp::SHT_REL>(symtab, layout,
-						    plocal_syms, p, rr);
-  else
-    {
-      gold_assert(p->sh_type == elfcpp::SHT_RELA);
-      this->emit_relocs_scan_reltype<elfcpp::SHT_RELA>(symtab, layout,
-						       plocal_syms, p, rr);
-    }
-}
-
-// Scan the input relocation for --emit-relocs, templatized on the
-// type of the relocation section.
-
-template<int size, bool big_endian>
-template<int sh_type>
-void
-Sized_relobj_file<size, big_endian>::emit_relocs_scan_reltype(
-    Symbol_table* symtab,
-    Layout* layout,
-    const unsigned char* plocal_syms,
-    const Read_relocs_data::Relocs_list::iterator& p,
-    Relocatable_relocs* rr)
-{
-  scan_relocatable_relocs<size, big_endian, sh_type,
-			  Emit_relocs_strategy<sh_type> >(
+  target->emit_relocs_scan(
     symtab,
     layout,
     this,
     p->data_shndx,
+    p->sh_type,
     p->contents->data(),
     p->reloc_count,
     p->output_section,
@@ -628,8 +571,8 @@ Sized_relobj_file<size, big_endian>::incremental_relocs_scan_reltype(
 						         reloc.get_r_offset()))
 	continue;
 
-      typename elfcpp::Elf_types<size>::Elf_WXword r_info =
-	  reloc.get_r_info();
+      // FIXME: Some targets have a non-standard r_info field.
+      typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
       const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
 
       if (r_sym >= this->local_symbol_count_)
@@ -1025,7 +968,7 @@ Sized_relobj_file<size, big_endian>::do_relocate_sections(
 	  if ((data_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
 	    this->split_stack_adjust(symtab, pshdrs, sh_type, index,
 				     prelocs, reloc_count, view, view_size,
-				     &reloc_map);
+				     &reloc_map, target);
 	}
 
       Relocatable_relocs* rr = NULL;
@@ -1142,6 +1085,7 @@ Sized_relobj_file<size, big_endian>::incremental_relocs_write_reltype(
     {
       Reloc reloc(prelocs);
 
+      // FIXME: Some targets have a non-standard r_info field.
       typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
       const unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
       const unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
@@ -1240,20 +1184,21 @@ Sized_relobj_file<size, big_endian>::split_stack_adjust(
     size_t reloc_count,
     unsigned char* view,
     section_size_type view_size,
-    Reloc_symbol_changes** reloc_map)
+    Reloc_symbol_changes** reloc_map,
+    const Sized_target<size, big_endian>* target)
 {
   if (sh_type == elfcpp::SHT_REL)
     this->split_stack_adjust_reltype<elfcpp::SHT_REL>(symtab, pshdrs, shndx,
 						      prelocs, reloc_count,
 						      view, view_size,
-						      reloc_map);
+						      reloc_map, target);
   else
     {
       gold_assert(sh_type == elfcpp::SHT_RELA);
       this->split_stack_adjust_reltype<elfcpp::SHT_RELA>(symtab, pshdrs, shndx,
 							 prelocs, reloc_count,
 							 view, view_size,
-							 reloc_map);
+							 reloc_map, target);
     }
 }
 
@@ -1271,7 +1216,8 @@ Sized_relobj_file<size, big_endian>::split_stack_adjust_reltype(
     size_t reloc_count,
     unsigned char* view,
     section_size_type view_size,
-    Reloc_symbol_changes** reloc_map)
+    Reloc_symbol_changes** reloc_map,
+    const Sized_target<size, big_endian>* target)
 {
   typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
   const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
@@ -1283,10 +1229,10 @@ Sized_relobj_file<size, big_endian>::split_stack_adjust_reltype(
   const unsigned char* pr = prelocs;
   for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
     {
-      Reltype reloc(pr);
-
-      typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
-      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+      // Some supported targets have a non-standard r_info field.
+      // If this call is too slow, we can move this routine to
+      // target-reloc.h and templatize it on Classify_reloc.
+      unsigned int r_sym = target->get_r_sym(pr);
       if (r_sym < local_count)
 	continue;
 
@@ -1305,9 +1251,9 @@ Sized_relobj_file<size, big_endian>::split_stack_adjust_reltype(
 	  && gsym->source() == Symbol::FROM_OBJECT
 	  && !gsym->object()->uses_split_stack())
 	{
-	  unsigned int r_type = elfcpp::elf_r_type<size>(reloc.get_r_info());
-	  if (parameters->target().is_call_to_non_split(gsym, r_type))
+	  if (parameters->target().is_call_to_non_split(gsym, pr))
 	    {
+	      Reltype reloc(pr);
 	      section_offset_type offset =
 		convert_to_section_size_type(reloc.get_r_offset());
 	      non_split_refs.push_back(offset);
@@ -1378,9 +1324,7 @@ Sized_relobj_file<size, big_endian>::split_stack_adjust_reltype(
 	    {
 	      Reltype reloc(pr);
 
-	      typename elfcpp::Elf_types<size>::Elf_WXword r_info =
-		reloc.get_r_info();
-	      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+	      unsigned int r_sym = target->get_r_sym(pr);
 	      if (r_sym < local_count)
 		continue;
 
@@ -1600,11 +1544,9 @@ Track_relocs<size, big_endian>::next_symndx() const
 {
   if (this->pos_ >= this->len_)
     return -1U;
-
-  // Rel and Rela start out the same, so we can use Rel to find the
-  // symbol index.
-  elfcpp::Rel<size, big_endian> rel(this->prelocs_ + this->pos_);
-  return elfcpp::elf_r_sym<size>(rel.get_r_info());
+  Sized_target<size, big_endian>* target
+      = parameters->sized_target<size, big_endian>();
+  return target->get_r_sym(this->prelocs_ + this->pos_);
 }
 
 // Return the addend of the next reloc, or 0 if there isn't one.
diff --git a/gold/s390.cc b/gold/s390.cc
index eb92fb7..2671441 100644
--- a/gold/s390.cc
+++ b/gold/s390.cc
@@ -348,6 +348,21 @@ class Target_s390 : public Sized_target<size, true>
 			  const unsigned char* plocal_symbols,
 			  Relocatable_relocs*);
 
+  // Scan the relocs for --emit-relocs.
+  void
+  emit_relocs_scan(Symbol_table* symtab,
+		   Layout* layout,
+		   Sized_relobj_file<size, true>* object,
+		   unsigned int data_shndx,
+		   unsigned int sh_type,
+		   const unsigned char* prelocs,
+		   size_t reloc_count,
+		   Output_section* output_section,
+		   bool needs_special_offset_handling,
+		   size_t local_symbol_count,
+		   const unsigned char* plocal_syms,
+		   Relocatable_relocs* rr);
+
   // Return a string used to fill a code section with nops.
   std::string
   do_code_fill(section_size_type length) const;
@@ -596,15 +611,6 @@ class Target_s390 : public Sized_target<size, true>
 		 section_size_type view_size);
   };
 
-  // A class which returns the size required for a relocation type,
-  // used while scanning relocs during a relocatable link.
-  class Relocatable_size_for_reloc
-  {
-   public:
-    unsigned int
-    get_size_for_reloc(unsigned int, Relobj*);
-  };
-
   // Adjust TLS relocation type based on the options and whether this
   // is a local symbol.
   static tls::Tls_optimization
@@ -3086,13 +3092,13 @@ Target_s390<size>::gc_process_relocs(Symbol_table* symtab,
 				       size_t local_symbol_count,
 				       const unsigned char* plocal_symbols)
 {
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, true>
+      Classify_reloc;
 
   if (sh_type == elfcpp::SHT_REL)
     return;
 
-  gold::gc_process_relocs<size, true, Target_s390<size>, elfcpp::SHT_RELA,
-			  typename Target_s390<size>::Scan,
-			  typename Target_s390<size>::Relocatable_size_for_reloc>(
+  gold::gc_process_relocs<size, true, Target_s390<size>, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -3924,6 +3930,9 @@ Target_s390<size>::scan_relocs(Symbol_table* symtab,
 				 size_t local_symbol_count,
 				 const unsigned char* plocal_symbols)
 {
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, true>
+      Classify_reloc;
+
   if (sh_type == elfcpp::SHT_REL)
     {
       gold_error(_("%s: unsupported REL reloc section"),
@@ -3931,8 +3940,7 @@ Target_s390<size>::scan_relocs(Symbol_table* symtab,
       return;
     }
 
-  gold::scan_relocs<size, true, Target_s390<size>, elfcpp::SHT_RELA,
-      typename Target_s390<size>::Scan>(
+  gold::scan_relocs<size, true, Target_s390<size>, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -4019,113 +4027,50 @@ Target_s390<size>::do_finalize_sections(
     }
 }
 
-// Return the size of a relocation while scanning during a relocatable
-// link.
+// Scan the relocs during a relocatable link.
 
 template<int size>
-unsigned int
-Target_s390<size>::Relocatable_size_for_reloc::get_size_for_reloc(
-    unsigned int r_type,
-    Relobj* object)
+void
+Target_s390<size>::scan_relocatable_relocs(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<size, true>* object,
+    unsigned int data_shndx,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    size_t local_symbol_count,
+    const unsigned char* plocal_symbols,
+    Relocatable_relocs* rr)
 {
-  switch (r_type)
-    {
-    case elfcpp::R_390_NONE:
-    case elfcpp::R_390_GNU_VTINHERIT:
-    case elfcpp::R_390_GNU_VTENTRY:
-    case elfcpp::R_390_TLS_GD32:          // Global-dynamic
-    case elfcpp::R_390_TLS_GD64:
-    case elfcpp::R_390_TLS_GDCALL:
-    case elfcpp::R_390_TLS_LDM32:         // Local-dynamic
-    case elfcpp::R_390_TLS_LDM64:
-    case elfcpp::R_390_TLS_LDO32:
-    case elfcpp::R_390_TLS_LDO64:
-    case elfcpp::R_390_TLS_LDCALL:
-    case elfcpp::R_390_TLS_IE32:          // Initial-exec
-    case elfcpp::R_390_TLS_IE64:
-    case elfcpp::R_390_TLS_IEENT:
-    case elfcpp::R_390_TLS_GOTIE12:
-    case elfcpp::R_390_TLS_GOTIE20:
-    case elfcpp::R_390_TLS_GOTIE32:
-    case elfcpp::R_390_TLS_GOTIE64:
-    case elfcpp::R_390_TLS_LOAD:
-    case elfcpp::R_390_TLS_LE32:          // Local-exec
-    case elfcpp::R_390_TLS_LE64:
-      return 0;
-
-    case elfcpp::R_390_64:
-    case elfcpp::R_390_PC64:
-    case elfcpp::R_390_GOT64:
-    case elfcpp::R_390_PLT64:
-    case elfcpp::R_390_GOTOFF64:
-    case elfcpp::R_390_GOTPLT64:
-    case elfcpp::R_390_PLTOFF64:
-      return 8;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, true>
+      Classify_reloc;
+  typedef gold::Default_scan_relocatable_relocs<Classify_reloc>
+      Scan_relocatable_relocs;
 
-    case elfcpp::R_390_32:
-    case elfcpp::R_390_PC32:
-    case elfcpp::R_390_GOT32:
-    case elfcpp::R_390_PLT32:
-    case elfcpp::R_390_GOTOFF32:
-    case elfcpp::R_390_GOTPC:
-    case elfcpp::R_390_PC32DBL:
-    case elfcpp::R_390_PLT32DBL:
-    case elfcpp::R_390_GOTPCDBL:
-    case elfcpp::R_390_GOTENT:
-    case elfcpp::R_390_GOTPLT32:
-    case elfcpp::R_390_GOTPLTENT:
-    case elfcpp::R_390_PLTOFF32:
-    case elfcpp::R_390_20:
-    case elfcpp::R_390_GOT20:
-    case elfcpp::R_390_GOTPLT20:
-      return 4;
-
-    case elfcpp::R_390_PC24DBL:
-    case elfcpp::R_390_PLT24DBL:
-      return 3;
-
-    case elfcpp::R_390_12:
-    case elfcpp::R_390_GOT12:
-    case elfcpp::R_390_GOTPLT12:
-    case elfcpp::R_390_PC12DBL:
-    case elfcpp::R_390_PLT12DBL:
-    case elfcpp::R_390_16:
-    case elfcpp::R_390_GOT16:
-    case elfcpp::R_390_PC16:
-    case elfcpp::R_390_PC16DBL:
-    case elfcpp::R_390_PLT16DBL:
-    case elfcpp::R_390_GOTOFF16:
-    case elfcpp::R_390_GOTPLT16:
-    case elfcpp::R_390_PLTOFF16:
-      return 2;
-
-    case elfcpp::R_390_8:
-      return 1;
-
-      // These are relocations which should only be seen by the
-      // dynamic linker, and should never be seen here.
-    case elfcpp::R_390_COPY:
-    case elfcpp::R_390_GLOB_DAT:
-    case elfcpp::R_390_JMP_SLOT:
-    case elfcpp::R_390_RELATIVE:
-    case elfcpp::R_390_IRELATIVE:
-    case elfcpp::R_390_TLS_DTPMOD:
-    case elfcpp::R_390_TLS_DTPOFF:
-    case elfcpp::R_390_TLS_TPOFF:
-      object->error(_("unexpected reloc %u in object file"), r_type);
-      return 0;
+  gold_assert(sh_type == elfcpp::SHT_RELA);
 
-    default:
-      object->error(_("unsupported reloc %u in object file"), r_type);
-      return 0;
-    }
+  gold::scan_relocatable_relocs<size, true, Scan_relocatable_relocs>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols,
+    rr);
 }
 
-// Scan the relocs during a relocatable link.
+// Scan the relocs for --emit-relocs.
 
 template<int size>
 void
-Target_s390<size>::scan_relocatable_relocs(
+Target_s390<size>::emit_relocs_scan(
     Symbol_table* symtab,
     Layout* layout,
     Sized_relobj_file<size, true>* object,
@@ -4136,16 +4081,17 @@ Target_s390<size>::scan_relocatable_relocs(
     Output_section* output_section,
     bool needs_special_offset_handling,
     size_t local_symbol_count,
-    const unsigned char* plocal_symbols,
+    const unsigned char* plocal_syms,
     Relocatable_relocs* rr)
 {
-  gold_assert(sh_type == elfcpp::SHT_RELA);
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, true>
+      Classify_reloc;
+  typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+      Emit_relocs_strategy;
 
-  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
-    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+  gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::scan_relocatable_relocs<size, true, elfcpp::SHT_RELA,
-      Scan_relocatable_relocs>(
+  gold::scan_relocatable_relocs<size, true, Emit_relocs_strategy>(
     symtab,
     layout,
     object,
@@ -4155,7 +4101,7 @@ Target_s390<size>::scan_relocatable_relocs(
     output_section,
     needs_special_offset_handling,
     local_symbol_count,
-    plocal_symbols,
+    plocal_syms,
     rr);
 }
 
@@ -4176,9 +4122,12 @@ Target_s390<size>::relocate_relocs(
     unsigned char* reloc_view,
     section_size_type reloc_view_size)
 {
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, true>
+      Classify_reloc;
+
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::relocate_relocs<size, true, elfcpp::SHT_RELA>(
+  gold::relocate_relocs<size, true, Classify_reloc>(
     relinfo,
     prelocs,
     reloc_count,
@@ -4259,11 +4208,13 @@ Target_s390<size>::relocate_section(
     section_size_type view_size,
     const Reloc_symbol_changes* reloc_symbol_changes)
 {
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, true>
+      Classify_reloc;
+
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::relocate_section<size, true, Target_s390<size>, elfcpp::SHT_RELA,
-			 typename Target_s390<size>::Relocate,
-			 gold::Default_comdat_behavior>(
+  gold::relocate_section<size, true, Target_s390<size>, Relocate,
+			 gold::Default_comdat_behavior, Classify_reloc>(
     relinfo,
     this,
     prelocs,
diff --git a/gold/sparc.cc b/gold/sparc.cc
index 049e0ab..c97c32c 100644
--- a/gold/sparc.cc
+++ b/gold/sparc.cc
@@ -131,6 +131,21 @@ class Target_sparc : public Sized_target<size, big_endian>
 			  const unsigned char* plocal_symbols,
 			  Relocatable_relocs*);
 
+  // Scan the relocs for --emit-relocs.
+  void
+  emit_relocs_scan(Symbol_table* symtab,
+		   Layout* layout,
+		   Sized_relobj_file<size, big_endian>* object,
+		   unsigned int data_shndx,
+		   unsigned int sh_type,
+		   const unsigned char* prelocs,
+		   size_t reloc_count,
+		   Output_section* output_section,
+		   bool needs_special_offset_handling,
+		   size_t local_symbol_count,
+		   const unsigned char* plocal_syms,
+		   Relocatable_relocs* rr);
+
   // Emit relocations for a section.
   void
   relocate_relocs(const Relocate_info<size, big_endian>*,
@@ -345,15 +360,6 @@ class Target_sparc : public Sized_target<size, big_endian>
     unsigned char *reloc_adjust_addr_;
   };
 
-  // A class which returns the size required for a relocation type,
-  // used while scanning relocs during a relocatable link.
-  class Relocatable_size_for_reloc
-  {
-   public:
-    unsigned int
-    get_size_for_reloc(unsigned int, Relobj*);
-  };
-
   // Get the GOT section, creating it if necessary.
   Output_data_got<size, big_endian>*
   got_section(Symbol_table*, Layout*);
@@ -3036,9 +3042,10 @@ Target_sparc<size, big_endian>::gc_process_relocs(
 {
   typedef Target_sparc<size, big_endian> Sparc;
   typedef typename Target_sparc<size, big_endian>::Scan Scan;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
 
-  gold::gc_process_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan,
-			  typename Target_sparc::Relocatable_size_for_reloc>(
+  gold::gc_process_relocs<size, big_endian, Sparc, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -3070,7 +3077,8 @@ Target_sparc<size, big_endian>::scan_relocs(
 			const unsigned char* plocal_symbols)
 {
   typedef Target_sparc<size, big_endian> Sparc;
-  typedef typename Target_sparc<size, big_endian>::Scan Scan;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
 
   if (sh_type == elfcpp::SHT_REL)
     {
@@ -3079,7 +3087,7 @@ Target_sparc<size, big_endian>::scan_relocs(
       return;
     }
 
-  gold::scan_relocs<size, big_endian, Sparc, elfcpp::SHT_RELA, Scan>(
+  gold::scan_relocs<size, big_endian, Sparc, Scan, Classify_reloc>(
     symtab,
     layout,
     this,
@@ -4142,11 +4150,13 @@ Target_sparc<size, big_endian>::relocate_section(
 {
   typedef Target_sparc<size, big_endian> Sparc;
   typedef typename Target_sparc<size, big_endian>::Relocate Sparc_relocate;
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
 
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::relocate_section<size, big_endian, Sparc, elfcpp::SHT_RELA,
-			 Sparc_relocate, gold::Default_comdat_behavior>(
+  gold::relocate_section<size, big_endian, Sparc, Sparc_relocate,
+			 gold::Default_comdat_behavior, Classify_reloc>(
     relinfo,
     this,
     prelocs,
@@ -4159,20 +4169,6 @@ Target_sparc<size, big_endian>::relocate_section(
     reloc_symbol_changes);
 }
 
-// Return the size of a relocation while scanning during a relocatable
-// link.
-
-template<int size, bool big_endian>
-unsigned int
-Target_sparc<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
-    unsigned int,
-    Relobj*)
-{
-  // We are always SHT_RELA, so we should never get here.
-  gold_unreachable();
-  return 0;
-}
-
 // Scan the relocs during a relocatable link.
 
 template<int size, bool big_endian>
@@ -4191,13 +4187,14 @@ Target_sparc<size, big_endian>::scan_relocatable_relocs(
 			const unsigned char* plocal_symbols,
 			Relocatable_relocs* rr)
 {
-  gold_assert(sh_type == elfcpp::SHT_RELA);
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_scan_relocatable_relocs<Classify_reloc>
+      Scan_relocatable_relocs;
 
-  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
-    Relocatable_size_for_reloc> Scan_relocatable_relocs;
+  gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_RELA,
-      Scan_relocatable_relocs>(
+  gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
     symtab,
     layout,
     object,
@@ -4211,6 +4208,45 @@ Target_sparc<size, big_endian>::scan_relocatable_relocs(
     rr);
 }
 
+// Scan the relocs for --emit-relocs.
+
+template<int size, bool big_endian>
+void
+Target_sparc<size, big_endian>::emit_relocs_scan(
+    Symbol_table* symtab,
+    Layout* layout,
+    Sized_relobj_file<size, big_endian>* object,
+    unsigned int data_shndx,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    size_t local_symbol_count,
+    const unsigned char* plocal_syms,
+    Relocatable_relocs* rr)
+{
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+  typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+      Emit_relocs_strategy;
+
+  gold_assert(sh_type == elfcpp::SHT_RELA);
+
+  gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
+    symtab,
+    layout,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_syms,
+    rr);
+}
+
 // Emit relocations for a section.
 
 template<int size, bool big_endian>
@@ -4228,9 +4264,12 @@ Target_sparc<size, big_endian>::relocate_relocs(
     unsigned char* reloc_view,
     section_size_type reloc_view_size)
 {
+  typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+      Classify_reloc;
+
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  gold::relocate_relocs<size, big_endian, elfcpp::SHT_RELA>(
+  gold::relocate_relocs<size, big_endian, Classify_reloc>(
     relinfo,
     prelocs,
     reloc_count,
diff --git a/gold/target-reloc.h b/gold/target-reloc.h
index cec5ee1..bdf673d 100644
--- a/gold/target-reloc.h
+++ b/gold/target-reloc.h
@@ -39,8 +39,8 @@ namespace gold
 // avoid making a function call for each relocation, and to avoid
 // repeating the generic code for each target.
 
-template<int size, bool big_endian, typename Target_type, int sh_type,
-	 typename Scan>
+template<int size, bool big_endian, typename Target_type,
+	 typename Scan, typename Classify[...]

[diff truncated at 100000 bytes]


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