+// Returns true if this relocation type could be that of a function pointer.
+inline bool
+Target_x86_64::Scan::possible_function_pointer_reloc(unsigned int r_type)
+{
+ switch (r_type)
+ {
+ case elfcpp::R_X86_64_64:
+ case elfcpp::R_X86_64_32:
+ case elfcpp::R_X86_64_32S:
+ case elfcpp::R_X86_64_16:
+ case elfcpp::R_X86_64_8:
+ case elfcpp::R_X86_64_GOT64:
+ case elfcpp::R_X86_64_GOT32:
+ case elfcpp::R_X86_64_GOTPCREL64:
+ case elfcpp::R_X86_64_GOTPCREL:
+ case elfcpp::R_X86_64_GOTPLT64:
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+// For safe ICF, scan a relocation for a local symbol to check if it
+// corresponds to a function pointer being taken. In that case mark
+// the function whose pointer was taken as not foldable.
+
+inline bool
+Target_x86_64::Scan::local_reloc_may_be_function_pointer(
+ Symbol_table* ,
+ Layout* ,
+ Target_x86_64* ,
+ Sized_relobj<64, false>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<64, false>& ,
+ unsigned int r_type,
+ const elfcpp::Sym<64, false>&)
+{
+ // When building a shared library, do not fold any local symbols as it is
+ // not possible to distinguish pointer taken versus a call by looking at
+ // the relocation types.
+ return (parameters->options().shared()
+ || possible_function_pointer_reloc(r_type));
+}
+
+// For safe ICF, scan a relocation for a global symbol to check if it
+// corresponds to a function pointer being taken. In that case mark
+// the function whose pointer was taken as not foldable.
+
+inline bool
+Target_x86_64::Scan::global_reloc_may_be_function_pointer(
+ Symbol_table*,
+ Layout* ,
+ Target_x86_64* ,
+ Sized_relobj<64, false>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<64, false>& ,
+ unsigned int r_type,
+ Symbol* gsym)
+{
+ // When building a shared library, do not fold symbols whose visibility
+ // is hidden, internal or protected.
+ return ((parameters->options().shared()
+ && (gsym->visibility() == elfcpp::STV_INTERNAL
+ || gsym->visibility() == elfcpp::STV_PROTECTED
+ || gsym->visibility() == elfcpp::STV_HIDDEN))
+ || possible_function_pointer_reloc(r_type));
+}
+