* i386.cc (Target_i386::Got_type): New enum declaration.
authorCary Coutant <ccoutant@google.com>
Tue, 25 Mar 2008 18:37:16 +0000 (18:37 +0000)
committerCary Coutant <ccoutant@google.com>
Tue, 25 Mar 2008 18:37:16 +0000 (18:37 +0000)
(Target_i386::Scan::local): Updated callers of Output_data_got
member functions.
(Target_i386::Scan::global): Likewise.
(Target_i386::Relocate::relocate): Likewise.
(Target_i386::Relocate::relocate_tls): Likewise.
* object.h (Got_offset_list): New class.
(Sized_relobj::local_has_got_offset): Added got_type parameter.
(Sized_relobj::local_got_offset): Likewise.
(Sized_relobj::set_local_got_offset): Likewise.
(Sized_relobj::local_has_tls_got_offset): Removed.
(Sized_relobj::local_tls_got_offset): Removed.
(Sized_relobj::set_local_tls_got_offset): Removed.
(Sized_relobj::Local_got_offsets): Changed to store a list of offsets.
* output.cc (Output_data_got::add_global): Added got_type parameter.
(Output_data_got::add_global_with_rel): Likewise.
(Output_data_got::add_global_with_rela): Likewise.
(Output_data_got::add_global_pair_with_rel): New function.
(Output_data_got::add_global_pair_with_rela): New function.
(Output_data_got::add_local): Added got_type parameter.
(Output_data_got::add_local_with_rel): Likewise.
(Output_data_got::add_local_with_rela): Likewise.
(Output_data_got::add_local_pair_with_rel): New function.
(Output_data_got::add_local_pair_with_rela): New function.
(Output_data_got::add_global_tls): Removed.
(Output_data_got::add_global_tls_with_rel): Removed.
(Output_data_got::add_global_tls_with_rela): Removed.
(Output_data_got::add_local_tls): Removed.
(Output_data_got::add_local_tls_with_rel): Removed.
(Output_data_got::add_local_tls_with_rela): Removed.
* output.h (Output_data_got::add_global): Added got_type parameter.
(Output_data_got::add_global_with_rel): Likewise.
(Output_data_got::add_global_with_rela): Likewise.
(Output_data_got::add_global_pair_with_rel): New function.
(Output_data_got::add_global_pair_with_rela): New function.
(Output_data_got::add_local): Added got_type parameter.
(Output_data_got::add_local_with_rel): Likewise.
(Output_data_got::add_local_with_rela): Likewise.
(Output_data_got::add_local_pair_with_rel): New function.
(Output_data_got::add_local_pair_with_rela): New function.
(Output_data_got::add_global_tls): Removed.
(Output_data_got::add_global_tls_with_rel): Removed.
(Output_data_got::add_global_tls_with_rela): Removed.
(Output_data_got::add_local_tls): Removed.
(Output_data_got::add_local_tls_with_rel): Removed.
(Output_data_got::add_local_tls_with_rela): Removed.
* resolve.cc (Symbol::override_base_with_special): Removed
reference to has_got_offset_ field.
* symtab.cc (Symbol::init_fields): Replaced initialization
of got_offset_ with got_offsets_.  Removed initialization
of has_got_offset_
*symtab.h (Symbol::has_got_offset): Aded got_type parameter.
(Symbol::got_offset): Likewise.
(Symbol::set_got_offset): Likewise.
(Symbol::has_tls_got_offset): Removed.
(Symbol::tls_got_offset): Removed.
(Symbol::set_tls_got_offset): Removed.
(Symbol::got_offset_): Removed.
(Symbol::tls_mod_got_offset_): Removed.
(Symbol::tls_pair_got_offset_): Removed.
(Symbol::got_offsets_): New field.
(Symbol::has_got_offset): Removed.
(Symbol::has_tls_mod_got_offset): Removed.
(Symbol::has_tls_pair_got_offset): Removed.
* x86_64.cc (Target_x86_64::Got_type): New enum declaration.
(Target_x86_64::Scan::local): Updated callers of Output_data_got
member functions.
(Target_x86_64::Scan::global): Likewise.
(Target_x86_64::Relocate::relocate): Likewise.
(Target_x86_64::Relocate::relocate_tls): Likewise.

gold/ChangeLog
gold/i386.cc
gold/object.h
gold/output.cc
gold/output.h
gold/resolve.cc
gold/symtab.cc
gold/symtab.h
gold/x86_64.cc

index 447712a..104646f 100644 (file)
@@ -1,3 +1,76 @@
+2008-03-24  Cary Coutant  <ccoutant@google.com>
+
+       * i386.cc (Target_i386::Got_type): New enum declaration.
+       (Target_i386::Scan::local): Updated callers of Output_data_got
+       member functions.
+       (Target_i386::Scan::global): Likewise.
+       (Target_i386::Relocate::relocate): Likewise.
+       (Target_i386::Relocate::relocate_tls): Likewise.
+       * object.h (Got_offset_list): New class.
+       (Sized_relobj::local_has_got_offset): Added got_type parameter.
+       (Sized_relobj::local_got_offset): Likewise.
+       (Sized_relobj::set_local_got_offset): Likewise.
+       (Sized_relobj::local_has_tls_got_offset): Removed.
+       (Sized_relobj::local_tls_got_offset): Removed.
+       (Sized_relobj::set_local_tls_got_offset): Removed.
+       (Sized_relobj::Local_got_offsets): Changed to store a list of offsets.
+       * output.cc (Output_data_got::add_global): Added got_type parameter.
+       (Output_data_got::add_global_with_rel): Likewise.
+       (Output_data_got::add_global_with_rela): Likewise.
+       (Output_data_got::add_global_pair_with_rel): New function.
+       (Output_data_got::add_global_pair_with_rela): New function.
+       (Output_data_got::add_local): Added got_type parameter.
+       (Output_data_got::add_local_with_rel): Likewise.
+       (Output_data_got::add_local_with_rela): Likewise.
+       (Output_data_got::add_local_pair_with_rel): New function.
+       (Output_data_got::add_local_pair_with_rela): New function.
+       (Output_data_got::add_global_tls): Removed.
+       (Output_data_got::add_global_tls_with_rel): Removed.
+       (Output_data_got::add_global_tls_with_rela): Removed.
+       (Output_data_got::add_local_tls): Removed.
+       (Output_data_got::add_local_tls_with_rel): Removed.
+       (Output_data_got::add_local_tls_with_rela): Removed.
+       * output.h (Output_data_got::add_global): Added got_type parameter.
+       (Output_data_got::add_global_with_rel): Likewise.
+       (Output_data_got::add_global_with_rela): Likewise.
+       (Output_data_got::add_global_pair_with_rel): New function.
+       (Output_data_got::add_global_pair_with_rela): New function.
+       (Output_data_got::add_local): Added got_type parameter.
+       (Output_data_got::add_local_with_rel): Likewise.
+       (Output_data_got::add_local_with_rela): Likewise.
+       (Output_data_got::add_local_pair_with_rel): New function.
+       (Output_data_got::add_local_pair_with_rela): New function.
+       (Output_data_got::add_global_tls): Removed.
+       (Output_data_got::add_global_tls_with_rel): Removed.
+       (Output_data_got::add_global_tls_with_rela): Removed.
+       (Output_data_got::add_local_tls): Removed.
+       (Output_data_got::add_local_tls_with_rel): Removed.
+       (Output_data_got::add_local_tls_with_rela): Removed.
+       * resolve.cc (Symbol::override_base_with_special): Removed
+       reference to has_got_offset_ field.
+       * symtab.cc (Symbol::init_fields): Replaced initialization
+       of got_offset_ with got_offsets_.  Removed initialization
+       of has_got_offset_
+       *symtab.h (Symbol::has_got_offset): Aded got_type parameter.
+       (Symbol::got_offset): Likewise.
+       (Symbol::set_got_offset): Likewise.
+       (Symbol::has_tls_got_offset): Removed.
+       (Symbol::tls_got_offset): Removed.
+       (Symbol::set_tls_got_offset): Removed.
+       (Symbol::got_offset_): Removed.
+       (Symbol::tls_mod_got_offset_): Removed.
+       (Symbol::tls_pair_got_offset_): Removed.
+       (Symbol::got_offsets_): New field.
+       (Symbol::has_got_offset): Removed.
+       (Symbol::has_tls_mod_got_offset): Removed.
+       (Symbol::has_tls_pair_got_offset): Removed.
+       * x86_64.cc (Target_x86_64::Got_type): New enum declaration.
+       (Target_x86_64::Scan::local): Updated callers of Output_data_got
+       member functions.
+       (Target_x86_64::Scan::global): Likewise.
+       (Target_x86_64::Relocate::relocate): Likewise.
+       (Target_x86_64::Relocate::relocate_tls): Likewise.
+
 2008-03-25  Ben Elliston  <bje@au.ibm.com>
 
        * yyscript.y: Fix spelling error in comment.
index cc55249..f12b6cd 100644 (file)
@@ -339,6 +339,15 @@ class Target_i386 : public Sized_target<32, false>
   // general Target structure.
   static const Target::Target_info i386_info;
 
+  // The types of GOT entries needed for this platform.
+  enum Got_type
+  {
+    GOT_TYPE_STANDARD = 0,      // GOT entry for a regular symbol
+    GOT_TYPE_TLS_OFFSET = 1,    // GOT entry for TLS offset
+    GOT_TYPE_TLS_PAIR = 2,      // GOT entry for TLS module/offset pair
+    GOT_TYPE_TLS_DESC = 3       // GOT entry for TLS_DESC pair
+  };
+
   // The GOT section.
   Output_data_got<32, false>* got_;
   // The PLT section.
@@ -933,7 +942,7 @@ Target_i386::Scan::local(const General_options&,
         // The symbol requires a GOT entry.
         Output_data_got<32, false>* got = target->got_section(symtab, layout);
         unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
-        if (got->add_local(object, r_sym))
+        if (got->add_local(object, r_sym, GOT_TYPE_STANDARD))
           {
             // If we are generating a shared object, we need to add a
             // dynamic RELATIVE relocation for this symbol's GOT entry.
@@ -941,10 +950,9 @@ Target_i386::Scan::local(const General_options&,
               {
                 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_relative(object, r_sym,
-                                            elfcpp::R_386_RELATIVE,
-                                            got,
-                                            object->local_got_offset(r_sym));
+                rel_dyn->add_local_relative(
+                    object, r_sym, elfcpp::R_386_RELATIVE, got,
+                    object->local_got_offset(r_sym, GOT_TYPE_STANDARD));
               }
           }
       }
@@ -991,10 +999,11 @@ Target_i386::Scan::local(const General_options&,
                 Output_data_got<32, false>* got
                     = target->got_section(symtab, layout);
                 unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
-                got->add_local_tls_with_rel(object, r_sym, 
-                                            lsym.get_st_shndx(), true,
-                                            target->rel_dyn_section(layout),
-                                            elfcpp::R_386_TLS_DTPMOD32);
+                got->add_local_pair_with_rel(object, r_sym, 
+                                             lsym.get_st_shndx(),
+                                             GOT_TYPE_TLS_PAIR,
+                                             target->rel_dyn_section(layout),
+                                             elfcpp::R_386_TLS_DTPMOD32, 0);
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_local(object, r_type);
@@ -1047,7 +1056,7 @@ Target_i386::Scan::local(const General_options&,
                unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
                                           ? elfcpp::R_386_TLS_TPOFF32
                                           : elfcpp::R_386_TLS_TPOFF);
-                got->add_local_with_rel(object, r_sym,
+                got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
                                         target->rel_dyn_section(layout),
                                         dyn_r_type);
              }
@@ -1210,7 +1219,7 @@ Target_i386::Scan::global(const General_options& options,
         // The symbol requires a GOT entry.
         Output_data_got<32, false>* got = target->got_section(symtab, layout);
         if (gsym->final_value_is_known())
-          got->add_global(gsym);
+          got->add_global(gsym, GOT_TYPE_STANDARD);
         else
           {
             // If this symbol is not fully resolved, we need to add a
@@ -1219,12 +1228,14 @@ Target_i386::Scan::global(const General_options& options,
             if (gsym->is_from_dynobj()
                 || gsym->is_undefined()
                 || gsym->is_preemptible())
-              got->add_global_with_rel(gsym, rel_dyn, elfcpp::R_386_GLOB_DAT);
+              got->add_global_with_rel(gsym, GOT_TYPE_STANDARD,
+                                       rel_dyn, elfcpp::R_386_GLOB_DAT);
             else
               {
-                if (got->add_global(gsym))
-                  rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE,
-                                               got, gsym->got_offset());
+                if (got->add_global(gsym, GOT_TYPE_STANDARD))
+                  rel_dyn->add_global_relative(
+                      gsym, elfcpp::R_386_RELATIVE, got,
+                      gsym->got_offset(GOT_TYPE_STANDARD));
               }
           }
       }
@@ -1291,7 +1302,7 @@ Target_i386::Scan::global(const General_options& options,
                // dtv-relative offset.
                 Output_data_got<32, false>* got
                     = target->got_section(symtab, layout);
-                got->add_global_tls_with_rel(gsym,
+                got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
                                              target->rel_dyn_section(layout),
                                              elfcpp::R_386_TLS_DTPMOD32,
                                              elfcpp::R_386_TLS_DTPOFF32);
@@ -1301,7 +1312,8 @@ Target_i386::Scan::global(const General_options& options,
                // Create a GOT entry for the tp-relative offset.
                 Output_data_got<32, false>* got
                     = target->got_section(symtab, layout);
-                got->add_global_with_rel(gsym, target->rel_dyn_section(layout),
+                got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+                                         target->rel_dyn_section(layout),
                                          elfcpp::R_386_TLS_TPOFF32);
              }
            else if (optimized_type != tls::TLSOPT_TO_LE)
@@ -1353,7 +1365,7 @@ Target_i386::Scan::global(const General_options& options,
                unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
                                           ? elfcpp::R_386_TLS_TPOFF32
                                           : elfcpp::R_386_TLS_TPOFF);
-                got->add_global_with_rel(gsym,
+                got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
                                          target->rel_dyn_section(layout),
                                          dyn_r_type);
              }
@@ -1576,14 +1588,16 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
     case elfcpp::R_386_GOT32:
       if (gsym != NULL)
         {
-          gold_assert(gsym->has_got_offset());
-          got_offset = gsym->got_offset() - target->got_size();
+          gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+          got_offset = (gsym->got_offset(GOT_TYPE_STANDARD)
+                        - target->got_size());
         }
       else
         {
           unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
-          gold_assert(object->local_has_got_offset(r_sym));
-          got_offset = object->local_got_offset(r_sym) - target->got_size();
+          gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+          got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
+                        - target->got_size());
         }
       have_got_offset = true;
       break;
@@ -1770,14 +1784,16 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
           unsigned int got_offset;
           if (gsym != NULL)
             {
-              gold_assert(gsym->has_tls_got_offset(true));
-              got_offset = gsym->tls_got_offset(true) - target->got_size();
+              gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_PAIR));
+              got_offset = (gsym->got_offset(GOT_TYPE_TLS_PAIR)
+                            - target->got_size());
             }
           else
             {
               unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
-              gold_assert(object->local_has_tls_got_offset(r_sym, true));
-              got_offset = (object->local_tls_got_offset(r_sym, true)
+              gold_assert(object->local_has_got_offset(r_sym,
+                                                       GOT_TYPE_TLS_PAIR));
+              got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_PAIR)
                            - target->got_size());
             }
           if (optimized_type == tls::TLSOPT_TO_IE)
@@ -1868,14 +1884,16 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
           unsigned int got_offset;
           if (gsym != NULL)
             {
-              gold_assert(gsym->has_got_offset());
-              got_offset = gsym->got_offset();
+              gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
+              got_offset = gsym->got_offset(GOT_TYPE_TLS_OFFSET);
             }
           else
             {
               unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
-              gold_assert(object->local_has_got_offset(r_sym));
-              got_offset = object->local_got_offset(r_sym);
+              gold_assert(object->local_has_got_offset(r_sym,
+                                                       GOT_TYPE_TLS_OFFSET));
+              got_offset = object->local_got_offset(r_sym,
+                                                    GOT_TYPE_TLS_OFFSET);
             }
           // For the R_386_TLS_IE relocation, we need to apply the
           // absolute address of the GOT entry.
index 3a74685..4a2ad8a 100644 (file)
@@ -976,6 +976,83 @@ class Symbol_value
   } u_;
 };
 
+// A GOT offset list.  A symbol may have more than one GOT offset
+// (e.g., when mixing modules compiled with two different TLS models),
+// but will usually have at most one.  GOT_TYPE identifies the type of
+// GOT entry; its values are specific to each target.
+
+class Got_offset_list
+{
+ public:
+  Got_offset_list()
+    : got_type_(-1U), got_offset_(0), got_next_(NULL)
+  { }
+
+  Got_offset_list(unsigned int got_type, unsigned int got_offset)
+    : got_type_(got_type), got_offset_(got_offset), got_next_(NULL)
+  { }
+
+  ~Got_offset_list()
+  { 
+    if (this->got_next_ != NULL)
+      {
+        delete this->got_next_;
+        this->got_next_ = NULL;
+      }
+  }
+
+  // Initialize the fields to their default values.
+  void
+  init()
+  {
+    this->got_type_ = -1U;
+    this->got_offset_ = 0;
+    this->got_next_ = NULL;
+  }
+
+  // Set the offset for the GOT entry of type GOT_TYPE.
+  void
+  set_offset(unsigned int got_type, unsigned int got_offset)
+  {
+    if (this->got_type_ == -1U)
+      {
+        this->got_type_ = got_type;
+        this->got_offset_ = got_offset;
+      }
+    else
+      {
+        for (Got_offset_list* g = this; g != NULL; g = g->got_next_)
+          {
+            if (g->got_type_ == got_type)
+              {
+                g->got_offset_ = got_offset;
+                return;
+              }
+          }
+        Got_offset_list* g = new Got_offset_list(got_type, got_offset);
+        g->got_next_ = this->got_next_;
+        this->got_next_ = g;
+      }
+  }
+
+  // Return the offset for a GOT entry of type GOT_TYPE.
+  unsigned int
+  get_offset(unsigned int got_type) const
+  {
+    for (const Got_offset_list* g = this; g != NULL; g = g->got_next_)
+      {
+        if (g->got_type_ == got_type)
+          return g->got_offset_;
+      }
+    return -1U;
+  }
+
+ private:
+  unsigned int got_type_;
+  unsigned int got_offset_;
+  Got_offset_list* got_next_;
+};
+
 // A regular object file.  This is size and endian specific.
 
 template<int size, bool big_endian>
@@ -1067,84 +1144,40 @@ class Sized_relobj : public Relobj
   // Return whether the local symbol SYMNDX has a GOT offset.
   // For TLS symbols, the GOT entry will hold its tp-relative offset.
   bool
-  local_has_got_offset(unsigned int symndx) const
+  local_has_got_offset(unsigned int symndx, unsigned int got_type) const
   {
-    return (this->local_got_offsets_.find(symndx)
-            != this->local_got_offsets_.end());
+    Local_got_offsets::const_iterator p =
+        this->local_got_offsets_.find(symndx);
+    return (p != this->local_got_offsets_.end()
+            && p->second->get_offset(got_type) != -1U);
   }
 
   // Return the GOT offset of the local symbol SYMNDX.
   unsigned int
-  local_got_offset(unsigned int symndx) const
+  local_got_offset(unsigned int symndx, unsigned int got_type) const
   {
     Local_got_offsets::const_iterator p =
         this->local_got_offsets_.find(symndx);
     gold_assert(p != this->local_got_offsets_.end());
-    return p->second;
+    unsigned int off = p->second->get_offset(got_type);
+    gold_assert(off != -1U);
+    return off;
   }
 
   // Set the GOT offset of the local symbol SYMNDX to GOT_OFFSET.
   void
-  set_local_got_offset(unsigned int symndx, unsigned int got_offset)
-  {
-    std::pair<Local_got_offsets::iterator, bool> ins =
-        this->local_got_offsets_.insert(std::make_pair(symndx, got_offset));
-    gold_assert(ins.second);
-  }
-
-  // Return whether the local TLS symbol SYMNDX has a GOT offset.
-  // The GOT entry at this offset will contain a module index. If
-  // NEED_PAIR is true, a second entry immediately following the first
-  // will contain the dtv-relative offset.
-  bool
-  local_has_tls_got_offset(unsigned int symndx, bool need_pair) const
+  set_local_got_offset(unsigned int symndx, unsigned int got_type,
+                       unsigned int got_offset)
   {
-    typename Local_tls_got_offsets::const_iterator p =
-        this->local_tls_got_offsets_.find(symndx);
-    if (p == this->local_tls_got_offsets_.end()
-        || (need_pair && !p->second.have_pair_))
-      return false;
-    return true;
-  }
-
-  // Return the offset of the GOT entry for the local TLS symbol SYMNDX.
-  // If NEED_PAIR is true, we need the offset of a pair of GOT entries;
-  // otherwise we need the offset of the GOT entry for the module index.
-  unsigned int
-  local_tls_got_offset(unsigned int symndx, bool need_pair) const
-  {
-    typename Local_tls_got_offsets::const_iterator p =
-        this->local_tls_got_offsets_.find(symndx);
-    gold_assert(p != this->local_tls_got_offsets_.end());
-    gold_assert(!need_pair || p->second.have_pair_);
-    return p->second.got_offset_;
-  }
-
-  // Set the offset of the GOT entry for the local TLS symbol SYMNDX
-  // to GOT_OFFSET. If HAVE_PAIR is true, we have a pair of GOT entries;
-  // otherwise, we have just a single entry for the module index.
-  void
-  set_local_tls_got_offset(unsigned int symndx, unsigned int got_offset,
-                           bool have_pair)
-  {
-    typename Local_tls_got_offsets::iterator p =
-        this->local_tls_got_offsets_.find(symndx);
-    if (p != this->local_tls_got_offsets_.end())
-      {
-        // An entry already existed for this symbol. This can happen
-        // if we see a relocation asking for the module index before
-        // a relocation asking for the pair. In that case, the original
-        // GOT entry will remain, but won't get used by any further
-        // relocations.
-        p->second.got_offset_ = got_offset;
-       gold_assert(have_pair);
-        p->second.have_pair_ = true;
-      }
+    Local_got_offsets::const_iterator p =
+        this->local_got_offsets_.find(symndx);
+    if (p != this->local_got_offsets_.end())
+      p->second->set_offset(got_type, got_offset);
     else
       {
-        std::pair<typename Local_tls_got_offsets::iterator, bool> ins =
-            this->local_tls_got_offsets_.insert(
-              std::make_pair(symndx, Tls_got_entry(got_offset, have_pair)));
+        Got_offset_list* g = new Got_offset_list(got_type, got_offset);
+        std::pair<Local_got_offsets::iterator, bool> ins =
+            this->local_got_offsets_.insert(std::make_pair(symndx, g));
         gold_assert(ins.second);
       }
   }
@@ -1365,12 +1398,11 @@ class Sized_relobj : public Relobj
   {
     this->local_values_.clear();
     this->local_got_offsets_.clear();
-    this->local_tls_got_offsets_.clear();
   }
 
   // The GOT offsets of local symbols. This map also stores GOT offsets
   // for tp-relative offsets for TLS symbols.
-  typedef Unordered_map<unsigned int, unsigned int> Local_got_offsets;
+  typedef Unordered_map<unsigned int, Got_offset_list*> Local_got_offsets;
 
   // The TLS GOT offsets of local symbols. The map stores the offsets
   // for either a single GOT entry that holds the module index of a TLS
@@ -1409,9 +1441,6 @@ class Sized_relobj : public Relobj
   // GOT offsets for local non-TLS symbols, and tp-relative offsets
   // for TLS symbols, indexed by symbol number.
   Local_got_offsets local_got_offsets_;
-  // GOT offsets for local TLS symbols, indexed by symbol number
-  // and GOT entry type.
-  Local_tls_got_offsets local_tls_got_offsets_;
   // Whether this object has a GNU style .eh_frame section.
   bool has_eh_frame_;
 };
index 85cc2b2..3a11aa4 100644 (file)
@@ -1059,14 +1059,16 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
 
 template<int size, bool big_endian>
 bool
-Output_data_got<size, big_endian>::add_global(Symbol* gsym)
+Output_data_got<size, big_endian>::add_global(
+    Symbol* gsym,
+    unsigned int got_type)
 {
-  if (gsym->has_got_offset())
+  if (gsym->has_got_offset(got_type))
     return false;
 
   this->entries_.push_back(Got_entry(gsym));
   this->set_got_size();
-  gsym->set_got_offset(this->last_got_offset());
+  gsym->set_got_offset(got_type, this->last_got_offset());
   return true;
 }
 
@@ -1076,16 +1078,17 @@ template<int size, bool big_endian>
 void
 Output_data_got<size, big_endian>::add_global_with_rel(
     Symbol* gsym,
+    unsigned int got_type,
     Rel_dyn* rel_dyn,
     unsigned int r_type)
 {
-  if (gsym->has_got_offset())
+  if (gsym->has_got_offset(got_type))
     return;
 
   this->entries_.push_back(Got_entry());
   this->set_got_size();
   unsigned int got_offset = this->last_got_offset();
-  gsym->set_got_offset(got_offset);
+  gsym->set_got_offset(got_type, got_offset);
   rel_dyn->add_global(gsym, r_type, this, got_offset);
 }
 
@@ -1093,260 +1096,198 @@ template<int size, bool big_endian>
 void
 Output_data_got<size, big_endian>::add_global_with_rela(
     Symbol* gsym,
+    unsigned int got_type,
     Rela_dyn* rela_dyn,
     unsigned int r_type)
 {
-  if (gsym->has_got_offset())
+  if (gsym->has_got_offset(got_type))
     return;
 
   this->entries_.push_back(Got_entry());
   this->set_got_size();
   unsigned int got_offset = this->last_got_offset();
-  gsym->set_got_offset(got_offset);
+  gsym->set_got_offset(got_type, got_offset);
   rela_dyn->add_global(gsym, r_type, this, got_offset, 0);
 }
 
-// Add an entry for a local symbol to the GOT.  This returns true if
-// this is a new GOT entry, false if the symbol already has a GOT
-// entry.
-
-template<int size, bool big_endian>
-bool
-Output_data_got<size, big_endian>::add_local(
-    Sized_relobj<size, big_endian>* object,
-    unsigned int symndx)
-{
-  if (object->local_has_got_offset(symndx))
-    return false;
-
-  this->entries_.push_back(Got_entry(object, symndx));
-  this->set_got_size();
-  object->set_local_got_offset(symndx, this->last_got_offset());
-  return true;
-}
-
-// Add an entry for a local symbol to the GOT, and add a dynamic
-// relocation of type R_TYPE for the GOT entry.
+// Add a pair of entries for a global symbol to the GOT, and add
+// dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively.
+// If R_TYPE_2 == 0, add the second entry with no relocation.
 template<int size, bool big_endian>
 void
-Output_data_got<size, big_endian>::add_local_with_rel(
-    Sized_relobj<size, big_endian>* object,
-    unsigned int symndx,
+Output_data_got<size, big_endian>::add_global_pair_with_rel(
+    Symbol* gsym,
+    unsigned int got_type,
     Rel_dyn* rel_dyn,
-    unsigned int r_type)
+    unsigned int r_type_1,
+    unsigned int r_type_2)
 {
-  if (object->local_has_got_offset(symndx))
+  if (gsym->has_got_offset(got_type))
     return;
 
   this->entries_.push_back(Got_entry());
-  this->set_got_size();
   unsigned int got_offset = this->last_got_offset();
-  object->set_local_got_offset(symndx, got_offset);
-  rel_dyn->add_local(object, symndx, r_type, this, got_offset);
+  gsym->set_got_offset(got_type, got_offset);
+  rel_dyn->add_global(gsym, r_type_1, this, got_offset);
+
+  this->entries_.push_back(Got_entry());
+  if (r_type_2 != 0)
+    {
+      got_offset = this->last_got_offset();
+      rel_dyn->add_global(gsym, r_type_2, this, got_offset);
+    }
+
+  this->set_got_size();
 }
 
 template<int size, bool big_endian>
 void
-Output_data_got<size, big_endian>::add_local_with_rela(
-    Sized_relobj<size, big_endian>* object,
-    unsigned int symndx,
+Output_data_got<size, big_endian>::add_global_pair_with_rela(
+    Symbol* gsym,
+    unsigned int got_type,
     Rela_dyn* rela_dyn,
-    unsigned int r_type)
+    unsigned int r_type_1,
+    unsigned int r_type_2)
 {
-  if (object->local_has_got_offset(symndx))
+  if (gsym->has_got_offset(got_type))
     return;
 
   this->entries_.push_back(Got_entry());
-  this->set_got_size();
   unsigned int got_offset = this->last_got_offset();
-  object->set_local_got_offset(symndx, got_offset);
-  rela_dyn->add_local(object, symndx, r_type, this, got_offset, 0);
+  gsym->set_got_offset(got_type, got_offset);
+  rela_dyn->add_global(gsym, r_type_1, this, got_offset, 0);
+
+  this->entries_.push_back(Got_entry());
+  if (r_type_2 != 0)
+    {
+      got_offset = this->last_got_offset();
+      rela_dyn->add_global(gsym, r_type_2, this, got_offset, 0);
+    }
+
+  this->set_got_size();
 }
 
-// Add an entry (or a pair of entries) for a global TLS symbol to the GOT.
-// In a pair of entries, the first value in the pair will be used for the
-// module index, and the second value will be used for the dtv-relative
-// offset. This returns true if this is a new GOT entry, false if the symbol
-// already has a GOT entry.
+// Add an entry for a local symbol to the GOT.  This returns true if
+// this is a new GOT entry, false if the symbol already has a GOT
+// entry.
 
 template<int size, bool big_endian>
 bool
-Output_data_got<size, big_endian>::add_global_tls(Symbol* gsym, bool need_pair)
+Output_data_got<size, big_endian>::add_local(
+    Sized_relobj<size, big_endian>* object,
+    unsigned int symndx,
+    unsigned int got_type)
 {
-  if (gsym->has_tls_got_offset(need_pair))
+  if (object->local_has_got_offset(symndx, got_type))
     return false;
 
-  this->entries_.push_back(Got_entry(gsym));
-  gsym->set_tls_got_offset(this->last_got_offset(), need_pair);
-  if (need_pair)
-    this->entries_.push_back(Got_entry(gsym));
+  this->entries_.push_back(Got_entry(object, symndx));
   this->set_got_size();
+  object->set_local_got_offset(symndx, got_type, this->last_got_offset());
   return true;
 }
 
-// Add an entry for a global TLS symbol to the GOT, and add a dynamic
-// relocation of type R_TYPE.
+// Add an entry for a local symbol to the GOT, and add a dynamic
+// relocation of type R_TYPE for the GOT entry.
 template<int size, bool big_endian>
 void
-Output_data_got<size, big_endian>::add_global_tls_with_rel(
-    Symbol* gsym,
+Output_data_got<size, big_endian>::add_local_with_rel(
+    Sized_relobj<size, big_endian>* object,
+    unsigned int symndx,
+    unsigned int got_type,
     Rel_dyn* rel_dyn,
     unsigned int r_type)
 {
-  if (gsym->has_tls_got_offset(false))
+  if (object->local_has_got_offset(symndx, got_type))
     return;
 
   this->entries_.push_back(Got_entry());
   this->set_got_size();
   unsigned int got_offset = this->last_got_offset();
-  gsym->set_tls_got_offset(got_offset, false);
-  rel_dyn->add_global(gsym, r_type, this, got_offset);
+  object->set_local_got_offset(symndx, got_type, got_offset);
+  rel_dyn->add_local(object, symndx, r_type, this, got_offset);
 }
 
 template<int size, bool big_endian>
 void
-Output_data_got<size, big_endian>::add_global_tls_with_rela(
-    Symbol* gsym,
+Output_data_got<size, big_endian>::add_local_with_rela(
+    Sized_relobj<size, big_endian>* object,
+    unsigned int symndx,
+    unsigned int got_type,
     Rela_dyn* rela_dyn,
     unsigned int r_type)
 {
-  if (gsym->has_tls_got_offset(false))
+  if (object->local_has_got_offset(symndx, got_type))
     return;
 
   this->entries_.push_back(Got_entry());
   this->set_got_size();
   unsigned int got_offset = this->last_got_offset();
-  gsym->set_tls_got_offset(got_offset, false);
-  rela_dyn->add_global(gsym, r_type, this, got_offset, 0);
-}
-
-// Add a pair of entries for a global TLS symbol to the GOT, and add
-// dynamic relocations of type MOD_R_TYPE and DTV_R_TYPE, respectively.
-template<int size, bool big_endian>
-void
-Output_data_got<size, big_endian>::add_global_tls_with_rel(
-    Symbol* gsym,
-    Rel_dyn* rel_dyn,
-    unsigned int mod_r_type,
-    unsigned int dtv_r_type)
-{
-  if (gsym->has_tls_got_offset(true))
-    return;
-
-  this->entries_.push_back(Got_entry());
-  unsigned int got_offset = this->last_got_offset();
-  gsym->set_tls_got_offset(got_offset, true);
-  rel_dyn->add_global(gsym, mod_r_type, this, got_offset);
-
-  this->entries_.push_back(Got_entry());
-  this->set_got_size();
-  got_offset = this->last_got_offset();
-  rel_dyn->add_global(gsym, dtv_r_type, this, got_offset);
-}
-
-template<int size, bool big_endian>
-void
-Output_data_got<size, big_endian>::add_global_tls_with_rela(
-    Symbol* gsym,
-    Rela_dyn* rela_dyn,
-    unsigned int mod_r_type,
-    unsigned int dtv_r_type)
-{
-  if (gsym->has_tls_got_offset(true))
-    return;
-
-  this->entries_.push_back(Got_entry());
-  unsigned int got_offset = this->last_got_offset();
-  gsym->set_tls_got_offset(got_offset, true);
-  rela_dyn->add_global(gsym, mod_r_type, this, got_offset, 0);
-
-  this->entries_.push_back(Got_entry());
-  this->set_got_size();
-  got_offset = this->last_got_offset();
-  rela_dyn->add_global(gsym, dtv_r_type, this, got_offset, 0);
-}
-
-// Add an entry (or a pair of entries) for a local TLS symbol to the GOT.
-// In a pair of entries, the first value in the pair will be used for the
-// module index, and the second value will be used for the dtv-relative
-// offset. This returns true if this is a new GOT entry, false if the symbol
-// already has a GOT entry.
-
-template<int size, bool big_endian>
-bool
-Output_data_got<size, big_endian>::add_local_tls(
-    Sized_relobj<size, big_endian>* object,
-    unsigned int symndx,
-    bool need_pair)
-{
-  if (object->local_has_tls_got_offset(symndx, need_pair))
-    return false;
-
-  this->entries_.push_back(Got_entry(object, symndx));
-  object->set_local_tls_got_offset(symndx, this->last_got_offset(), need_pair);
-  if (need_pair)
-    this->entries_.push_back(Got_entry(object, symndx));
-  this->set_got_size();
-  return true;
+  object->set_local_got_offset(symndx, got_type, got_offset);
+  rela_dyn->add_local(object, symndx, r_type, this, got_offset, 0);
 }
 
-// Add an entry (or pair of entries) for a local TLS symbol to the GOT,
-// and add a dynamic relocation of type R_TYPE for the first GOT entry.
-// Because this is a local symbol, the first GOT entry can be relocated
-// relative to a section symbol, and the second GOT entry will have an
-// dtv-relative value that can be computed at link time.
+// Add a pair of entries for a local symbol to the GOT, and add
+// dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively.
+// If R_TYPE_2 == 0, add the second entry with no relocation.
 template<int size, bool big_endian>
 void
-Output_data_got<size, big_endian>::add_local_tls_with_rel(
+Output_data_got<size, big_endian>::add_local_pair_with_rel(
     Sized_relobj<size, big_endian>* object,
     unsigned int symndx,
     unsigned int shndx,
-    bool need_pair,
+    unsigned int got_type,
     Rel_dyn* rel_dyn,
-    unsigned int r_type)
+    unsigned int r_type_1,
+    unsigned int r_type_2)
 {
-  if (object->local_has_tls_got_offset(symndx, need_pair))
+  if (object->local_has_got_offset(symndx, got_type))
     return;
 
   this->entries_.push_back(Got_entry());
   unsigned int got_offset = this->last_got_offset();
-  object->set_local_tls_got_offset(symndx, got_offset, need_pair);
+  object->set_local_got_offset(symndx, got_type, got_offset);
   section_offset_type off;
   Output_section* os = object->output_section(shndx, &off);
-  rel_dyn->add_output_section(os, r_type, this, got_offset);
+  rel_dyn->add_output_section(os, r_type_1, this, got_offset);
 
-  // The second entry of the pair will be statically initialized
-  // with the TLS offset of the symbol.
-  if (need_pair)
-    this->entries_.push_back(Got_entry(object, symndx));
+  this->entries_.push_back(Got_entry(object, symndx));
+  if (r_type_2 != 0)
+    {
+      got_offset = this->last_got_offset();
+      rel_dyn->add_output_section(os, r_type_2, this, got_offset);
+    }
 
   this->set_got_size();
 }
 
 template<int size, bool big_endian>
 void
-Output_data_got<size, big_endian>::add_local_tls_with_rela(
+Output_data_got<size, big_endian>::add_local_pair_with_rela(
     Sized_relobj<size, big_endian>* object,
     unsigned int symndx,
     unsigned int shndx,
-    bool need_pair,
+    unsigned int got_type,
     Rela_dyn* rela_dyn,
-    unsigned int r_type)
+    unsigned int r_type_1,
+    unsigned int r_type_2)
 {
-  if (object->local_has_tls_got_offset(symndx, need_pair))
+  if (object->local_has_got_offset(symndx, got_type))
     return;
 
   this->entries_.push_back(Got_entry());
   unsigned int got_offset = this->last_got_offset();
-  object->set_local_tls_got_offset(symndx, got_offset, need_pair);
+  object->set_local_got_offset(symndx, got_type, got_offset);
   section_offset_type off;
   Output_section* os = object->output_section(shndx, &off);
-  rela_dyn->add_output_section(os, r_type, this, got_offset, 0);
+  rela_dyn->add_output_section(os, r_type_1, this, got_offset, 0);
 
-  // The second entry of the pair will be statically initialized
-  // with the TLS offset of the symbol.
-  if (need_pair)
-    this->entries_.push_back(Got_entry(object, symndx));
+  this->entries_.push_back(Got_entry(object, symndx));
+  if (r_type_2 != 0)
+    {
+      got_offset = this->last_got_offset();
+      rela_dyn->add_output_section(os, r_type_2, this, got_offset, 0);
+    }
 
   this->set_got_size();
 }
index e394538..2b864f3 100644 (file)
@@ -1362,85 +1362,62 @@ class Output_data_got : public Output_section_data_build
   // Add an entry for a global symbol to the GOT.  Return true if this
   // is a new GOT entry, false if the symbol was already in the GOT.
   bool
-  add_global(Symbol* gsym);
+  add_global(Symbol* gsym, unsigned int got_type);
 
   // Add an entry for a global symbol to the GOT, and add a dynamic
   // relocation of type R_TYPE for the GOT entry.
   void
-  add_global_with_rel(Symbol* gsym, Rel_dyn* rel_dyn, unsigned int r_type);
+  add_global_with_rel(Symbol* gsym, unsigned int got_type,
+                      Rel_dyn* rel_dyn, unsigned int r_type);
 
   void
-  add_global_with_rela(Symbol* gsym, Rela_dyn* rela_dyn, unsigned int r_type);
+  add_global_with_rela(Symbol* gsym, unsigned int got_type,
+                       Rela_dyn* rela_dyn, unsigned int r_type);
+
+  // Add a pair of entries for a global symbol to the GOT, and add
+  // dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively.
+  void
+  add_global_pair_with_rel(Symbol* gsym, unsigned int got_type,
+                           Rel_dyn* rel_dyn, unsigned int r_type_1,
+                           unsigned int r_type_2);
+
+  void
+  add_global_pair_with_rela(Symbol* gsym, unsigned int got_type,
+                            Rela_dyn* rela_dyn, unsigned int r_type_1,
+                            unsigned int r_type_2);
 
   // Add an entry for a local symbol to the GOT.  This returns true if
   // this is a new GOT entry, false if the symbol already has a GOT
   // entry.
   bool
-  add_local(Sized_relobj<size, big_endian>* object, unsigned int sym_index);
+  add_local(Sized_relobj<size, big_endian>* object, unsigned int sym_index,
+            unsigned int got_type);
 
-  // Add an entry for a global symbol to the GOT, and add a dynamic
+  // Add an entry for a local symbol to the GOT, and add a dynamic
   // relocation of type R_TYPE for the GOT entry.
   void
   add_local_with_rel(Sized_relobj<size, big_endian>* object,
-                     unsigned int sym_index, Rel_dyn* rel_dyn,
-                     unsigned int r_type);
+                     unsigned int sym_index, unsigned int got_type,
+                     Rel_dyn* rel_dyn, unsigned int r_type);
 
   void
   add_local_with_rela(Sized_relobj<size, big_endian>* object,
-                      unsigned int sym_index, Rela_dyn* rela_dyn,
-                      unsigned int r_type);
-
-  // Add an entry (or pair of entries) for a global TLS symbol to the GOT.
-  // Return true if this is a new GOT entry, false if the symbol was
-  // already in the GOT.
-  bool
-  add_global_tls(Symbol* gsym, bool need_pair);
-
-  // Add an entry for a global TLS symbol to the GOT, and add a dynamic
-  // relocation of type R_TYPE.
-  void
-  add_global_tls_with_rel(Symbol* gsym, Rel_dyn* rel_dyn,
-                          unsigned int r_type);
-
-  void
-  add_global_tls_with_rela(Symbol* gsym, Rela_dyn* rela_dyn,
-                           unsigned int r_type);
-
-  // Add a pair of entries for a global TLS symbol to the GOT, and add
-  // dynamic relocations of type MOD_R_TYPE and DTV_R_TYPE, respectively.
-  void
-  add_global_tls_with_rel(Symbol* gsym, Rel_dyn* rel_dyn,
-                          unsigned int mod_r_type,
-                          unsigned int dtv_r_type);
-
-  void
-  add_global_tls_with_rela(Symbol* gsym, Rela_dyn* rela_dyn,
-                           unsigned int mod_r_type,
-                           unsigned int dtv_r_type);
-
-  // Add an entry (or pair of entries) for a local TLS symbol to the GOT.
-  // This returns true if this is a new GOT entry, false if the symbol
-  // already has a GOT entry.
-  bool
-  add_local_tls(Sized_relobj<size, big_endian>* object,
-               unsigned int sym_index, bool need_pair);
+                      unsigned int sym_index, unsigned int got_type,
+                      Rela_dyn* rela_dyn, unsigned int r_type);
 
-  // Add an entry (or pair of entries) for a local TLS symbol to the GOT,
-  // and add a dynamic relocation of type R_TYPE for the first GOT entry.
-  // Because this is a local symbol, the first GOT entry can be relocated
-  // relative to a section symbol, and the second GOT entry will have an
-  // dtv-relative value that can be computed at link time.
+  // Add a pair of entries for a local symbol to the GOT, and add
+  // dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively.
   void
-  add_local_tls_with_rel(Sized_relobj<size, big_endian>* object,
-                         unsigned int sym_index, unsigned int shndx,
-                         bool need_pair, Rel_dyn* rel_dyn,
-                         unsigned int r_type);
+  add_local_pair_with_rel(Sized_relobj<size, big_endian>* object,
+                          unsigned int sym_index, unsigned int shndx,
+                          unsigned int got_type, Rel_dyn* rel_dyn,
+                          unsigned int r_type_1, unsigned int r_type_2);
 
   void
-  add_local_tls_with_rela(Sized_relobj<size, big_endian>* object,
-                         unsigned int sym_index, unsigned int shndx,
-                         bool need_pair, Rela_dyn* rela_dyn,
-                         unsigned int r_type);
+  add_local_pair_with_rela(Sized_relobj<size, big_endian>* object,
+                          unsigned int sym_index, unsigned int shndx,
+                          unsigned int got_type, Rela_dyn* rela_dyn,
+                          unsigned int r_type_1, unsigned int r_type_2);
 
   // Add a constant to the GOT.  This returns the offset of the new
   // entry from the start of the GOT.
index 3300000..00e9278 100644 (file)
@@ -679,7 +679,6 @@ Symbol::override_base_with_special(const Symbol* from)
   // somehow.
   gold_assert(!from->is_target_special_ || this->is_target_special_);
   gold_assert(!from->is_forwarder_);
-  gold_assert(!from->has_got_offset_);
   gold_assert(!from->has_plt_offset_);
   gold_assert(!from->has_warning_);
   gold_assert(!from->is_copied_from_dynobj_);
index eef3a4b..3bd3833 100644 (file)
@@ -53,7 +53,7 @@ Symbol::init_fields(const char* name, const char* version,
   this->version_ = version;
   this->symtab_index_ = 0;
   this->dynsym_index_ = 0;
-  this->got_offset_ = 0;
+  this->got_offsets_.init();
   this->plt_offset_ = 0;
   this->type_ = type;
   this->binding_ = binding;
@@ -66,7 +66,6 @@ Symbol::init_fields(const char* name, const char* version,
   this->needs_dynsym_entry_ = false;
   this->in_reg_ = false;
   this->in_dyn_ = false;
-  this->has_got_offset_ = false;
   this->has_plt_offset_ = false;
   this->has_warning_ = false;
   this->is_copied_from_dynobj_ = false;
index 8da9e6d..bd41794 100644 (file)
@@ -323,53 +323,22 @@ class Symbol
   // Return whether this symbol has an entry in the GOT section.
   // For a TLS symbol, this GOT entry will hold its tp-relative offset.
   bool
-  has_got_offset() const
-  { return this->has_got_offset_; }
+  has_got_offset(unsigned int got_type) const
+  { return this->got_offsets_.get_offset(got_type) != -1U; }
 
   // Return the offset into the GOT section of this symbol.
   unsigned int
-  got_offset() const
+  got_offset(unsigned int got_type) const
   {
-    gold_assert(this->has_got_offset());
-    return this->got_offset_;
+    unsigned int got_offset = this->got_offsets_.get_offset(got_type);
+    gold_assert(got_offset != -1U);
+    return got_offset;
   }
 
   // Set the GOT offset of this symbol.
   void
-  set_got_offset(unsigned int got_offset)
-  {
-    this->has_got_offset_ = true;
-    this->got_offset_ = got_offset;
-  }
-
-  // Return whether this TLS symbol has an entry in the GOT section for
-  // its module index or, if NEED_PAIR is true, has a pair of entries
-  // for its module index and dtv-relative offset.
-  bool
-  has_tls_got_offset(bool need_pair) const
-  {
-    return (this->has_tls_mod_got_offset_
-            && (!need_pair || this->has_tls_pair_got_offset_));
-  }
-
-  // Return the offset into the GOT section for this symbol's TLS module
-  // index or, if NEED_PAIR is true, for the pair of entries for the
-  // module index and dtv-relative offset.
-  unsigned int
-  tls_got_offset(bool need_pair) const
-  {
-    gold_assert(this->has_tls_got_offset(need_pair));
-    return this->tls_mod_got_offset_;
-  }
-
-  // Set the GOT offset of this symbol.
-  void
-  set_tls_got_offset(unsigned int got_offset, bool have_pair)
-  {
-    this->has_tls_mod_got_offset_ = true;
-    this->has_tls_pair_got_offset_ = have_pair;
-    this->tls_mod_got_offset_ = got_offset;
-  }
+  set_got_offset(unsigned int got_type, unsigned int got_offset)
+  { this->got_offsets_.set_offset(got_type, got_offset); }
 
   // Return whether this symbol has an entry in the PLT section.
   bool
@@ -719,18 +688,11 @@ class Symbol
   unsigned int dynsym_index_;
 
   // If this symbol has an entry in the GOT section (has_got_offset_
-  // is true), this is the offset from the start of the GOT section.
-  // For a TLS symbol, if has_tls_tpoff_got_offset_ is true, this
-  // serves as the GOT offset for the GOT entry that holds its
-  // TP-relative offset.
-  unsigned int got_offset_;
-
-  // If this is a TLS symbol and has an entry in the GOT section
-  // for a module index or a pair of entries (module index,
-  // dtv-relative offset), these are the offsets from the start
-  // of the GOT section.
-  unsigned int tls_mod_got_offset_;
-  unsigned int tls_pair_got_offset_;
+  // is true), this holds the offset from the start of the GOT section.
+  // A symbol may have more than one GOT offset (e.g., when mixing
+  // modules compiled with two different TLS models), but will usually
+  // have at most one.
+  Got_offset_list got_offsets_;
 
   // If this symbol has an entry in the PLT section (has_plt_offset_
   // is true), then this is the offset from the start of the PLT
@@ -769,15 +731,6 @@ class Symbol
   bool in_reg_ : 1;
   // True if we've seen this symbol in a dynamic object.
   bool in_dyn_ : 1;
-  // True if the symbol has an entry in the GOT section.
-  // For a TLS symbol, this GOT entry will hold its tp-relative offset.
-  bool has_got_offset_ : 1;
-  // True if the symbol has an entry in the GOT section for its
-  // module index.
-  bool has_tls_mod_got_offset_ : 1;
-  // True if the symbol has a pair of entries in the GOT section for its
-  // module index and dtv-relative offset.
-  bool has_tls_pair_got_offset_ : 1;
   // True if the symbol has an entry in the PLT section.
   bool has_plt_offset_ : 1;
   // True if this is a dynamic symbol which needs a special value in
index b64f6a8..72c0779 100644 (file)
@@ -324,6 +324,14 @@ class Target_x86_64 : public Sized_target<64, false>
   // general Target structure.
   static const Target::Target_info x86_64_info;
 
+  enum Got_type
+  {
+    GOT_TYPE_STANDARD = 0,      // GOT entry for a regular symbol
+    GOT_TYPE_TLS_OFFSET = 1,    // GOT entry for TLS offset
+    GOT_TYPE_TLS_PAIR = 2,      // GOT entry for TLS module/offset pair
+    GOT_TYPE_TLS_DESC = 3       // GOT entry for TLS_DESC pair
+  };
+
   // The GOT section.
   Output_data_got<64, false>* got_;
   // The PLT section.
@@ -893,7 +901,7 @@ Target_x86_64::Scan::local(const General_options&,
         // The symbol requires a GOT entry.
         Output_data_got<64, false>* got = target->got_section(symtab, layout);
         unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
-        if (got->add_local(object, r_sym))
+        if (got->add_local(object, r_sym, GOT_TYPE_STANDARD))
           {
             // If we are generating a shared object, we need to add a
             // dynamic relocation for this symbol's GOT entry.
@@ -902,16 +910,15 @@ Target_x86_64::Scan::local(const General_options&,
                 Reloc_section* rela_dyn = target->rela_dyn_section(layout);
                // R_X86_64_RELATIVE assumes a 64-bit relocation.
                if (r_type != elfcpp::R_X86_64_GOT32)
-                  rela_dyn->add_local_relative(object, r_sym,
-                                               elfcpp::R_X86_64_RELATIVE, got,
-                                               object->local_got_offset(r_sym),
-                                               0);
+                  rela_dyn->add_local_relative(
+                      object, r_sym, elfcpp::R_X86_64_RELATIVE, got,
+                      object->local_got_offset(r_sym, GOT_TYPE_STANDARD), 0);
                 else
                   {
                     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);
+                    rela_dyn->add_local(
+                        object, r_sym, r_type, got,
+                        object->local_got_offset(r_sym, GOT_TYPE_STANDARD), 0);
                   }
               }
           }
@@ -955,10 +962,11 @@ Target_x86_64::Scan::local(const General_options&,
                 Output_data_got<64, false>* got
                     = target->got_section(symtab, layout);
                 unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
-                got->add_local_tls_with_rela(object, r_sym,
-                                             lsym.get_st_shndx(), true,
-                                             target->rela_dyn_section(layout),
-                                             elfcpp::R_X86_64_DTPMOD64);
+                got->add_local_pair_with_rela(object, r_sym,
+                                              lsym.get_st_shndx(),
+                                              GOT_TYPE_TLS_PAIR,
+                                              target->rela_dyn_section(layout),
+                                              elfcpp::R_X86_64_DTPMOD64, 0);
               }
             else if (optimized_type != tls::TLSOPT_TO_LE)
              unsupported_reloc_local(object, r_type);
@@ -994,7 +1002,7 @@ Target_x86_64::Scan::local(const General_options&,
                Output_data_got<64, false>* got
                    = target->got_section(symtab, layout);
                unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
-               got->add_local_with_rela(object, r_sym,
+               got->add_local_with_rela(object, r_sym, GOT_TYPE_TLS_OFFSET,
                                         target->rela_dyn_section(layout),
                                         elfcpp::R_X86_64_TPOFF64);
               }
@@ -1140,7 +1148,7 @@ Target_x86_64::Scan::global(const General_options& options,
         // The symbol requires a GOT entry.
         Output_data_got<64, false>* got = target->got_section(symtab, layout);
         if (gsym->final_value_is_known())
-          got->add_global(gsym);
+          got->add_global(gsym, GOT_TYPE_STANDARD);
         else
           {
             // If this symbol is not fully resolved, we need to add a
@@ -1149,14 +1157,14 @@ Target_x86_64::Scan::global(const General_options& options,
             if (gsym->is_from_dynobj()
                 || gsym->is_undefined()
                 || gsym->is_preemptible())
-              got->add_global_with_rela(gsym, rela_dyn,
+              got->add_global_with_rela(gsym, GOT_TYPE_STANDARD, rela_dyn,
                                         elfcpp::R_X86_64_GLOB_DAT);
             else
               {
-                if (got->add_global(gsym))
-                  rela_dyn->add_global_relative(gsym,
-                                                elfcpp::R_X86_64_RELATIVE,
-                                                got, gsym->got_offset(), 0);
+                if (got->add_global(gsym, GOT_TYPE_STANDARD))
+                  rela_dyn->add_global_relative(
+                      gsym, elfcpp::R_X86_64_RELATIVE, got,
+                      gsym->got_offset(GOT_TYPE_STANDARD), 0);
               }
           }
         // For GOTPLT64, we also need a PLT entry (but only if the
@@ -1229,17 +1237,17 @@ Target_x86_64::Scan::global(const General_options& options,
                 // dtv-relative offset.
                 Output_data_got<64, false>* got
                     = target->got_section(symtab, layout);
-                got->add_global_tls_with_rela(gsym,
-                                              target->rela_dyn_section(layout),
-                                              elfcpp::R_X86_64_DTPMOD64,
-                                              elfcpp::R_X86_64_DTPOFF64);
+                got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_PAIR,
+                                               target->rela_dyn_section(layout),
+                                               elfcpp::R_X86_64_DTPMOD64,
+                                               elfcpp::R_X86_64_DTPOFF64);
              }
            else if (optimized_type == tls::TLSOPT_TO_IE)
              {
                 // Create a GOT entry for the tp-relative offset.
                 Output_data_got<64, false>* got
                     = target->got_section(symtab, layout);
-                got->add_global_with_rela(gsym,
+                got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
                                           target->rela_dyn_section(layout),
                                           elfcpp::R_X86_64_TPOFF64);
              }
@@ -1276,7 +1284,7 @@ Target_x86_64::Scan::global(const General_options& options,
                // Create a GOT entry for the tp-relative offset.
                Output_data_got<64, false>* got
                    = target->got_section(symtab, layout);
-               got->add_global_with_rela(gsym,
+               got->add_global_with_rela(gsym, GOT_TYPE_TLS_OFFSET,
                                          target->rela_dyn_section(layout),
                                          elfcpp::R_X86_64_TPOFF64);
               }
@@ -1456,14 +1464,15 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
     case elfcpp::R_X86_64_GOTPCREL64:
       if (gsym != NULL)
         {
-          gold_assert(gsym->has_got_offset());
-          got_offset = gsym->got_offset() - target->got_size();
+          gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+          got_offset = gsym->got_offset(GOT_TYPE_STANDARD) - target->got_size();
         }
       else
         {
           unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
-          gold_assert(object->local_has_got_offset(r_sym));
-          got_offset = object->local_got_offset(r_sym) - target->got_size();
+          gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+          got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
+                        - target->got_size());
         }
       have_got_offset = true;
       break;
@@ -1691,14 +1700,16 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
           unsigned int got_offset;
           if (gsym != NULL)
             {
-              gold_assert(gsym->has_tls_got_offset(true));
-              got_offset = gsym->tls_got_offset(true) - target->got_size();
+              gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_PAIR));
+              got_offset = (gsym->got_offset(GOT_TYPE_TLS_PAIR)
+                            - target->got_size());
             }
           else
             {
               unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
-              gold_assert(object->local_has_tls_got_offset(r_sym, true));
-              got_offset = (object->local_tls_got_offset(r_sym, true)
+              gold_assert(object->local_has_got_offset(r_sym,
+                          GOT_TYPE_TLS_PAIR));
+              got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_PAIR)
                             - target->got_size());
             }
           if (optimized_type == tls::TLSOPT_TO_IE)
@@ -1776,14 +1787,16 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
           unsigned int got_offset;
           if (gsym != NULL)
             {
-              gold_assert(gsym->has_got_offset());
-              got_offset = gsym->got_offset() - target->got_size();
+              gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
+              got_offset = (gsym->got_offset(GOT_TYPE_TLS_OFFSET)
+                            - target->got_size());
             }
           else
             {
               unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
-              gold_assert(object->local_has_got_offset(r_sym));
-              got_offset = (object->local_got_offset(r_sym)
+              gold_assert(object->local_has_got_offset(r_sym,
+                                                       GOT_TYPE_TLS_OFFSET));
+              got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET)
                             - target->got_size());
             }
          value = target->got_plt_section()->address() + got_offset;