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]: Allow relative calculations for non-R_*_RELATIVE relocs.


Ok Ian, this is what I came up with.

With this and the included sparc target changes, the entire GOLD
testsuite as of two days ago passes for me on sparc.

Once this is settled I'll hit those new testcases you added over the
past few days.

If you don't like the new attribute name, I can easily change it to
something you think is more appropriate.

Thanks!

gold/

2010-02-11  David S. Miller  <davem@davemloft.net>

	* output.h (Output_reloc<SHT_REL>::Output_reloc): Add
	use_relative_calculations parameter.
	(Output_reloc<SHT_REL>::use_relative_calculations): New.
	(Output_reloc<SHT_REL>::use_relative_calculations_): New.
	(Output_reloc<SHT_RELA>::Output_reloc): Add
	use_relative_calculations parameter.
	(Output_reloc<SHT_RELA>::use_relative_calculations): New.
	(Output_data_reloc::add_global): Handle use_relative_calculations.
	(Output_data_reloc::add_global_relative): Likewise.
	(Output_data_reloc::add_local): Likewise.
	(Output_data_reloc::add_local_relative): Likewise.
	* output.cc (Output_reloc<SHT_REL>::Output_reloc): Handle
	use_relative_calculations.
	(Output_reloc::set_needs_dynsym_index): Test ->use_relative_calculations_
	instead of ->is_relative_
	(Output_reloc::write_rel): Likewise.
	(Output_reloc::write): Likewise.
	(Output_reloc::compare): Do not attempt to sort by symbol index when
	->use_relative_calculations is true.

	* sparc.cc (Target_sparc::Scan::local): Use ->add_local_relative as needed.
	(Target_sparc::Scan::global): Use ->add_global_relative as needed.  Also,
	emit appropriate unaligned vs. aligned dynamic reloc based upon relocation
	offset.
	
diff --git a/gold/output.cc b/gold/output.cc
index 4b34b8b..12c1e0e 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -638,9 +638,12 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     unsigned int type,
     Output_data* od,
     Address address,
-    bool is_relative)
+    bool is_relative,
+    bool use_relative_calculations)
   : address_(address), local_sym_index_(GSYM_CODE), type_(type),
-    is_relative_(is_relative), is_section_symbol_(false), shndx_(INVALID_CODE)
+    is_relative_(is_relative),
+    use_relative_calculations_(use_relative_calculations),
+    is_section_symbol_(false), shndx_(INVALID_CODE)
 {
   // this->type_ is a bitfield; make sure TYPE fits.
   gold_assert(this->type_ == type);
@@ -657,9 +660,12 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     Sized_relobj<size, big_endian>* relobj,
     unsigned int shndx,
     Address address,
-    bool is_relative)
+    bool is_relative,
+    bool use_relative_calculations)
   : address_(address), local_sym_index_(GSYM_CODE), type_(type),
-    is_relative_(is_relative), is_section_symbol_(false), shndx_(shndx)
+    is_relative_(is_relative),
+    use_relative_calculations_(use_relative_calculations),
+    is_section_symbol_(false), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
   // this->type_ is a bitfield; make sure TYPE fits.
@@ -680,10 +686,12 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     Output_data* od,
     Address address,
     bool is_relative,
+    bool use_relative_calculations,
     bool is_section_symbol)
   : address_(address), local_sym_index_(local_sym_index), type_(type),
-    is_relative_(is_relative), is_section_symbol_(is_section_symbol),
-    shndx_(INVALID_CODE)
+    is_relative_(is_relative),
+    use_relative_calculations_(use_relative_calculations),
+    is_section_symbol_(is_section_symbol), shndx_(INVALID_CODE)
 {
   gold_assert(local_sym_index != GSYM_CODE
               && local_sym_index != INVALID_CODE);
@@ -703,10 +711,12 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     unsigned int shndx,
     Address address,
     bool is_relative,
+    bool use_relative_calculations,
     bool is_section_symbol)
   : address_(address), local_sym_index_(local_sym_index), type_(type),
-    is_relative_(is_relative), is_section_symbol_(is_section_symbol),
-    shndx_(shndx)
+    is_relative_(is_relative),
+    use_relative_calculations_(use_relative_calculations),
+    is_section_symbol_(is_section_symbol), shndx_(shndx)
 {
   gold_assert(local_sym_index != GSYM_CODE
               && local_sym_index != INVALID_CODE);
@@ -728,7 +738,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     Output_data* od,
     Address address)
   : address_(address), local_sym_index_(SECTION_CODE), type_(type),
-    is_relative_(false), is_section_symbol_(true), shndx_(INVALID_CODE)
+    is_relative_(false), use_relative_calculations_(false),
+    is_section_symbol_(true), shndx_(INVALID_CODE)
 {
   // this->type_ is a bitfield; make sure TYPE fits.
   gold_assert(this->type_ == type);
@@ -748,7 +759,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     unsigned int shndx,
     Address address)
   : address_(address), local_sym_index_(SECTION_CODE), type_(type),
-    is_relative_(false), is_section_symbol_(true), shndx_(shndx)
+    is_relative_(false), use_relative_calculations_(false),
+    is_section_symbol_(true), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
   // this->type_ is a bitfield; make sure TYPE fits.
@@ -769,7 +781,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     Output_data* od,
     Address address)
   : address_(address), local_sym_index_(0), type_(type),
-    is_relative_(false), is_section_symbol_(false), shndx_(INVALID_CODE)
+    is_relative_(false), use_relative_calculations_(false),
+    is_section_symbol_(false), shndx_(INVALID_CODE)
 {
   // this->type_ is a bitfield; make sure TYPE fits.
   gold_assert(this->type_ == type);
@@ -784,7 +797,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     unsigned int shndx,
     Address address)
   : address_(address), local_sym_index_(0), type_(type),
-    is_relative_(false), is_section_symbol_(false), shndx_(shndx)
+    is_relative_(false), use_relative_calculations_(false),
+    is_section_symbol_(false), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
   // this->type_ is a bitfield; make sure TYPE fits.
@@ -802,7 +816,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     Output_data* od,
     Address address)
   : address_(address), local_sym_index_(TARGET_CODE), type_(type),
-    is_relative_(false), is_section_symbol_(false), shndx_(INVALID_CODE)
+    is_relative_(false), use_relative_calculations_(false),
+    is_section_symbol_(false), shndx_(INVALID_CODE)
 {
   // this->type_ is a bitfield; make sure TYPE fits.
   gold_assert(this->type_ == type);
@@ -818,7 +833,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     unsigned int shndx,
     Address address)
   : address_(address), local_sym_index_(TARGET_CODE), type_(type),
-    is_relative_(false), is_section_symbol_(false), shndx_(shndx)
+    is_relative_(false), use_relative_calculations_(false),
+    is_section_symbol_(false), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
   // this->type_ is a bitfield; make sure TYPE fits.
@@ -834,7 +850,7 @@ void
 Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
 set_needs_dynsym_index()
 {
-  if (this->is_relative_)
+  if (this->use_relative_calculations_)
     return;
   switch (this->local_sym_index_)
     {
@@ -995,7 +1011,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
     Write_rel* wr) const
 {
   wr->put_r_offset(this->get_address());
-  unsigned int sym_index = this->is_relative_ ? 0 : this->get_symbol_index();
+  unsigned int sym_index = (this->use_relative_calculations_
+			    ? 0 : this->get_symbol_index());
   wr->put_r_info(elfcpp::elf_r_info<size>(sym_index, this->type_));
 }
 
@@ -1053,7 +1070,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
     }
   else if (r2.is_relative_)
     return 1;
-  else
+  else if (!this->use_relative_calculations_
+	   && !r2.use_relative_calculations_)
     {
       unsigned int sym1 = this->get_symbol_index();
       unsigned int sym2 = r2.get_symbol_index();
@@ -1097,7 +1115,7 @@ Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write(
   if (this->rel_.is_target_specific())
     addend = parameters->target().reloc_addend(this->rel_.target_arg(),
 					       this->rel_.type(), addend);
-  else if (this->rel_.is_relative())
+  else if (this->rel_.use_relative_calculations())
     addend = this->rel_.symbol_value(addend);
   else if (this->rel_.is_local_section_symbol())
     addend = this->rel_.local_section_offset(addend);
diff --git a/gold/output.h b/gold/output.h
index a549b74..7fce367 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -974,23 +974,24 @@ 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);
+	       Address address, bool is_relative, bool use_relative_calculations);
 
   Output_reloc(Symbol* gsym, unsigned int type,
                Sized_relobj<size, big_endian>* relobj,
-	       unsigned int shndx, Address address, bool is_relative);
+	       unsigned int shndx, Address address, bool is_relative,
+	       bool use_relative_calculations);
 
   // A reloc against a local symbol or local section symbol.
 
   Output_reloc(Sized_relobj<size, big_endian>* relobj,
 	       unsigned int local_sym_index, unsigned int type,
 	       Output_data* od, Address address, bool is_relative,
-               bool is_section_symbol);
+               bool use_relative_calculations, bool is_section_symbol);
 
   Output_reloc(Sized_relobj<size, big_endian>* relobj,
 	       unsigned int local_sym_index, unsigned int type,
 	       unsigned int shndx, Address address, bool is_relative,
-               bool is_section_symbol);
+               bool use_relative_calculations, bool is_section_symbol);
 
   // A reloc against the STT_SECTION symbol of an output section.
 
@@ -1029,6 +1030,12 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   is_relative() const
   { return this->is_relative_; }
 
+  // Return whether this is a relocation which should use RELATIVE
+  // calculations.
+  bool
+  use_relative_calculations() const
+  { return this->use_relative_calculations_; }
+
   // Return whether this is against a local section symbol.
   bool
   is_local_section_symbol() const
@@ -1155,6 +1162,9 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   unsigned int type_ : 30;
   // True if the relocation is a RELATIVE relocation.
   bool is_relative_ : 1;
+  // True if the relocation is not RELATIVE but should be computed
+  // just like one
+  bool use_relative_calculations_ : 1;
   // True if the relocation is against a section symbol.
   bool is_section_symbol_ : 1;
   // If the reloc address is an input section in an object, the
@@ -1181,15 +1191,18 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   // A reloc against a global symbol.
 
   Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
-	       Address address, Addend addend, bool is_relative)
-    : rel_(gsym, type, od, address, is_relative), addend_(addend)
+	       Address address, Addend addend, bool is_relative,
+	       bool use_relative_calculations)
+    : rel_(gsym, type, od, address, is_relative, use_relative_calculations),
+      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)
-    : rel_(gsym, type, relobj, shndx, address, is_relative), addend_(addend)
+	       bool is_relative, bool use_relative_calculations)
+    : rel_(gsym, type, relobj, shndx, address, is_relative,
+	   use_relative_calculations), addend_(addend)
   { }
 
   // A reloc against a local symbol.
@@ -1197,18 +1210,20 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   Output_reloc(Sized_relobj<size, big_endian>* relobj,
 	       unsigned int local_sym_index, unsigned int type,
 	       Output_data* od, Address address,
-	       Addend addend, bool is_relative, bool is_section_symbol)
+	       Addend addend, bool is_relative,
+	       bool use_relative_calculations, bool is_section_symbol)
     : rel_(relobj, local_sym_index, type, od, address, is_relative,
-           is_section_symbol),
+           use_relative_calculations, is_section_symbol),
       addend_(addend)
   { }
 
   Output_reloc(Sized_relobj<size, big_endian>* relobj,
 	       unsigned int local_sym_index, unsigned int type,
 	       unsigned int shndx, Address address,
-	       Addend addend, bool is_relative, bool is_section_symbol)
+	       Addend addend, bool is_relative,
+	       bool use_relative_calculations, bool is_section_symbol)
     : rel_(relobj, local_sym_index, type, shndx, address, is_relative,
-           is_section_symbol),
+           use_relative_calculations, is_section_symbol),
       addend_(addend)
   { }
 
@@ -1257,6 +1272,12 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   is_relative() const
   { return this->rel_.is_relative(); }
 
+  // Return whether this is relocation should use RELATIVE
+  // calculations.
+  bool
+  use_relative_calculations() const
+  { return this->rel_.use_relative_calculations(); }
+
   // Write the reloc entry to an output view.
   void
   write(unsigned char* pov) const;
@@ -1413,14 +1434,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)); }
+  { this->add(od, Output_reloc_type(gsym, type, od, address, 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)); }
 
   // These are to simplify the Copy_relocs class.
 
@@ -1447,7 +1468,12 @@ 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)); }
+  { this->add(od, Output_reloc_type(gsym, type, od, address, true, true)); }
+
+  void
+  add_global_relative(Symbol* gsym, bool is_relative, unsigned int type,
+		      Output_data* od, Address address)
+  { this->add(od, Output_reloc_type(gsym, type, od, address, is_relative, true)); }
 
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
@@ -1455,7 +1481,16 @@ 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));
+  }
+
+  void
+  add_global_relative(Symbol* gsym, bool is_relative, 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,
+                                    is_relative, true));
   }
 
   // Add a reloc against a local symbol.
@@ -1466,7 +1501,7 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 	    Output_data* od, Address address)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
-                                    address, false, false));
+                                    address, false, false, false));
   }
 
   void
@@ -1475,7 +1510,7 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 	    Output_data* od, unsigned int shndx, Address address)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
-				    address, false, false));
+				    address, false, false, false));
   }
 
   // Add a RELATIVE reloc against a local symbol.
@@ -1486,7 +1521,16 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 	             Output_data* od, Address address)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
-                                    address, true, false));
+                                    address, true, true, false));
+  }
+
+  void
+  add_local_relative(Sized_relobj<size, big_endian>* relobj, bool is_relative,
+	             unsigned int local_sym_index, unsigned int type,
+	             Output_data* od, Address address)
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
+                                    address, is_relative, true, false));
   }
 
   void
@@ -1495,7 +1539,16 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 	             Output_data* od, unsigned int shndx, Address address)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
-				    address, true, false));
+				    address, true, true, false));
+  }
+
+  void
+  add_local_relative(Sized_relobj<size, big_endian>* relobj, bool is_relative,
+	             unsigned int local_sym_index, unsigned int type,
+	             Output_data* od, unsigned int shndx, Address address)
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+				    address, is_relative, true, false));
   }
 
   // Add a reloc against a local section symbol.  This will be
@@ -1508,7 +1561,7 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
                     Output_data* od, Address address)
   {
     this->add(od, Output_reloc_type(relobj, input_shndx, type, od,
-                                    address, false, true));
+                                    address, false, false, true));
   }
 
   void
@@ -1517,7 +1570,7 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
                     Output_data* od, unsigned int shndx, Address address)
   {
     this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
-                                    address, false, true));
+                                    address, false, false, true));
   }
 
   // A reloc against the STT_SECTION symbol of an output section.
@@ -1587,7 +1640,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)); }
 
   void
   add_global(Symbol* gsym, unsigned int type, Output_data* od,
@@ -1595,7 +1648,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)); }
+                                    addend, false, false)); }
 
   // Add a RELATIVE reloc against a global symbol.  The final output
   // relocation will not reference the symbol, but we must keep the symbol
@@ -1605,14 +1658,28 @@ 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)
-  { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true)); }
+  { this->add(od, Output_reloc_type(gsym, type, od, address, addend, true,
+				    true)); }
+
+  void
+  add_global_relative(Symbol* gsym, bool is_relative, unsigned int type,
+		      Output_data* od, Address address, Addend addend)
+  { this->add(od, Output_reloc_type(gsym, type, od, address, addend,
+				    is_relative, true)); }
 
   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)
   { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
-                                    addend, true)); }
+                                    addend, true, true)); }
+
+  void
+  add_global_relative(Symbol* gsym, bool is_relative, unsigned int type,
+		      Output_data* od, 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, is_relative, true)); }
 
   // Add a reloc against a local symbol.
 
@@ -1622,7 +1689,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 	    Output_data* od, Address address, Addend addend)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
-				    addend, false, false));
+				    addend, false, false, false));
   }
 
   void
@@ -1632,7 +1699,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 	    Addend addend)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
-                                    address, addend, false, false));
+                                    address, addend, false, false, false));
   }
 
   // Add a RELATIVE reloc against a local symbol.
@@ -1643,7 +1710,16 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 	             Output_data* od, Address address, Addend addend)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
-				    addend, true, false));
+				    addend, true, true, false));
+  }
+
+  void
+  add_local_relative(Sized_relobj<size, big_endian>* relobj, bool is_relative,
+	             unsigned int local_sym_index, unsigned int type,
+	             Output_data* od, Address address, Addend addend)
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
+				    addend, is_relative, true, false));
   }
 
   void
@@ -1653,7 +1729,17 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 	             Addend addend)
   {
     this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
-                                    address, addend, true, false));
+                                    address, addend, true, true, false));
+  }
+
+  void
+  add_local_relative(Sized_relobj<size, big_endian>* relobj, bool is_relative,
+	             unsigned int local_sym_index, unsigned int type,
+	             Output_data* od, unsigned int shndx, Address address,
+	             Addend addend)
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+                                    address, addend, is_relative, true, false));
   }
 
   // Add a reloc against a local section symbol.  This will be
@@ -1666,7 +1752,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
                     Output_data* od, Address address, Addend addend)
   {
     this->add(od, Output_reloc_type(relobj, input_shndx, type, od, address,
-				    addend, false, true));
+				    addend, false, false, true));
   }
 
   void
@@ -1676,7 +1762,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 	             Addend addend)
   {
     this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
-                                    address, addend, false, true));
+                                    address, addend, false, false, true));
   }
 
   // A reloc against the STT_SECTION symbol of an output section.
diff --git a/gold/sparc.cc b/gold/sparc.cc
index 234c5f5..3373594 100644
--- a/gold/sparc.cc
+++ b/gold/sparc.cc
@@ -1686,20 +1686,11 @@ Target_sparc<size, big_endian>::Scan::local(
             }
           else
             {
-	      unsigned int shndx = lsym.get_st_shndx();
-	      bool is_ordinary;
-
               gold_assert(lsym.get_st_value() == 0);
-	      shndx = object->adjust_sym_shndx(r_sym, shndx,
-					       &is_ordinary);
-	      if (!is_ordinary)
-		object->error(_("section symbol %u has bad shndx %u"),
-			      r_sym, shndx);
-	      else
-		rela_dyn->add_local_section(object, shndx,
-					    r_type, output_section,
-					    data_shndx, reloc.get_r_offset(),
-					    reloc.get_r_addend());
+	      rela_dyn->add_local_relative(object, false, r_sym, orig_r_type,
+					   output_section, data_shndx,
+					   reloc.get_r_offset(),
+					   reloc.get_r_addend());
             }
         }
       break;
@@ -1847,13 +1838,15 @@ Target_sparc<size, big_endian>::Scan::local(
 		if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_OFFSET))
 		  {
 		    Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+		    unsigned int off = got->add_constant(0);
+
+		    object->set_local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET, off);
 
-		    got->add_local_with_rela(object, r_sym,
-					     GOT_TYPE_TLS_OFFSET,
-					     rela_dyn,
-					     (size == 64 ?
-					      elfcpp::R_SPARC_TLS_TPOFF64 :
-					      elfcpp::R_SPARC_TLS_TPOFF32));
+		    rela_dyn->add_local_relative(object, false, r_sym,
+						 (size == 64 ?
+						  elfcpp::R_SPARC_TLS_TPOFF64 :
+						  elfcpp::R_SPARC_TLS_TPOFF32),
+						 got, off, 0);
 		  }
 	      }
 	    else if (optimized_type != tls::TLSOPT_TO_LE)
@@ -1869,9 +1862,9 @@ Target_sparc<size, big_endian>::Scan::local(
                 gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
                 unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
                 Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-                rela_dyn->add_local(object, r_sym, r_type,
-				    output_section, data_shndx,
-				    reloc.get_r_offset(), 0);
+                rela_dyn->add_local_relative(object, false, r_sym, r_type,
+					     output_section, data_shndx,
+					     reloc.get_r_offset(), 0);
 	      }
 	    break;
 	  }
@@ -2046,6 +2039,38 @@ Target_sparc<size, big_endian>::Scan::global(
         // Make a dynamic relocation if necessary.
         if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
           {
+	    unsigned int r_off = reloc.get_r_offset();
+
+	    // The assembler can sometimes emit unaligned relocations
+	    // for dwarf2 cfi directives. 
+	    switch (r_type)
+	      {
+	      case elfcpp::R_SPARC_16:
+		if (r_off & 0x1)
+		  orig_r_type = r_type = elfcpp::R_SPARC_UA16;
+		break;
+	      case elfcpp::R_SPARC_32:
+		if (r_off & 0x3)
+		  orig_r_type = r_type = elfcpp::R_SPARC_UA32;
+		break;
+	      case elfcpp::R_SPARC_64:
+		if (r_off & 0x7)
+		  orig_r_type = r_type = elfcpp::R_SPARC_UA64;
+		break;
+	      case elfcpp::R_SPARC_UA16:
+		if (!(r_off & 0x1))
+		  orig_r_type = r_type = elfcpp::R_SPARC_16;
+		break;
+	      case elfcpp::R_SPARC_UA32:
+		if (!(r_off & 0x3))
+		  orig_r_type = r_type = elfcpp::R_SPARC_32;
+		break;
+	      case elfcpp::R_SPARC_UA64:
+		if (!(r_off & 0x7))
+		  orig_r_type = r_type = elfcpp::R_SPARC_64;
+		break;
+	      }
+
             if (gsym->may_need_copy_reloc())
               {
 	        target->copy_reloc(symtab, layout, object,
@@ -2066,10 +2091,19 @@ Target_sparc<size, big_endian>::Scan::global(
                 Reloc_section* rela_dyn = target->rela_dyn_section(layout);
 
 		check_non_pic(object, r_type);
-		rela_dyn->add_global(gsym, orig_r_type, output_section,
-				     object, data_shndx,
-				     reloc.get_r_offset(),
-				     reloc.get_r_addend());
+		if (gsym->is_from_dynobj()
+		    || gsym->is_undefined()
+		    || gsym->is_preemptible())
+		  rela_dyn->add_global(gsym, orig_r_type, output_section,
+				       object, data_shndx,
+				       reloc.get_r_offset(),
+				       reloc.get_r_addend());
+		else
+		  rela_dyn->add_global_relative(gsym, false, orig_r_type,
+						output_section,
+						object, data_shndx,
+						reloc.get_r_offset(),
+						reloc.get_r_addend());
               }
           }
       }
@@ -2201,10 +2235,10 @@ Target_sparc<size, big_endian>::Scan::global(
 	    if (parameters->options().shared())
 	      {
 		Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-		rela_dyn->add_global(gsym, orig_r_type,
-				     output_section, object,
-				     data_shndx, reloc.get_r_offset(),
-				     0);
+		rela_dyn->add_global_relative(gsym, false, orig_r_type,
+					      output_section, object,
+					      data_shndx, reloc.get_r_offset(),
+					      0);
 	      }
 	    break;
 


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