From edfbb029539d1e67751ca7dd7c6ff3cbe702a6c2 Mon Sep 17 00:00:00 2001
From: Cary Coutant <ccoutant@google.com>
Date: Thu, 17 Apr 2008 02:00:54 +0000
Subject: [PATCH] 	* i386.cc (Target_i386::define_tls_base_symbol): New
 function. 	(Target_i386::tls_base_symbol_defined_): New field. 
 (Target_i386::Scan::local): Define _TLS_MODULE_BASE_ symbol. 
 (Target_i386::Scan::global): Likewise. 	* symtab.cc
 (sized_finalize_symbol): Add check for TLS symbol. 	* x86_64.cc
 (Target_x86_64::define_tls_base_symbol): New function. 
 (Target_x86_64::tls_base_symbol_defined_): New field. 
 (Target_x86_64::Scan::local): Define _TLS_MODULE_BASE_ symbol. 
 (Target_x86_64::Scan::global): Likewise.

---
 gold/ChangeLog | 12 ++++++++++++
 gold/i386.cc   | 31 ++++++++++++++++++++++++++++++-
 gold/symtab.cc |  4 +++-
 gold/x86_64.cc | 31 ++++++++++++++++++++++++++++++-
 4 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/gold/ChangeLog b/gold/ChangeLog
index 228fc936e79..0bc62aba335 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,15 @@
+2008-04-16  Cary Coutant  <ccoutant@google.com>
+
+	* i386.cc (Target_i386::define_tls_base_symbol): New function.
+	(Target_i386::tls_base_symbol_defined_): New field.
+	(Target_i386::Scan::local): Define _TLS_MODULE_BASE_ symbol.
+	(Target_i386::Scan::global): Likewise.
+	* symtab.cc (sized_finalize_symbol): Add check for TLS symbol.
+	* x86_64.cc (Target_x86_64::define_tls_base_symbol): New function.
+	(Target_x86_64::tls_base_symbol_defined_): New field.
+	(Target_x86_64::Scan::local): Define _TLS_MODULE_BASE_ symbol.
+	(Target_x86_64::Scan::global): Likewise.
+
 2008-04-16  Cary Coutant  <ccoutant@google.com>
 
 	* symtab.h (Symbol::is_strong_undefined): Removed unused function.
diff --git a/gold/i386.cc b/gold/i386.cc
index 917ec0b64ac..3e2483664dc 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -59,7 +59,7 @@ class Target_i386 : public Sized_target<32, false>
     : Sized_target<32, false>(&i386_info),
       got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
       copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
-      got_mod_index_offset_(-1U)
+      got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
   { }
 
   // Scan the relocations to look for symbol adjustments.
@@ -323,6 +323,10 @@ class Target_i386 : public Sized_target<32, false>
   void
   make_plt_entry(Symbol_table*, Layout*, Symbol*);
 
+  // Define the _TLS_MODULE_BASE_ symbol at the end of the TLS segment.
+  void
+  define_tls_base_symbol(Symbol_table*, Layout*);
+
   // Create a GOT entry for the TLS module index.
   unsigned int
   got_mod_index_entry(Symbol_table* symtab, Layout* layout,
@@ -391,6 +395,8 @@ class Target_i386 : public Sized_target<32, false>
   Output_data_space* dynbss_;
   // Offset of the GOT entry for the TLS module index.
   unsigned int got_mod_index_offset_;
+  // True if the _TLS_MODULE_BASE_ symbol has been defined.
+  bool tls_base_symbol_defined_;
 };
 
 const Target::Target_info Target_i386::i386_info =
@@ -719,6 +725,27 @@ Target_i386::make_plt_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym)
   this->plt_->add_entry(gsym);
 }
 
+// Define the _TLS_MODULE_BASE_ symbol at the end of the TLS segment.
+
+void
+Target_i386::define_tls_base_symbol(Symbol_table* symtab, Layout* layout)
+{
+  if (this->tls_base_symbol_defined_)
+    return;
+
+  Output_segment* tls_segment = layout->tls_segment();
+  if (tls_segment != NULL)
+    {
+      symtab->define_in_output_segment("_TLS_MODULE_BASE_", NULL,
+				       tls_segment, 0, 0,
+				       elfcpp::STT_TLS,
+				       elfcpp::STB_LOCAL,
+				       elfcpp::STV_HIDDEN, 0,
+				       Symbol::SEGMENT_END, true);
+    }
+  this->tls_base_symbol_defined_ = true;
+}
+
 // Create a GOT entry for the TLS module index.
 
 unsigned int
@@ -959,6 +986,7 @@ Target_i386::Scan::local(const General_options&,
 	    break;
 
 	  case elfcpp::R_386_TLS_GOTDESC:     // Global-dynamic (from ~oliva)
+	    target->define_tls_base_symbol(symtab, layout);
             if (optimized_type == tls::TLSOPT_NONE)
               {
                 // Create a double GOT entry with an R_386_TLS_DESC reloc.
@@ -1285,6 +1313,7 @@ Target_i386::Scan::global(const General_options&,
 	    break;
 
 	  case elfcpp::R_386_TLS_GOTDESC:     // Global-dynamic (~oliva url)
+	    target->define_tls_base_symbol(symtab, layout);
             if (optimized_type == tls::TLSOPT_NONE)
               {
                 // Create a double GOT entry with an R_386_TLS_DESC reloc.
diff --git a/gold/symtab.cc b/gold/symtab.cc
index ee826b33929..9b23790551f 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -1839,7 +1839,9 @@ Symbol_table::sized_finalize_symbol(Symbol* unsized_sym)
     case Symbol::IN_OUTPUT_SEGMENT:
       {
 	Output_segment* os = sym->output_segment();
-	value = sym->value() + os->vaddr();
+	value = sym->value();
+        if (sym->type() != elfcpp::STT_TLS)
+	  value += os->vaddr();
 	switch (sym->offset_base())
 	  {
 	  case Symbol::SEGMENT_START:
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 6fea4e38376..247f9d0322c 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -63,7 +63,7 @@ class Target_x86_64 : public Sized_target<64, false>
     : Sized_target<64, false>(&x86_64_info),
       got_(NULL), plt_(NULL), got_plt_(NULL), rela_dyn_(NULL),
       copy_relocs_(elfcpp::R_X86_64_COPY), dynbss_(NULL),
-      got_mod_index_offset_(-1U)
+      got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
   { }
 
   // Scan the relocations to look for symbol adjustments.
@@ -324,6 +324,10 @@ class Target_x86_64 : public Sized_target<64, false>
   void
   make_plt_entry(Symbol_table*, Layout*, Symbol*);
 
+  // Define the _TLS_MODULE_BASE_ symbol at the end of the TLS segment.
+  void
+  define_tls_base_symbol(Symbol_table*, Layout*);
+
   // Create the reserved PLT and GOT entries for the TLS descriptor resolver.
   void
   reserve_tlsdesc_entries(Symbol_table* symtab, Layout* layout);
@@ -394,6 +398,8 @@ class Target_x86_64 : public Sized_target<64, false>
   Output_data_space* dynbss_;
   // Offset of the GOT entry for the TLS module index.
   unsigned int got_mod_index_offset_;
+  // True if the _TLS_MODULE_BASE_ symbol has been defined.
+  bool tls_base_symbol_defined_;
 };
 
 const Target::Target_info Target_x86_64::x86_64_info =
@@ -771,6 +777,27 @@ Target_x86_64::make_plt_entry(Symbol_table* symtab, Layout* layout,
   this->plt_->add_entry(gsym);
 }
 
+// Define the _TLS_MODULE_BASE_ symbol at the end of the TLS segment.
+
+void
+Target_x86_64::define_tls_base_symbol(Symbol_table* symtab, Layout* layout)
+{
+  if (this->tls_base_symbol_defined_)
+    return;
+
+  Output_segment* tls_segment = layout->tls_segment();
+  if (tls_segment != NULL)
+    {
+      symtab->define_in_output_segment("_TLS_MODULE_BASE_", NULL,
+				       tls_segment, 0, 0,
+				       elfcpp::STT_TLS,
+				       elfcpp::STB_LOCAL,
+				       elfcpp::STV_HIDDEN, 0,
+				       Symbol::SEGMENT_END, true);
+    }
+  this->tls_base_symbol_defined_ = true;
+}
+
 // Create the reserved PLT and GOT entries for the TLS descriptor resolver.
 
 void
@@ -1093,6 +1120,7 @@ Target_x86_64::Scan::local(const General_options&,
             break;
 
           case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+            target->define_tls_base_symbol(symtab, layout);
 	    if (optimized_type == tls::TLSOPT_NONE)
 	      {
 	        // Create reserved PLT and GOT entries for the resolver.
@@ -1393,6 +1421,7 @@ Target_x86_64::Scan::global(const General_options&,
 	    break;
 
           case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+            target->define_tls_base_symbol(symtab, layout);
 	    if (optimized_type == tls::TLSOPT_NONE)
 	      {
 	        // Create reserved PLT and GOT entries for the resolver.