x86-64-biarch
[platform/upstream/binutils.git] / gold / i386.cc
index 47779d0..d28c444 100644 (file)
@@ -1,7 +1,6 @@
 // i386.cc -- i386 target support for gold.
 
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
-// Free Software Foundation, Inc.
+// Copyright (C) 2006-2014 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -48,6 +47,32 @@ namespace
 
 using namespace gold;
 
+// A class to handle the .got.plt section.
+
+class Output_data_got_plt_i386 : public Output_section_data_build
+{
+ public:
+  Output_data_got_plt_i386(Layout* layout)
+    : Output_section_data_build(4),
+      layout_(layout)
+  { }
+
+ protected:
+  // Write out the PLT data.
+  void
+  do_write(Output_file*);
+
+  // Write to a map file.
+  void
+  do_print_to_mapfile(Mapfile* mapfile) const
+  { mapfile->print_output_data(this, "** GOT PLT"); }
+
+ private:
+  // A pointer to the Layout class, so that we can find the .dynamic
+  // section when we write out the GOT PLT section.
+  Layout* layout_;
+};
+
 // A class to handle the PLT data.
 // This is an abstract base class that handles most of the linker details
 // but does not know the actual contents of PLT entries.  The derived
@@ -59,7 +84,7 @@ class Output_data_plt_i386 : public Output_section_data
   typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
 
   Output_data_plt_i386(Layout*, uint64_t addralign,
-                      Output_data_space*, Output_data_space*);
+                      Output_data_got_plt_i386*, Output_data_space*);
 
   // Add an entry to the PLT.
   void
@@ -202,9 +227,6 @@ 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
@@ -214,7 +236,7 @@ class Output_data_plt_i386 : public Output_section_data
   // regular relocatoins and the TLS_DESC relocations.
   Reloc_section* irelative_rel_;
   // The .got.plt section.
-  Output_data_space* got_plt_;
+  Output_data_got_plt_i386* got_plt_;
   // The part of the .got.plt section used for IRELATIVE relocs.
   Output_data_space* got_irelative_;
   // The number of PLT entries.
@@ -237,7 +259,7 @@ class Output_data_plt_i386_standard : public Output_data_plt_i386
 {
  public:
   Output_data_plt_i386_standard(Layout* layout,
-                               Output_data_space* got_plt,
+                               Output_data_got_plt_i386* got_plt,
                                Output_data_space* got_irelative)
     : Output_data_plt_i386(layout, plt_entry_size, got_plt, got_irelative)
   { }
@@ -268,7 +290,7 @@ class Output_data_plt_i386_exec : public Output_data_plt_i386_standard
 {
 public:
   Output_data_plt_i386_exec(Layout* layout,
-                           Output_data_space* got_plt,
+                           Output_data_got_plt_i386* got_plt,
                            Output_data_space* got_irelative)
     : Output_data_plt_i386_standard(layout, got_plt, got_irelative)
   { }
@@ -299,7 +321,7 @@ class Output_data_plt_i386_dyn : public Output_data_plt_i386_standard
 {
  public:
   Output_data_plt_i386_dyn(Layout* layout,
-                          Output_data_space* got_plt,
+                          Output_data_got_plt_i386* got_plt,
                           Output_data_space* got_irelative)
     : Output_data_plt_i386_standard(layout, got_plt, got_irelative)
   { }
@@ -337,7 +359,7 @@ class Target_i386 : public Sized_target<32, false>
     : Sized_target<32, false>(info),
       got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
       got_tlsdesc_(NULL), global_offset_table_(NULL), rel_dyn_(NULL),
-      rel_irelative_(NULL), copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
+      rel_irelative_(NULL), copy_relocs_(elfcpp::R_386_COPY),
       got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
   { }
 
@@ -414,7 +436,7 @@ class Target_i386 : public Sized_target<32, false>
                  const unsigned char* prelocs,
                  size_t reloc_count,
                  Output_section* output_section,
-                 off_t offset_in_output_section,
+                 elfcpp::Elf_types<32>::Elf_Off offset_in_output_section,
                  const Relocatable_relocs*,
                  unsigned char* view,
                  elfcpp::Elf_types<32>::Elf_Addr view_address,
@@ -507,14 +529,14 @@ class Target_i386 : public Sized_target<32, false>
   // This chooses the right PLT flavor for an executable or a shared object.
   Output_data_plt_i386*
   make_data_plt(Layout* layout,
-               Output_data_space* got_plt,
+               Output_data_got_plt_i386* got_plt,
                Output_data_space* got_irelative,
                bool dyn)
   { return this->do_make_data_plt(layout, got_plt, got_irelative, dyn); }
 
   virtual Output_data_plt_i386*
   do_make_data_plt(Layout* layout,
-                  Output_data_space* got_plt,
+                  Output_data_got_plt_i386* got_plt,
                   Output_data_space* got_irelative,
                   bool dyn)
   {
@@ -721,7 +743,7 @@ class Target_i386 : public Sized_target<32, false>
   got_section(Symbol_table*, Layout*);
 
   // Get the GOT PLT section.
-  Output_data_space*
+  Output_data_got_plt_i386*
   got_plt_section() const
   {
     gold_assert(this->got_plt_ != NULL);
@@ -814,7 +836,7 @@ class Target_i386 : public Sized_target<32, false>
   // The PLT section.
   Output_data_plt_i386* plt_;
   // The GOT PLT section.
-  Output_data_space* got_plt_;
+  Output_data_got_plt_i386* got_plt_;
   // The GOT section for IRELATIVE relocations.
   Output_data_space* got_irelative_;
   // The GOT section for TLSDESC relocations.
@@ -827,8 +849,6 @@ class Target_i386 : public Sized_target<32, false>
   Reloc_section* rel_irelative_;
   // Relocs saved to avoid a COPY reloc.
   Copy_relocs<elfcpp::SHT_REL, 32, false> copy_relocs_;
-  // Space for variables copied with a COPY reloc.
-  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.
@@ -857,7 +877,8 @@ const Target::Target_info Target_i386::i386_info =
   0,                   // small_common_section_flags
   0,                   // large_common_section_flags
   NULL,                        // attributes_section
-  NULL                 // attributes_vendor
+  NULL,                        // attributes_vendor
+  "_start"             // entry_symbol_name
 };
 
 // Get the GOT section, creating it if necessary.
@@ -887,7 +908,7 @@ Target_i386::got_section(Symbol_table* symtab, Layout* layout)
                                       | elfcpp::SHF_WRITE),
                                      this->got_, got_order, true);
 
-      this->got_plt_ = new Output_data_space(4, "** GOT PLT");
+      this->got_plt_ = new Output_data_got_plt_i386(layout);
       layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
                                      (elfcpp::SHF_ALLOC
                                       | elfcpp::SHF_WRITE),
@@ -974,18 +995,39 @@ Target_i386::rel_irelative_section(Layout* layout)
   return this->rel_irelative_;
 }
 
+// Write the first three reserved words of the .got.plt section.
+// The remainder of the section is written while writing the PLT
+// in Output_data_plt_i386::do_write.
+
+void
+Output_data_got_plt_i386::do_write(Output_file* of)
+{
+  // 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.
+  const off_t got_file_offset = this->offset();
+  gold_assert(this->data_size() >= 12);
+  unsigned char* const got_view = of->get_output_view(got_file_offset, 12);
+  Output_section* dynamic = this->layout_->dynamic_section();
+  uint32_t dynamic_addr = dynamic == NULL ? 0 : dynamic->address();
+  elfcpp::Swap<32, false>::writeval(got_view, dynamic_addr);
+  memset(got_view + 4, 0, 8);
+  of->write_output_view(got_file_offset, 12, got_view);
+}
+
 // Create the PLT section.  The ordinary .got section is an argument,
 // since we need to refer to the start.  We also create our own .got
 // section just for PLT entries.
 
 Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
                                           uint64_t addralign,
-                                          Output_data_space* got_plt,
+                                          Output_data_got_plt_i386* got_plt,
                                           Output_data_space* got_irelative)
   : Output_section_data(addralign),
-    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_()
+    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,
@@ -1151,16 +1193,19 @@ Output_data_plt_i386::address_for_global(const Symbol* gsym)
   if (gsym->type() == elfcpp::STT_GNU_IFUNC
       && gsym->can_use_relative_reloc(false))
     offset = (this->count_ + 1) * this->get_plt_entry_size();
-  return this->address() + offset;
+  return this->address() + offset + gsym->plt_offset();
 }
 
 // Return the PLT address to use for a local symbol.  These are always
 // IRELATIVE relocs.
 
 uint64_t
-Output_data_plt_i386::address_for_local(const Relobj*, unsigned int)
+Output_data_plt_i386::address_for_local(const Relobj* object,
+                                       unsigned int r_sym)
 {
-  return this->address() + (this->count_ + 1) * this->get_plt_entry_size();
+  return (this->address()
+         + (this->count_ + 1) * this->get_plt_entry_size()
+         + object->local_plt_offset(r_sym));
 }
 
 // The first entry in the PLT for an executable.
@@ -1322,6 +1367,7 @@ Output_data_plt_i386::do_write(Output_file* of)
   const section_size_type got_size =
     convert_to_section_size_type(this->got_plt_->data_size()
                                 + this->got_irelative_->data_size());
+
   unsigned char* const got_view = of->get_output_view(got_file_offset,
                                                      got_size);
 
@@ -1333,18 +1379,9 @@ Output_data_plt_i386::do_write(Output_file* of)
   this->fill_first_plt_entry(pov, got_address);
   pov += this->get_plt_entry_size();
 
-  unsigned char* got_pov = got_view;
-
-  // 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;
+  // The first three entries in the GOT are reserved, and are written
+  // by Output_data_got_plt_i386::do_write.
+  unsigned char* got_pov = got_view + 12;
 
   const int rel_size = elfcpp::Elf_sizes<32>::rel_size;
 
@@ -2112,7 +2149,8 @@ Target_i386::Scan::global(Symbol_table* symtab,
        // Make a dynamic relocation if necessary.
        if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
          {
-           if (gsym->may_need_copy_reloc())
+           if (!parameters->options().output_is_position_independent()
+               && gsym->may_need_copy_reloc())
              {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
@@ -2173,7 +2211,8 @@ Target_i386::Scan::global(Symbol_table* symtab,
        // Make a dynamic relocation if necessary.
        if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
          {
-           if (gsym->may_need_copy_reloc())
+           if (parameters->options().output_is_executable()
+               && gsym->may_need_copy_reloc())
              {
                target->copy_reloc(symtab, layout, object,
                                   data_shndx, output_section, gsym, reloc);
@@ -2658,6 +2697,9 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
        }
     }
 
+  if (view == NULL)
+    return true;
+
   const Sized_relobj_file<32, false>* object = relinfo->object;
 
   // Pick the value to use for symbols defined in shared objects.
@@ -2677,8 +2719,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
   else if (gsym != NULL
           && gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
     {
-      symval.set_output_value(target->plt_address_for_global(gsym)
-                             + gsym->plt_offset());
+      symval.set_output_value(target->plt_address_for_global(gsym));
       psymval = &symval;
     }
   else if (gsym == NULL && psymval->is_ifunc_symbol())
@@ -2686,8 +2727,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
       unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
       if (object->local_has_plt_offset(r_sym))
        {
-         symval.set_output_value(target->plt_address_for_local(object, r_sym)
-                                 + object->local_plt_offset(r_sym));
+         symval.set_output_value(target->plt_address_for_local(object, r_sym));
          psymval = &symval;
        }
     }
@@ -3486,7 +3526,7 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo,
   gold_assert(sh_type == elfcpp::SHT_REL);
 
   gold::relocate_section<32, false, Target_i386, elfcpp::SHT_REL,
-                        Target_i386::Relocate>(
+                        Target_i386::Relocate, gold::Default_comdat_behavior>(
     relinfo,
     this,
     prelocs,
@@ -3616,7 +3656,7 @@ Target_i386::relocate_relocs(
     const unsigned char* prelocs,
     size_t reloc_count,
     Output_section* output_section,
-    off_t offset_in_output_section,
+    elfcpp::Elf_types<32>::Elf_Off offset_in_output_section,
     const Relocatable_relocs* rr,
     unsigned char* view,
     elfcpp::Elf_types<32>::Elf_Addr view_address,
@@ -3649,7 +3689,7 @@ uint64_t
 Target_i386::do_dynsym_value(const Symbol* gsym) const
 {
   gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset());
-  return this->plt_address_for_global(gsym) + gsym->plt_offset();
+  return this->plt_address_for_global(gsym);
 }
 
 // Return a string used to fill a code section with nops to take up
@@ -3832,7 +3872,7 @@ class Output_data_plt_i386_nacl : public Output_data_plt_i386
 {
  public:
   Output_data_plt_i386_nacl(Layout* layout,
-                           Output_data_space* got_plt,
+                           Output_data_got_plt_i386* got_plt,
                            Output_data_space* got_irelative)
     : Output_data_plt_i386(layout, plt_entry_size, got_plt, got_irelative)
   { }
@@ -3861,7 +3901,7 @@ class Output_data_plt_i386_nacl_exec : public Output_data_plt_i386_nacl
 {
 public:
   Output_data_plt_i386_nacl_exec(Layout* layout,
-                                Output_data_space* got_plt,
+                                Output_data_got_plt_i386* got_plt,
                                 Output_data_space* got_irelative)
     : Output_data_plt_i386_nacl(layout, got_plt, got_irelative)
   { }
@@ -3890,7 +3930,7 @@ class Output_data_plt_i386_nacl_dyn : public Output_data_plt_i386_nacl
 {
  public:
   Output_data_plt_i386_nacl_dyn(Layout* layout,
-                               Output_data_space* got_plt,
+                               Output_data_got_plt_i386* got_plt,
                                Output_data_space* got_irelative)
     : Output_data_plt_i386_nacl(layout, got_plt, got_irelative)
   { }
@@ -3924,7 +3964,7 @@ class Target_i386_nacl : public Target_i386
  protected:
   virtual Output_data_plt_i386*
   do_make_data_plt(Layout* layout,
-                  Output_data_space* got_plt,
+                  Output_data_got_plt_i386* got_plt,
                   Output_data_space* got_irelative,
                   bool dyn)
   {
@@ -3934,6 +3974,9 @@ class Target_i386_nacl : public Target_i386
       return new Output_data_plt_i386_nacl_exec(layout, got_plt, got_irelative);
   }
 
+  virtual std::string
+  do_code_fill(section_size_type length) const;
+
  private:
   static const Target::Target_info i386_nacl_info;
 };
@@ -3960,7 +4003,8 @@ const Target::Target_info Target_i386_nacl::i386_nacl_info =
   0,                   // small_common_section_flags
   0,                   // large_common_section_flags
   NULL,                        // attributes_section
-  NULL                 // attributes_vendor
+  NULL,                        // attributes_vendor
+  "_start"             // entry_symbol_name
 };
 
 #define        NACLMASK        0xe0            // 32-byte alignment mask
@@ -4133,6 +4177,15 @@ Output_data_plt_i386_nacl::plt_eh_frame_fde[plt_eh_frame_fde_size] =
   elfcpp::DW_CFA_nop
 };
 
+// Return a string used to fill a code section with nops.
+// For NaCl, long NOPs are only valid if they do not cross
+// bundle alignment boundaries, so keep it simple with one-byte NOPs.
+std::string
+Target_i386_nacl::do_code_fill(section_size_type length) const
+{
+  return std::string(length, static_cast<char>(0x90));
+}
+
 // The selector for i386-nacl object files.
 
 class Target_selector_i386_nacl