* layout.cc (Layout::relaxation_loop_body): Only clear load_seg if
[deliverable/binutils-gdb.git] / gold / i386.cc
index 6c6c4b414894811d3542c3d3de33754fd888dc65..445bc68a940127bb70fc1dc9084f6d73cca9bc75 100644 (file)
@@ -166,6 +166,9 @@ class Output_data_plt_i386 : public Output_section_data
     unsigned int got_offset;
   };
 
+  // A pointer to the Layout class, so that we can find the .dynamic
+  // section when we write out the GOT PLT section.
+  Layout* layout_;
   // The reloc section.
   Reloc_section* rel_;
   // The TLS_DESC relocations, if necessary.  These must follow the
@@ -712,23 +715,37 @@ Target_i386::got_section(Symbol_table* symtab, Layout* layout)
 
       this->got_ = new Output_data_got<32, false>();
 
+      // When using -z now, we can treat .got.plt as a relro section.
+      // Without -z now, it is modified after program startup by lazy
+      // PLT relocations.
+      bool is_got_plt_relro = parameters->options().now();
+      Output_section_order got_order = (is_got_plt_relro
+                                       ? ORDER_RELRO
+                                       : ORDER_RELRO_LAST);
+      Output_section_order got_plt_order = (is_got_plt_relro
+                                           ? ORDER_RELRO
+                                           : ORDER_NON_RELRO_FIRST);
+
       layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
                                      (elfcpp::SHF_ALLOC
                                       | elfcpp::SHF_WRITE),
-                                     this->got_, ORDER_RELRO_LAST, true);
+                                     this->got_, got_order, true);
 
       this->got_plt_ = new Output_data_space(4, "** GOT PLT");
       layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
                                      (elfcpp::SHF_ALLOC
                                       | elfcpp::SHF_WRITE),
-                                     this->got_plt_, ORDER_NON_RELRO_FIRST,
-                                     false);
+                                     this->got_plt_, got_plt_order,
+                                     is_got_plt_relro);
 
       // The first three entries are reserved.
       this->got_plt_->set_current_data_size(3 * 4);
 
-      // Those bytes can go into the relro segment.
-      layout->increase_relro(3 * 4);
+      if (!is_got_plt_relro)
+       {
+         // Those bytes can go into the relro segment.
+         layout->increase_relro(3 * 4);
+       }
 
       // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
       this->global_offset_table_ =
@@ -747,7 +764,7 @@ Target_i386::got_section(Symbol_table* symtab, Layout* layout)
                                      (elfcpp::SHF_ALLOC
                                       | elfcpp::SHF_WRITE),
                                      this->got_irelative_,
-                                     ORDER_NON_RELRO_FIRST, false);
+                                     got_plt_order, is_got_plt_relro);
 
       // If there are any TLSDESC relocations, they get GOT entries in
       // .got.plt after the jump slot entries.
@@ -756,7 +773,7 @@ Target_i386::got_section(Symbol_table* symtab, Layout* layout)
                                      (elfcpp::SHF_ALLOC
                                       | elfcpp::SHF_WRITE),
                                      this->got_tlsdesc_,
-                                     ORDER_NON_RELRO_FIRST, false);
+                                     got_plt_order, is_got_plt_relro);
     }
 
   return this->got_;
@@ -808,9 +825,9 @@ Target_i386::rel_irelative_section(Layout* layout)
 Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
                                           Output_data_space* got_plt,
                                           Output_data_space* got_irelative)
-  : Output_section_data(16), tls_desc_rel_(NULL), irelative_rel_(NULL),
-    got_plt_(got_plt), got_irelative_(got_irelative), count_(0),
-    irelative_count_(0), global_ifuncs_(), local_ifuncs_()
+  : Output_section_data(16), layout_(layout), tls_desc_rel_(NULL),
+    irelative_rel_(NULL), got_plt_(got_plt), got_irelative_(got_irelative),
+    count_(0), irelative_count_(0), global_ifuncs_(), local_ifuncs_()
 {
   this->rel_ = new Reloc_section(false);
   layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
@@ -1124,8 +1141,16 @@ Output_data_plt_i386::do_write(Output_file* of)
 
   unsigned char* got_pov = got_view;
 
-  memset(got_pov, 0, 12);
-  got_pov += 12;
+  // The first entry in the GOT is the address of the .dynamic section
+  // aka the PT_DYNAMIC segment.  The next two entries are reserved.
+  // We saved space for them when we created the section in
+  // Target_i386::got_section.
+  Output_section* dynamic = this->layout_->dynamic_section();
+  uint32_t dynamic_addr = dynamic == NULL ? 0 : dynamic->address();
+  elfcpp::Swap<32, false>::writeval(got_pov, dynamic_addr);
+  got_pov += 4;
+  memset(got_pov, 0, 8);
+  got_pov += 8;
 
   const int rel_size = elfcpp::Elf_sizes<32>::rel_size;
 
@@ -1985,9 +2010,24 @@ Target_i386::Scan::global(Symbol_table* symtab,
             // If this symbol is not fully resolved, we need to add a
             // GOT entry with a dynamic relocation.
             Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+
+           // Use a GLOB_DAT rather than a RELATIVE reloc if:
+           //
+           // 1) The symbol may be defined in some other module.
+           //
+           // 2) We are building a shared library and this is a
+           // protected symbol; using GLOB_DAT means that the dynamic
+           // linker can use the address of the PLT in the main
+           // executable when appropriate so that function address
+           // comparisons work.
+           //
+           // 3) This is a STT_GNU_IFUNC symbol in position dependent
+           // code, again so that function address comparisons work.
             if (gsym->is_from_dynobj()
                 || gsym->is_undefined()
                 || gsym->is_preemptible()
+               || (gsym->visibility() == elfcpp::STV_PROTECTED
+                   && parameters->options().shared())
                || (gsym->type() == elfcpp::STT_GNU_IFUNC
                    && parameters->options().output_is_position_independent()))
               got->add_global_with_rel(gsym, GOT_TYPE_STANDARD,
@@ -2638,7 +2678,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
     case elfcpp::R_386_TLS_GD:           // Global-dynamic
       if (optimized_type == tls::TLSOPT_TO_LE)
        {
-         gold_assert(tls_segment != NULL);
+         if (tls_segment == NULL)
+           {
+             gold_assert(parameters->errors()->error_count() > 0
+                         || issue_undefined_symbol_error(gsym));
+             return;
+           }
          this->tls_gd_to_le(relinfo, relnum, tls_segment,
                             rel, r_type, value, view,
                             view_size);
@@ -2664,7 +2709,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
             }
           if (optimized_type == tls::TLSOPT_TO_IE)
            {
-              gold_assert(tls_segment != NULL);
+             if (tls_segment == NULL)
+               {
+                 gold_assert(parameters->errors()->error_count() > 0
+                             || issue_undefined_symbol_error(gsym));
+                 return;
+               }
              this->tls_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type,
                                  got_offset, view, view_size);
               break;
@@ -2687,7 +2737,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU;
       if (optimized_type == tls::TLSOPT_TO_LE)
         {
-         gold_assert(tls_segment != NULL);
+         if (tls_segment == NULL)
+           {
+             gold_assert(parameters->errors()->error_count() > 0
+                         || issue_undefined_symbol_error(gsym));
+             return;
+           }
          this->tls_desc_gd_to_le(relinfo, relnum, tls_segment,
                                  rel, r_type, value, view,
                                  view_size);
@@ -2722,7 +2777,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
             }
           if (optimized_type == tls::TLSOPT_TO_IE)
            {
-              gold_assert(tls_segment != NULL);
+             if (tls_segment == NULL)
+               {
+                 gold_assert(parameters->errors()->error_count() > 0
+                             || issue_undefined_symbol_error(gsym));
+                 return;
+               }
              this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type,
                                       got_offset, view, view_size);
               break;
@@ -2754,7 +2814,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU;
       if (optimized_type == tls::TLSOPT_TO_LE)
        {
-          gold_assert(tls_segment != NULL);
+         if (tls_segment == NULL)
+           {
+             gold_assert(parameters->errors()->error_count() > 0
+                         || issue_undefined_symbol_error(gsym));
+             return;
+           }
          this->tls_ld_to_le(relinfo, relnum, tls_segment, rel, r_type,
                             value, view, view_size);
          break;
@@ -2785,7 +2850,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
          elfcpp::Shdr<32, false> shdr(relinfo->data_shdr);
          if ((shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
            {
-             gold_assert(tls_segment != NULL);
+             if (tls_segment == NULL)
+               {
+                 gold_assert(parameters->errors()->error_count() > 0
+                             || issue_undefined_symbol_error(gsym));
+                 return;
+               }
              value -= tls_segment->memsz();
            }
        }
@@ -2797,7 +2867,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
     case elfcpp::R_386_TLS_IE_32:
       if (optimized_type == tls::TLSOPT_TO_LE)
        {
-          gold_assert(tls_segment != NULL);
+         if (tls_segment == NULL)
+           {
+             gold_assert(parameters->errors()->error_count() > 0
+                         || issue_undefined_symbol_error(gsym));
+             return;
+           }
          Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
                                              rel, r_type, value, view,
                                              view_size);
@@ -2841,7 +2916,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       // have been created for this location, so do not apply it now.
       if (!parameters->options().shared())
         {
-          gold_assert(tls_segment != NULL);
+         if (tls_segment == NULL)
+           {
+             gold_assert(parameters->errors()->error_count() > 0
+                         || issue_undefined_symbol_error(gsym));
+             return;
+           }
           value -= tls_segment->memsz();
           Relocate_functions<32, false>::rel32(view, value);
         }
@@ -2852,7 +2932,12 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       // have been created for this location, so do not apply it now.
       if (!parameters->options().shared())
         {
-          gold_assert(tls_segment != NULL);
+         if (tls_segment == NULL)
+           {
+             gold_assert(parameters->errors()->error_count() > 0
+                         || issue_undefined_symbol_error(gsym));
+             return;
+           }
           value = tls_segment->memsz() - value;
           Relocate_functions<32, false>::rel32(view, value);
         }
This page took 0.027304 seconds and 4 git commands to generate.