This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: GOLD handling of weak symbols (including x86 vs. ARM)


How does the patch below look?

Cary Coutant <ccoutant@google.com> writes:
>> In other words, FUNCTION_CALL isn't used to mean a relocation which is a
>> function call. ?It means a symbol which is a function. ?It should
>> probably be renamed to IS_FUNCTION. ?Or just omitted, and
>> needs_dynamic_reloc can check the symbol type itself.
>
> It actually was intended to mean that it's a function call, but in the
> case of i386 and x86_64, it's only a best guess. We don't always set
> FUNCTION_CALL when the symbol type is STT_FUNC -- only when the
> relocation type also suggests that it might be a function call.

OK, in the patch I've kept the FUNCTION_CALL name and restricted it to
cases where the canonical function address is definitely not needed.

>> It seems to me that the distinguishing characteristic of "foo@PLT" is
>> not that it is a function call, it is that the relocation specifically
>> requires the PLT. ?I suspect that the right thing to do here is to
>> always use the use the PLT offset, if there is one, for R_386_PLT32.
>
> Agreed. If the relocation type forces the use of a PLT, we shouldn't
> even call use_plt_offset(). Same for R_X86_64_PLT32 and (I think)
> R_X86_64_PLTOFF64.

I suppose we'd still need to check has_plt_offset() though, so you'd
end up with:

   if (has_plt_offset()
       && (r_type == ...
           || r_type == ...
           || use_plt_offset(...something based on r_type...)))

I agree with Ian that it would make it easier to get this right in
future ports if we put all the logic in use_plt_offset(), using the same
target-specific function to get the flags for both needs_dynamic_reloc()
and use_plt_offset().

With the new definition of FUNCTION_CALL, a check along the lines of:

    if (flags & FUNCTION_CALL)
      return true;

would be correct after needs_dynamic_reloc().  (I'd put it there so
that we'd be consistent in the treatment of absolute function calls
in PIC output objects.  That's usually user error, of course, but if we
haven't diagnosed it by this point, we should report it as an invalid
dynamic reloc rather than silently generate wrong code.)  However,
I think it's better to keep the is_weak_undefined() check too, to make
it clear why this FUNCTION_CALL check is needed.

There may be other bits of code that could take advantage of
get_reference_flags(), but the patch feels pretty invasive.

Tested on x86_64-linux-gnu and arm-linux-gnueabi.  OK to install?

Richard


gold/
	* symtab.h (Symbol::NON_PIC_REF): Remove.
	(Symbol::RELATIVE_REF, Symbol::TLS_REF): New Reference_flags.
	(Symbol::FUNCTION_CALL): Renumber.  Reword comment.
	(Symbol::needs_dynamic_reloc): Don't check NON_PIC_REF.
	(Symbol::use_plt_offset): Take a flags argument and pass it
	directly to needs_dynamic_reloc.  Restrict check for undefined
	weak symbols to function calls.
	* arm.cc (Target_arm::Scan::get_reference_flags): New function.
	(Target_arm::Scan::global): Use it.
	(Target_arm::Scan::scan_reloc_for_stub): Likewise.
	(Target_arm::Relocate::relocate): Likewise.
	(Target_arm::Relocate::should_apply_static_reloc): Replace flags
	parameter with an r_type parameter.  Use get_reference_flags
	to get the flags.
	(Target_arm::Relocate::relocate): Update accordingly.
	* i386.cc (Target_i386::Scan::get_reference_flags): New function.
	(Target_i386::Scan::reloc_needs_plt_for_ifunc): Use it.
	(Target_i386::Scan::global): Likewise.
	(Target_i386::Relocate::relocate): Likewise.
	(Target_i386::Relocate::should_apply_static_reloc): Replace flags
	parameter with an r_type parameter.  Use get_reference_flags
	to get the flags.
	(Target_i386::Relocate::relocate): Update accordingly.
	* powerpc.cc (Target_powerpc::Scan::get_reference_flags): New function.
	(Target_powerpc::Scan::global): Use it.
	(Target_powerpc::Scan::scan_reloc_for_stub): Likewise.
	(Target_powerpc::Relocate::relocate): Likewise.
	* sparc.cc (Target_sparc::Scan::get_reference_flags): New function.
	(Target_sparc::Scan::global): Use it.
	(Target_sparc::Scan::scan_reloc_for_stub): Likewise.
	(Target_sparc::Relocate::relocate): Likewise.
	* x86_64.cc (Target_x86_64::Scan::get_reference_flags): New function.
	(Target_x86_64::Scan::reloc_needs_plt_for_ifunc): Use it.
	(Target_x86_64::Scan::global): Likewise.
	(Target_x86_64::Relocate::relocate): Likewise.

Index: gold/symtab.h
===================================================================
--- gold/symtab.h	2010-11-09 08:21:13.000000000 +0000
+++ gold/symtab.h	2010-11-09 08:21:23.000000000 +0000
@@ -614,15 +614,20 @@ #define GOLD_SYMTAB_H
 
   // When determining whether a reference to a symbol needs a dynamic
   // relocation, we need to know several things about the reference.
-  // These flags may be or'ed together.
+  // These flags may be or'ed together.  0 means that the symbol
+  // isn't referenced at all.
   enum Reference_flags
   {
-    // Reference to the symbol's absolute address.
+    // A reference to the symbol's absolute address.  This includes
+    // references that cause an absolute address to be stored in the GOT.
     ABSOLUTE_REF = 1,
-    // A non-PIC reference.
-    NON_PIC_REF = 2,
-    // A function call.
-    FUNCTION_CALL = 4
+    // A reference that calculates the offset of the symbol from some
+    // anchor point, such as the PC or GOT.
+    RELATIVE_REF = 2,
+    // A TLS-related reference.
+    TLS_REF = 4,
+    // A reference that can always be treated as a function call.
+    FUNCTION_CALL = 8
   };
 
   // Given a direct absolute or pc-relative static relocation against
@@ -653,12 +658,8 @@ #define GOLD_SYMTAB_H
       return true;
 
     // A function call that can branch to a local PLT entry does not need
-    // a dynamic relocation.  A non-pic pc-relative function call in a
-    // shared library cannot use a PLT entry.
-    if ((flags & FUNCTION_CALL)
-        && this->has_plt_offset()
-        && !((flags & NON_PIC_REF)
-             && parameters->options().output_is_position_independent()))
+    // a dynamic relocation.
+    if ((flags & FUNCTION_CALL) && this->has_plt_offset())
       return false;
 
     // A reference to any PLT entry in a non-position-independent executable
@@ -679,12 +680,10 @@ #define GOLD_SYMTAB_H
   }
 
   // Whether we should use the PLT offset associated with a symbol for
-  // a relocation.  IS_NON_PIC_REFERENCE is true if this is a non-PIC
-  // reloc--the same set of relocs for which we would pass NON_PIC_REF
-  // to the needs_dynamic_reloc function.
+  // a relocation.  FLAGS is a set of Reference_flags.
 
   bool
-  use_plt_offset(bool is_non_pic_reference) const
+  use_plt_offset(int flags) const
   {
     // If the symbol doesn't have a PLT offset, then naturally we
     // don't want to use it.
@@ -697,10 +696,7 @@ #define GOLD_SYMTAB_H
 
     // 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 (this->needs_dynamic_reloc(FUNCTION_CALL
-				  | (is_non_pic_reference
-				     ? NON_PIC_REF
-				     : 0)))
+    if (this->needs_dynamic_reloc(flags))
       return false;
 
     // If the symbol is from a dynamic object, we need to use the PLT
@@ -714,10 +710,10 @@ #define GOLD_SYMTAB_H
 	&& (this->is_undefined() || this->is_preemptible()))
       return true;
 
-    // If this is a weak undefined symbol, we need to use the PLT
-    // entry; the symbol may be defined by a library loaded at
-    // runtime.
-    if (this->is_weak_undefined())
+    // 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 & FUNCTION_CALL) && this->is_weak_undefined())
       return true;
 
     // Otherwise we can use the regular definition.
Index: gold/arm.cc
===================================================================
--- gold/arm.cc	2010-11-09 08:21:13.000000000 +0000
+++ gold/arm.cc	2010-11-09 08:21:23.000000000 +0000
@@ -2530,6 +2530,9 @@ class Target_arm : public Sized_target<3
       : issued_non_pic_error_(false)
     { }
 
+    static inline int
+    get_reference_flags(unsigned int r_type);
+
     inline void
     local(Symbol_table* symtab, Layout* layout, Target_arm* target,
 	  Sized_relobj<32, big_endian>* object,
@@ -2612,7 +2615,7 @@ class Target_arm : public Sized_target<3
     // Return whether the static relocation needs to be applied.
     inline bool
     should_apply_static_reloc(const Sized_symbol<32>* gsym,
-			      int ref_flags,
+			      unsigned int r_type,
 			      bool is_32bit,
 			      Output_section* output_section);
 
@@ -7487,6 +7490,125 @@ Target_arm<big_endian>::optimize_tls_rel
   return tls::TLSOPT_NONE;
 }
 
+// Get the Reference_flags for a particular relocation.
+
+template<bool big_endian>
+int
+Target_arm<big_endian>::Scan::get_reference_flags(unsigned int r_type)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_ARM_NONE:
+    case elfcpp::R_ARM_V4BX:
+    case elfcpp::R_ARM_GNU_VTENTRY:
+    case elfcpp::R_ARM_GNU_VTINHERIT:
+      // No symbol reference.
+      return 0;
+
+    case elfcpp::R_ARM_ABS32:
+    case elfcpp::R_ARM_ABS16:
+    case elfcpp::R_ARM_ABS12:
+    case elfcpp::R_ARM_THM_ABS5:
+    case elfcpp::R_ARM_ABS8:
+    case elfcpp::R_ARM_BASE_ABS:
+    case elfcpp::R_ARM_MOVW_ABS_NC:
+    case elfcpp::R_ARM_MOVT_ABS:
+    case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+    case elfcpp::R_ARM_THM_MOVT_ABS:
+    case elfcpp::R_ARM_ABS32_NOI:
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_ARM_REL32:
+    case elfcpp::R_ARM_LDR_PC_G0:
+    case elfcpp::R_ARM_SBREL32:
+    case elfcpp::R_ARM_THM_PC8:
+    case elfcpp::R_ARM_BASE_PREL:
+    case elfcpp::R_ARM_MOVW_PREL_NC:
+    case elfcpp::R_ARM_MOVT_PREL:
+    case elfcpp::R_ARM_THM_MOVW_PREL_NC:
+    case elfcpp::R_ARM_THM_MOVT_PREL:
+    case elfcpp::R_ARM_THM_ALU_PREL_11_0:
+    case elfcpp::R_ARM_THM_PC12:
+    case elfcpp::R_ARM_REL32_NOI:
+    case elfcpp::R_ARM_ALU_PC_G0_NC:
+    case elfcpp::R_ARM_ALU_PC_G0:
+    case elfcpp::R_ARM_ALU_PC_G1_NC:
+    case elfcpp::R_ARM_ALU_PC_G1:
+    case elfcpp::R_ARM_ALU_PC_G2:
+    case elfcpp::R_ARM_LDR_PC_G1:
+    case elfcpp::R_ARM_LDR_PC_G2:
+    case elfcpp::R_ARM_LDRS_PC_G0:
+    case elfcpp::R_ARM_LDRS_PC_G1:
+    case elfcpp::R_ARM_LDRS_PC_G2:
+    case elfcpp::R_ARM_LDC_PC_G0:
+    case elfcpp::R_ARM_LDC_PC_G1:
+    case elfcpp::R_ARM_LDC_PC_G2:
+    case elfcpp::R_ARM_ALU_SB_G0_NC:
+    case elfcpp::R_ARM_ALU_SB_G0:
+    case elfcpp::R_ARM_ALU_SB_G1_NC:
+    case elfcpp::R_ARM_ALU_SB_G1:
+    case elfcpp::R_ARM_ALU_SB_G2:
+    case elfcpp::R_ARM_LDR_SB_G0:
+    case elfcpp::R_ARM_LDR_SB_G1:
+    case elfcpp::R_ARM_LDR_SB_G2:
+    case elfcpp::R_ARM_LDRS_SB_G0:
+    case elfcpp::R_ARM_LDRS_SB_G1:
+    case elfcpp::R_ARM_LDRS_SB_G2:
+    case elfcpp::R_ARM_LDC_SB_G0:
+    case elfcpp::R_ARM_LDC_SB_G1:
+    case elfcpp::R_ARM_LDC_SB_G2:
+    case elfcpp::R_ARM_MOVW_BREL_NC:
+    case elfcpp::R_ARM_MOVT_BREL:
+    case elfcpp::R_ARM_MOVW_BREL:
+    case elfcpp::R_ARM_THM_MOVW_BREL_NC:
+    case elfcpp::R_ARM_THM_MOVT_BREL:
+    case elfcpp::R_ARM_THM_MOVW_BREL:
+    case elfcpp::R_ARM_GOTOFF32:
+    case elfcpp::R_ARM_GOTOFF12:
+    case elfcpp::R_ARM_PREL31:
+    case elfcpp::R_ARM_SBREL31:
+      return Symbol::RELATIVE_REF;
+
+    case elfcpp::R_ARM_PLT32:
+    case elfcpp::R_ARM_CALL:
+    case elfcpp::R_ARM_JUMP24:
+    case elfcpp::R_ARM_THM_CALL:
+    case elfcpp::R_ARM_THM_JUMP24:
+    case elfcpp::R_ARM_THM_JUMP19:
+    case elfcpp::R_ARM_THM_JUMP6:
+    case elfcpp::R_ARM_THM_JUMP11:
+    case elfcpp::R_ARM_THM_JUMP8:
+      return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+    case elfcpp::R_ARM_GOT_BREL:
+    case elfcpp::R_ARM_GOT_ABS:
+    case elfcpp::R_ARM_GOT_PREL:
+      // Absolute in GOT.
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_ARM_TLS_GD32:	// Global-dynamic
+    case elfcpp::R_ARM_TLS_LDM32:	// Local-dynamic
+    case elfcpp::R_ARM_TLS_LDO32:	// Alternate local-dynamic
+    case elfcpp::R_ARM_TLS_IE32:	// Initial-exec
+    case elfcpp::R_ARM_TLS_LE32:	// Local-exec
+      return Symbol::TLS_REF;
+
+    case elfcpp::R_ARM_TARGET1:
+    case elfcpp::R_ARM_TARGET2:
+    case elfcpp::R_ARM_COPY:
+    case elfcpp::R_ARM_GLOB_DAT:
+    case elfcpp::R_ARM_JUMP_SLOT:
+    case elfcpp::R_ARM_RELATIVE:
+    case elfcpp::R_ARM_PC24:
+    case elfcpp::R_ARM_LDR_SBREL_11_0_NC:
+    case elfcpp::R_ARM_ALU_SBREL_19_12_NC:
+    case elfcpp::R_ARM_ALU_SBREL_27_20_CK:
+    default:
+      // Not expected.  We will give an error later.
+      return 0;
+    }
+}
+
 // Report an unsupported relocation against a local symbol.
 
 template<bool big_endian>
@@ -7993,7 +8115,7 @@ Target_arm<big_endian>::Scan::global(Sym
               gsym->set_needs_dynsym_value();
           }
         // Make a dynamic relocation if necessary.
-        if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
+        if (gsym->needs_dynamic_reloc(get_reference_flags(r_type)))
           {
             if (gsym->may_need_copy_reloc())
               {
@@ -8074,8 +8196,7 @@ Target_arm<big_endian>::Scan::global(Sym
       // Relative addressing relocations.
       {
 	// Make a dynamic relocation if necessary.
-	int flags = Symbol::NON_PIC_REF;
-	if (gsym->needs_dynamic_reloc(flags))
+	if (gsym->needs_dynamic_reloc(get_reference_flags(r_type)))
 	  {
 	    if (target->may_need_copy_reloc(gsym))
 	      {
@@ -8515,7 +8636,7 @@ template<bool big_endian>
 inline bool
 Target_arm<big_endian>::Relocate::should_apply_static_reloc(
     const Sized_symbol<32>* gsym,
-    int ref_flags,
+    unsigned int r_type,
     bool is_32bit,
     Output_section* output_section)
 {
@@ -8525,6 +8646,8 @@ Target_arm<big_endian>::Relocate::should
   if ((output_section->flags() & elfcpp::SHF_ALLOC) == 0)
       return true;
 
+  int ref_flags = Scan::get_reference_flags(r_type);
+
   // For local symbols, we will have created a non-RELATIVE dynamic
   // relocation only if (a) the output is position independent,
   // (b) the relocation is absolute (not pc- or segment-relative), and
@@ -8630,7 +8753,7 @@ Target_arm<big_endian>::Relocate::reloca
 	{
 	  // This is a global symbol.  Determine if we use PLT and if the
 	  // final target is THUMB.
-	  if (gsym->use_plt_offset(reloc_is_non_pic(r_type)))
+	  if (gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
 	    {
 	      // This uses a PLT, change the symbol value.
 	      symval.set_output_value(target->plt_section()->address()
@@ -8754,62 +8877,53 @@ Target_arm<big_endian>::Relocate::reloca
       break;
 
     case elfcpp::R_ARM_ABS8:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
 	reloc_status = Arm_relocate_functions::abs8(view, object, psymval);
       break;
 
     case elfcpp::R_ARM_ABS12:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
 	reloc_status = Arm_relocate_functions::abs12(view, object, psymval);
       break;
 
     case elfcpp::R_ARM_ABS16:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
 	reloc_status = Arm_relocate_functions::abs16(view, object, psymval);
       break;
 
     case elfcpp::R_ARM_ABS32:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, true, output_section))
 	reloc_status = Arm_relocate_functions::abs32(view, object, psymval,
 						     thumb_bit);
       break;
 
     case elfcpp::R_ARM_ABS32_NOI:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, true, output_section))
 	// No thumb bit for this relocation: (S + A)
 	reloc_status = Arm_relocate_functions::abs32(view, object, psymval,
 						     0);
       break;
 
     case elfcpp::R_ARM_MOVW_ABS_NC:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
 	reloc_status = Arm_relocate_functions::movw(view, object, psymval,
 						    0, thumb_bit,
 						    check_overflow);
       break;
 
     case elfcpp::R_ARM_MOVT_ABS:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
 	reloc_status = Arm_relocate_functions::movt(view, object, psymval, 0);
       break;
 
     case elfcpp::R_ARM_THM_MOVW_ABS_NC:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
 	reloc_status = Arm_relocate_functions::thm_movw(view, object, psymval,
        						        0, thumb_bit, false);
       break;
 
     case elfcpp::R_ARM_THM_MOVT_ABS:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
 	reloc_status = Arm_relocate_functions::thm_movt(view, object,
 							psymval, 0);
       break;
@@ -8852,8 +8966,7 @@ Target_arm<big_endian>::Relocate::reloca
       break;
 
     case elfcpp::R_ARM_THM_ABS5:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
 	reloc_status = Arm_relocate_functions::thm_abs5(view, object, psymval);
       break;
 
@@ -8883,13 +8996,8 @@ Target_arm<big_endian>::Relocate::reloca
       break;
 
     case elfcpp::R_ARM_BASE_ABS:
-      {
-	if (!should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				      output_section))
-	  break;
-
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
 	reloc_status = Arm_relocate_functions::base_abs(view, sym_origin);
-      }
       break;
 
     case elfcpp::R_ARM_GOT_BREL:
@@ -10743,7 +10851,7 @@ Target_arm<big_endian>::scan_reloc_for_s
     {
       // This is a global symbol.  Determine if we use PLT and if the
       // final target is THUMB.
-      if (gsym->use_plt_offset(Relocate::reloc_is_non_pic(r_type)))
+      if (gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
 	{
 	  // This uses a PLT, change the symbol value.
 	  symval.set_output_value(this->plt_section()->address()
Index: gold/i386.cc
===================================================================
--- gold/i386.cc	2010-11-09 08:21:13.000000000 +0000
+++ gold/i386.cc	2010-11-09 08:21:23.000000000 +0000
@@ -335,6 +335,9 @@ class Target_i386 : public Target_freebs
   // The class which scans relocations.
   struct Scan
   {
+    static inline int
+    get_reference_flags(unsigned int r_type);
+
     inline void
     local(Symbol_table* symtab, Layout* layout, Target_i386* target,
 	  Sized_relobj<32, false>* object,
@@ -406,7 +409,7 @@ class Target_i386 : public Target_freebs
     // Return whether the static relocation needs to be applied.
     inline bool
     should_apply_static_reloc(const Sized_symbol<32>* gsym,
-                              int ref_flags,
+                              unsigned int r_type,
                               bool is_32bit,
 			      Output_section* output_section);
 
@@ -1191,41 +1194,49 @@ Target_i386::optimize_tls_reloc(bool is_
     }
 }
 
-// Report an unsupported relocation against a local symbol.
-
-void
-Target_i386::Scan::unsupported_reloc_local(Sized_relobj<32, false>* object,
-					   unsigned int r_type)
-{
-  gold_error(_("%s: unsupported reloc %u against local symbol"),
-	     object->name().c_str(), r_type);
-}
-
-// Return whether we need to make a PLT entry for a relocation of a
-// given type against a STT_GNU_IFUNC symbol.
+// Get the Reference_flags for a particular relocation.
 
-bool
-Target_i386::Scan::reloc_needs_plt_for_ifunc(Sized_relobj<32, false>* object,
-					     unsigned int r_type)
+int
+Target_i386::Scan::get_reference_flags(unsigned int r_type)
 {
   switch (r_type)
     {
     case elfcpp::R_386_NONE:
     case elfcpp::R_386_GNU_VTINHERIT:
     case elfcpp::R_386_GNU_VTENTRY:
-      return false;
+    case elfcpp::R_386_GOTPC:
+      // No symbol reference.
+      return 0;
 
     case elfcpp::R_386_32:
     case elfcpp::R_386_16:
     case elfcpp::R_386_8:
+      return Symbol::ABSOLUTE_REF;
+
     case elfcpp::R_386_PC32:
     case elfcpp::R_386_PC16:
     case elfcpp::R_386_PC8:
-    case elfcpp::R_386_PLT32:
     case elfcpp::R_386_GOTOFF:
-    case elfcpp::R_386_GOTPC:
+      return Symbol::RELATIVE_REF;
+
+    case elfcpp::R_386_PLT32:
+      return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
     case elfcpp::R_386_GOT32:
-      return true;
+      // Absolute in GOT.
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_386_TLS_GD:            // Global-dynamic
+    case elfcpp::R_386_TLS_GOTDESC:       // Global-dynamic (from ~oliva url)
+    case elfcpp::R_386_TLS_DESC_CALL:
+    case elfcpp::R_386_TLS_LDM:           // Local-dynamic
+    case elfcpp::R_386_TLS_LDO_32:        // Alternate local-dynamic
+    case elfcpp::R_386_TLS_IE:            // Initial-exec
+    case elfcpp::R_386_TLS_IE_32:
+    case elfcpp::R_386_TLS_GOTIE:
+    case elfcpp::R_386_TLS_LE:            // Local-exec
+    case elfcpp::R_386_TLS_LE_32:
+      return Symbol::TLS_REF;
 
     case elfcpp::R_386_COPY:
     case elfcpp::R_386_GLOB_DAT:
@@ -1237,23 +1248,6 @@ Target_i386::Scan::reloc_needs_plt_for_i
     case elfcpp::R_386_TLS_DTPOFF32:
     case elfcpp::R_386_TLS_TPOFF32:
     case elfcpp::R_386_TLS_DESC:
-      // We will give an error later.
-      return false;
-
-    case elfcpp::R_386_TLS_GD:
-    case elfcpp::R_386_TLS_GOTDESC:
-    case elfcpp::R_386_TLS_DESC_CALL:
-    case elfcpp::R_386_TLS_LDM:
-    case elfcpp::R_386_TLS_LDO_32:
-    case elfcpp::R_386_TLS_IE:
-    case elfcpp::R_386_TLS_IE_32:
-    case elfcpp::R_386_TLS_GOTIE:
-    case elfcpp::R_386_TLS_LE:
-    case elfcpp::R_386_TLS_LE_32:
-      gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
-		 object->name().c_str(), r_type);
-      return false;
-
     case elfcpp::R_386_32PLT:
     case elfcpp::R_386_TLS_GD_32:
     case elfcpp::R_386_TLS_GD_PUSH:
@@ -1265,11 +1259,35 @@ Target_i386::Scan::reloc_needs_plt_for_i
     case elfcpp::R_386_TLS_LDM_POP:
     case elfcpp::R_386_USED_BY_INTEL_200:
     default:
-      // We will give an error later.
-      return false;
+      // Not expected.  We will give an error later.
+      return 0;
     }
 }
 
+// Report an unsupported relocation against a local symbol.
+
+void
+Target_i386::Scan::unsupported_reloc_local(Sized_relobj<32, false>* object,
+					   unsigned int r_type)
+{
+  gold_error(_("%s: unsupported reloc %u against local symbol"),
+	     object->name().c_str(), r_type);
+}
+
+// Return whether we need to make a PLT entry for a relocation of a
+// given type against a STT_GNU_IFUNC symbol.
+
+bool
+Target_i386::Scan::reloc_needs_plt_for_ifunc(Sized_relobj<32, false>* object,
+					     unsigned int r_type)
+{
+  int flags = get_reference_flags(r_type);
+  if (flags & Symbol::TLS_REF)
+    gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
+               object->name().c_str(), r_type);
+  return flags != 0;
+}
+
 // Scan a relocation for a local symbol.
 
 inline void
@@ -1676,7 +1694,7 @@ Target_i386::Scan::global(Symbol_table* 
               gsym->set_needs_dynsym_value();
           }
         // Make a dynamic relocation if necessary.
-        if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
+        if (gsym->needs_dynamic_reloc(get_reference_flags(r_type)))
           {
             if (gsym->may_need_copy_reloc())
               {
@@ -1737,10 +1755,7 @@ Target_i386::Scan::global(Symbol_table* 
               target->make_plt_entry(symtab, layout, gsym);
           }
         // Make a dynamic relocation if necessary.
-        int flags = Symbol::NON_PIC_REF;
-        if (gsym->is_func())
-          flags |= Symbol::FUNCTION_CALL;
-        if (gsym->needs_dynamic_reloc(flags))
+        if (gsym->needs_dynamic_reloc(get_reference_flags(r_type)))
           {
             if (gsym->may_need_copy_reloc())
               {
@@ -2109,7 +2124,7 @@ Target_i386::do_finalize_sections(
 
 inline bool
 Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym,
-                                                 int ref_flags,
+                                                 unsigned int r_type,
                                                  bool is_32bit,
 						 Output_section* output_section)
 {
@@ -2119,6 +2134,8 @@ Target_i386::Relocate::should_apply_stat
   if ((output_section->flags() & elfcpp::SHF_ALLOC) == 0)
     return true;
 
+  int ref_flags = Scan::get_reference_flags(r_type);
+
   // For local symbols, we will have created a non-RELATIVE dynamic
   // relocation only if (a) the output is position independent,
   // (b) the relocation is absolute (not pc- or segment-relative), and
@@ -2176,7 +2193,7 @@ Target_i386::Relocate::relocate(const Re
   if (gsym != NULL
       && gsym->type() == elfcpp::STT_GNU_IFUNC
       && r_type == elfcpp::R_386_32
-      && gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF)
+      && gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type))
       && gsym->can_use_relative_reloc(false)
       && !gsym->is_from_dynobj()
       && !gsym->is_undefined()
@@ -2186,9 +2203,7 @@ Target_i386::Relocate::relocate(const Re
       // want to use the real value of the symbol, not the PLT offset.
     }
   else if (gsym != NULL
-	   && gsym->use_plt_offset(r_type == elfcpp::R_386_PC8
-				   || r_type == elfcpp::R_386_PC16
-				   || r_type == elfcpp::R_386_PC32))
+	   && gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
     {
       symval.set_output_value(target->plt_section()->address()
 			      + gsym->plt_offset());
@@ -2242,52 +2257,33 @@ Target_i386::Relocate::relocate(const Re
       break;
 
     case elfcpp::R_386_32:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, true, output_section))
         Relocate_functions<32, false>::rel32(view, object, psymval);
       break;
 
     case elfcpp::R_386_PC32:
-      {
-        int ref_flags = Symbol::NON_PIC_REF;
-        if (gsym != NULL && gsym->is_func())
-          ref_flags |= Symbol::FUNCTION_CALL;
-        if (should_apply_static_reloc(gsym, ref_flags, true, output_section))
-          Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
-      }
+      if (should_apply_static_reloc(gsym, r_type, true, output_section))
+        Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
       break;
 
     case elfcpp::R_386_16:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
         Relocate_functions<32, false>::rel16(view, object, psymval);
       break;
 
     case elfcpp::R_386_PC16:
-      {
-        int ref_flags = Symbol::NON_PIC_REF;
-        if (gsym != NULL && gsym->is_func())
-          ref_flags |= Symbol::FUNCTION_CALL;
-        if (should_apply_static_reloc(gsym, ref_flags, false, output_section))
-          Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
-      }
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
+        Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
       break;
 
     case elfcpp::R_386_8:
-      if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false,
-				    output_section))
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
         Relocate_functions<32, false>::rel8(view, object, psymval);
       break;
 
     case elfcpp::R_386_PC8:
-      {
-        int ref_flags = Symbol::NON_PIC_REF;
-        if (gsym != NULL && gsym->is_func())
-          ref_flags |= Symbol::FUNCTION_CALL;
-        if (should_apply_static_reloc(gsym, ref_flags, false,
-				      output_section))
-          Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
-      }
+      if (should_apply_static_reloc(gsym, r_type, false, output_section))
+        Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
       break;
 
     case elfcpp::R_386_PLT32:
Index: gold/powerpc.cc
===================================================================
--- gold/powerpc.cc	2010-11-09 08:21:13.000000000 +0000
+++ gold/powerpc.cc	2010-11-09 08:21:23.000000000 +0000
@@ -188,6 +188,9 @@ class Target_powerpc : public Sized_targ
       : issued_non_pic_error_(false)
     { }
 
+    static inline int
+    get_reference_flags(unsigned int r_type);
+
     inline void
     local(Symbol_table* symtab, Layout* layout, Target_powerpc* target,
 	  Sized_relobj<size, big_endian>* object,
@@ -1105,6 +1108,69 @@ optimize_tls_reloc(bool /* is_final */, 
     }
 }
 
+// Get the Reference_flags for a particular relocation.
+
+template<int size, bool big_endian>
+int
+Target_powerpc<size, big_endian>::Scan::get_reference_flags(
+			unsigned int r_type)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_POWERPC_NONE:
+    case elfcpp::R_POWERPC_GNU_VTINHERIT:
+    case elfcpp::R_POWERPC_GNU_VTENTRY:
+    case elfcpp::R_PPC64_TOC:
+      // No symbol reference.
+      return 0;
+
+    case elfcpp::R_POWERPC_ADDR16:
+    case elfcpp::R_POWERPC_ADDR16_LO:
+    case elfcpp::R_POWERPC_ADDR16_HI:
+    case elfcpp::R_POWERPC_ADDR16_HA:
+    case elfcpp::R_POWERPC_ADDR32:
+    case elfcpp::R_PPC64_ADDR64:
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_POWERPC_REL24:
+    case elfcpp::R_PPC_LOCAL24PC:
+    case elfcpp::R_PPC_REL16:
+    case elfcpp::R_PPC_REL16_LO:
+    case elfcpp::R_PPC_REL16_HI:
+    case elfcpp::R_PPC_REL16_HA:
+      return Symbol::RELATIVE_REF;
+
+    case elfcpp::R_PPC_PLTREL24:
+      return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+    case elfcpp::R_POWERPC_GOT16:
+    case elfcpp::R_POWERPC_GOT16_LO:
+    case elfcpp::R_POWERPC_GOT16_HI:
+    case elfcpp::R_POWERPC_GOT16_HA:
+    case elfcpp::R_PPC64_TOC16:
+    case elfcpp::R_PPC64_TOC16_LO:
+    case elfcpp::R_PPC64_TOC16_HI:
+    case elfcpp::R_PPC64_TOC16_HA:
+    case elfcpp::R_PPC64_TOC16_DS:
+    case elfcpp::R_PPC64_TOC16_LO_DS:
+      // Absolute in GOT.
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_POWERPC_GOT_TPREL16:
+    case elfcpp::R_POWERPC_TLS:
+      return Symbol::TLS_REF;
+
+    case elfcpp::R_POWERPC_COPY:
+    case elfcpp::R_POWERPC_GLOB_DAT:
+    case elfcpp::R_POWERPC_JMP_SLOT:
+    case elfcpp::R_POWERPC_RELATIVE:
+    case elfcpp::R_POWERPC_DTPMOD:
+    default:
+      // Not expected.  We will give an error later.
+      return 0;
+    }
+}
+
 // Report an unsupported relocation against a local symbol.
 
 template<int size, bool big_endian>
@@ -1400,7 +1466,7 @@ Target_powerpc<size, big_endian>::Scan::
               gsym->set_needs_dynsym_value();
           }
         // Make a dynamic relocation if necessary.
-        if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
+        if (gsym->needs_dynamic_reloc(get_reference_flags(r_type)))
           {
             if (gsym->may_need_copy_reloc())
               {
@@ -1450,10 +1516,7 @@ Target_powerpc<size, big_endian>::Scan::
 	if (gsym->needs_plt_entry())
 	  target->make_plt_entry(symtab, layout, gsym);
 	// Make a dynamic relocation if necessary.
-	int flags = Symbol::NON_PIC_REF;
-	if (gsym->type() == elfcpp::STT_FUNC)
-	  flags |= Symbol::FUNCTION_CALL;
-	if (gsym->needs_dynamic_reloc(flags))
+	if (gsym->needs_dynamic_reloc(get_reference_flags(r_type)))
 	  {
 	    if (gsym->may_need_copy_reloc())
 	      {
@@ -1682,12 +1745,7 @@ Target_powerpc<size, big_endian>::Reloca
   // Pick the value to use for symbols defined in shared objects.
   Symbol_value<size> symval;
   if (gsym != NULL
-      && gsym->use_plt_offset(r_type == elfcpp::R_POWERPC_REL24
-			      || r_type == elfcpp::R_PPC_LOCAL24PC
-			      || r_type == elfcpp::R_PPC_REL16
-			      || r_type == elfcpp::R_PPC_REL16_LO
-			      || r_type == elfcpp::R_PPC_REL16_HI
-			      || r_type == elfcpp::R_PPC_REL16_HA))
+      && gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
     {
       elfcpp::Elf_Xword value;
 
Index: gold/sparc.cc
===================================================================
--- gold/sparc.cc	2010-11-09 08:21:13.000000000 +0000
+++ gold/sparc.cc	2010-11-09 08:21:23.000000000 +0000
@@ -198,6 +198,9 @@ class Target_sparc : public Sized_target
       : issued_non_pic_error_(false)
     { }
 
+    static inline int
+    get_reference_flags(unsigned int r_type);
+
     inline void
     local(Symbol_table* symtab, Layout* layout, Target_sparc* target,
 	  Sized_relobj<size, big_endian>* object,
@@ -1576,6 +1579,119 @@ optimize_tls_reloc(bool is_final, int r_
     }
 }
 
+// Get the Reference_flags for a particular relocation.
+
+template<int size, bool big_endian>
+int
+Target_sparc<size, big_endian>::Scan::get_reference_flags(unsigned int r_type)
+{
+  r_type &= 0xff;
+  switch (r_type)
+    {
+    case elfcpp::R_SPARC_NONE:
+    case elfcpp::R_SPARC_REGISTER:
+    case elfcpp::R_SPARC_GNU_VTINHERIT:
+    case elfcpp::R_SPARC_GNU_VTENTRY:
+      // No symbol reference.
+      return 0;
+
+    case elfcpp::R_SPARC_UA64:
+    case elfcpp::R_SPARC_64:
+    case elfcpp::R_SPARC_HIX22:
+    case elfcpp::R_SPARC_LOX10:
+    case elfcpp::R_SPARC_H44:
+    case elfcpp::R_SPARC_M44:
+    case elfcpp::R_SPARC_L44:
+    case elfcpp::R_SPARC_HH22:
+    case elfcpp::R_SPARC_HM10:
+    case elfcpp::R_SPARC_LM22:
+    case elfcpp::R_SPARC_HI22:
+    case elfcpp::R_SPARC_LO10:
+    case elfcpp::R_SPARC_OLO10:
+    case elfcpp::R_SPARC_UA32:
+    case elfcpp::R_SPARC_32:
+    case elfcpp::R_SPARC_UA16:
+    case elfcpp::R_SPARC_16:
+    case elfcpp::R_SPARC_11:
+    case elfcpp::R_SPARC_10:
+    case elfcpp::R_SPARC_8:
+    case elfcpp::R_SPARC_7:
+    case elfcpp::R_SPARC_6:
+    case elfcpp::R_SPARC_5:
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_SPARC_DISP8:
+    case elfcpp::R_SPARC_DISP16:
+    case elfcpp::R_SPARC_DISP32:
+    case elfcpp::R_SPARC_DISP64:
+    case elfcpp::R_SPARC_PC_HH22:
+    case elfcpp::R_SPARC_PC_HM10:
+    case elfcpp::R_SPARC_PC_LM22:
+    case elfcpp::R_SPARC_PC10:
+    case elfcpp::R_SPARC_PC22:
+    case elfcpp::R_SPARC_WDISP30:
+    case elfcpp::R_SPARC_WDISP22:
+    case elfcpp::R_SPARC_WDISP19:
+    case elfcpp::R_SPARC_WDISP16:
+      return Symbol::RELATIVE_REF;
+
+    case elfcpp::R_SPARC_PLT64:
+    case elfcpp::R_SPARC_PLT32:
+    case elfcpp::R_SPARC_HIPLT22:
+    case elfcpp::R_SPARC_LOPLT10:
+    case elfcpp::R_SPARC_PCPLT10:
+      return Symbol::FUNCTION_CALL | Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_SPARC_PCPLT32:
+    case elfcpp::R_SPARC_PCPLT22:
+    case elfcpp::R_SPARC_WPLT30:
+      return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+    case elfcpp::R_SPARC_GOTDATA_OP:
+    case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
+    case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
+    case elfcpp::R_SPARC_GOT10:
+    case elfcpp::R_SPARC_GOT13:
+    case elfcpp::R_SPARC_GOT22:
+      // Absolute in GOT.
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
+    case elfcpp::R_SPARC_TLS_GD_LO10:
+    case elfcpp::R_SPARC_TLS_GD_ADD:
+    case elfcpp::R_SPARC_TLS_GD_CALL:
+    case elfcpp::R_SPARC_TLS_LDM_HI22:	// Local-dynamic
+    case elfcpp::R_SPARC_TLS_LDM_LO10:
+    case elfcpp::R_SPARC_TLS_LDM_ADD:
+    case elfcpp::R_SPARC_TLS_LDM_CALL:
+    case elfcpp::R_SPARC_TLS_LDO_HIX22:	// Alternate local-dynamic
+    case elfcpp::R_SPARC_TLS_LDO_LOX10:
+    case elfcpp::R_SPARC_TLS_LDO_ADD:
+    case elfcpp::R_SPARC_TLS_LE_HIX22:
+    case elfcpp::R_SPARC_TLS_LE_LOX10:
+    case elfcpp::R_SPARC_TLS_IE_HI22:	// Initial-exec
+    case elfcpp::R_SPARC_TLS_IE_LO10:
+    case elfcpp::R_SPARC_TLS_IE_LD:
+    case elfcpp::R_SPARC_TLS_IE_LDX:
+    case elfcpp::R_SPARC_TLS_IE_ADD:
+      return Symbol::TLS_REF;
+
+    case elfcpp::R_SPARC_COPY:
+    case elfcpp::R_SPARC_GLOB_DAT:
+    case elfcpp::R_SPARC_JMP_SLOT:
+    case elfcpp::R_SPARC_RELATIVE:
+    case elfcpp::R_SPARC_TLS_DTPMOD64:
+    case elfcpp::R_SPARC_TLS_DTPMOD32:
+    case elfcpp::R_SPARC_TLS_DTPOFF64:
+    case elfcpp::R_SPARC_TLS_DTPOFF32:
+    case elfcpp::R_SPARC_TLS_TPOFF64:
+    case elfcpp::R_SPARC_TLS_TPOFF32:
+    default:
+      // Not expected.  We will give an error later.
+      return 0;
+    }
+}
+
 // Generate a PLT entry slot for a call to __tls_get_addr
 template<int size, bool big_endian>
 void
@@ -2068,10 +2184,7 @@ Target_sparc<size, big_endian>::Scan::gl
 	if (gsym->needs_plt_entry())
 	  target->make_plt_entry(symtab, layout, gsym);
 	// Make a dynamic relocation if necessary.
-	int flags = Symbol::NON_PIC_REF;
-	if (gsym->type() == elfcpp::STT_FUNC)
-	  flags |= Symbol::FUNCTION_CALL;
-	if (gsym->needs_dynamic_reloc(flags))
+	if (gsym->needs_dynamic_reloc(get_reference_flags(r_type)))
 	  {
 	    if (gsym->may_need_copy_reloc())
 	      {
@@ -2127,7 +2240,7 @@ Target_sparc<size, big_endian>::Scan::gl
               gsym->set_needs_dynsym_value();
           }
         // Make a dynamic relocation if necessary.
-        if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
+        if (gsym->needs_dynamic_reloc(get_reference_flags(r_type)))
           {
 	    unsigned int r_off = reloc.get_r_offset();
 
@@ -2512,19 +2625,7 @@ Target_sparc<size, big_endian>::Relocate
   // Pick the value to use for symbols defined in shared objects.
   Symbol_value<size> symval;
   if (gsym != NULL
-      && gsym->use_plt_offset(r_type == elfcpp::R_SPARC_DISP8
-			      || r_type == elfcpp::R_SPARC_DISP16
-			      || r_type == elfcpp::R_SPARC_DISP32
-			      || r_type == elfcpp::R_SPARC_DISP64
-			      || r_type == elfcpp::R_SPARC_PC_HH22
-			      || r_type == elfcpp::R_SPARC_PC_HM10
-			      || r_type == elfcpp::R_SPARC_PC_LM22
-			      || r_type == elfcpp::R_SPARC_PC10
-			      || r_type == elfcpp::R_SPARC_PC22
-			      || r_type == elfcpp::R_SPARC_WDISP30
-			      || r_type == elfcpp::R_SPARC_WDISP22
-			      || r_type == elfcpp::R_SPARC_WDISP19
-			      || r_type == elfcpp::R_SPARC_WDISP16))
+      && gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
     {
       elfcpp::Elf_Xword value;
 
Index: gold/x86_64.cc
===================================================================
--- gold/x86_64.cc	2010-11-09 08:21:13.000000000 +0000
+++ gold/x86_64.cc	2010-11-09 08:21:23.000000000 +0000
@@ -362,6 +362,9 @@ class Target_x86_64 : public Target_free
       : issued_non_pic_error_(false)
     { }
 
+    static inline int
+    get_reference_flags(unsigned int r_type);
+
     inline void
     local(Symbol_table* symtab, Layout* layout, Target_x86_64* target,
 	  Sized_relobj<64, false>* object,
@@ -1236,6 +1239,73 @@ Target_x86_64::optimize_tls_reloc(bool i
     }
 }
 
+// Get the Reference_flags for a particular relocation.
+
+int
+Target_x86_64::Scan::get_reference_flags(unsigned int r_type)
+{
+  switch (r_type)
+    {
+    case elfcpp::R_X86_64_NONE:
+    case elfcpp::R_X86_64_GNU_VTINHERIT:
+    case elfcpp::R_X86_64_GNU_VTENTRY:
+    case elfcpp::R_X86_64_GOTPC32:
+    case elfcpp::R_X86_64_GOTPC64:
+      // No symbol reference.
+      return 0;
+
+    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:
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_X86_64_PC64:
+    case elfcpp::R_X86_64_PC32:
+    case elfcpp::R_X86_64_PC16:
+    case elfcpp::R_X86_64_PC8:
+    case elfcpp::R_X86_64_GOTOFF64:
+      return Symbol::RELATIVE_REF;
+
+    case elfcpp::R_X86_64_PLT32:
+    case elfcpp::R_X86_64_PLTOFF64:
+      return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF;
+
+    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:
+      // Absolute in GOT.
+      return Symbol::ABSOLUTE_REF;
+
+    case elfcpp::R_X86_64_TLSGD:            // Global-dynamic
+    case elfcpp::R_X86_64_GOTPC32_TLSDESC:  // Global-dynamic (from ~oliva url)
+    case elfcpp::R_X86_64_TLSDESC_CALL:
+    case elfcpp::R_X86_64_TLSLD:            // Local-dynamic
+    case elfcpp::R_X86_64_DTPOFF32:
+    case elfcpp::R_X86_64_DTPOFF64:
+    case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
+    case elfcpp::R_X86_64_TPOFF32:          // Local-exec
+      return Symbol::TLS_REF;
+
+    case elfcpp::R_X86_64_COPY:
+    case elfcpp::R_X86_64_GLOB_DAT:
+    case elfcpp::R_X86_64_JUMP_SLOT:
+    case elfcpp::R_X86_64_RELATIVE:
+    case elfcpp::R_X86_64_IRELATIVE:
+    case elfcpp::R_X86_64_TPOFF64:
+    case elfcpp::R_X86_64_DTPMOD64:
+    case elfcpp::R_X86_64_TLSDESC:
+    case elfcpp::R_X86_64_SIZE32:
+    case elfcpp::R_X86_64_SIZE64:
+    default:
+      // Not expected.  We will give an error later.
+      return 0;
+    }
+}
+
 // Report an unsupported relocation against a local symbol.
 
 void
@@ -1297,63 +1367,11 @@ bool
 Target_x86_64::Scan::reloc_needs_plt_for_ifunc(Sized_relobj<64, false>* object,
 					       unsigned int r_type)
 {
-  switch (r_type)
-    {
-    case elfcpp::R_X86_64_NONE:
-    case elfcpp::R_X86_64_GNU_VTINHERIT:
-    case elfcpp::R_X86_64_GNU_VTENTRY:
-      return false;
-
-    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_PC64:
-    case elfcpp::R_X86_64_PC32:
-    case elfcpp::R_X86_64_PC16:
-    case elfcpp::R_X86_64_PC8:
-    case elfcpp::R_X86_64_PLT32:
-    case elfcpp::R_X86_64_GOTPC32:
-    case elfcpp::R_X86_64_GOTOFF64:
-    case elfcpp::R_X86_64_GOTPC64:
-    case elfcpp::R_X86_64_PLTOFF64:
-    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;
-
-    case elfcpp::R_X86_64_COPY:
-    case elfcpp::R_X86_64_GLOB_DAT:
-    case elfcpp::R_X86_64_JUMP_SLOT:
-    case elfcpp::R_X86_64_RELATIVE:
-    case elfcpp::R_X86_64_IRELATIVE:
-    case elfcpp::R_X86_64_TPOFF64:
-    case elfcpp::R_X86_64_DTPMOD64:
-    case elfcpp::R_X86_64_TLSDESC:
-      // We will give an error later.
-      return false;
-
-    case elfcpp::R_X86_64_TLSGD:
-    case elfcpp::R_X86_64_GOTPC32_TLSDESC:
-    case elfcpp::R_X86_64_TLSDESC_CALL:
-    case elfcpp::R_X86_64_TLSLD:
-    case elfcpp::R_X86_64_DTPOFF32:
-    case elfcpp::R_X86_64_DTPOFF64:
-    case elfcpp::R_X86_64_GOTTPOFF:
-    case elfcpp::R_X86_64_TPOFF32:
-      gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
-		 object->name().c_str(), r_type);
-      return false;
-
-    case elfcpp::R_X86_64_SIZE32:
-    case elfcpp::R_X86_64_SIZE64:
-    default:
-      // We will give an error later.
-      return false;
-    }
+  int flags = get_reference_flags(r_type);
+  if (flags & Symbol::TLS_REF)
+    gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
+               object->name().c_str(), r_type);
+  return flags != 0;
 }
 
 // Scan a relocation for a local symbol.
@@ -1779,7 +1797,7 @@ Target_x86_64::Scan::global(Symbol_table
               gsym->set_needs_dynsym_value();
           }
         // Make a dynamic relocation if necessary.
-        if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
+        if (gsym->needs_dynamic_reloc(get_reference_flags(r_type)))
           {
             if (gsym->may_need_copy_reloc())
               {
@@ -1836,10 +1854,7 @@ Target_x86_64::Scan::global(Symbol_table
         if (gsym->needs_plt_entry())
           target->make_plt_entry(symtab, layout, gsym);
         // Make a dynamic relocation if necessary.
-        int flags = Symbol::NON_PIC_REF;
-        if (gsym->is_func())
-          flags |= Symbol::FUNCTION_CALL;
-        if (gsym->needs_dynamic_reloc(flags))
+        if (gsym->needs_dynamic_reloc(get_reference_flags(r_type)))
           {
             if (gsym->may_need_copy_reloc())
               {
@@ -2242,10 +2257,7 @@ Target_x86_64::Relocate::relocate(const 
   // Pick the value to use for symbols defined in the PLT.
   Symbol_value<64> symval;
   if (gsym != NULL
-      && gsym->use_plt_offset(r_type == elfcpp::R_X86_64_PC64
-			      || r_type == elfcpp::R_X86_64_PC32
-			      || r_type == elfcpp::R_X86_64_PC16
-			      || r_type == elfcpp::R_X86_64_PC8))
+      && gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
     {
       symval.set_output_value(target->plt_section()->address()
 			      + gsym->plt_offset());


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]