Support dynamic relocations against local section symbols.
authorIan Lance Taylor <iant@google.com>
Tue, 12 Feb 2008 00:28:48 +0000 (00:28 +0000)
committerIan Lance Taylor <iant@google.com>
Tue, 12 Feb 2008 00:28:48 +0000 (00:28 +0000)
gold/i386.cc
gold/object.cc
gold/object.h
gold/output.cc
gold/output.h
gold/x86_64.cc

index d6e42f46501402a7bb4f094c68fcf460a6a37b62..2d8efdd5ecb2ed3d6b7695fd4a495c359a825530 100644 (file)
@@ -898,9 +898,19 @@ Target_i386::Scan::local(const General_options&,
       if (parameters->output_is_position_independent())
         {
           Reloc_section* rel_dyn = target->rel_dyn_section(layout);
-          unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
-          rel_dyn->add_local(object, r_sym, r_type, output_section, data_shndx,
-                             reloc.get_r_offset());
+          if (lsym.get_st_type() != elfcpp::STT_SECTION)
+            {
+              unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+              rel_dyn->add_local(object, r_sym, r_type, output_section,
+                                 data_shndx, reloc.get_r_offset());
+            }
+          else
+            {
+              gold_assert(lsym.get_st_value() == 0);
+              rel_dyn->add_local_section(object, lsym.get_st_shndx(),
+                                         r_type, output_section,
+                                         data_shndx, reloc.get_r_offset());
+            }
         }
       break;
 
@@ -1053,6 +1063,7 @@ Target_i386::Scan::local(const General_options&,
            if (output_is_shared)
              {
                // We need to create a dynamic relocation.
+                gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
                 unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
                 unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32
                                            ? elfcpp::R_386_TLS_TPOFF32
index 1adb851ba1dd9f2e4f251cb7aaa75f7da6363511..3db6f851b9e66ee24e1b66ba378c52809a5699f2 100644 (file)
@@ -884,12 +884,14 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
       if (shndx < shnum && mo[shndx].output_section == NULL)
         {
          lv.set_no_output_symtab_entry();
+          gold_assert(!lv.needs_output_dynsym_entry());
           continue;
         }
 
       if (sym.get_st_type() == elfcpp::STT_SECTION)
        {
          lv.set_no_output_symtab_entry();
+          gold_assert(!lv.needs_output_dynsym_entry());
          continue;
        }
 
index 36a2e1f495f9c1e1eaf8de136724215eb57d823a..4011bdcf221815bda7659e91b2e8c5b1241f0af3 100644 (file)
@@ -874,6 +874,7 @@ class Symbol_value
   void
   set_needs_output_dynsym_entry()
   {
+    gold_assert(!this->is_section_symbol());
     this->output_dynsym_index_ = 0;
   }
 
@@ -897,7 +898,8 @@ class Symbol_value
   unsigned int
   output_dynsym_index() const
   {
-    gold_assert(this->output_dynsym_index_ != 0);
+    gold_assert(this->output_dynsym_index_ != 0
+                && this->output_dynsym_index_ != -1U);
     return this->output_dynsym_index_;
   }
 
@@ -924,7 +926,10 @@ class Symbol_value
   // Record that this is a section symbol.
   void
   set_is_section_symbol()
-  { this->is_section_symbol_ = true; }
+  {
+    gold_assert(!this->needs_output_dynsym_entry());
+    this->is_section_symbol_ = true;
+  }
 
   // Record that this is a TLS symbol.
   void
index 8aca916be0bea6a202effc92f0e8b591b787a8db..107ed09c4bcc36adbf5eb97735d3735e0487a239 100644 (file)
@@ -608,12 +608,14 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     Address address,
     bool is_relative)
   : address_(address), local_sym_index_(GSYM_CODE), type_(type),
-    is_relative_(is_relative), shndx_(INVALID_CODE)
+    is_relative_(is_relative), is_section_symbol_(false), shndx_(INVALID_CODE)
 {
+  // this->type_ is a bitfield; make sure TYPE fits.
+  gold_assert(this->type_ == type);
   this->u1_.gsym = gsym;
   this->u2_.od = od;
-  if (dynamic && !is_relative)
-    gsym->set_needs_dynsym_entry();
+  if (dynamic)
+    this->set_needs_dynsym_index();
 }
 
 template<bool dynamic, int size, bool big_endian>
@@ -625,13 +627,15 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     Address address,
     bool is_relative)
   : address_(address), local_sym_index_(GSYM_CODE), type_(type),
-    is_relative_(is_relative), shndx_(shndx)
+    is_relative_(is_relative), is_section_symbol_(false), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
+  // this->type_ is a bitfield; make sure TYPE fits.
+  gold_assert(this->type_ == type);
   this->u1_.gsym = gsym;
   this->u2_.relobj = relobj;
-  if (dynamic && !is_relative)
-    gsym->set_needs_dynsym_entry();
+  if (dynamic)
+    this->set_needs_dynsym_index();
 }
 
 // A reloc against a local symbol.
@@ -643,16 +647,20 @@ 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_section_symbol)
   : address_(address), local_sym_index_(local_sym_index), type_(type),
-    is_relative_(is_relative), shndx_(INVALID_CODE)
+    is_relative_(is_relative), is_section_symbol_(is_section_symbol),
+    shndx_(INVALID_CODE)
 {
   gold_assert(local_sym_index != GSYM_CODE
               && local_sym_index != INVALID_CODE);
+  // this->type_ is a bitfield; make sure TYPE fits.
+  gold_assert(this->type_ == type);
   this->u1_.relobj = relobj;
   this->u2_.od = od;
-  if (dynamic && !is_relative)
-    relobj->set_needs_output_dynsym_entry(local_sym_index);
+  if (dynamic)
+    this->set_needs_dynsym_index();
 }
 
 template<bool dynamic, int size, bool big_endian>
@@ -662,17 +670,21 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
     unsigned int type,
     unsigned int shndx,
     Address address,
-    bool is_relative)
+    bool is_relative,
+    bool is_section_symbol)
   : address_(address), local_sym_index_(local_sym_index), type_(type),
-    is_relative_(is_relative), shndx_(shndx)
+    is_relative_(is_relative), is_section_symbol_(is_section_symbol),
+    shndx_(shndx)
 {
   gold_assert(local_sym_index != GSYM_CODE
               && local_sym_index != INVALID_CODE);
   gold_assert(shndx != INVALID_CODE);
+  // this->type_ is a bitfield; make sure TYPE fits.
+  gold_assert(this->type_ == type);
   this->u1_.relobj = relobj;
   this->u2_.relobj = relobj;
-  if (dynamic && !is_relative)
-    relobj->set_needs_output_dynsym_entry(local_sym_index);
+  if (dynamic)
+    this->set_needs_dynsym_index();
 }
 
 // A reloc against the STT_SECTION symbol of an output section.
@@ -684,12 +696,16 @@ 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), shndx_(INVALID_CODE)
+    is_relative_(false), is_section_symbol_(true), shndx_(INVALID_CODE)
 {
+  // this->type_ is a bitfield; make sure TYPE fits.
+  gold_assert(this->type_ == type);
   this->u1_.os = os;
   this->u2_.od = od;
   if (dynamic)
-    os->set_needs_dynsym_index();
+    this->set_needs_dynsym_index();
+  else
+    os->set_needs_symtab_index();
 }
 
 template<bool dynamic, int size, bool big_endian>
@@ -700,13 +716,59 @@ 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), shndx_(shndx)
+    is_relative_(false), is_section_symbol_(true), shndx_(shndx)
 {
   gold_assert(shndx != INVALID_CODE);
+  // this->type_ is a bitfield; make sure TYPE fits.
+  gold_assert(this->type_ == type);
   this->u1_.os = os;
   this->u2_.relobj = relobj;
   if (dynamic)
-    os->set_needs_dynsym_index();
+    this->set_needs_dynsym_index();
+  else
+    os->set_needs_symtab_index();
+}
+
+// Record that we need a dynamic symbol index for this relocation.
+
+template<bool dynamic, int size, bool big_endian>
+void
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
+set_needs_dynsym_index()
+{
+  if (this->is_relative_)
+    return;
+  switch (this->local_sym_index_)
+    {
+    case INVALID_CODE:
+      gold_unreachable();
+
+    case GSYM_CODE:
+      this->u1_.gsym->set_needs_dynsym_entry();
+      break;
+
+    case SECTION_CODE:
+      this->u1_.os->set_needs_dynsym_index();
+      break;
+
+    case 0:
+      break;
+
+    default:
+      {
+        const unsigned int lsi = this->local_sym_index_;
+        if (!this->is_section_symbol_)
+          this->u1_.relobj->set_needs_output_dynsym_entry(lsi);
+        else
+          {
+            section_offset_type dummy;
+            Output_section* os = this->u1_.relobj->output_section(lsi, &dummy);
+            gold_assert(os != NULL);
+            os->set_needs_dynsym_index();
+          }
+      }
+      break;
+    }
 }
 
 // Get the symbol index of a relocation.
@@ -744,16 +806,47 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
       break;
 
     default:
-      if (dynamic)
-        index = this->u1_.relobj->dynsym_index(this->local_sym_index_);
-      else
-       index = this->u1_.relobj->symtab_index(this->local_sym_index_);
+      {
+        const unsigned int lsi = this->local_sym_index_;
+        if (!this->is_section_symbol_)
+          {
+            if (dynamic)
+              index = this->u1_.relobj->dynsym_index(lsi);
+            else
+              index = this->u1_.relobj->symtab_index(lsi);
+          }
+        else
+          {
+            section_offset_type dummy;
+            Output_section* os = this->u1_.relobj->output_section(lsi, &dummy);
+            gold_assert(os != NULL);
+            if (dynamic)
+              index = os->dynsym_index();
+            else
+              index = os->symtab_index();
+          }
+      }
       break;
     }
   gold_assert(index != -1U);
   return index;
 }
 
+// For a local section symbol, get the section offset of the input
+// section within the output section.
+
+template<bool dynamic, int size, bool big_endian>
+section_offset_type
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
+  local_section_offset() const
+{
+  const unsigned int lsi = this->local_sym_index_;
+  section_offset_type offset;
+  Output_section* os = this->u1_.relobj->output_section(lsi, &offset);
+  gold_assert(os != NULL);
+  return offset;
+}
+
 // Write out the offset and info fields of a Rel or Rela relocation
 // entry.
 
@@ -825,8 +918,10 @@ Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write(
   elfcpp::Rela_write<size, big_endian> orel(pov);
   this->rel_.write_rel(&orel);
   Addend addend = this->addend_;
-  if (rel_.is_relative())
-    addend += rel_.symbol_value();
+  if (this->rel_.is_relative())
+    addend += this->rel_.symbol_value();
+  if (this->rel_.is_local_section_symbol())
+    addend += this->rel_.local_section_offset();
   orel.put_r_addend(addend);
 }
 
index fbfdb256264c5cbf0858b6633c99405fa93eb6e4..8f7a5644759c33012a3802d1810bf65236ee69e3 100644 (file)
@@ -767,9 +767,9 @@ class Output_data_strtab : public Output_section_data
 // or elfcpp::SHT_RELA, and also on whether this is a dynamic
 // relocation or an ordinary relocation.
 
-// A relocation can be against a global symbol, a local symbol, an
-// output section, or the undefined symbol at index 0.  We represent
-// the latter by using a NULL global symbol.
+// A relocation can be against a global symbol, a local symbol, a
+// local section symbol, an output section, or the undefined symbol at
+// index 0.  We represent the latter by using a NULL global symbol.
 
 template<int sh_type, bool dynamic, int size, bool big_endian>
 class Output_reloc;
@@ -786,6 +786,11 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
     : local_sym_index_(INVALID_CODE)
   { }
 
+  // We have a bunch of different constructors.  They come in pairs
+  // depending on how the address of the relocation is specified.  It
+  // can either be an offset in an Output_data or an offset in an
+  // input section.
+
   // A reloc against a global symbol.
 
   Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
@@ -794,15 +799,17 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
               unsigned int shndx, Address address, bool is_relative);
 
-  // A reloc against a local symbol.
+  // 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);
+              Output_data* od, Address address, bool is_relative,
+               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);
+              unsigned int shndx, Address address, bool is_relative,
+               bool is_section_symbol);
 
   // A reloc against the STT_SECTION symbol of an output section.
 
@@ -817,6 +824,21 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   is_relative() const
   { return this->is_relative_; }
 
+  // Return whether this is against a local section symbol.
+  bool
+  is_local_section_symbol() const
+  {
+    return (this->local_sym_index_ != GSYM_CODE
+            && this->local_sym_index_ != SECTION_CODE
+            && this->local_sym_index_ != INVALID_CODE
+            && this->is_section_symbol_);
+  }
+
+  // For a local section symbol, return the offset of the input
+  // section within the output section.
+  section_offset_type
+  local_section_offset() const;
+
   // Get the value of the symbol referred to by a Rel relocation.
 
   Address
@@ -831,8 +853,11 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   void write_rel(Write_rel*) const;
 
  private:
-  // Return the symbol index.  We can't do a double template
-  // specialization, so we do a secondary template here.
+  // Record that we need a dynamic symbol index.
+  void
+  set_needs_dynsym_index();
+
+  // Return the symbol index.
   unsigned int
   get_symbol_index() const;
 
@@ -849,36 +874,45 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 
   union
   {
-    // For a local symbol, the object.  We will never generate a
-    // relocation against a local symbol in a dynamic object; that
-    // doesn't make sense.  And our callers will always be
-    // templatized, so we use Sized_relobj here.
+    // For a local symbol or local section symbol
+    // (this->local_sym_index_ >= 0), the object.  We will never
+    // generate a relocation against a local symbol in a dynamic
+    // object; that doesn't make sense.  And our callers will always
+    // be templatized, so we use Sized_relobj here.
     Sized_relobj<size, big_endian>* relobj;
-    // For a global symbol, the symbol.  If this is NULL, it indicates
-    // a relocation against the undefined 0 symbol.
+    // For a global symbol (this->local_sym_index_ == GSYM_CODE, the
+    // symbol.  If this is NULL, it indicates a relocation against the
+    // undefined 0 symbol.
     Symbol* gsym;
-    // For a relocation against an output section, the output section.
+    // For a relocation against an output section
+    // (this->local_sym_index_ == SECTION_CODE), the output section.
     Output_section* os;
   } u1_;
   union
   {
-    // If shndx_ is not INVALID CODE, the object which holds the input
-    // section being used to specify the reloc address.
+    // If this->shndx_ is not INVALID CODE, the object which holds the
+    // input section being used to specify the reloc address.
     Relobj* relobj;
-    // If shndx_ is INVALID_CODE, the output data being used to
+    // If this->shndx_ is INVALID_CODE, the output data being used to
     // specify the reloc address.  This may be NULL if the reloc
     // address is absolute.
     Output_data* od;
   } u2_;
   // The address offset within the input section or the Output_data.
   Address address_;
-  // For a local symbol, the local symbol index.  This is GSYM_CODE
-  // for a global symbol, or INVALID_CODE for an uninitialized value.
+  // This is GSYM_CODE for a global symbol, or SECTION_CODE for a
+  // relocation against an output section, or INVALID_CODE for an
+  // uninitialized value.  Otherwise, for a local symbol
+  // (this->is_section_symbol_ is false), the local symbol index.  For
+  // a local section symbol (this->is_section_symbol_ is true), the
+  // section index in the input file.
   unsigned int local_sym_index_;
   // The reloc type--a processor specific code.
-  unsigned int type_ : 31;
+  unsigned int type_ : 30;
   // True if the relocation is a RELATIVE relocation.
   bool is_relative_ : 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
   // section index.  This is INVALID_CODE if the reloc address is
   // specified in some other way.
@@ -918,16 +952,18 @@ 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)
-    : rel_(relobj, local_sym_index, type, od, address, is_relative),
+              Addend addend, bool is_relative, bool is_section_symbol)
+    : rel_(relobj, local_sym_index, type, od, address, is_relative,
+           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)
-    : rel_(relobj, local_sym_index, type, shndx, address, is_relative),
+              Addend addend, bool is_relative, bool is_section_symbol)
+    : rel_(relobj, local_sym_index, type, shndx, address, is_relative,
+           is_section_symbol),
       addend_(addend)
   { }
 
@@ -1010,7 +1046,7 @@ template<bool dynamic, int size, bool big_endian>
 class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   : public Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>
 {
- private: 
+ private:
   typedef Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size,
                                 big_endian> Base;
 
@@ -1045,8 +1081,10 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
                       Relobj* relobj, unsigned int shndx, Address address)
-  { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
-                                    true)); }
+  {
+    this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
+                                    true));
+  }
 
   // Add a reloc against a local symbol.
 
@@ -1054,15 +1092,19 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   add_local(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)); }
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
+                                    address, false, false));
+  }
 
   void
   add_local(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)); }
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+                                   address, false, false));
+  }
 
   // Add a RELATIVE reloc against a local symbol.
 
@@ -1070,15 +1112,41 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   add_local_relative(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, true)); }
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
+                                    address, true, false));
+  }
 
   void
   add_local_relative(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, true)); }
+  {
+    this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
+                                   address, true, false));
+  }
+
+  // Add a reloc against a local section symbol.  This will be
+  // converted into a reloc against the STT_SECTION symbol of the
+  // output section.
+
+  void
+  add_local_section(Sized_relobj<size, big_endian>* relobj,
+                    unsigned int input_shndx, unsigned int type,
+                    Output_data* od, Address address)
+  {
+    this->add(od, Output_reloc_type(relobj, input_shndx, type, od,
+                                    address, false, true));
+  }
+
+  void
+  add_local_section(Sized_relobj<size, big_endian>* relobj,
+                    unsigned int input_shndx, unsigned int type,
+                    Output_data* od, unsigned int shndx, Address address)
+  {
+    this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
+                                    address, false, true));
+  }
 
   // A reloc against the STT_SECTION symbol of an output section.
   // OS is the Output_section that the relocation refers to; OD is
@@ -1101,7 +1169,7 @@ template<bool dynamic, int size, bool big_endian>
 class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   : public Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>
 {
- private: 
+ private:
   typedef Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size,
                                 big_endian> Base;
 
@@ -1154,7 +1222,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));
+                                   addend, false, false));
   }
 
   void
@@ -1164,7 +1232,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));
+                                    address, addend, false, false));
   }
 
   // Add a RELATIVE reloc against a local symbol.
@@ -1175,7 +1243,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));
+                                   addend, true, false));
   }
 
   void
@@ -1185,7 +1253,30 @@ 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));
+                                    address, addend, true, false));
+  }
+
+  // Add a reloc against a local section symbol.  This will be
+  // converted into a reloc against the STT_SECTION symbol of the
+  // output section.
+
+  void
+  add_local_section(Sized_relobj<size, big_endian>* relobj,
+                    unsigned int input_shndx, unsigned int type,
+                    Output_data* od, Address address, Addend addend)
+  {
+    this->add(od, Output_reloc_type(relobj, input_shndx, type, od, address,
+                                   addend, false, true));
+  }
+
+  void
+  add_local_section(Sized_relobj<size, big_endian>* relobj,
+                    unsigned int input_shndx, unsigned int type,
+                    Output_data* od, unsigned int shndx, Address address,
+                    Addend addend)
+  {
+    this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
+                                    address, addend, false, true));
   }
 
   // A reloc against the STT_SECTION symbol of an output section.
index 54357fdaebe082296b038abe347adc9a316402ff..d5869dc5f6dd918a32cf547cda0d0af78d6ad61c 100644 (file)
@@ -828,10 +828,10 @@ Target_x86_64::Scan::local(const General_options&,
 
     case elfcpp::R_X86_64_64:
       // If building a shared library (or a position-independent
-      // executable), we need to create a dynamic relocation for
-      // this location. The relocation applied at link time will
-      // apply the link-time value, so we flag the location with
-      // an R_386_RELATIVE relocation so the dynamic loader can
+      // executable), we need to create a dynamic relocation for this
+      // location.  The relocation applied at link time will apply the
+      // link-time value, so we flag the location with an
+      // R_X86_64_RELATIVE relocation so the dynamic loader can
       // relocate it easily.
       if (parameters->output_is_position_independent())
         {
@@ -850,18 +850,27 @@ Target_x86_64::Scan::local(const General_options&,
     case elfcpp::R_X86_64_16:
     case elfcpp::R_X86_64_8:
       // If building a shared library (or a position-independent
-      // executable), we need to create a dynamic relocation for
-      // this location. The relocation applied at link time will
-      // apply the link-time value, so we flag the location with
-      // an R_386_RELATIVE relocation so the dynamic loader can
-      // relocate it easily.
+      // executable), we need to create a dynamic relocation for this
+      // location.  We can't use an R_X86_64_RELATIVE relocation
+      // because that is always a 64-bit relocation.
       if (parameters->output_is_position_independent())
         {
           Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-          unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
-          rela_dyn->add_local(object, r_sym, r_type, output_section,
-                              data_shndx, reloc.get_r_offset(),
-                              reloc.get_r_addend());
+          if (lsym.get_st_type() != elfcpp::STT_SECTION)
+            {
+              unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
+              rela_dyn->add_local(object, r_sym, r_type, output_section,
+                                  data_shndx, reloc.get_r_offset(),
+                                  reloc.get_r_addend());
+            }
+          else
+            {
+              gold_assert(lsym.get_st_value() == 0);
+              rela_dyn->add_local_section(object, lsym.get_st_shndx(),
+                                          r_type, output_section,
+                                          data_shndx, reloc.get_r_offset(),
+                                          reloc.get_r_addend());
+            }
         }
       break;
 
@@ -909,8 +918,12 @@ Target_x86_64::Scan::local(const General_options&,
                                                object->local_got_offset(r_sym),
                                                0);
                 else
-                  rela_dyn->add_local(object, r_sym, r_type,
-                                      got, object->local_got_offset(r_sym), 0);
+                  {
+                    gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+                    rela_dyn->add_local(object, r_sym, r_type,
+                                        got, object->local_got_offset(r_sym),
+                                        0);
+                  }
               }
           }
         // For GOTPLT64, we'd normally want a PLT section, but since