[GOLD] Got_entry::write addends

Message ID YTBFxqB9vIxGrAVm@squeak.grove.modra.org
State New
Headers show
Series
  • [GOLD] Got_entry::write addends
Related show

Commit Message

Alan Modra via Binutils Sept. 2, 2021, 3:32 a.m.
This takes care of writing out GOT entries with addends.  The local
symbol case was already largely handled, except for passing the addend
to tls_offset_for_local which might need the addend in a
local_got_offset call.  That's needed also in tls_offset_for_global.

I'm assuming here that GOT entries for function symbols won't ever
have addends, and in particular that a GOT entry referencing PLT call
stub code won't want an offset into the code.

	PR 28192
	* output.cc (Output_data_got::Got_entry::write): Include addend
	in global symbol value.  Pass addend to tls_offset_for_*.
	* powerpc.cc (Target_powerpc::do_tls_offset_for_local): Handle addend.
	(Target_powerpc::do_tls_offset_for_global): Likewise.
	* s390.cc (Target_s390::do_tls_offset_for_local): Likewise.
	(Target_s390::do_tls_offset_for_global): Likewise.
	* target.h (Target::tls_offset_for_local): Add addend param.
	(Target::tls_offset_for_global): Likewise.
	(Target::do_tls_offset_for_local): Likewise.
	(Target::do_tls_offset_for_global): Likewise.


-- 
Alan Modra
Australia Development Lab, IBM

Patch

diff --git a/gold/output.cc b/gold/output.cc
index c5f7eef0fbb..7ad8750aa36 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -1412,10 +1412,17 @@  Output_data_got<got_size, big_endian>::Got_entry::write(
 	      default:
 		gold_unreachable();
 	      }
+	    // If this is a GOT entry for a known value global symbol,
+	    // then the value should include the addend.  If the value
+	    // is not known leave the value as zero; The GOT entry
+	    // will be set by a dynamic relocation.
+	    if (this->addend_ && gsym->final_value_is_known())
+	      val += this->addend_;
 	    if (this->use_plt_or_tls_offset_
 		&& gsym->type() == elfcpp::STT_TLS)
 	      val += parameters->target().tls_offset_for_global(gsym,
-								got_indx);
+								got_indx,
+								this->addend_);
 	  }
       }
       break;
@@ -1444,7 +1451,8 @@  Output_data_got<got_size, big_endian>::Got_entry::write(
 	    val = convert_types<Valtype, uint64_t>(lval);
 	    if (this->use_plt_or_tls_offset_ && is_tls)
 	      val += parameters->target().tls_offset_for_local(object, lsi,
-							       got_indx);
+							       got_indx,
+							       this->addend_);
 	  }
       }
       break;
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 11b98695e64..0b6405915c2 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -825,12 +825,14 @@  class Target_powerpc : public Sized_target<size, big_endian>
   int64_t
   do_tls_offset_for_local(const Relobj* object,
 			  unsigned int symndx,
-			  unsigned int got_indx) const;
+			  unsigned int got_indx,
+			  uint64_t addend) const;
 
   // Return the offset to use for the GOT_INDX'th got entry which is
   // for global tls symbol GSYM.
   int64_t
-  do_tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const;
+  do_tls_offset_for_global(Symbol* gsym, unsigned int got_indx,
+			   uint64_t addend) const;
 
   void
   do_function_location(Symbol_location*) const;
@@ -12790,7 +12792,8 @@  int64_t
 Target_powerpc<size, big_endian>::do_tls_offset_for_local(
     const Relobj* object,
     unsigned int symndx,
-    unsigned int got_indx) const
+    unsigned int got_indx,
+    uint64_t addend) const
 {
   const Powerpc_relobj<size, big_endian>* ppc_object
     = static_cast<const Powerpc_relobj<size, big_endian>*>(object);
@@ -12799,9 +12802,10 @@  Target_powerpc<size, big_endian>::do_tls_offset_for_local(
       for (Got_type got_type = GOT_TYPE_TLSGD;
 	   got_type <= GOT_TYPE_TPREL;
 	   got_type = Got_type(got_type + 1))
-	if (ppc_object->local_has_got_offset(symndx, got_type))
+	if (ppc_object->local_has_got_offset(symndx, got_type, addend))
 	  {
-	    unsigned int off = ppc_object->local_got_offset(symndx, got_type);
+	    unsigned int off
+	      = ppc_object->local_got_offset(symndx, got_type, addend);
 	    if (got_type == GOT_TYPE_TLSGD)
 	      off += size / 8;
 	    if (off == got_indx * (size / 8))
@@ -12822,16 +12826,17 @@  template<int size, bool big_endian>
 int64_t
 Target_powerpc<size, big_endian>::do_tls_offset_for_global(
     Symbol* gsym,
-    unsigned int got_indx) const
+    unsigned int got_indx,
+    uint64_t addend) const
 {
   if (gsym->type() == elfcpp::STT_TLS)
     {
       for (Got_type got_type = GOT_TYPE_TLSGD;
 	   got_type <= GOT_TYPE_TPREL;
 	   got_type = Got_type(got_type + 1))
-	if (gsym->has_got_offset(got_type))
+	if (gsym->has_got_offset(got_type, addend))
 	  {
-	    unsigned int off = gsym->got_offset(got_type);
+	    unsigned int off = gsym->got_offset(got_type, addend);
 	    if (got_type == GOT_TYPE_TLSGD)
 	      off += size / 8;
 	    if (off == got_indx * (size / 8))
diff --git a/gold/s390.cc b/gold/s390.cc
index 600e70810d3..3095320524f 100644
--- a/gold/s390.cc
+++ b/gold/s390.cc
@@ -401,12 +401,14 @@  class Target_s390 : public Sized_target<size, true>
   int64_t
   do_tls_offset_for_local(const Relobj* object,
 			  unsigned int symndx,
-			  unsigned int got_indx) const;
+			  unsigned int got_indx,
+			  uint64_t addend) const;
 
   // Return the offset to use for the GOT_INDX'th got entry which is
   // for global tls symbol GSYM.
   int64_t
-  do_tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const;
+  do_tls_offset_for_global(Symbol* gsym, unsigned int got_indx,
+			   uint64_t addend) const;
 
   // This function should be defined in targets that can use relocation
   // types to determine (implemented in local_reloc_may_be_function_pointer
@@ -4218,7 +4220,8 @@  int64_t
 Target_s390<size>::do_tls_offset_for_local(
     const Relobj*,
     unsigned int,
-    unsigned int) const
+    unsigned int,
+    uint64_t) const
 {
   // The only way we can get called is when IEENT/GOTIE12/GOTIE20
   // couldn't be optimised to LE.
@@ -4232,7 +4235,8 @@  template<int size>
 int64_t
 Target_s390<size>::do_tls_offset_for_global(
     Symbol*,
-    unsigned int) const
+    unsigned int,
+    uint64_t) const
 {
   Output_segment* tls_segment = layout_->tls_segment();
   return -tls_segment->memsz();
diff --git a/gold/target.h b/gold/target.h
index 24f7111e922..4fce9fdf2c7 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -289,14 +289,16 @@  class Target
   int64_t
   tls_offset_for_local(const Relobj* object,
 		       unsigned int symndx,
-		       unsigned int got_indx) const
-  { return do_tls_offset_for_local(object, symndx, got_indx); }
+		       unsigned int got_indx,
+		       uint64_t addend) const
+  { return do_tls_offset_for_local(object, symndx, got_indx, addend); }
 
   // Return the offset to use for the GOT_INDX'th got entry which is
   // for global tls symbol GSYM.
   int64_t
-  tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const
-  { return do_tls_offset_for_global(gsym, got_indx); }
+  tls_offset_for_global(Symbol* gsym, unsigned int got_indx,
+			uint64_t addend) const
+  { return do_tls_offset_for_global(gsym, got_indx, addend); }
 
   // For targets that use function descriptors, if LOC is the location
   // of a function, modify it to point at the function entry location.
@@ -648,11 +650,12 @@  class Target
   { gold_unreachable(); }
 
   virtual int64_t
-  do_tls_offset_for_local(const Relobj*, unsigned int, unsigned int) const
+  do_tls_offset_for_local(const Relobj*, unsigned int, unsigned int,
+			  uint64_t) const
   { gold_unreachable(); }
 
   virtual int64_t
-  do_tls_offset_for_global(Symbol*, unsigned int) const
+  do_tls_offset_for_global(Symbol*, unsigned int, uint64_t) const
   { gold_unreachable(); }
 
   virtual void