From 4d625b70fc3fb7facc7159feb8d49b78ac6641f9 Mon Sep 17 00:00:00 2001 From: Cary Coutant Date: Fri, 11 Dec 2015 07:43:59 -0800 Subject: 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. --- gold/target-reloc.h | 216 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 164 insertions(+), 52 deletions(-) (limited to 'gold/target-reloc.h') 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 +template inline void scan_relocs( Symbol_table* symtab, @@ -55,8 +55,8 @@ scan_relocs( size_t local_count, const unsigned char* plocal_syms) { - typedef typename Reloc_types::Reloc Reltype; - const int reloc_size = Reloc_types::reloc_size; + typedef typename Classify_reloc::Reltype Reltype; + const int reloc_size = Classify_reloc::reloc_size; const int sym_size = elfcpp::Elf_sizes::sym_size; Scan scan; @@ -69,9 +69,8 @@ scan_relocs( reloc.get_r_offset())) continue; - typename elfcpp::Elf_types::Elf_WXword r_info = reloc.get_r_info(); - unsigned int r_sym = elfcpp::elf_r_sym(r_info); - unsigned int r_type = elfcpp::elf_r_type(r_info); + unsigned int r_sym = Classify_reloc::get_r_sym(&reloc); + unsigned int r_type = Classify_reloc::get_r_type(&reloc); if (r_sym < local_count) { @@ -253,9 +252,10 @@ issue_undefined_symbol_error(const Symbol* sym) // symbol for the relocation, ignoring the symbol index in the // relocation. -template + typename Relocate_comdat_behavior, + typename Classify_reloc> inline void relocate_section( const Relocate_info* relinfo, @@ -269,8 +269,8 @@ relocate_section( section_size_type view_size, const Reloc_symbol_changes* reloc_symbol_changes) { - typedef typename Reloc_types::Reloc Reltype; - const int reloc_size = Reloc_types::reloc_size; + typedef typename Classify_reloc::Reltype Reltype; + const int reloc_size = Classify_reloc::reloc_size; Relocate relocate; Relocate_comdat_behavior relocate_comdat_behavior; @@ -295,8 +295,7 @@ relocate_section( continue; } - typename elfcpp::Elf_types::Elf_WXword r_info = reloc.get_r_info(); - unsigned int r_sym = elfcpp::elf_r_sym(r_info); + unsigned int r_sym = Classify_reloc::get_r_sym(&reloc); const Sized_symbol* sym; @@ -399,8 +398,8 @@ relocate_section( if (offset < 0 || static_cast(offset) >= view_size) v = NULL; - if (!relocate.relocate(relinfo, sh_type, target, output_section, - i, prelocs, sym, psymval, + if (!relocate.relocate(relinfo, Classify_reloc::sh_type, target, + output_section, i, prelocs, sym, psymval, v, view_address + offset, view_size)) continue; @@ -464,18 +463,90 @@ apply_relocation(const Relocate_info* relinfo, view + r_offset, address + r_offset, view_size); } +// A class for inquiring about properties of a relocation, +// used while scanning relocs during a relocatable link and +// garbage collection. This class may be used as the default +// for SHT_RELA targets, but SHT_REL targets must implement +// a derived class that overrides get_size_for_reloc. +// The MIPS-64 target also needs to override the methods +// for accessing the r_sym and r_type fields of a relocation, +// due to its non-standard use of the r_info field. + +template +class Default_classify_reloc +{ + public: + typedef typename Reloc_types::Reloc + Reltype; + typedef typename Reloc_types::Reloc_write + Reltype_write; + static const int reloc_size = + Reloc_types::reloc_size; + static const int sh_type = sh_type_; + + // Return the symbol referred to by the relocation. + static inline unsigned int + get_r_sym(const Reltype* reloc) + { return elfcpp::elf_r_sym(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(reloc->get_r_info()); } + + // Return the explicit addend of the relocation (return 0 for SHT_REL). + static inline typename elfcpp::Elf_types::Elf_Swxword + get_r_addend(const Reltype* reloc) + { return Reloc_types::get_reloc_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(reloc->get_r_info()); + new_reloc->put_r_info(elfcpp::elf_r_info(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::Elf_Swxword addend) + { Reloc_types::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, Relobj*) + { + gold_unreachable(); + return 0; + } +}; + // This class may be used as a typical class for the -// Scan_relocatable_reloc parameter to scan_relocatable_relocs. The -// template parameter Classify_reloc must be a class type which -// provides a function get_size_for_reloc which returns the number of -// bytes to which a reloc applies. This class is intended to capture -// the most typical target behaviour, while still permitting targets -// to define their own independent class for Scan_relocatable_reloc. - -template +// Scan_relocatable_reloc parameter to scan_relocatable_relocs. +// This class is intended to capture the most typical target behaviour, +// while still permitting targets to define their own independent class +// for Scan_relocatable_reloc. + +template class Default_scan_relocatable_relocs { public: + typedef typename Classify_reloc::Reltype Reltype; + static const int reloc_size = Classify_reloc::reloc_size; + static const int sh_type = Classify_reloc::sh_type; + + // Return the symbol referred to by the relocation. + static inline unsigned int + get_r_sym(const Reltype* reloc) + { return Classify_reloc::get_r_sym(reloc); } + + // Return the type of the relocation. + static inline unsigned int + get_r_type(const Reltype* reloc) + { return Classify_reloc::get_r_type(reloc); } + // Return the strategy to use for a local symbol which is not a // section symbol, given the relocation type. inline Relocatable_relocs::Reloc_strategy @@ -497,8 +568,7 @@ class Default_scan_relocatable_relocs return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA; else { - Classify_reloc classify; - switch (classify.get_size_for_reloc(r_type, object)) + switch (Classify_reloc::get_size_for_reloc(r_type, object)) { case 0: return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0; @@ -523,6 +593,56 @@ class Default_scan_relocatable_relocs { return Relocatable_relocs::RELOC_COPY; } }; +// This is a strategy class used with scan_relocatable_relocs +// and --emit-relocs. + +template +class Default_emit_relocs_strategy +{ + public: + typedef typename Classify_reloc::Reltype Reltype; + static const int reloc_size = Classify_reloc::reloc_size; + static const int sh_type = Classify_reloc::sh_type; + + // Return the symbol referred to by the relocation. + static inline unsigned int + get_r_sym(const Reltype* reloc) + { return Classify_reloc::get_r_sym(reloc); } + + // Return the type of the relocation. + static inline unsigned int + get_r_type(const Reltype* reloc) + { return Classify_reloc::get_r_type(reloc); } + + // 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 relocs during a relocatable link. This is a default // definition which should work for most targets. // Scan_relocatable_reloc must name a class type which provides three @@ -531,8 +651,7 @@ class Default_scan_relocatable_relocs // local_section_strategy. Most targets should be able to use // Default_scan_relocatable_relocs as this class. -template +template void scan_relocatable_relocs( Symbol_table*, @@ -547,8 +666,8 @@ scan_relocatable_relocs( const unsigned char* plocal_syms, Relocatable_relocs* rr) { - typedef typename Reloc_types::Reloc Reltype; - const int reloc_size = Reloc_types::reloc_size; + typedef typename Scan_relocatable_reloc::Reltype Reltype; + const int reloc_size = Scan_relocatable_reloc::reloc_size; const int sym_size = elfcpp::Elf_sizes::sym_size; Scan_relocatable_reloc scan; @@ -564,10 +683,9 @@ scan_relocatable_relocs( strategy = Relocatable_relocs::RELOC_DISCARD; else { - typename elfcpp::Elf_types::Elf_WXword r_info = - reloc.get_r_info(); - const unsigned int r_sym = elfcpp::elf_r_sym(r_info); - const unsigned int r_type = elfcpp::elf_r_type(r_info); + const unsigned int r_sym = Scan_relocatable_reloc::get_r_sym(&reloc); + const unsigned int r_type = + Scan_relocatable_reloc::get_r_type(&reloc); if (r_sym >= local_symbol_count) strategy = scan.global_strategy(r_type, object, r_sym); @@ -610,7 +728,7 @@ scan_relocatable_relocs( // Relocate relocs. Called for a relocatable link, and for --emit-relocs. // This is a default definition which should work for most targets. -template +template void relocate_relocs( const Relocate_info* relinfo, @@ -625,10 +743,9 @@ relocate_relocs( section_size_type reloc_view_size) { typedef typename elfcpp::Elf_types::Elf_Addr Address; - typedef typename Reloc_types::Reloc Reltype; - typedef typename Reloc_types::Reloc_write - Reltype_write; - const int reloc_size = Reloc_types::reloc_size; + typedef typename Classify_reloc::Reltype Reltype; + typedef typename Classify_reloc::Reltype_write Reltype_write; + const int reloc_size = Classify_reloc::reloc_size; const Address invalid_address = static_cast
(0) - 1; Sized_relobj_file* const object = relinfo->object; @@ -647,8 +764,8 @@ relocate_relocs( // Target wants to handle this relocation. Sized_target* target = parameters->sized_target(); - target->relocate_special_relocatable(relinfo, sh_type, prelocs, - i, output_section, + target->relocate_special_relocatable(relinfo, Classify_reloc::sh_type, + prelocs, i, output_section, offset_in_output_section, view, view_address, view_size, pwrite); @@ -658,9 +775,7 @@ relocate_relocs( Reltype reloc(prelocs); Reltype_write reloc_write(pwrite); - typename elfcpp::Elf_types::Elf_WXword r_info = reloc.get_r_info(); - const unsigned int r_sym = elfcpp::elf_r_sym(r_info); - const unsigned int r_type = elfcpp::elf_r_type(r_info); + const unsigned int r_sym = Classify_reloc::get_r_sym(&reloc); // Get the new symbol index. @@ -748,16 +863,15 @@ relocate_relocs( } reloc_write.put_r_offset(new_offset); - reloc_write.put_r_info(elfcpp::elf_r_info(new_symndx, r_type)); + Classify_reloc::put_r_info(&reloc_write, &reloc, new_symndx); // Handle the reloc addend based on the strategy. if (strategy == Relocatable_relocs::RELOC_COPY) { - if (sh_type == elfcpp::SHT_RELA) - Reloc_types:: - copy_reloc_addend(&reloc_write, - &reloc); + if (Classify_reloc::sh_type == elfcpp::SHT_RELA) + Classify_reloc::put_r_addend(&reloc_write, + Classify_reloc::get_r_addend(&reloc)); } else { @@ -777,12 +891,10 @@ relocate_relocs( case Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA: { typename elfcpp::Elf_types::Elf_Swxword addend; - addend = Reloc_types:: - get_reloc_addend(&reloc); + addend = Classify_reloc::get_r_addend(&reloc); gold_assert(os != NULL); addend = psymval->value(object, addend) - os->address(); - Reloc_types:: - set_reloc_addend(&reloc_write, addend); + Classify_reloc::put_r_addend(&reloc_write, addend); } break; -- cgit v1.1