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]

[PATCH 1/2] Allow use_plt_offset to be specified for global relocations in Gold


This is an infrastructure change to enable the next patch, which
adds support for IFUNC on sparc in Gold.

Relative relocations are weird on sparc.  On most other cpus the
relocation is computed by the dynamic linker using an assignment.
But on sparc, it's added to whatever value is in the reloc
location.

That's why sparc.cc has all this code which puts the constant
zero into the GOT slot and then does a R_SPARC_RELATIVE against
that.

So, for IFUNC, I need to use the relocation to get the PLT entry
address instead of using the GOT entry calculation to achieve
that.

Therefore, extend the existing use_plt_offset reloc facility in
Gold so that it can be used for global relocations and not just
local ones.

gold/

	* output.h (Output_reloc): Allow use_plt_offset for global relocs too.
	(class Output_data_reloc): Adjust calls to Output_reloc_type.
	(Output_data_reloc::add_global_relative): (RELA only) Add use_plt_offset.
	* output.cc (Output_reloc::Output_reloc): Add use_plt_offset flag for
	global relocs too.
	(Output_reloc::symbol_value): Respect use_plt_offset_ for global symbols.
	* powerpc.cc (Target_powerpc::Scan::global): Adjust add_global_relative
	calls.
	* sparc.cc (Target_sparc::Scan::global): Likewise.
	* x86_64.cc (Target_x86_64::Scan::global): Likewise.
---
 gold/output.cc  |   19 ++++++++++++++-----
 gold/output.h   |   56 +++++++++++++++++++++++++++++--------------------------
 gold/powerpc.cc |    6 +++---
 gold/sparc.cc   |    4 ++--
 gold/x86_64.cc  |   14 +++++++-------
 5 files changed, 56 insertions(+), 43 deletions(-)

diff --git a/gold/output.cc b/gold/output.cc
index ca19039..2236916 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -705,10 +705,11 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     Output_data* od,
     Address address,
     bool is_relative,
-    bool is_symbolless)
+    bool is_symbolless,
+    bool use_plt_offset)
   : address_(address), local_sym_index_(GSYM_CODE), type_(type),
     is_relative_(is_relative), is_symbolless_(is_symbolless),
-    is_section_symbol_(false), use_plt_offset_(false), shndx_(INVALID_CODE)
+    is_section_symbol_(false), use_plt_offset_(use_plt_offset), shndx_(INVALID_CODE)
 {
   // this->type_ is a bitfield; make sure TYPE fits.
   gold_assert(this->type_ == type);
@@ -726,10 +727,11 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     unsigned int shndx,
     Address address,
     bool is_relative,
-    bool is_symbolless)
+    bool is_symbolless,
+    bool use_plt_offset)
   : address_(address), local_sym_index_(GSYM_CODE), type_(type),
     is_relative_(is_relative), is_symbolless_(is_symbolless),
-    is_section_symbol_(false), use_plt_offset_(false), shndx_(shndx)
+    is_section_symbol_(false), use_plt_offset_(use_plt_offset), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
   // this->type_ is a bitfield; make sure TYPE fits.
@@ -1116,7 +1118,14 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::symbol_value(
     {
       const Sized_symbol<size>* sym;
       sym = static_cast<const Sized_symbol<size>*>(this->u1_.gsym);
-      return sym->value() + addend;
+      if (this->use_plt_offset_ && sym->has_plt_offset())
+	{
+	  uint64_t plt_address =
+	    parameters->target().plt_address_for_global(sym);
+	  return plt_address + sym->plt_offset();
+	}
+      else
+	return sym->value() + addend;
     }
   gold_assert(this->local_sym_index_ != SECTION_CODE
 	      && this->local_sym_index_ != TARGET_CODE
diff --git a/gold/output.h b/gold/output.h
index 838ca3d..3796e91 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -1021,12 +1021,13 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   // A reloc against a global symbol.
 
   Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
-	       Address address, bool is_relative, bool is_symbolless);
+	       Address address, bool is_relative, bool is_symbolless,
+	       bool use_plt_offset);
 
   Output_reloc(Symbol* gsym, unsigned int type,
                Sized_relobj<size, big_endian>* relobj,
 	       unsigned int shndx, Address address, bool is_relative,
-	       bool is_symbolless);
+	       bool is_symbolless, bool use_plt_offset);
 
   // A reloc against a local symbol or local section symbol.
 
@@ -1226,8 +1227,7 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   bool is_symbolless_ : 1;
   // True if the relocation is against a section symbol.
   bool is_section_symbol_ : 1;
-  // True if the addend should be the PLT offset.  This is used only
-  // for RELATIVE relocations to local symbols.
+  // True if the addend should be the PLT offset.
   // (Used only for RELA, but stored here for space.)
   bool use_plt_offset_ : 1;
   // If the reloc address is an input section in an object, the
@@ -1255,17 +1255,18 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 
   Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
 	       Address address, Addend addend, bool is_relative,
-	       bool is_symbolless)
-    : rel_(gsym, type, od, address, is_relative, is_symbolless),
+	       bool is_symbolless, bool use_plt_offset)
+    : rel_(gsym, type, od, address, is_relative, is_symbolless,
+	   use_plt_offset),
       addend_(addend)
   { }
 
   Output_reloc(Symbol* gsym, unsigned int type,
                Sized_relobj<size, big_endian>* relobj,
 	       unsigned int shndx, Address address, Addend addend,
-	       bool is_relative, bool is_symbolless)
+	       bool is_relative, bool is_symbolless, bool use_plt_offset)
     : rel_(gsym, type, relobj, shndx, address, is_relative,
-	   is_symbolless), addend_(addend)
+	   is_symbolless, use_plt_offset), addend_(addend)
   { }
 
   // A reloc against a local symbol.
@@ -1558,14 +1559,14 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 
   void
   add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
-  { this->add(od, Output_reloc_type(gsym, type, od, address, false, false)); }
+  { this->add(od, Output_reloc_type(gsym, type, od, address, false, false, false)); }
 
   void
   add_global(Symbol* gsym, unsigned int type, Output_data* od,
              Sized_relobj<size, big_endian>* relobj,
 	     unsigned int shndx, Address address)
   { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
-                                    false, false)); }
+                                    false, false, false)); }
 
   void
   add_global_generic(Symbol* gsym, unsigned int type, Output_data* od,
@@ -1574,7 +1575,7 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
     gold_assert(addend == 0);
     this->add(od, Output_reloc_type(gsym, type, od,
 				    convert_types<Address, uint64_t>(address),
-				    false, false));
+				    false, false, false));
   }
 
   void
@@ -1587,7 +1588,7 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
       static_cast<Sized_relobj<size, big_endian>*>(relobj);
     this->add(od, Output_reloc_type(gsym, type, sized_relobj, shndx,
 				    convert_types<Address, uint64_t>(address),
-				    false, false));
+				    false, false, false));
   }
 
   // Add a RELATIVE reloc against a global symbol.  The final relocation
@@ -1596,7 +1597,8 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
                       Address address)
-  { this->add(od, Output_reloc_type(gsym, type, od, address, true, true)); }
+  { this->add(od, Output_reloc_type(gsym, type, od, address, true, true,
+				    false)); }
 
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
@@ -1604,7 +1606,7 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
                       unsigned int shndx, Address address)
   {
     this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
-                                    true, true));
+                                    true, true, false));
   }
 
   // Add a global relocation which does not use a symbol for the relocation,
@@ -1613,7 +1615,8 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   void
   add_symbolless_global_addend(Symbol* gsym, unsigned int type,
 			       Output_data* od, Address address)
-  { this->add(od, Output_reloc_type(gsym, type, od, address, false, true)); }
+  { this->add(od, Output_reloc_type(gsym, type, od, address, false, true,
+				    false)); }
 
   void
   add_symbolless_global_addend(Symbol* gsym, unsigned int type,
@@ -1622,7 +1625,7 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 			       unsigned int shndx, Address address)
   {
     this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
-                                    false, true));
+                                    false, true, false));
   }
 
   // Add a reloc against a local symbol.
@@ -1825,7 +1828,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   add_global(Symbol* gsym, unsigned int type, Output_data* od,
 	     Address address, Addend addend)
   { this->add(od, Output_reloc_type(gsym, type, od, address, addend,
-                                    false, false)); }
+                                    false, false, false)); }
 
   void
   add_global(Symbol* gsym, unsigned int type, Output_data* od,
@@ -1833,7 +1836,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 	     unsigned int shndx, Address address,
 	     Addend addend)
   { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
-                                    addend, false, false)); }
+                                    addend, false, false, false)); }
 
   void
   add_global_generic(Symbol* gsym, unsigned int type, Output_data* od,
@@ -1842,7 +1845,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
     this->add(od, Output_reloc_type(gsym, type, od,
 				    convert_types<Address, uint64_t>(address),
 				    convert_types<Addend, uint64_t>(addend),
-				    false, false));
+				    false, false, false));
   }
 
   void
@@ -1855,7 +1858,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
     this->add(od, Output_reloc_type(gsym, type, sized_relobj, shndx,
 				    convert_types<Address, uint64_t>(address),
 				    convert_types<Addend, uint64_t>(addend),
-				    false, false));
+				    false, false, false));
   }
 
   // Add a RELATIVE reloc against a global symbol.  The final output
@@ -1865,16 +1868,17 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
-	              Address address, Addend addend)
+	              Address address, Addend addend, bool use_plt_offset)
   { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true,
-				    true)); }
+				    true, use_plt_offset)); }
 
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
                       Sized_relobj<size, big_endian>* relobj,
-                      unsigned int shndx, Address address, Addend addend)
+                      unsigned int shndx, Address address, Addend addend,
+		      bool use_plt_offset)
   { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
-                                    addend, true, true)); }
+                                    addend, true, true, use_plt_offset)); }
 
   // Add a global relocation which does not use a symbol for the relocation,
   // but which gets its addend from a symbol.
@@ -1883,7 +1887,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   add_symbolless_global_addend(Symbol* gsym, unsigned int type, Output_data* od,
 			       Address address, Addend addend)
   { this->add(od, Output_reloc_type(gsym, type, od, address, addend,
-				    false, true)); }
+				    false, true, false)); }
 
   void
   add_symbolless_global_addend(Symbol* gsym, unsigned int type,
@@ -1891,7 +1895,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 			       Sized_relobj<size, big_endian>* relobj,
 			       unsigned int shndx, Address address, Addend addend)
   { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
-                                    addend, false, true)); }
+                                    addend, false, true, false)); }
 
   // Add a reloc against a local symbol.
 
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 372443f..b443304 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -1486,7 +1486,7 @@ Target_powerpc<size, big_endian>::Scan::global(
                 rela_dyn->add_global_relative(gsym, elfcpp::R_POWERPC_RELATIVE,
 					      output_section, object,
 					      data_shndx, reloc.get_r_offset(),
-					      reloc.get_r_addend());
+					      reloc.get_r_addend(), false);
               }
             else
               {
@@ -1505,7 +1505,7 @@ Target_powerpc<size, big_endian>::Scan::global(
 						output_section, object,
 						data_shndx,
 						reloc.get_r_offset(),
-						reloc.get_r_addend());
+						reloc.get_r_addend(), false);
               }
           }
       }
@@ -1574,7 +1574,7 @@ Target_powerpc<size, big_endian>::Scan::global(
 
 		gsym->set_got_offset(GOT_TYPE_STANDARD, off);
 		rela_dyn->add_global_relative(gsym, elfcpp::R_POWERPC_RELATIVE,
-					      got, off, 0);
+					      got, off, 0, false);
 	      }
           }
       }
diff --git a/gold/sparc.cc b/gold/sparc.cc
index ee82367..e1bdc8e 100644
--- a/gold/sparc.cc
+++ b/gold/sparc.cc
@@ -2333,7 +2333,7 @@ Target_sparc<size, big_endian>::Scan::global(
                 rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
 					      output_section, object,
 					      data_shndx, reloc.get_r_offset(),
-					      reloc.get_r_addend());
+					      reloc.get_r_addend(), false);
               }
             else
               {
@@ -2387,7 +2387,7 @@ Target_sparc<size, big_endian>::Scan::global(
 
 		gsym->set_got_offset(GOT_TYPE_STANDARD, off);
 		rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
-					      got, off, 0);
+					      got, off, 0, false);
 	      }
           }
       }
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 3962e1e..d67924b 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -1667,24 +1667,24 @@ Target_x86_64<size>::reserve_global_got_entry(unsigned int got_index,
 				 this->got_, got_offset, 0);
 	  else
 	    rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_RELATIVE,
-					  this->got_, got_offset, 0);
+					  this->got_, got_offset, 0, false);
 	}
       break;
     case GOT_TYPE_TLS_OFFSET:
       rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_TPOFF64,
-				    this->got_, got_offset, 0);
+				    this->got_, got_offset, 0, false);
       break;
     case GOT_TYPE_TLS_PAIR:
       this->got_->reserve_slot(got_index + 1);
       rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_DTPMOD64,
-				    this->got_, got_offset, 0);
+				    this->got_, got_offset, 0, false);
       rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_DTPOFF64,
-				    this->got_, got_offset + 8, 0);
+				    this->got_, got_offset + 8, 0, false);
       break;
     case GOT_TYPE_TLS_DESC:
       this->got_->reserve_slot(got_index + 1);
       rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_TLSDESC,
-				    this->got_, got_offset, 0);
+				    this->got_, got_offset, 0, false);
       break;
     default:
       gold_unreachable();
@@ -2505,7 +2505,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
 					      output_section, object,
 					      data_shndx,
 					      reloc.get_r_offset(),
-					      reloc.get_r_addend());
+					      reloc.get_r_addend(), false);
               }
             else
               {
@@ -2612,7 +2612,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab,
 		    unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD);
 		    rela_dyn->add_global_relative(gsym,
 						  elfcpp::R_X86_64_RELATIVE,
-						  got, got_off, 0);
+						  got, got_off, 0, false);
 		  }
               }
           }
-- 
1.7.9.5


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