2010-04-18 Sriraman Tallam <tmsriram@google.com>
[deliverable/binutils-gdb.git] / gold / x86_64.cc
index fea2ec9b914836fd41c7d1739e7b9ab4611b9f2b..9110278ebb8414ef2dcccc822734202aad21a320 100644 (file)
@@ -39,6 +39,7 @@
 #include "tls.h"
 #include "freebsd.h"
 #include "gc.h"
+#include "icf.h"
 
 namespace
 {
@@ -69,6 +70,16 @@ class Target_x86_64 : public Target_freebsd<64, false>
       tls_base_symbol_defined_(false)
   { }
 
+  // This function should be defined in targets that can use relocation
+  // types to determine (implemented in local_reloc_may_be_function_pointer
+  // and global_reloc_may_be_function_pointer)
+  // if a function's pointer is taken.  ICF uses this in safe mode to only
+  // fold those functions whose pointer is defintely not taken.  For x86_64
+  // pie binaries, safe ICF cannot be done by looking at relocation types.
+  inline bool
+  can_check_for_function_pointers() const
+  { return !parameters->options().pie(); }
+
   // Hook for a new output section.
   void
   do_new_output_section(Output_section*) const;
@@ -224,6 +235,26 @@ class Target_x86_64 : public Target_freebsd<64, false>
           const elfcpp::Rela<64, false>& reloc, unsigned int r_type,
           Symbol* gsym);
 
+    inline bool
+    local_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
+                                       Target_x86_64* target,
+                                       Sized_relobj<64, false>* object,
+                                       unsigned int data_shndx,
+                                       Output_section* output_section,
+                                       const elfcpp::Rela<64, false>& reloc,
+                                       unsigned int r_type,
+                                       const elfcpp::Sym<64, false>& lsym);
+
+    inline bool
+    global_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
+                                        Target_x86_64* target,
+                                        Sized_relobj<64, false>* object,
+                                        unsigned int data_shndx,
+                                        Output_section* output_section,
+                                        const elfcpp::Rela<64, false>& reloc,
+                                        unsigned int r_type,
+                                        Symbol* gsym);
+
   private:
     static void
     unsupported_reloc_local(Sized_relobj<64, false>*, unsigned int r_type);
@@ -235,6 +266,9 @@ class Target_x86_64 : public Target_freebsd<64, false>
     void
     check_non_pic(Relobj*, unsigned int r_type);
 
+    inline bool
+    possible_function_pointer_reloc(unsigned int r_type);
+
     // Whether we have issued an error about a non-PIC compilation.
     bool issued_non_pic_error_;
   };
@@ -1364,6 +1398,77 @@ Target_x86_64::Scan::unsupported_reloc_global(Sized_relobj<64, false>* object,
             object->name().c_str(), r_type, gsym->demangled_name().c_str());
 }
 
+// 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));
+}
+
 // Scan a relocation for a global symbol.
 
 inline void
@@ -2053,7 +2158,7 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
   elfcpp::Elf_types<64>::Elf_Addr value = psymval->value(relinfo->object, 0);
 
   const bool is_final = (gsym == NULL
-                        ? !parameters->options().output_is_position_independent()
+                        ? !parameters->options().shared()
                         : gsym->final_value_is_known());
   const tls::Tls_optimization optimized_type
       = Target_x86_64::optimize_tls_reloc(is_final, r_type);
This page took 0.024849 seconds and 4 git commands to generate.