merge from gcc
[deliverable/binutils-gdb.git] / gold / i386.cc
index 11204f48b319f6e55e34a485960f2956a87bf025..c01b5f2233244c561b21518b542d4f1dc5800ece 100644 (file)
@@ -113,7 +113,8 @@ class Target_i386 : public Target_freebsd<32, false>
                   bool needs_special_offset_handling,
                   unsigned char* view,
                   elfcpp::Elf_types<32>::Elf_Addr view_address,
-                  section_size_type view_size);
+                  section_size_type view_size,
+                  const Reloc_symbol_changes*);
 
   // Scan the relocs during a relocatable link.
   void
@@ -168,6 +169,13 @@ class Target_i386 : public Target_freebsd<32, false>
     return Target::do_is_local_label_name(name);
   }
 
+  // Adjust -fstack-split code which calls non-stack-split code.
+  void
+  do_calls_non_split(Relobj* object, unsigned int shndx,
+                    section_offset_type fnoffset, section_size_type fnsize,
+                    unsigned char* view, section_size_type view_size,
+                    std::string* from, std::string* to) const;
+
   // Return the size of the GOT section.
   section_size_type
   got_size()
@@ -212,7 +220,7 @@ class Target_i386 : public Target_freebsd<32, false>
    public:
     Relocate()
       : skip_call_tls_get_addr_(false),
-       local_dynamic_type_(LOCAL_DYNAMIC_NONE)
+       local_dynamic_type_(LOCAL_DYNAMIC_NONE), ldo_addrs_()
     { }
 
     ~Relocate()
@@ -307,6 +315,10 @@ class Target_i386 : public Target_freebsd<32, false>
                 unsigned char* view,
                 section_size_type view_size);
 
+    // Fix up LDO_32 relocations we've already seen.
+    void
+    fix_up_ldo(const Relocate_info<32, false>*);
+
     // We need to keep track of which type of local dynamic relocation
     // we have seen, so that we can optimize R_386_TLS_LDO_32 correctly.
     enum Local_dynamic_type
@@ -322,6 +334,8 @@ class Target_i386 : public Target_freebsd<32, false>
     // The type of local dynamic relocation we have seen in the section
     // being relocated, if any.
     Local_dynamic_type local_dynamic_type_;
+    // A list of LDO_32 offsets, in case we find LDM after LDO_32.
+    std::vector<unsigned char*> ldo_addrs_;
   };
 
   // A class which returns the size required for a relocation type,
@@ -375,17 +389,6 @@ class Target_i386 : public Target_freebsd<32, false>
   Reloc_section*
   rel_dyn_section(Layout*);
 
-  // Return true if the symbol may need a COPY relocation.
-  // References from an executable object to non-function symbols
-  // defined in a dynamic object may need a COPY relocation.
-  bool
-  may_need_copy_reloc(Symbol* gsym)
-  {
-    return (!parameters->options().shared()
-            && gsym->is_from_dynobj()
-            && gsym->type() != elfcpp::STT_FUNC);
-  }
-
   // Add a potential copy relocation.
   void
   copy_reloc(Symbol_table* symtab, Layout* layout,
@@ -444,7 +447,11 @@ const Target::Target_info Target_i386::i386_info =
   "/usr/lib/libc.so.1",        // dynamic_linker
   0x08048000,          // default_text_segment_address
   0x1000,              // abi_pagesize (overridable by -z max-page-size)
-  0x1000               // common_pagesize (overridable by -z common-page-size)
+  0x1000,              // common_pagesize (overridable by -z common-page-size)
+  elfcpp::SHN_UNDEF,   // small_common_shndx
+  elfcpp::SHN_UNDEF,   // large_common_shndx
+  0,                   // small_common_section_flags
+  0                    // large_common_section_flags
 };
 
 // Get the GOT section, creating it if necessary.
@@ -1209,7 +1216,7 @@ Target_i386::Scan::global(const General_options&,
         // Make a dynamic relocation if necessary.
         if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF))
           {
-            if (target->may_need_copy_reloc(gsym))
+            if (gsym->may_need_copy_reloc())
               {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
@@ -1255,7 +1262,7 @@ Target_i386::Scan::global(const General_options&,
           flags |= Symbol::FUNCTION_CALL;
         if (gsym->needs_dynamic_reloc(flags))
           {
-            if (target->may_need_copy_reloc(gsym))
+            if (gsym->may_need_copy_reloc())
               {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
@@ -1929,6 +1936,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
 
     case elfcpp::R_386_TLS_GOTDESC:      // Global-dynamic (from ~oliva url)
     case elfcpp::R_386_TLS_DESC_CALL:
+      if (this->local_dynamic_type_ == LOCAL_DYNAMIC_NONE)
+       this->fix_up_ldo(relinfo);
       this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU;
       if (optimized_type == tls::TLSOPT_TO_LE)
         {
@@ -1987,6 +1996,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
                                   "TLS relocations"));
          break;
        }
+      else if (this->local_dynamic_type_ == LOCAL_DYNAMIC_NONE)
+       this->fix_up_ldo(relinfo);
       this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU;
       if (optimized_type == tls::TLSOPT_TO_LE)
        {
@@ -2014,11 +2025,18 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       // This reloc can appear in debugging sections, in which case we
       // won't see the TLS_LDM reloc.  The local_dynamic_type field
       // tells us this.
-      if (optimized_type == tls::TLSOPT_TO_LE
-          && this->local_dynamic_type_ != LOCAL_DYNAMIC_NONE)
+      if (optimized_type == tls::TLSOPT_TO_LE)
        {
-          gold_assert(tls_segment != NULL);
-          value -= tls_segment->memsz();
+          if (this->local_dynamic_type_ != LOCAL_DYNAMIC_NONE)
+           {
+             gold_assert(tls_segment != NULL);
+             value -= tls_segment->memsz();
+           }
+         else
+           {
+             // We may see the LDM later.
+             this->ldo_addrs_.push_back(view);
+           }
        }
       Relocate_functions<32, false>::rel32(view, value);
       break;
@@ -2426,6 +2444,24 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo,
   Relocate_functions<32, false>::rel32(view, value);
 }
 
+// If we see an LDM reloc after we handled any LDO_32 relocs, fix up
+// the LDO_32 relocs.
+
+void
+Target_i386::Relocate::fix_up_ldo(const Relocate_info<32, false>* relinfo)
+{
+  if (this->ldo_addrs_.empty())
+    return;
+  Output_segment* tls_segment = relinfo->layout->tls_segment();
+  gold_assert(tls_segment != NULL);
+  elfcpp::Elf_types<32>::Elf_Addr value = - tls_segment->memsz();
+  for (std::vector<unsigned char*>::const_iterator p = this->ldo_addrs_.begin();
+       p != this->ldo_addrs_.end();
+       ++p)
+    Relocate_functions<32, false>::rel32(*p, value);
+  this->ldo_addrs_.clear();
+}
+
 // Relocate section data.
 
 void
@@ -2437,7 +2473,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
                              bool needs_special_offset_handling,
                              unsigned char* view,
                              elfcpp::Elf_types<32>::Elf_Addr address,
-                             section_size_type view_size)
+                             section_size_type view_size,
+                             const Reloc_symbol_changes* reloc_symbol_changes)
 {
   gold_assert(sh_type == elfcpp::SHT_REL);
 
@@ -2451,7 +2488,8 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
     needs_special_offset_handling,
     view,
     address,
-    view_size);
+    view_size,
+    reloc_symbol_changes);
 }
 
 // Return the size of a relocation while scanning during a relocatable
@@ -2671,6 +2709,63 @@ Target_i386::do_code_fill(section_size_type length) const
   return std::string(nops[length], length);
 }
 
+// FNOFFSET in section SHNDX in OBJECT is the start of a function
+// compiled with -fstack-split.  The function calls non-stack-split
+// code.  We have to change the function so that it always ensures
+// that it has enough stack space to run some random function.
+
+void
+Target_i386::do_calls_non_split(Relobj* object, unsigned int shndx,
+                               section_offset_type fnoffset,
+                               section_size_type fnsize,
+                               unsigned char* view,
+                               section_size_type view_size,
+                               std::string* from,
+                               std::string* to) const
+{
+  // The function starts with a comparison of the stack pointer and a
+  // field in the TCB.  This is followed by a jump.
+
+  // cmp %gs:NN,%esp
+  if (this->match_view(view, view_size, fnoffset, "\x65\x3b\x25", 3)
+      && fnsize > 7)
+    {
+      // We will call __morestack if the carry flag is set after this
+      // comparison.  We turn the comparison into an stc instruction
+      // and some nops.
+      view[fnoffset] = '\xf9';
+      this->set_view_to_nop(view, view_size, fnoffset + 1, 6);
+    }
+  // lea NN(%esp),%ecx
+  else if (this->match_view(view, view_size, fnoffset, "\x8d\x8c\x24", 3)
+          && fnsize > 7)
+    {
+      // This is loading an offset from the stack pointer for a
+      // comparison.  The offset is negative, so we decrease the
+      // offset by the amount of space we need for the stack.  This
+      // means we will avoid calling __morestack if there happens to
+      // be plenty of space on the stack already.
+      unsigned char* pval = view + fnoffset + 3;
+      uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval);
+      val -= parameters->options().split_stack_adjust_size();
+      elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
+    }
+  else
+    {
+      if (!object->has_no_split_stack())
+       object->error(_("failed to match split-stack sequence at "
+                       "section %u offset %0zx"),
+                     shndx, fnoffset);
+      return;
+    }
+
+  // We have to change the function so that it calls
+  // __morestack_non_split instead of __morestack.  The former will
+  // allocate additional stack space.
+  *from = "__morestack";
+  *to = "__morestack_non_split";
+}
+
 // The selector for i386 object files.
 
 class Target_selector_i386 : public Target_selector_freebsd
This page took 0.025759 seconds and 4 git commands to generate.