* output.h (Output_reloc<SHT_REL>::Output_reloc): Add
authorDavid S. Miller <davem@redhat.com>
Sat, 13 Feb 2010 00:01:20 +0000 (00:01 +0000)
committerDavid S. Miller <davem@redhat.com>
Sat, 13 Feb 2010 00:01:20 +0000 (00:01 +0000)
is_symbolless parameter.
(Output_reloc<SHT_REL>::is_symbolless): New.
(Output_reloc<SHT_REL>::is_symbolless_): New.
(Output_reloc<SHT_REL>::type_): Decrease to 29 bits.
(Output_reloc<SHT_RELA>::Output_reloc): Add is_symbolless parameter.
(Output_reloc<SHT_RELA>::is_symbolless): New.
(Output_data_reloc::add_global): Handle is_symbolless.
(Output_data_reloc::add_global_relative): Likewise.
(Output_data_reloc::add_local): Likewise.
(Output_data_reloc::add_local_relative): Likewise.
(Output_data_reloc::add_symbolless_global_addend): New.
(Output_data_reloc::add_symbolless_local_addend): New.
* output.cc (Output_reloc<SHT_REL>::Output_reloc): Handle
is_symbolless.
(Output_reloc::set_needs_dynsym_index): Test ->is_symbolless_
instead of ->is_relative_
(Output_reloc::write): Likewise.
(Output_reloc::get_symbol_index): Return 0 when ->is_symbolless_
(Output_reloc::write_rel): Simplify.

* sparc.cc (Target_sparc::Scan::local): Use
->add_symbolless_local_addend as needed.
(Target_sparc::Scan::global): Use ->add_symbolless_global_addend as
needed.  Also, emit appropriate unaligned vs. aligned dynamic reloc
based upon relocation offset.

gold/ChangeLog
gold/output.cc
gold/output.h
gold/sparc.cc

index 0b50ead..936d0b9 100644 (file)
@@ -1,3 +1,32 @@
+2010-02-12  David S. Miller  <davem@davemloft.net>
+
+       * output.h (Output_reloc<SHT_REL>::Output_reloc): Add
+       is_symbolless parameter.
+       (Output_reloc<SHT_REL>::is_symbolless): New.
+       (Output_reloc<SHT_REL>::is_symbolless_): New.
+       (Output_reloc<SHT_REL>::type_): Decrease to 29 bits.
+       (Output_reloc<SHT_RELA>::Output_reloc): Add is_symbolless parameter.
+       (Output_reloc<SHT_RELA>::is_symbolless): New.
+       (Output_data_reloc::add_global): Handle is_symbolless.
+       (Output_data_reloc::add_global_relative): Likewise.
+       (Output_data_reloc::add_local): Likewise.
+       (Output_data_reloc::add_local_relative): Likewise.
+       (Output_data_reloc::add_symbolless_global_addend): New.
+       (Output_data_reloc::add_symbolless_local_addend): New.
+       * output.cc (Output_reloc<SHT_REL>::Output_reloc): Handle
+       is_symbolless.
+       (Output_reloc::set_needs_dynsym_index): Test ->is_symbolless_
+       instead of ->is_relative_
+       (Output_reloc::write): Likewise.
+       (Output_reloc::get_symbol_index): Return 0 when ->is_symbolless_
+       (Output_reloc::write_rel): Simplify.
+
+       * sparc.cc (Target_sparc::Scan::local): Use
+       ->add_symbolless_local_addend as needed.
+       (Target_sparc::Scan::global): Use ->add_symbolless_global_addend as
+       needed.  Also, emit appropriate unaligned vs. aligned dynamic reloc
+       based upon relocation offset.
+
 2010-02-11  Doug Kwan  <dougkwan@google.com>
 
        * arm.cc (Target_arm::Scan::local): Fix bugs in relocation handling.
index 4b34b8b..1c2533c 100644 (file)
@@ -638,9 +638,11 @@ 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 is_symbolless)
   : address_(address), local_sym_index_(GSYM_CODE), type_(type),
-    is_relative_(is_relative), is_section_symbol_(false), shndx_(INVALID_CODE)
+    is_relative_(is_relative), is_symbolless_(is_symbolless),
+    is_section_symbol_(false), shndx_(INVALID_CODE)
 {
   // this->type_ is a bitfield; make sure TYPE fits.
   gold_assert(this->type_ == type);
@@ -657,9 +659,11 @@ 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 is_symbolless)
   : address_(address), local_sym_index_(GSYM_CODE), type_(type),
-    is_relative_(is_relative), is_section_symbol_(false), shndx_(shndx)
+    is_relative_(is_relative), is_symbolless_(is_symbolless),
+    is_section_symbol_(false), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
   // this->type_ is a bitfield; make sure TYPE fits.
@@ -680,10 +684,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_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), is_symbolless_(is_symbolless),
+    is_section_symbol_(is_section_symbol), shndx_(INVALID_CODE)
 {
   gold_assert(local_sym_index != GSYM_CODE
               && local_sym_index != INVALID_CODE);
@@ -703,10 +708,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_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), is_symbolless_(is_symbolless),
+    is_section_symbol_(is_section_symbol), shndx_(shndx)
 {
   gold_assert(local_sym_index != GSYM_CODE
               && local_sym_index != INVALID_CODE);
@@ -728,7 +734,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), is_symbolless_(false),
+    is_section_symbol_(true), shndx_(INVALID_CODE)
 {
   // this->type_ is a bitfield; make sure TYPE fits.
   gold_assert(this->type_ == type);
@@ -748,7 +755,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), is_symbolless_(false),
+    is_section_symbol_(true), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
   // this->type_ is a bitfield; make sure TYPE fits.
@@ -769,7 +777,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), is_symbolless_(false),
+    is_section_symbol_(false), shndx_(INVALID_CODE)
 {
   // this->type_ is a bitfield; make sure TYPE fits.
   gold_assert(this->type_ == type);
@@ -784,7 +793,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), is_symbolless_(false),
+    is_section_symbol_(false), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
   // this->type_ is a bitfield; make sure TYPE fits.
@@ -802,7 +812,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), is_symbolless_(false),
+    is_section_symbol_(false), shndx_(INVALID_CODE)
 {
   // this->type_ is a bitfield; make sure TYPE fits.
   gold_assert(this->type_ == type);
@@ -818,7 +829,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), is_symbolless_(false),
+    is_section_symbol_(false), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
   // this->type_ is a bitfield; make sure TYPE fits.
@@ -834,7 +846,7 @@ void
 Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
 set_needs_dynsym_index()
 {
-  if (this->is_relative_)
+  if (this->is_symbolless_)
     return;
   switch (this->local_sym_index_)
     {
@@ -876,6 +888,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
   const
 {
   unsigned int index;
+  if (this->is_symbolless_)
+    return 0;
   switch (this->local_sym_index_)
     {
     case INVALID_CODE:
@@ -995,7 +1009,7 @@ 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->get_symbol_index();
   wr->put_r_info(elfcpp::elf_r_info<size>(sym_index, this->type_));
 }
 
@@ -1097,7 +1111,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_.is_symbolless())
     addend = this->rel_.symbol_value(addend);
   else if (this->rel_.is_local_section_symbol())
     addend = this->rel_.local_section_offset(addend);
index a549b74..9008bdd 100644 (file)
@@ -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 is_symbolless);
 
   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 is_symbolless);
 
   // 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 is_symbolless, 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 is_symbolless, 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 not use
+  // a symbol, but which obtains its addend from a symbol.
+  bool
+  is_symbolless() const
+  { return this->is_symbolless_; }
+
   // Return whether this is against a local section symbol.
   bool
   is_local_section_symbol() const
@@ -1152,9 +1159,12 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   // input file.
   unsigned int local_sym_index_;
   // The reloc type--a processor specific code.
-  unsigned int type_ : 30;
+  unsigned int type_ : 29;
   // True if the relocation is a RELATIVE relocation.
   bool is_relative_ : 1;
+  // True if the relocation is one which should not use
+  // a symbol, but which obtains its addend from a symbol.
+  bool is_symbolless_ : 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 is_symbolless)
+    : rel_(gsym, type, od, address, is_relative, is_symbolless),
+      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 is_symbolless)
+    : rel_(gsym, type, relobj, shndx, address, is_relative,
+          is_symbolless), 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 is_symbolless, bool is_section_symbol)
     : rel_(relobj, local_sym_index, type, od, address, is_relative,
-           is_section_symbol),
+           is_symbolless, 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 is_symbolless, bool is_section_symbol)
     : rel_(relobj, local_sym_index, type, shndx, address, is_relative,
-           is_section_symbol),
+           is_symbolless, 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 a relocation which should not use
+  // a symbol, but which obtains its addend from a symbol.
+  bool
+  is_symbolless() const
+  { return this->rel_.is_symbolless(); }
+
   // 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,7 @@ 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, unsigned int type, Output_data* od,
@@ -1455,7 +1476,25 @@ 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));
+  }
+
+  // Add a global relocation which does not use a symbol for the relocation,
+  // but which gets its addend from a symbol.
+
+  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)); }
+
+  void
+  add_symbolless_global_addend(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, true));
   }
 
   // Add a reloc against a local symbol.
@@ -1466,7 +1505,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 +1514,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 +1525,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, true, false));
+                                    address, true, true, false));
   }
 
   void
@@ -1495,7 +1534,29 @@ 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));
+  }
+
+  // Add a local relocation which does not use a symbol for the relocation,
+  // but which gets its addend from a symbol.
+
+  void
+  add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+                             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, false, true, false));
+  }
+
+  void
+  add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+                             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, false, true, false));
   }
 
   // Add a reloc against a local section symbol.  This will be
@@ -1508,7 +1569,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 +1578,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 +1648,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 +1656,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 +1666,32 @@ 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, 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)); }
+
+  // Add a global relocation which does not use a symbol for the relocation,
+  // but which gets its addend from a symbol.
+
+  void
+  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)); }
+
+  void
+  add_symbolless_global_addend(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, false, true)); }
 
   // Add a reloc against a local symbol.
 
@@ -1622,7 +1701,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 +1711,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 +1722,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, true, false));
+                                   addend, true, true, false));
   }
 
   void
@@ -1653,7 +1732,29 @@ 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));
+  }
+
+  // Add a local relocation which does not use a symbol for the relocation,
+  // but which gets it's addend from a symbol.
+
+  void
+  add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+                             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, false, true, false));
+  }
+
+  void
+  add_symbolless_local_addend(Sized_relobj<size, big_endian>* relobj,
+                             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, false, true, false));
   }
 
   // Add a reloc against a local section symbol.  This will be
@@ -1666,7 +1767,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 +1777,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.
index 234c5f5..ab25203 100644 (file)
@@ -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_symbolless_local_addend(object, 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_symbolless_local_addend(object, 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_symbolless_local_addend(object, 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_symbolless_global_addend(gsym, 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_symbolless_global_addend(gsym, orig_r_type,
+                                                      output_section, object,
+                                                      data_shndx, reloc.get_r_offset(),
+                                                      0);
              }
            break;