This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gold patch committed] Fix x86/x86_64 TLSDESC with -z relro


The TLSDESC relocations used with -mtls-dialect=gnu2 did not work in
gold when using -z relro.  The problem was that the GOT entries were
created in the regular .got section, which, when using -z relro, is
marked read-only after relocations are complete.  The TLSDESC
relocations are resolved lazily, so attempting to set them while the
program was running failed.  I committed this path to fix the problem by
moving the GOT entries into the .got.plt section.

Ian

2010-08-02  Ian Lance Taylor  <iant@google.com>

	* i386.cc (class Target_i386): Add got_tlsdesc_ field.
	(Target_i386::Target_i386):: Initialize got_tlsdesc_.
	(Target_i386::got_tlsdesc_section): New function.
	(Target_i386::got_section): Create space for GOT entries for
	TLSDESC relocations.
	(Target_i386::Scan::local): Use TLSDESC GOT for unoptimized
	R_386_TLS_GOTDESC.
	(Target_i386::Scan::global): Likewise.
	(Target_i386::Relocate::relocate_tls): Adjust GOT offset when
	using TLSDESC GOT.
	* x86_64.cc (class Target_x86_64): Add got_tlsdesc_ field.
	(Target_x86_64::Target_x86_64):: Initialize got_tlsdesc_.
	(Target_x86_64::got_tlsdesc_section): New function.
	(Target_x86_64::got_section): Create space for GOT entries for
	TLSDESC relocations.
	(Target_x86_64::Scan::local): Use TLSDESC GOT for unoptimized
	R_386_TLS_GOTDESC.
	(Target_x86_64::Scan::global): Likewise.
	(Target_x86_64::Relocate::relocate_tls): Adjust GOT offset when
	using TLSDESC GOT.

Index: i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.119
diff -p -u -r1.119 i386.cc
--- i386.cc	29 Jul 2010 18:57:28 -0000	1.119
+++ i386.cc	2 Aug 2010 10:02:38 -0000
@@ -1,6 +1,6 @@
 // i386.cc -- i386 target support for gold.
 
-// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -59,8 +59,9 @@ class Target_i386 : public Target_freebs
 
   Target_i386()
     : Target_freebsd<32, false>(&i386_info),
-      got_(NULL), plt_(NULL), got_plt_(NULL), global_offset_table_(NULL),
-      rel_dyn_(NULL), copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
+      got_(NULL), plt_(NULL), got_plt_(NULL), got_tlsdesc_(NULL),
+      global_offset_table_(NULL), rel_dyn_(NULL),
+      copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
       got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
   { }
 
@@ -385,6 +386,14 @@ class Target_i386 : public Target_freebs
     return this->got_plt_;
   }
 
+  // Get the GOT section for TLSDESC entries.
+  Output_data_got<32, false>*
+  got_tlsdesc_section() const
+  {
+    gold_assert(this->got_tlsdesc_ != NULL);
+    return this->got_tlsdesc_;
+  }
+
   // Create a PLT entry for a global symbol.
   void
   make_plt_entry(Symbol_table*, Layout*, Symbol*);
@@ -447,6 +456,8 @@ class Target_i386 : public Target_freebs
   Output_data_plt_i386* plt_;
   // The GOT PLT section.
   Output_data_space* got_plt_;
+  // The GOT section for TLSDESC relocations.
+  Output_data_got<32, false>* got_tlsdesc_;
   // The _GLOBAL_OFFSET_TABLE_ symbol.
   Symbol* global_offset_table_;
   // The dynamic reloc section.
@@ -521,6 +532,15 @@ Target_i386::got_section(Symbol_table* s
 				      elfcpp::STB_LOCAL,
 				      elfcpp::STV_HIDDEN, 0,
 				      false, false);
+
+      // If there are any TLSDESC relocations, they get GOT entries in
+      // .got.plt after the jump slot entries.
+      this->got_tlsdesc_ = new Output_data_got<32, false>();
+      layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+				      (elfcpp::SHF_ALLOC
+				       | elfcpp::SHF_WRITE),
+				      this->got_tlsdesc_, false, false, false,
+				      true);
     }
 
   return this->got_;
@@ -1117,9 +1137,13 @@ Target_i386::Scan::local(Symbol_table* s
 	    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.
-                Output_data_got<32, false>* got
-                    = target->got_section(symtab, layout);
+                // Create a double GOT entry with an R_386_TLS_DESC
+                // reloc.  The R_386_TLS_DESC reloc is resolved
+                // lazily, so the GOT entry needs to be in an area in
+                // .got.plt, not .got.  Call got_section to make sure
+                // the section has been created.
+		target->got_section(symtab, layout);
+                Output_data_got<32, false>* got = target->got_tlsdesc_section();
                 unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
 		if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC))
 		  {
@@ -1501,9 +1525,13 @@ Target_i386::Scan::global(Symbol_table* 
 	    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.
-                Output_data_got<32, false>* got
-                    = target->got_section(symtab, layout);
+                // Create a double GOT entry with an R_386_TLS_DESC
+                // reloc.  The R_386_TLS_DESC reloc is resolved
+                // lazily, so the GOT entry needs to be in an area in
+                // .got.plt, not .got.  Call got_section to make sure
+                // the section has been created.
+		target->got_section(symtab, layout);
+                Output_data_got<32, false>* got = target->got_tlsdesc_section();
 		Reloc_section* rt = target->rel_tls_desc_section(layout);
                 got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt,
                                              elfcpp::R_386_TLS_DESC, 0);
@@ -2046,18 +2074,27 @@ Target_i386::Relocate::relocate_tls(cons
           unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
                                    ? GOT_TYPE_TLS_NOFFSET
                                    : GOT_TYPE_TLS_DESC);
-          unsigned int got_offset;
+          unsigned int got_offset = 0;
+	  if (r_type == elfcpp::R_386_TLS_GOTDESC
+	      && optimized_type == tls::TLSOPT_NONE)
+	    {
+	      // We created GOT entries in the .got.tlsdesc portion of
+	      // the .got.plt section, but the offset stored in the
+	      // symbol is the offset within .got.tlsdesc.
+	      got_offset = (target->got_size()
+			    + target->got_plt_section()->data_size());
+	    }
           if (gsym != NULL)
             {
               gold_assert(gsym->has_got_offset(got_type));
-              got_offset = gsym->got_offset(got_type) - target->got_size();
+              got_offset += gsym->got_offset(got_type) - 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_type));
-              got_offset = (object->local_got_offset(r_sym, got_type)
-			    - target->got_size());
+              got_offset += (object->local_got_offset(r_sym, got_type)
+			     - target->got_size());
             }
           if (optimized_type == tls::TLSOPT_TO_IE)
 	    {
Index: x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.110
diff -p -u -r1.110 x86_64.cc
--- x86_64.cc	29 Jul 2010 18:57:28 -0000	1.110
+++ x86_64.cc	2 Aug 2010 10:02:38 -0000
@@ -1,6 +1,6 @@
 // x86_64.cc -- x86_64 target support for gold.
 
-// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -64,8 +64,9 @@ class Target_x86_64 : public Target_free
 
   Target_x86_64()
     : Target_freebsd<64, false>(&x86_64_info),
-      got_(NULL), plt_(NULL), got_plt_(NULL), global_offset_table_(NULL),
-      rela_dyn_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY), dynbss_(NULL),
+      got_(NULL), plt_(NULL), got_plt_(NULL), got_tlsdesc_(NULL),
+      global_offset_table_(NULL), rela_dyn_(NULL),
+      copy_relocs_(elfcpp::R_X86_64_COPY), dynbss_(NULL),
       got_mod_index_offset_(-1U), tlsdesc_reloc_info_(),
       tls_base_symbol_defined_(false)
   { }
@@ -403,6 +404,14 @@ class Target_x86_64 : public Target_free
     return this->got_plt_;
   }
 
+  // Get the GOT section for TLSDESC entries.
+  Output_data_got<64, false>*
+  got_tlsdesc_section() const
+  {
+    gold_assert(this->got_tlsdesc_ != NULL);
+    return this->got_tlsdesc_;
+  }
+
   // Create the PLT section.
   void
   make_plt_section(Symbol_table* symtab, Layout* layout);
@@ -486,6 +495,8 @@ class Target_x86_64 : public Target_free
   Output_data_plt_x86_64* plt_;
   // The GOT PLT section.
   Output_data_space* got_plt_;
+  // The GOT section for TLSDESC relocations.
+  Output_data_got<64, false>* got_tlsdesc_;
   // The _GLOBAL_OFFSET_TABLE_ symbol.
   Symbol* global_offset_table_;
   // The dynamic reloc section.
@@ -574,6 +585,15 @@ Target_x86_64::got_section(Symbol_table*
 				      elfcpp::STB_LOCAL,
 				      elfcpp::STV_HIDDEN, 0,
 				      false, false);
+
+      // If there are any TLSDESC relocations, they get GOT entries in
+      // .got.plt after the jump slot entries.
+      this->got_tlsdesc_ = new Output_data_got<64, false>();
+      layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+				      (elfcpp::SHF_ALLOC
+				       | elfcpp::SHF_WRITE),
+				      this->got_tlsdesc_, false, false, false,
+				      true);
     }
 
   return this->got_;
@@ -1306,9 +1326,13 @@ Target_x86_64::Scan::local(Symbol_table*
 	        // Create reserved PLT and GOT entries for the resolver.
 	        target->reserve_tlsdesc_entries(symtab, layout);
 
-	        // Generate a double GOT entry with an R_X86_64_TLSDESC reloc.
-                Output_data_got<64, false>* got
-                    = target->got_section(symtab, layout);
+	        // Generate a double GOT entry with an
+	        // R_X86_64_TLSDESC reloc.  The R_X86_64_TLSDESC reloc
+	        // is resolved lazily, so the GOT entry needs to be in
+	        // an area in .got.plt, not .got.  Call got_section to
+	        // make sure the section has been created.
+		target->got_section(symtab, layout);
+                Output_data_got<64, false>* got = target->got_tlsdesc_section();
                 unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
 		if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC))
 		  {
@@ -1687,9 +1711,13 @@ Target_x86_64::Scan::global(Symbol_table
 	        // Create reserved PLT and GOT entries for the resolver.
 	        target->reserve_tlsdesc_entries(symtab, layout);
 
-	        // Create a double GOT entry with an R_X86_64_TLSDESC reloc.
-                Output_data_got<64, false>* got
-                    = target->got_section(symtab, layout);
+	        // Create a double GOT entry with an R_X86_64_TLSDESC
+	        // reloc.  The R_X86_64_TLSDESC reloc is resolved
+	        // lazily, so the GOT entry needs to be in an area in
+	        // .got.plt, not .got.  Call got_section to make sure
+	        // the section has been created.
+		target->got_section(symtab, layout);
+                Output_data_got<64, false>* got = target->got_tlsdesc_section();
 		Reloc_section *rt = target->rela_tlsdesc_section(layout);
                 got->add_global_pair_with_rela(gsym, GOT_TYPE_TLS_DESC, rt,
                                                elfcpp::R_X86_64_TLSDESC, 0);
@@ -2229,18 +2257,27 @@ Target_x86_64::Relocate::relocate_tls(co
           unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
                                    ? GOT_TYPE_TLS_OFFSET
                                    : GOT_TYPE_TLS_DESC);
-          unsigned int got_offset;
+          unsigned int got_offset = 0;
+	  if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC
+	      && optimized_type == tls::TLSOPT_NONE)
+	    {
+	      // We created GOT entries in the .got.tlsdesc portion of
+	      // the .got.plt section, but the offset stored in the
+	      // symbol is the offset within .got.tlsdesc.
+	      got_offset = (target->got_size()
+			    + target->got_plt_section()->data_size());
+	    }
           if (gsym != NULL)
             {
               gold_assert(gsym->has_got_offset(got_type));
-              got_offset = gsym->got_offset(got_type) - target->got_size();
+              got_offset += gsym->got_offset(got_type) - 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_type));
-              got_offset = (object->local_got_offset(r_sym, got_type)
-                            - target->got_size());
+              got_offset += (object->local_got_offset(r_sym, got_type)
+			     - target->got_size());
             }
           if (optimized_type == tls::TLSOPT_TO_IE)
             {

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