* elflink.c (_bfd_elf_link_assign_sym_version): Improve error
[deliverable/binutils-gdb.git] / gold / i386.cc
index 488da799f8054c0e05071bc9c6c2d31ec8d002cb..448453aa349505c7234a2d4c4821679159fa0ee9 100644 (file)
@@ -27,9 +27,12 @@ class Output_data_plt_i386;
 class Target_i386 : public Sized_target<32, false>
 {
  public:
+  typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
+
   Target_i386()
     : Sized_target<32, false>(&i386_info),
-      got_(NULL), plt_(NULL), got_plt_(NULL)
+      got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
+      copy_relocs_(NULL), dynbss_(NULL)
   { }
 
   // Scan the relocations to look for symbol adjustments.
@@ -46,6 +49,10 @@ class Target_i386 : public Sized_target<32, false>
              const unsigned char* plocal_symbols,
              Symbol** global_symbols);
 
+  // Finalize the sections.
+  void
+  do_finalize_sections(const General_options*, Layout*);
+
   // Relocate a section.
   void
   relocate_section(const Relocate_info<32, false>*,
@@ -102,7 +109,7 @@ class Target_i386 : public Sized_target<32, false>
     relocate(const Relocate_info<32, false>*, Target_i386*, size_t relnum,
             const elfcpp::Rel<32, false>&,
             unsigned int r_type, const Sized_symbol<32>*,
-            elfcpp::Elf_types<32>::Elf_Addr,
+            const Symbol_value<32>*,
             unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
             off_t);
 
@@ -112,7 +119,7 @@ class Target_i386 : public Sized_target<32, false>
     relocate_tls(const Relocate_info<32, false>*, size_t relnum,
                 const elfcpp::Rel<32, false>&,
                 unsigned int r_type, const Sized_symbol<32>*,
-                elfcpp::Elf_types<32>::Elf_Addr,
+                const Symbol_value<32>*,
                 unsigned char*, elfcpp::Elf_types<32>::Elf_Addr, off_t);
 
     // Do a TLS Initial-Exec to Local-Exec transition.
@@ -170,9 +177,14 @@ class Target_i386 : public Sized_target<32, false>
     return this->plt_;
   }
 
+  // Get the dynamic reloc section, creating it if necessary.
+  Reloc_section*
+  rel_dyn_section(Layout*);
+
   // Copy a relocation against a global symbol.
   void
-  copy_reloc(const General_options*, Sized_relobj<32, false>*, unsigned int,
+  copy_reloc(const General_options*, Symbol_table*, Layout*,
+            Sized_relobj<32, false>*, unsigned int,
             Symbol*, const elfcpp::Rel<32, false>&);
 
   // Information about this specific target which we pass to the
@@ -185,6 +197,12 @@ class Target_i386 : public Sized_target<32, false>
   Output_data_plt_i386* plt_;
   // The GOT PLT section.
   Output_data_space* got_plt_;
+  // The dynamic reloc section.
+  Reloc_section* rel_dyn_;
+  // Relocs saved to avoid a COPY reloc.
+  Copy_relocs<32, false>* copy_relocs_;
+  // Space for variables copied with a COPY reloc.
+  Output_data_space* dynbss_;
 };
 
 const Target::Target_info Target_i386::i386_info =
@@ -213,7 +231,8 @@ Target_i386::got_section(const General_options* options, Symbol_table* symtab,
       this->got_ = new Output_data_got<32, false>(options);
 
       layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-                                     elfcpp::SHF_ALLOC, this->got_);
+                                     elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+                                     this->got_);
 
       // The old GNU linker creates a .got.plt section.  We just
       // create another set of data in the .got section.  Note that we
@@ -221,16 +240,17 @@ Target_i386::got_section(const General_options* options, Symbol_table* symtab,
       // might be empty.
       this->got_plt_ = new Output_data_space(4);
       layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
-                                     elfcpp::SHF_ALLOC, this->got_plt_);
+                                     elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
+                                     this->got_plt_);
 
       // The first three entries are reserved.
       this->got_plt_->set_space_size(3 * 4);
 
       // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
-      symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_",
+      symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL,
                                    this->got_plt_,
                                    0, 0, elfcpp::STT_OBJECT,
-                                   elfcpp::STB_GLOBAL,
+                                   elfcpp::STB_LOCAL,
                                    elfcpp::STV_HIDDEN, 0,
                                    false, false);
     }
@@ -238,6 +258,21 @@ Target_i386::got_section(const General_options* options, Symbol_table* symtab,
   return this->got_;
 }
 
+// Get the dynamic reloc section, creating it if necessary.
+
+Target_i386::Reloc_section*
+Target_i386::rel_dyn_section(Layout* layout)
+{
+  if (this->rel_dyn_ == NULL)
+    {
+      gold_assert(layout != NULL);
+      this->rel_dyn_ = new Reloc_section();
+      layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL,
+                                     elfcpp::SHF_ALLOC, this->rel_dyn_);
+    }
+  return this->rel_dyn_;
+}
+
 // A class to handle the PLT data.
 
 class Output_data_plt_i386 : public Output_section_data
@@ -251,6 +286,15 @@ class Output_data_plt_i386 : public Output_section_data
   void
   add_entry(Symbol* gsym);
 
+  // Return the .rel.plt section data.
+  const Reloc_section*
+  rel_plt() const
+  { return this->rel_; }
+
+ protected:
+  void
+  do_adjust_output_section(Output_section* os);
+
  private:
   // The size of an entry in the PLT.
   static const int plt_entry_size = 16;
@@ -300,6 +344,16 @@ Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
                                  elfcpp::SHF_ALLOC, this->rel_);
 }
 
+// For some reason
+
+void
+Output_data_plt_i386::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);
+}
+
 // Add an entry to the PLT.
 
 void
@@ -321,6 +375,7 @@ Output_data_plt_i386::add_entry(Symbol* gsym)
   this->got_plt_->set_space_size(got_offset + 4);
 
   // Every PLT entry needs a reloc.
+  gsym->set_needs_dynsym_entry();
   this->rel_->add_global(gsym, elfcpp::R_386_JUMP_SLOT, this->got_plt_,
                         got_offset);
 
@@ -470,6 +525,10 @@ Target_i386::make_plt_entry(const General_options* options,
 
       this->plt_ = new Output_data_plt_i386(layout, this->got_plt_,
                                            options->is_shared());
+      layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
+                                     (elfcpp::SHF_ALLOC
+                                      | elfcpp::SHF_EXECINSTR),
+                                     this->plt_);
     }
 
   this->plt_->add_entry(gsym);
@@ -493,18 +552,71 @@ Target_i386::make_plt_entry(const General_options* options,
 
 void
 Target_i386::copy_reloc(const General_options* options,
+                       Symbol_table* symtab,
+                       Layout* layout,
                        Sized_relobj<32, false>* object,
                        unsigned int data_shndx, Symbol* gsym,
-                       const elfcpp::Rel<32, false>&)
+                       const elfcpp::Rel<32, false>& rel)
 {
-  if (!Relocate_functions<32, false>::need_copy_reloc(options, object,
-                                                     data_shndx, gsym))
+  Sized_symbol<32>* ssym;
+  ssym = symtab->get_sized_symbol SELECT_SIZE_NAME(32) (gsym
+                                                       SELECT_SIZE(32));
+
+  if (!Copy_relocs<32, false>::need_copy_reloc(options, object,
+                                              data_shndx, ssym))
     {
       // So far we do not need a COPY reloc.  Save this relocation.
-      // If it turns out that we never a COPY reloc for this symbol,
-      // then we emit the relocation.
+      // If it turns out that we never need a COPY reloc for this
+      // symbol, then we will emit the relocation.
+      if (this->copy_relocs_ == NULL)
+       this->copy_relocs_ = new Copy_relocs<32, false>();
+      this->copy_relocs_->save(ssym, object, data_shndx, rel);
     }
+  else
+    {
+      // Allocate space for this symbol in the .bss section.
+
+      elfcpp::Elf_types<32>::Elf_WXword symsize = ssym->symsize();
+
+      // There is no defined way to determine the required alignment
+      // of the symbol.  We pick the alignment based on the size.  We
+      // set an arbitrary maximum of 256.
+      unsigned int align;
+      for (align = 1; align < 512; align <<= 1)
+       if ((symsize & align) != 0)
+         break;
 
+      if (this->dynbss_ == NULL)
+       {
+         this->dynbss_ = new Output_data_space(align);
+         layout->add_output_section_data(".bss",
+                                         elfcpp::SHT_NOBITS,
+                                         (elfcpp::SHF_ALLOC
+                                          | elfcpp::SHF_WRITE),
+                                         this->dynbss_);
+       }
+
+      Output_data_space* dynbss = this->dynbss_;
+
+      if (align > dynbss->addralign())
+       dynbss->set_space_alignment(align);
+
+      off_t dynbss_size = dynbss->data_size();
+      dynbss_size = align_address(dynbss_size, align);
+      off_t offset = dynbss_size;
+      dynbss->set_space_size(dynbss_size + symsize);
+
+      // Define the symbol in the .dynbss section.
+      symtab->define_in_output_data(this, ssym->name(), ssym->version(),
+                                   dynbss, offset, symsize, ssym->type(),
+                                   ssym->binding(), ssym->visibility(),
+                                   ssym->nonvis(), false, false);
+
+      // Add the COPY reloc.
+      ssym->set_needs_dynsym_entry();
+      Reloc_section* rel_dyn = this->rel_dyn_section(layout);
+      rel_dyn->add_global(ssym, elfcpp::R_386_COPY, dynbss, offset);
+    }
 }
 
 // Optimize the TLS relocation type based on what we know about the
@@ -707,7 +819,7 @@ Target_i386::Scan::global(const General_options& options,
       // relocation in order to avoid a COPY relocation.
       gold_assert(!options.is_shared());
 
-      if (gsym->is_defined_in_dynobj())
+      if (gsym->is_from_dynobj())
        {
          // This symbol is defined in a dynamic object.  If it is a
          // function, we make a PLT entry.  Otherwise we need to
@@ -715,7 +827,8 @@ Target_i386::Scan::global(const General_options& options,
          if (gsym->type() == elfcpp::STT_FUNC)
            target->make_plt_entry(&options, symtab, layout, gsym);
          else
-           target->copy_reloc(&options, object, data_shndx, gsym, reloc);
+           target->copy_reloc(&options, symtab, layout, object, data_shndx,
+                              gsym, reloc);
        }
 
       break;
@@ -854,6 +967,57 @@ Target_i386::scan_relocs(const General_options& options,
     global_symbols);
 }
 
+// Finalize the sections.
+
+void
+Target_i386::do_finalize_sections(const General_options* options,
+                                 Layout* layout)
+{
+  // Fill in some more dynamic tags.
+  Output_data_dynamic* const odyn = layout->dynamic_data();
+  if (odyn != NULL)
+    {
+      if (this->got_plt_ != NULL)
+       odyn->add_section_address(elfcpp::DT_PLTGOT, this->got_plt_);
+
+      if (this->plt_ != NULL)
+       {
+         const Output_data* od = this->plt_->rel_plt();
+         odyn->add_section_size(elfcpp::DT_PLTRELSZ, od);
+         odyn->add_section_address(elfcpp::DT_JMPREL, od);
+         odyn->add_constant(elfcpp::DT_PLTREL, elfcpp::DT_REL);
+       }
+
+      if (this->rel_dyn_ != NULL)
+       {
+         const Output_data* od = this->rel_dyn_;
+         odyn->add_section_address(elfcpp::DT_REL, od);
+         odyn->add_section_size(elfcpp::DT_RELSZ, od);
+         odyn->add_constant(elfcpp::DT_RELENT,
+                            elfcpp::Elf_sizes<32>::rel_size);
+       }
+
+      if (!options->is_shared())
+       {
+         // The value of the DT_DEBUG tag is filled in by the dynamic
+         // linker at run time, and used by the debugger.
+         odyn->add_constant(elfcpp::DT_DEBUG, 0);
+       }
+    }
+
+  // Emit any relocs we saved in an attempt to avoid generating COPY
+  // relocs.
+  if (this->copy_relocs_ == NULL)
+    return;
+  if (this->copy_relocs_->any_to_emit())
+    {
+      Reloc_section* rel_dyn = this->rel_dyn_section(layout);
+      this->copy_relocs_->emit(rel_dyn);
+    }
+  delete this->copy_relocs_;
+  this->copy_relocs_ = NULL;
+}
+
 // Perform a relocation.
 
 inline bool
@@ -863,7 +1027,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
                                const elfcpp::Rel<32, false>& rel,
                                unsigned int r_type,
                                const Sized_symbol<32>* gsym,
-                               elfcpp::Elf_types<32>::Elf_Addr value,
+                               const Symbol_value<32>* psymval,
                                unsigned char* view,
                                elfcpp::Elf_types<32>::Elf_Addr address,
                                off_t view_size)
@@ -886,14 +1050,19 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
     }
 
   // Pick the value to use for symbols defined in shared objects.
-  if (gsym != NULL && gsym->is_defined_in_dynobj())
+  Symbol_value<32> symval;
+  if (gsym != NULL && gsym->is_from_dynobj())
     {
-      if (gsym->has_plt_offset())
-       address = target->plt_section()->address() + gsym->plt_offset();
-      else
+      if (!gsym->has_plt_offset())
        gold_unreachable();
+
+      symval.set_output_value(target->plt_section()->address()
+                             + gsym->plt_offset());
+      psymval = &symval;
     }
 
+  const Sized_relobj<32, false>* object = relinfo->object;
+
   switch (r_type)
     {
     case elfcpp::R_386_NONE:
@@ -902,51 +1071,57 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
       break;
 
     case elfcpp::R_386_32:
-      Relocate_functions<32, false>::rel32(view, value);
+      Relocate_functions<32, false>::rel32(view, object, psymval);
       break;
 
     case elfcpp::R_386_PC32:
-      Relocate_functions<32, false>::pcrel32(view, value, address);
+      Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
       break;
 
     case elfcpp::R_386_16:
-      Relocate_functions<32, false>::rel16(view, value);
+      Relocate_functions<32, false>::rel16(view, object, psymval);
       break;
 
     case elfcpp::R_386_PC16:
-      Relocate_functions<32, false>::pcrel16(view, value, address);
+      Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
       break;
 
     case elfcpp::R_386_8:
-      Relocate_functions<32, false>::rel8(view, value);
+      Relocate_functions<32, false>::rel8(view, object, psymval);
       break;
 
     case elfcpp::R_386_PC8:
-      Relocate_functions<32, false>::pcrel8(view, value, address);
+      Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
       break;
 
     case elfcpp::R_386_PLT32:
       gold_assert(gsym->has_plt_offset()
                  || gsym->final_value_is_known(relinfo->options));
-      Relocate_functions<32, false>::pcrel32(view, value, address);
+      Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
       break;
 
     case elfcpp::R_386_GOT32:
       // Local GOT offsets not yet supported.
       gold_assert(gsym);
       gold_assert(gsym->has_got_offset());
-      value = gsym->got_offset();
-      Relocate_functions<32, false>::rel32(view, value);
+      Relocate_functions<32, false>::rel32(view, gsym->got_offset());
       break;
 
     case elfcpp::R_386_GOTOFF:
-      value -= target->got_section(NULL, NULL, NULL)->address();
-      Relocate_functions<32, false>::rel32(view, value);
+      {
+       elfcpp::Elf_types<32>::Elf_Addr value;
+       value = (psymval->value(object, 0)
+                - target->got_section(NULL, NULL, NULL)->address());
+       Relocate_functions<32, false>::rel32(view, value);
+      }
       break;
 
     case elfcpp::R_386_GOTPC:
-      value = target->got_section(NULL, NULL, NULL)->address();
-      Relocate_functions<32, false>::pcrel32(view, value, address);
+      {
+       elfcpp::Elf_types<32>::Elf_Addr value;
+       value = target->got_section(NULL, NULL, NULL)->address();
+       Relocate_functions<32, false>::pcrel32(view, value, address);
+      }
       break;
 
     case elfcpp::R_386_COPY:
@@ -975,7 +1150,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
     case elfcpp::R_386_TLS_LE_32:
     case elfcpp::R_386_TLS_GOTDESC:
     case elfcpp::R_386_TLS_DESC_CALL:
-      this->relocate_tls(relinfo, relnum, rel, r_type, gsym, value, view,
+      this->relocate_tls(relinfo, relnum, rel, r_type, gsym, psymval, view,
                         address, view_size);
       break;
 
@@ -1009,7 +1184,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
                                    const elfcpp::Rel<32, false>& rel,
                                    unsigned int r_type,
                                    const Sized_symbol<32>* gsym,
-                                   elfcpp::Elf_types<32>::Elf_Addr value,
+                                   const Symbol_value<32>* psymval,
                                    unsigned char* view,
                                    elfcpp::Elf_types<32>::Elf_Addr,
                                    off_t view_size)
@@ -1023,6 +1198,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
       gold_exit(false);
     }
 
+  elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(relinfo->object, 0);
+
   const bool is_final = (gsym == NULL
                         ? !relinfo->options->is_shared()
                         : gsym->final_value_is_known(relinfo->options));
This page took 0.031155 seconds and 4 git commands to generate.