+// Apply an incremental relocation.
+
+template<int size, bool big_endian, typename Target_type,
+ typename Relocate>
+void
+apply_relocation(const Relocate_info<size, big_endian>* relinfo,
+ Target_type* target,
+ typename elfcpp::Elf_types<size>::Elf_Addr r_offset,
+ unsigned int r_type,
+ typename elfcpp::Elf_types<size>::Elf_Swxword r_addend,
+ const Symbol* gsym,
+ unsigned char* view,
+ typename elfcpp::Elf_types<size>::Elf_Addr address,
+ section_size_type view_size)
+{
+ // Construct the ELF relocation in a temporary buffer.
+ const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+ unsigned char relbuf[reloc_size];
+ elfcpp::Rela_write<size, big_endian> orel(relbuf);
+ orel.put_r_offset(r_offset);
+ orel.put_r_info(elfcpp::elf_r_info<size>(0, r_type));
+ orel.put_r_addend(r_addend);
+
+ // Setup a Symbol_value for the global symbol.
+ const Sized_symbol<size>* sym = static_cast<const Sized_symbol<size>*>(gsym);
+ Symbol_value<size> symval;
+ gold_assert(sym->has_symtab_index() && sym->symtab_index() != -1U);
+ symval.set_output_symtab_index(sym->symtab_index());
+ symval.set_output_value(sym->value());
+ if (gsym->type() == elfcpp::STT_TLS)
+ symval.set_is_tls_symbol();
+ else if (gsym->type() == elfcpp::STT_GNU_IFUNC)
+ symval.set_is_ifunc_symbol();
+
+ Relocate relocate;
+ relocate.relocate(relinfo, elfcpp::SHT_RELA, target, NULL,
+ -1U, relbuf, sym, &symval,
+ 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<int sh_type_, int size, bool big_endian>
+class Default_classify_reloc
+{
+ public:
+ typedef typename Reloc_types<sh_type_, size, big_endian>::Reloc
+ Reltype;
+ typedef typename Reloc_types<sh_type_, size, big_endian>::Reloc_write
+ Reltype_write;
+ static const int reloc_size =
+ Reloc_types<sh_type_, size, big_endian>::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<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 explicit addend of the relocation (return 0 for SHT_REL).
+ static inline typename elfcpp::Elf_types<size>::Elf_Swxword
+ get_r_addend(const Reltype* reloc)
+ { return Reloc_types<sh_type_, size, big_endian>::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<size>(reloc->get_r_info());
+ new_reloc->put_r_info(elfcpp::elf_r_info<size>(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<size>::Elf_Swxword addend)
+ { Reloc_types<sh_type_, size, 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, Relobj*)
+ {
+ gold_unreachable();
+ return 0;
+ }
+};
+