* layout.cc (Layout::get_output_section): Add is_interp and
[deliverable/binutils-gdb.git] / gold / x86_64.cc
index f523ae9f26449291a4f238cde54a334b28f6a6d7..c325fc00daa5f0232108e40c51edad1574580288 100644 (file)
@@ -1,6 +1,6 @@
 // x86_64.cc -- x86_64 target support for gold.
 
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -37,6 +37,8 @@
 #include "target-reloc.h"
 #include "target-select.h"
 #include "tls.h"
+#include "freebsd.h"
+#include "gc.h"
 
 namespace
 {
@@ -52,7 +54,7 @@ class Output_data_plt_x86_64;
 //   http://people.redhat.com/drepper/tls.pdf
 //   http://www.lsd.ic.unicamp.br/~oliva/writeups/TLS/RFC-TLSDESC-x86.txt
 
-class Target_x86_64 : public Sized_target<64, false>
+class Target_x86_64 : public Target_freebsd<64, false>
 {
  public:
   // In the x86_64 ABI (p 68), it says "The AMD64 ABI architectures
@@ -60,16 +62,33 @@ class Target_x86_64 : public Sized_target<64, false>
   typedef Output_data_reloc<elfcpp::SHT_RELA, true, 64, false> Reloc_section;
 
   Target_x86_64()
-    : Sized_target<64, false>(&x86_64_info),
+    : Target_freebsd<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), tls_base_symbol_defined_(false)
   { }
 
+  // Hook for a new output section.
+  void
+  do_new_output_section(Output_section*) const;
+
+  // Scan the relocations to look for symbol adjustments.
+  void
+  gc_process_relocs(Symbol_table* symtab,
+                   Layout* layout,
+                   Sized_relobj<64, false>* object,
+                   unsigned int data_shndx,
+                   unsigned int sh_type,
+                   const unsigned char* prelocs,
+                   size_t reloc_count,
+                   Output_section* output_section,
+                   bool needs_special_offset_handling,
+                   size_t local_symbol_count,
+                   const unsigned char* plocal_symbols);
+
   // Scan the relocations to look for symbol adjustments.
   void
-  scan_relocs(const General_options& options,
-             Symbol_table* symtab,
+  scan_relocs(Symbol_table* symtab,
              Layout* layout,
              Sized_relobj<64, false>* object,
              unsigned int data_shndx,
@@ -83,7 +102,7 @@ class Target_x86_64 : public Sized_target<64, false>
 
   // Finalize the sections.
   void
-  do_finalize_sections(Layout*);
+  do_finalize_sections(Layout*, const Input_objects*);
 
   // Return the value to use for a dynamic which requires special
   // treatment.
@@ -100,12 +119,12 @@ class Target_x86_64 : public Sized_target<64, false>
                   bool needs_special_offset_handling,
                   unsigned char* view,
                   elfcpp::Elf_types<64>::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
-  scan_relocatable_relocs(const General_options& options,
-                         Symbol_table* symtab,
+  scan_relocatable_relocs(Symbol_table* symtab,
                          Layout* layout,
                          Sized_relobj<64, false>* object,
                          unsigned int data_shndx,
@@ -139,9 +158,16 @@ class Target_x86_64 : public Sized_target<64, false>
 
   // Return whether SYM is defined by the ABI.
   bool
-  do_is_defined_by_abi(Symbol* sym) const
+  do_is_defined_by_abi(const Symbol* sym) const
   { return strcmp(sym->name(), "__tls_get_addr") == 0; }
 
+  // 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()
@@ -160,8 +186,7 @@ class Target_x86_64 : public Sized_target<64, false>
     { }
 
     inline void
-    local(const General_options& options, Symbol_table* symtab,
-         Layout* layout, Target_x86_64* target,
+    local(Symbol_table* symtab, Layout* layout, Target_x86_64* target,
          Sized_relobj<64, false>* object,
          unsigned int data_shndx,
          Output_section* output_section,
@@ -169,8 +194,7 @@ class Target_x86_64 : public Sized_target<64, false>
          const elfcpp::Sym<64, false>& lsym);
 
     inline void
-    global(const General_options& options, Symbol_table* symtab,
-          Layout* layout, Target_x86_64* target,
+    global(Symbol_table* symtab, Layout* layout, Target_x86_64* target,
           Sized_relobj<64, false>* object,
           unsigned int data_shndx,
           Output_section* output_section,
@@ -212,8 +236,8 @@ class Target_x86_64 : public Sized_target<64, false>
     // Do a relocation.  Return false if the caller should not issue
     // any warnings about this relocation.
     inline bool
-    relocate(const Relocate_info<64, false>*, Target_x86_64*, size_t relnum,
-            const elfcpp::Rela<64, false>&,
+    relocate(const Relocate_info<64, false>*, Target_x86_64*, Output_section*,
+            size_t relnum, const elfcpp::Rela<64, false>&,
             unsigned int r_type, const Sized_symbol<64>*,
             const Symbol_value<64>*,
             unsigned char*, elfcpp::Elf_types<64>::Elf_Addr,
@@ -330,7 +354,7 @@ 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.
+  // Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
   void
   define_tls_base_symbol(Symbol_table*, Layout*);
 
@@ -355,20 +379,10 @@ class Target_x86_64 : public Sized_target<64, false>
   Reloc_section*
   rela_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, Relobj* object,
+  copy_reloc(Symbol_table* symtab, Layout* layout,
+             Sized_relobj<64, false>* object,
             unsigned int shndx, Output_section* output_section,
             Symbol* sym, const elfcpp::Rela<64, false>& reloc)
   {
@@ -421,9 +435,23 @@ const Target::Target_info Target_x86_64::x86_64_info =
   "/lib/ld64.so.1",     // program interpreter
   0x400000,            // 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_X86_64_LCOMMON,  // large_common_shndx
+  0,                   // small_common_section_flags
+  elfcpp::SHF_X86_64_LARGE     // large_common_section_flags
 };
 
+// This is called when a new output section is created.  This is where
+// we handle the SHF_X86_64_LARGE.
+
+void
+Target_x86_64::do_new_output_section(Output_section *os) const
+{
+  if ((os->flags() & elfcpp::SHF_X86_64_LARGE) != 0)
+    os->set_is_large_section();
+}
+
 // Get the GOT section, creating it if necessary.
 
 Output_data_got<64, false>*
@@ -439,18 +467,18 @@ Target_x86_64::got_section(Symbol_table* symtab, Layout* layout)
       os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
                                           (elfcpp::SHF_ALLOC
                                            | elfcpp::SHF_WRITE),
-                                          this->got_);
+                                          this->got_, false);
       os->set_is_relro();
 
       // The old GNU linker creates a .got.plt section.  We just
       // create another set of data in the .got section.  Note that we
       // always create a PLT if we create a GOT, although the PLT
       // might be empty.
-      this->got_plt_ = new Output_data_space(8);
+      this->got_plt_ = new Output_data_space(8, "** GOT PLT");
       os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
                                           (elfcpp::SHF_ALLOC
                                            | elfcpp::SHF_WRITE),
-                                          this->got_plt_);
+                                          this->got_plt_, false);
       os->set_is_relro();
 
       // The first three entries are reserved.
@@ -478,7 +506,7 @@ Target_x86_64::rela_dyn_section(Layout* layout)
       gold_assert(layout != NULL);
       this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
       layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
-                                     elfcpp::SHF_ALLOC, this->rela_dyn_);
+                                     elfcpp::SHF_ALLOC, this->rela_dyn_, true);
     }
   return this->rela_dyn_;
 }
@@ -526,6 +554,11 @@ class Output_data_plt_x86_64 : public Output_section_data
   void
   do_adjust_output_section(Output_section* os);
 
+  // Write to a map file.
+  void
+  do_print_to_mapfile(Mapfile* mapfile) const
+  { mapfile->print_output_data(this, _("** PLT")); }
+
  private:
   // The size of an entry in the PLT.
   static const int plt_entry_size = 16;
@@ -573,15 +606,13 @@ Output_data_plt_x86_64::Output_data_plt_x86_64(Layout* layout,
 {
   this->rel_ = new Reloc_section(false);
   layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
-                                 elfcpp::SHF_ALLOC, this->rel_);
+                                 elfcpp::SHF_ALLOC, this->rel_, true);
 }
 
 void
 Output_data_plt_x86_64::do_adjust_output_section(Output_section* os)
 {
-  // UnixWare sets the entsize of .plt to 4, and so does the old GNU
-  // linker, and so do we.
-  os->set_entsize(4);
+  os->set_entsize(plt_entry_size);
 }
 
 // Add an entry to the PLT.
@@ -771,7 +802,7 @@ Target_x86_64::make_plt_section(Symbol_table* symtab, Layout* layout)
       layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
                                      (elfcpp::SHF_ALLOC
                                       | elfcpp::SHF_EXECINSTR),
-                                     this->plt_);
+                                     this->plt_, false);
     }
 }
 
@@ -790,7 +821,7 @@ 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.
+// Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
 
 void
 Target_x86_64::define_tls_base_symbol(Symbol_table* symtab, Layout* layout)
@@ -801,12 +832,16 @@ Target_x86_64::define_tls_base_symbol(Symbol_table* symtab, Layout* layout)
   Output_segment* tls_segment = layout->tls_segment();
   if (tls_segment != NULL)
     {
+      bool is_exec = parameters->options().output_is_executable();
       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);
+                                      (is_exec
+                                       ? Symbol::SEGMENT_END
+                                       : Symbol::SEGMENT_START),
+                                      true);
     }
   this->tls_base_symbol_defined_ = true;
 }
@@ -948,6 +983,7 @@ Target_x86_64::Scan::check_non_pic(Relobj* object, unsigned int r_type)
       // error per object file.
       if (this->issued_non_pic_error_)
         return;
+      gold_assert(parameters->options().output_is_position_independent());
       object->error(_("requires unsupported dynamic reloc; "
                       "recompile with -fPIC"));
       this->issued_non_pic_error_ = true;
@@ -961,8 +997,7 @@ Target_x86_64::Scan::check_non_pic(Relobj* object, unsigned int r_type)
 // Scan a relocation for a local symbol.
 
 inline void
-Target_x86_64::Scan::local(const General_options&,
-                           Symbol_table* symtab,
+Target_x86_64::Scan::local(Symbol_table* symtab,
                            Layout* layout,
                            Target_x86_64* target,
                            Sized_relobj<64, false>* object,
@@ -1242,8 +1277,7 @@ Target_x86_64::Scan::unsupported_reloc_global(Sized_relobj<64, false>* object,
 // Scan a relocation for a global symbol.
 
 inline void
-Target_x86_64::Scan::global(const General_options&,
-                            Symbol_table* symtab,
+Target_x86_64::Scan::global(Symbol_table* symtab,
                             Layout* layout,
                             Target_x86_64* target,
                             Sized_relobj<64, false>* object,
@@ -1280,7 +1314,7 @@ Target_x86_64::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);
@@ -1320,7 +1354,7 @@ Target_x86_64::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);
@@ -1534,11 +1568,44 @@ Target_x86_64::Scan::global(const General_options&,
     }
 }
 
+void
+Target_x86_64::gc_process_relocs(Symbol_table* symtab,
+                                 Layout* layout,
+                                 Sized_relobj<64, false>* object,
+                                 unsigned int data_shndx,
+                                 unsigned int sh_type,
+                                 const unsigned char* prelocs,
+                                 size_t reloc_count,
+                                Output_section* output_section,
+                                bool needs_special_offset_handling,
+                                 size_t local_symbol_count,
+                                 const unsigned char* plocal_symbols)
+{
+
+  if (sh_type == elfcpp::SHT_REL)
+    {
+      return;
+    }
+
+   gold::gc_process_relocs<64, false, Target_x86_64, elfcpp::SHT_RELA,
+                           Target_x86_64::Scan>(
+    symtab,
+    layout,
+    this,
+    object,
+    data_shndx,
+    prelocs,
+    reloc_count,
+    output_section,
+    needs_special_offset_handling,
+    local_symbol_count,
+    plocal_symbols);
+}
 // Scan relocations for a section.
 
 void
-Target_x86_64::scan_relocs(const General_options& options,
-                           Symbol_table* symtab,
+Target_x86_64::scan_relocs(Symbol_table* symtab,
                            Layout* layout,
                            Sized_relobj<64, false>* object,
                            unsigned int data_shndx,
@@ -1559,7 +1626,6 @@ Target_x86_64::scan_relocs(const General_options& options,
 
   gold::scan_relocs<64, false, Target_x86_64, elfcpp::SHT_RELA,
       Target_x86_64::Scan>(
-    options,
     symtab,
     layout,
     this,
@@ -1576,7 +1642,7 @@ Target_x86_64::scan_relocs(const General_options& options,
 // Finalize the sections.
 
 void
-Target_x86_64::do_finalize_sections(Layout* layout)
+Target_x86_64::do_finalize_sections(Layout* layout, const Input_objects*)
 {
   // Fill in some more dynamic tags.
   Output_data_dynamic* const odyn = layout->dynamic_data();
@@ -1631,6 +1697,7 @@ Target_x86_64::do_finalize_sections(Layout* layout)
 inline bool
 Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
                                   Target_x86_64* target,
+                                 Output_section*,
                                   size_t relnum,
                                   const elfcpp::Rela<64, false>& rela,
                                   unsigned int r_type,
@@ -1642,7 +1709,8 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
 {
   if (this->skip_call_tls_get_addr_)
     {
-      if (r_type != elfcpp::R_X86_64_PLT32
+      if ((r_type != elfcpp::R_X86_64_PLT32
+           && r_type != elfcpp::R_X86_64_PC32)
          || gsym == NULL
          || strcmp(gsym->name(), "__tls_get_addr") != 0)
        {
@@ -1659,10 +1727,10 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
   // Pick the value to use for symbols defined in shared objects.
   Symbol_value<64> symval;
   if (gsym != NULL
-      && (gsym->is_from_dynobj()
-          || (parameters->options().shared()
-              && (gsym->is_undefined() || gsym->is_preemptible())))
-      && gsym->has_plt_offset())
+      && gsym->use_plt_offset(r_type == elfcpp::R_X86_64_PC64
+                             || r_type == elfcpp::R_X86_64_PC32
+                             || r_type == elfcpp::R_X86_64_PC16
+                             || r_type == elfcpp::R_X86_64_PC8))
     {
       symval.set_output_value(target->plt_section()->address()
                              + gsym->plt_offset());
@@ -2038,7 +2106,6 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
       break;
 
     case elfcpp::R_X86_64_DTPOFF32:
-      gold_assert(tls_segment != NULL);
       if (optimized_type == tls::TLSOPT_TO_LE)
         {
           // This relocation type is used in debugging information.
@@ -2046,20 +2113,25 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
           // haven't seen a TLSLD reloc, then we assume we should not
           // optimize this reloc.
           if (this->saw_tls_block_reloc_)
-            value -= tls_segment->memsz();
+           {
+              gold_assert(tls_segment != NULL);
+              value -= tls_segment->memsz();
+           }
         }
-      Relocate_functions<64, false>::rela32(view, value, 0);
+      Relocate_functions<64, false>::rela32(view, value, addend);
       break;
 
     case elfcpp::R_X86_64_DTPOFF64:
-      gold_assert(tls_segment != NULL);
       if (optimized_type == tls::TLSOPT_TO_LE)
         {
           // See R_X86_64_DTPOFF32, just above, for why we test this.
           if (this->saw_tls_block_reloc_)
-            value -= tls_segment->memsz();
+           {
+             gold_assert(tls_segment != NULL);
+             value -= tls_segment->memsz();
+           }
         }
-      Relocate_functions<64, false>::rela64(view, value, 0);
+      Relocate_functions<64, false>::rela64(view, value, addend);
       break;
 
     case elfcpp::R_X86_64_GOTTPOFF:         // Initial-exec
@@ -2101,7 +2173,7 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
 
     case elfcpp::R_X86_64_TPOFF32:          // Local-exec
       value -= tls_segment->memsz();
-      Relocate_functions<64, false>::rela32(view, value, 0);
+      Relocate_functions<64, false>::rela32(view, value, addend);
       break;
     }
 }
@@ -2343,15 +2415,17 @@ Target_x86_64::Relocate::tls_ie_to_le(const Relocate_info<64, false>* relinfo,
 // Relocate section data.
 
 void
-Target_x86_64::relocate_section(const Relocate_info<64, false>* relinfo,
-                                unsigned int sh_type,
-                                const unsigned char* prelocs,
-                                size_t reloc_count,
-                               Output_section* output_section,
-                               bool needs_special_offset_handling,
-                                unsigned char* view,
-                                elfcpp::Elf_types<64>::Elf_Addr address,
-                                section_size_type view_size)
+Target_x86_64::relocate_section(
+    const Relocate_info<64, false>* relinfo,
+    unsigned int sh_type,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    Output_section* output_section,
+    bool needs_special_offset_handling,
+    unsigned char* view,
+    elfcpp::Elf_types<64>::Elf_Addr address,
+    section_size_type view_size,
+    const Reloc_symbol_changes* reloc_symbol_changes)
 {
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
@@ -2365,7 +2439,8 @@ Target_x86_64::relocate_section(const Relocate_info<64, 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
@@ -2440,8 +2515,7 @@ Target_x86_64::Relocatable_size_for_reloc::get_size_for_reloc(
 // Scan the relocs during a relocatable link.
 
 void
-Target_x86_64::scan_relocatable_relocs(const General_options& options,
-                                      Symbol_table* symtab,
+Target_x86_64::scan_relocatable_relocs(Symbol_table* symtab,
                                       Layout* layout,
                                       Sized_relobj<64, false>* object,
                                       unsigned int data_shndx,
@@ -2461,7 +2535,6 @@ Target_x86_64::scan_relocatable_relocs(const General_options& options,
 
   gold::scan_relocatable_relocs<64, false, elfcpp::SHT_RELA,
       Scan_relocatable_relocs>(
-    options,
     symtab,
     layout,
     object,
@@ -2539,40 +2612,40 @@ Target_x86_64::do_code_fill(section_size_type length) const
   // Nop sequences of various lengths.
   const char nop1[1] = { 0x90 };                   // nop
   const char nop2[2] = { 0x66, 0x90 };             // xchg %ax %ax
-  const char nop3[3] = { 0x8d, 0x76, 0x00 };       // leal 0(%esi),%esi
-  const char nop4[4] = { 0x8d, 0x74, 0x26, 0x00};  // leal 0(%esi,1),%esi
-  const char nop5[5] = { 0x90, 0x8d, 0x74, 0x26,   // nop
-                         0x00 };                   // leal 0(%esi,1),%esi
-  const char nop6[6] = { 0x8d, 0xb6, 0x00, 0x00,   // leal 0L(%esi),%esi
+  const char nop3[3] = { 0x0f, 0x1f, 0x00 };       // nop (%rax)
+  const char nop4[4] = { 0x0f, 0x1f, 0x40, 0x00};  // nop 0(%rax)
+  const char nop5[5] = { 0x0f, 0x1f, 0x44, 0x00,   // nop 0(%rax,%rax,1)
+                         0x00 };
+  const char nop6[6] = { 0x66, 0x0f, 0x1f, 0x44,   // nopw 0(%rax,%rax,1)
                          0x00, 0x00 };
-  const char nop7[7] = { 0x8d, 0xb4, 0x26, 0x00,   // leal 0L(%esi,1),%esi
+  const char nop7[7] = { 0x0f, 0x1f, 0x80, 0x00,   // nopl 0L(%rax)
                          0x00, 0x00, 0x00 };
-  const char nop8[8] = { 0x90, 0x8d, 0xb4, 0x26,   // nop
-                         0x00, 0x00, 0x00, 0x00 }; // leal 0L(%esi,1),%esi
-  const char nop9[9] = { 0x89, 0xf6, 0x8d, 0xbc,   // movl %esi,%esi
-                         0x27, 0x00, 0x00, 0x00,   // leal 0L(%edi,1),%edi
+  const char nop8[8] = { 0x0f, 0x1f, 0x84, 0x00,   // nopl 0L(%rax,%rax,1)
+                         0x00, 0x00, 0x00, 0x00 };
+  const char nop9[9] = { 0x66, 0x0f, 0x1f, 0x84,   // nopw 0L(%rax,%rax,1)
+                         0x00, 0x00, 0x00, 0x00,
                          0x00 };
-  const char nop10[10] = { 0x8d, 0x76, 0x00, 0x8d, // leal 0(%esi),%esi
-                           0xbc, 0x27, 0x00, 0x00, // leal 0L(%edi,1),%edi
+  const char nop10[10] = { 0x66, 0x2e, 0x0f, 0x1f, // nopw %cs:0L(%rax,%rax,1)
+                           0x84, 0x00, 0x00, 0x00,
                            0x00, 0x00 };
-  const char nop11[11] = { 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi
-                           0x8d, 0xbc, 0x27, 0x00, // leal 0L(%edi,1),%edi
+  const char nop11[11] = { 0x66, 0x66, 0x2e, 0x0f, // data16
+                           0x1f, 0x84, 0x00, 0x00, // nopw %cs:0L(%rax,%rax,1)
                            0x00, 0x00, 0x00 };
-  const char nop12[12] = { 0x8d, 0xb6, 0x00, 0x00, // leal 0L(%esi),%esi
-                           0x00, 0x00, 0x8d, 0xbf, // leal 0L(%edi),%edi
+  const char nop12[12] = { 0x66, 0x66, 0x66, 0x2e, // data16; data16
+                           0x0f, 0x1f, 0x84, 0x00, // nopw %cs:0L(%rax,%rax,1)
                            0x00, 0x00, 0x00, 0x00 };
-  const char nop13[13] = { 0x8d, 0xb6, 0x00, 0x00, // leal 0L(%esi),%esi
-                           0x00, 0x00, 0x8d, 0xbc, // leal 0L(%edi,1),%edi
-                           0x27, 0x00, 0x00, 0x00,
+  const char nop13[13] = { 0x66, 0x66, 0x66, 0x66, // data16; data16; data16
+                           0x2e, 0x0f, 0x1f, 0x84, // nopw %cs:0L(%rax,%rax,1)
+                           0x00, 0x00, 0x00, 0x00,
                            0x00 };
-  const char nop14[14] = { 0x8d, 0xb4, 0x26, 0x00, // leal 0L(%esi,1),%esi
-                           0x00, 0x00, 0x00, 0x8d, // leal 0L(%edi,1),%edi
-                           0xbc, 0x27, 0x00, 0x00,
+  const char nop14[14] = { 0x66, 0x66, 0x66, 0x66, // data16; data16; data16
+                           0x66, 0x2e, 0x0f, 0x1f, // data16
+                           0x84, 0x00, 0x00, 0x00, // nopw %cs:0L(%rax,%rax,1)
                            0x00, 0x00 };
-  const char nop15[15] = { 0xeb, 0x0d, 0x90, 0x90, // jmp .+15
-                           0x90, 0x90, 0x90, 0x90, // nop,nop,nop,...
-                           0x90, 0x90, 0x90, 0x90,
-                           0x90, 0x90, 0x90 };
+  const char nop15[15] = { 0x66, 0x66, 0x66, 0x66, // data16; data16; data16
+                           0x66, 0x66, 0x2e, 0x0f, // data16; data16
+                           0x1f, 0x84, 0x00, 0x00, // nopw %cs:0L(%rax,%rax,1)
+                           0x00, 0x00, 0x00 };
 
   const char* nops[16] = {
     NULL,
@@ -2583,18 +2656,77 @@ Target_x86_64::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_x86_64::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 %fs:NN,%rsp
+  if (this->match_view(view, view_size, fnoffset, "\x64\x48\x3b\x24\x25", 5)
+      && fnsize > 9)
+    {
+      // 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, 8);
+    }
+  // lea NN(%rsp),%r10
+  else if (this->match_view(view, view_size, fnoffset, "\x4c\x8d\x94\x24", 4)
+          && fnsize > 8)
+    {
+      // 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 + 4;
+      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 x86_64 object files.
 
-class Target_selector_x86_64 : public Target_selector
+class Target_selector_x86_64 : public Target_selector_freebsd
 {
 public:
   Target_selector_x86_64()
-    : Target_selector(elfcpp::EM_X86_64, 64, false, "elf64-x86-64")
+    : Target_selector_freebsd(elfcpp::EM_X86_64, 64, false, "elf64-x86-64",
+                             "elf64-x86-64-freebsd")
   { }
 
   Target*
   do_instantiate_target()
   { return new Target_x86_64(); }
+
 };
 
 Target_selector_x86_64 target_selector_x86_64;
This page took 0.032658 seconds and 4 git commands to generate.