Remove powerpc.cc copy of use_plt_offset
authorAlan Modra <amodra@gmail.com>
Fri, 1 Nov 2013 05:39:56 +0000 (16:09 +1030)
committerAlan Modra <amodra@gmail.com>
Mon, 4 Nov 2013 05:30:13 +0000 (16:00 +1030)
This adds an extra flag for needs_dynamic_reloc() in order to remove
the copy of this function and use_plt_offset() in powerpc.cc, and
tweaks the powerpc get_reference_flags() to return the flag as
appropriate.  ELFv2 does not want ELFv1 behaviour here.

* symtab.h (Symbol::Reference_flags): Add FUNC_DESC_ABI.
(Symbol::needs_dynamic_reloc): Test new flag.
* powerpc.cc (needs_dynamic_reloc, use_plt_offset): Delete.
(Target_powerpc::Scan::get_reference_flags): Add target param.
Return FUNC_DESC_ABI for 64-bit ELFv1.
(Target_powerpc::Branch_info::make_stub): Adjust get_reference_flags
call.
(Target_powerpc::Scan::global): Use Symbol::needs_dynamic_reloc.
(Target_powerpc::Relocate::relocate): Use Symbol::use_plt_offset.

gold/powerpc.cc
gold/symtab.h

index 0d6822d03bdd42ade74d38021d6cf48cc69ef158..ada4d0c010c4f913270ea7664b9635a67eb5dce9 100644 (file)
@@ -918,7 +918,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
     { }
 
     static inline int
-    get_reference_flags(unsigned int r_type);
+    get_reference_flags(unsigned int r_type, const Target_powerpc* target);
 
     inline void
     local(Symbol_table* symtab, Layout* layout, Target_powerpc* target,
@@ -1429,102 +1429,6 @@ at_tls_transform(uint32_t insn, unsigned int reg)
   return insn;
 }
 
-// Modified version of symtab.h class Symbol member
-// Given a direct absolute or pc-relative static relocation against
-// the global symbol, this function returns whether a dynamic relocation
-// is needed.
-
-template<int size>
-bool
-needs_dynamic_reloc(const Symbol* gsym, int flags)
-{
-  // No dynamic relocations in a static link!
-  if (parameters->doing_static_link())
-    return false;
-
-  // A reference to an undefined symbol from an executable should be
-  // statically resolved to 0, and does not need a dynamic relocation.
-  // This matches gnu ld behavior.
-  if (gsym->is_undefined() && !parameters->options().shared())
-    return false;
-
-  // A reference to an absolute symbol does not need a dynamic relocation.
-  if (gsym->is_absolute())
-    return false;
-
-  // An absolute reference within a position-independent output file
-  // will need a dynamic relocation.
-  if ((flags & Symbol::ABSOLUTE_REF)
-      && parameters->options().output_is_position_independent())
-    return true;
-
-  // A function call that can branch to a local PLT entry does not need
-  // a dynamic relocation.
-  if ((flags & Symbol::FUNCTION_CALL) && gsym->has_plt_offset())
-    return false;
-
-  // A reference to any PLT entry in a non-position-independent executable
-  // does not need a dynamic relocation.
-  // Except due to having function descriptors on powerpc64 we don't define
-  // functions to their plt code in an executable, so this doesn't apply.
-  if (size == 32
-      && !parameters->options().output_is_position_independent()
-      && gsym->has_plt_offset())
-    return false;
-
-  // A reference to a symbol defined in a dynamic object or to a
-  // symbol that is preemptible will need a dynamic relocation.
-  if (gsym->is_from_dynobj()
-      || gsym->is_undefined()
-      || gsym->is_preemptible())
-    return true;
-
-  // For all other cases, return FALSE.
-  return false;
-}
-
-// Modified version of symtab.h class Symbol member
-// Whether we should use the PLT offset associated with a symbol for
-// a relocation.  FLAGS is a set of Reference_flags.
-
-template<int size>
-bool
-use_plt_offset(const Symbol* gsym, int flags)
-{
-  // If the symbol doesn't have a PLT offset, then naturally we
-  // don't want to use it.
-  if (!gsym->has_plt_offset())
-    return false;
-
-  // For a STT_GNU_IFUNC symbol we always have to use the PLT entry.
-  if (gsym->type() == elfcpp::STT_GNU_IFUNC)
-    return true;
-
-  // If we are going to generate a dynamic relocation, then we will
-  // wind up using that, so no need to use the PLT entry.
-  if (needs_dynamic_reloc<size>(gsym, flags))
-    return false;
-
-  // If the symbol is from a dynamic object, we need to use the PLT
-  // entry.
-  if (gsym->is_from_dynobj())
-    return true;
-
-  // If we are generating a shared object, and this symbol is
-  // undefined or preemptible, we need to use the PLT entry.
-  if (parameters->options().shared()
-      && (gsym->is_undefined() || gsym->is_preemptible()))
-    return true;
-
-  // If this is a call to a weak undefined symbol, we need to use
-  // the PLT entry; the symbol may be defined by a library loaded
-  // at runtime.
-  if ((flags & Symbol::FUNCTION_CALL) && gsym->is_weak_undefined())
-    return true;
-
-  // Otherwise we can use the regular definition.
-  return false;
-}
 
 template<int size, bool big_endian>
 class Powerpc_relocate_functions
@@ -2619,8 +2523,11 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
   if (sym != NULL && sym->is_forwarder())
     sym = symtab->resolve_forwards(sym);
   const Sized_symbol<size>* gsym = static_cast<const Sized_symbol<size>*>(sym);
+  Target_powerpc<size, big_endian>* target =
+    static_cast<Target_powerpc<size, big_endian>*>(
+      parameters->sized_target<size, big_endian>());
   if (gsym != NULL
-      ? use_plt_offset<size>(gsym, Scan::get_reference_flags(this->r_type_))
+      ? gsym->use_plt_offset(Scan::get_reference_flags(this->r_type_, target))
       : this->object_->local_has_plt_offset(this->r_sym_))
     {
       if (stub_table == NULL)
@@ -2706,9 +2613,6 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
       if (size == 64 && is_branch_reloc(this->r_type_))
        {
          unsigned int dest_shndx;
-         Target_powerpc<size, big_endian>* target =
-           static_cast<Target_powerpc<size, big_endian>*>(
-               parameters->sized_target<size, big_endian>());
          to = target->symval_for_branch(symtab, to, gsym,
                                         this->object_, &dest_shndx);
        }
@@ -5002,8 +4906,12 @@ Target_powerpc<size, big_endian>::tlsld_got_offset(
 
 template<int size, bool big_endian>
 int
-Target_powerpc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
+Target_powerpc<size, big_endian>::Scan::get_reference_flags(
+    unsigned int r_type,
+    const Target_powerpc* target)
 {
+  int ref = 0;
+
   switch (r_type)
     {
     case elfcpp::R_POWERPC_NONE:
@@ -5011,7 +4919,7 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
     case elfcpp::R_POWERPC_GNU_VTENTRY:
     case elfcpp::R_PPC64_TOC:
       // No symbol reference.
-      return 0;
+      break;
 
     case elfcpp::R_PPC64_ADDR64:
     case elfcpp::R_PPC64_UADDR64:
@@ -5022,13 +4930,15 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
     case elfcpp::R_POWERPC_ADDR16_LO:
     case elfcpp::R_POWERPC_ADDR16_HI:
     case elfcpp::R_POWERPC_ADDR16_HA:
-      return Symbol::ABSOLUTE_REF;
+      ref = Symbol::ABSOLUTE_REF;
+      break;
 
     case elfcpp::R_POWERPC_ADDR24:
     case elfcpp::R_POWERPC_ADDR14:
     case elfcpp::R_POWERPC_ADDR14_BRTAKEN:
     case elfcpp::R_POWERPC_ADDR14_BRNTAKEN:
-      return Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF;
+      ref = Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF;
+      break;
 
     case elfcpp::R_PPC64_REL64:
     case elfcpp::R_POWERPC_REL32:
@@ -5037,14 +4947,16 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
     case elfcpp::R_POWERPC_REL16_LO:
     case elfcpp::R_POWERPC_REL16_HI:
     case elfcpp::R_POWERPC_REL16_HA:
-      return Symbol::RELATIVE_REF;
+      ref = Symbol::RELATIVE_REF;
+      break;
 
     case elfcpp::R_POWERPC_REL24:
     case elfcpp::R_PPC_PLTREL24:
     case elfcpp::R_POWERPC_REL14:
     case elfcpp::R_POWERPC_REL14_BRTAKEN:
     case elfcpp::R_POWERPC_REL14_BRNTAKEN:
-      return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+      ref = Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+      break;
 
     case elfcpp::R_POWERPC_GOT16:
     case elfcpp::R_POWERPC_GOT16_LO:
@@ -5059,11 +4971,13 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
     case elfcpp::R_PPC64_TOC16_DS:
     case elfcpp::R_PPC64_TOC16_LO_DS:
       // Absolute in GOT.
-      return Symbol::ABSOLUTE_REF;
+      ref = Symbol::ABSOLUTE_REF;
+      break;
 
     case elfcpp::R_POWERPC_GOT_TPREL16:
     case elfcpp::R_POWERPC_TLS:
-      return Symbol::TLS_REF;
+      ref = Symbol::TLS_REF;
+      break;
 
     case elfcpp::R_POWERPC_COPY:
     case elfcpp::R_POWERPC_GLOB_DAT:
@@ -5072,8 +4986,12 @@ Target_powerpc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
     case elfcpp::R_POWERPC_DTPMOD:
     default:
       // Not expected.  We will give an error later.
-      return 0;
+      break;
     }
+
+  if (size == 64 && target->abiversion() < 2)
+    ref |= Symbol::FUNC_DESC_ABI;
+  return ref;
 }
 
 // Report an unsupported relocation against a local symbol.
@@ -5764,7 +5682,7 @@ Target_powerpc<size, big_endian>::Scan::global(
              gsym->set_needs_dynsym_value();
          }
        // Make a dynamic relocation if necessary.
-       if (needs_dynamic_reloc<size>(gsym, Scan::get_reference_flags(r_type))
+       if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type, target))
            || (size == 64 && is_ifunc))
          {
            if (gsym->may_need_copy_reloc())
@@ -5824,7 +5742,7 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_PPC64_REL64:
     case elfcpp::R_POWERPC_REL32:
       // Make a dynamic relocation if necessary.
-      if (needs_dynamic_reloc<size>(gsym, Scan::get_reference_flags(r_type)))
+      if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type, target)))
        {
          if (gsym->may_need_copy_reloc())
            {
@@ -6601,7 +6519,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
   bool has_plt_value = false;
   unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
   if ((gsym != NULL
-       ? use_plt_offset<size>(gsym, Scan::get_reference_flags(r_type))
+       ? gsym->use_plt_offset(Scan::get_reference_flags(r_type, target))
        : object->local_has_plt_offset(r_sym))
       && (!psymval->is_ifunc_symbol()
          || Scan::reloc_needs_plt_for_ifunc(object, r_type, false)))
index 9299ea8abe9bb36ab4ab24b3e60fcb43342e6c97..1232c97747ef6d92f52524405bdc698ccc431d2a 100644 (file)
@@ -638,7 +638,10 @@ class Symbol
     // A TLS-related reference.
     TLS_REF = 4,
     // A reference that can always be treated as a function call.
-    FUNCTION_CALL = 8
+    FUNCTION_CALL = 8,
+    // When set, says that dynamic relocations are needed even if a
+    // symbol has a plt entry.
+    FUNC_DESC_ABI = 16,
   };
 
   // Given a direct absolute or pc-relative static relocation against
@@ -675,7 +678,8 @@ class Symbol
 
     // A reference to any PLT entry in a non-position-independent executable
     // does not need a dynamic relocation.
-    if (!parameters->options().output_is_position_independent()
+    if (!(flags & FUNC_DESC_ABI)
+       && !parameters->options().output_is_position_independent()
         && this->has_plt_offset())
       return false;