2010-02-24 Doug Kwan <dougkwan@google.com>
authorDoug Kwan <dougkwan@google.com>
Wed, 24 Feb 2010 20:45:12 +0000 (20:45 +0000)
committerDoug Kwan <dougkwan@google.com>
Wed, 24 Feb 2010 20:45:12 +0000 (20:45 +0000)
* arm.cc (Arm_output_data_got): New class.
(ARM_TCB_SIZE): New constant
(Target_arm): Use Arm_output_data_got instead of Output_data_got.
(Arm_output_section::fix_exidx_coverage): Add a parameter for layout.
If user uses a script with a SECTIONS clause, issue only a warning
for a misplaced EXIDX input section.  Otherwise, issue an error.
  (Arm_relobj::do_gc_process_relocs): Exit early if we are not doing
garbage collection.
(Target_arm::got_mode_index_entry): Handle static linking.
(Target_arm::Scan::local): Ditto.
(Target_arm::Scan::global): Ditto.
(Target_arm::Relocate::relocate_tls): Handle static linking.  Fix
all incorrectly implemented relocations.
(Target_arm::fix_exidx_coverage): Pass layout to
Arm_output_section::fix_exidx_coverage.
* layout.cc (Layout::section_name_mapping): Remove trailing dots
from ".ARM.exidx." and ".ARM.extab.".

gold/ChangeLog
gold/arm.cc
gold/layout.cc

index 6259834dd94badc5537f1ea287bfd49adf98e251..a7bf29943ab3734cfe553e33e4ffcce64e45d9f5 100644 (file)
@@ -1,3 +1,23 @@
+2010-02-24  Doug Kwan  <dougkwan@google.com>
+
+       * arm.cc (Arm_output_data_got): New class.
+       (ARM_TCB_SIZE): New constant
+       (Target_arm): Use Arm_output_data_got instead of Output_data_got.
+       (Arm_output_section::fix_exidx_coverage): Add a parameter for layout.
+       If user uses a script with a SECTIONS clause, issue only a warning
+       for a misplaced EXIDX input section.  Otherwise, issue an error.
+       (Arm_relobj::do_gc_process_relocs): Exit early if we are not doing
+       garbage collection.
+       (Target_arm::got_mode_index_entry): Handle static linking.
+       (Target_arm::Scan::local): Ditto.
+       (Target_arm::Scan::global): Ditto.
+       (Target_arm::Relocate::relocate_tls): Handle static linking.  Fix
+       all incorrectly implemented relocations.
+       (Target_arm::fix_exidx_coverage): Pass layout to 
+       Arm_output_section::fix_exidx_coverage.
+       * layout.cc (Layout::section_name_mapping): Remove trailing dots
+       from ".ARM.exidx." and ".ARM.extab.".
+
 2010-02-23  Viktor Kutuzov  <vkutuzov@accesssoftek.com>
 
        * arm.cc (Target_arm::do_finalize_sections): Create attribute
index b8141e0a7c10eddb6f459f3a4e835ed1846b4443..ca34023f435a80efaa47a5cb088239b6f2ab5b3a 100644 (file)
@@ -83,6 +83,9 @@ class Arm_relobj;
 template<bool big_endian>
 class Arm_relocate_functions;
 
+template<bool big_endian>
+class Arm_output_data_got;
+
 template<bool big_endian>
 class Target_arm;
 
@@ -97,6 +100,9 @@ const int32_t THM_MAX_BWD_BRANCH_OFFSET = (-(1 << 22) + 4);
 const int32_t THM2_MAX_FWD_BRANCH_OFFSET = (((1 << 24) - 2) + 4);
 const int32_t THM2_MAX_BWD_BRANCH_OFFSET = (-(1 << 24) + 4);
 
+// Thread Control Block size.
+const size_t ARM_TCB_SIZE = 8;
+
 // The arm target class.
 //
 // This is a very simple port of gold for ARM-EABI.  It is intended for
@@ -1318,7 +1324,8 @@ class Arm_output_section : public Output_section
   // is a list of text input sections sorted in ascending order of their
   // output addresses.
   void
-  fix_exidx_coverage(const Text_section_list& sorted_text_section,
+  fix_exidx_coverage(Layout* layout,
+                    const Text_section_list& sorted_text_section,
                     Symbol_table* symtab);
 
  private:
@@ -1778,6 +1785,144 @@ class Cortex_a8_reloc
   Arm_address destination_;
 };
 
+// Arm_output_data_got class.  We derive this from Output_data_got to add
+// extra methods to handle TLS relocations in a static link.
+
+template<bool big_endian>
+class Arm_output_data_got : public Output_data_got<32, big_endian>
+{
+ public:
+  Arm_output_data_got(Symbol_table* symtab, Layout* layout)
+    : Output_data_got<32, big_endian>(), symbol_table_(symtab), layout_(layout)
+  { }
+
+  // Add a static entry for the GOT entry at OFFSET.  GSYM is a global
+  // symbol and R_TYPE is the code of a dynamic relocation that needs to be
+  // applied in a static link.
+  void
+  add_static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym)
+  { this->static_relocs_.push_back(Static_reloc(got_offset, r_type, gsym)); }
+
+  // Add a static reloc for the GOT entry at OFFSET.  RELOBJ is an object
+  // defining a local symbol with INDEX.  R_TYPE is the code of a dynamic
+  // relocation that needs to be applied in a static link.
+  void
+  add_static_reloc(unsigned int got_offset, unsigned int r_type,
+                  Sized_relobj<32, big_endian>* relobj, unsigned int index)
+  {
+    this->static_relocs_.push_back(Static_reloc(got_offset, r_type, relobj,
+                                               index));
+  }
+
+  // Add a GOT pair for R_ARM_TLS_GD32.  The creates a pair of GOT entries.
+  // The first one is initialized to be 1, which is the module index for
+  // the main executable and the second one 0.  A reloc of the type
+  // R_ARM_TLS_DTPOFF32 will be created for the second GOT entry and will
+  // be applied by gold.  GSYM is a global symbol.
+  void
+  add_tls_gd32_with_static_reloc(unsigned int got_type, Symbol* gsym);
+
+  // Same as the above but for a local symbol in OBJECT with INDEX.
+  void
+  add_tls_gd32_with_static_reloc(unsigned int got_type,
+                                Sized_relobj<32, big_endian>* object,
+                                unsigned int index);
+
+ protected:
+  // Write out the GOT table.
+  void
+  do_write(Output_file*);
+
+ private:
+  // This class represent dynamic relocations that need to be applied by
+  // gold because we are using TLS relocations in a static link.
+  class Static_reloc
+  {
+   public:
+    Static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym)
+      : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(true)
+    { this->u_.global.symbol = gsym; }
+
+    Static_reloc(unsigned int got_offset, unsigned int r_type,
+         Sized_relobj<32, big_endian>* relobj, unsigned int index)
+      : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(false)
+    {
+      this->u_.local.relobj = relobj;
+      this->u_.local.index = index;
+    }
+
+    // Return the GOT offset.
+    unsigned int
+    got_offset() const
+    { return this->got_offset_; }
+
+    // Relocation type.
+    unsigned int
+    r_type() const
+    { return this->r_type_; }
+
+    // Whether the symbol is global or not.
+    bool
+    symbol_is_global() const
+    { return this->symbol_is_global_; }
+
+    // For a relocation against a global symbol, the global symbol.
+    Symbol*
+    symbol() const
+    {
+      gold_assert(this->symbol_is_global_);
+      return this->u_.global.symbol;
+    }
+
+    // For a relocation against a local symbol, the defining object.
+    Sized_relobj<32, big_endian>*
+    relobj() const
+    {
+      gold_assert(!this->symbol_is_global_);
+      return this->u_.local.relobj;
+    }
+
+    // For a relocation against a local symbol, the local symbol index.
+    unsigned int
+    index() const
+    {
+      gold_assert(!this->symbol_is_global_);
+      return this->u_.local.index;
+    }
+
+   private:
+    // GOT offset of the entry to which this relocation is applied.
+    unsigned int got_offset_;
+    // Type of relocation.
+    unsigned int r_type_;
+    // Whether this relocation is against a global symbol.
+    bool symbol_is_global_;
+    // A global or local symbol.
+    union
+    {
+      struct
+      {
+       // For a global symbol, the symbol itself.
+       Symbol* symbol;
+      } global;
+      struct
+      {
+       // For a local symbol, the object defining object.
+       Sized_relobj<32, big_endian>* relobj;
+       // For a local symbol, the symbol index.
+       unsigned int index;
+      } local;
+    } u_;
+  };
+
+  // Symbol table of the output object.
+  Symbol_table* symbol_table_;
+  // Layout of the output object.
+  Layout* layout_;
+  // Static relocs to be applied to the GOT.
+  std::vector<Static_reloc> static_relocs_;
+};
+
 // Utilities for manipulating integers of up to 32-bits
 
 namespace utils
@@ -2332,7 +2477,7 @@ class Target_arm : public Sized_target<32, big_endian>
   optimize_tls_reloc(bool is_final, int r_type);
 
   // Get the GOT section, creating it if necessary.
-  Output_data_got<32, big_endian>*
+  Arm_output_data_got<big_endian>*
   got_section(Symbol_table*, Layout*);
 
   // Get the GOT PLT section.
@@ -2506,7 +2651,7 @@ class Target_arm : public Sized_target<32, big_endian>
          Cortex_a8_relocs_info;
 
   // The GOT section.
-  Output_data_got<32, big_endian>* got_;
+  Arm_output_data_got<big_endian>* got_;
   // The PLT section.
   Output_data_plt_arm<big_endian>* plt_;
   // The GOT PLT section.
@@ -3791,14 +3936,14 @@ Arm_relocate_functions<big_endian>::thm_jump19(
 // Get the GOT section, creating it if necessary.
 
 template<bool big_endian>
-Output_data_got<32, big_endian>*
+Arm_output_data_got<big_endian>*
 Target_arm<big_endian>::got_section(Symbol_table* symtab, Layout* layout)
 {
   if (this->got_ == NULL)
     {
       gold_assert(symtab != NULL && layout != NULL);
 
-      this->got_ = new Output_data_got<32, big_endian>();
+      this->got_ = new Arm_output_data_got<big_endian>(symtab, layout);
 
       Output_section* os;
       os = layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
@@ -5382,6 +5527,7 @@ Arm_output_section<big_endian>::append_text_sections_to_list(
 template<bool big_endian>
 void
 Arm_output_section<big_endian>::fix_exidx_coverage(
+    Layout* layout,
     const Text_section_list& sorted_text_sections,
     Symbol_table* symtab)
 {
@@ -5445,9 +5591,18 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
       if (known_input_sections.find(sid) == known_input_sections.end())
        {
          // This is odd.  We have not seen this EXIDX input section before.
-         // We cannot do fix-up.
-         gold_error(_("EXIDX section %u of %s is not in EXIDX output section"),
-                    exidx_shndx, exidx_relobj->name().c_str());
+         // We cannot do fix-up.  If we saw a SECTIONS clause in a script,
+         // issue a warning instead.  We assume the user knows what he
+         // or she is doing.  Otherwise, this is an error.
+         if (layout->script_options()->saw_sections_clause())
+           gold_warning(_("unwinding may not work because EXIDX input section"
+                          " %u of %s is not in EXIDX output section"),
+                        exidx_shndx, exidx_relobj->name().c_str());
+         else
+           gold_error(_("unwinding may not work because EXIDX input section"
+                        " %u of %s is not in EXIDX output section"),
+                      exidx_shndx, exidx_relobj->name().c_str());
+
          exidx_fixup.add_exidx_cantunwind_as_needed();
          continue;
        }
@@ -6273,6 +6428,11 @@ Arm_relobj<big_endian>::do_gc_process_relocs(Symbol_table* symtab,
   // First, call base class method to process relocations in this object.
   Sized_relobj<32, big_endian>::do_gc_process_relocs(symtab, layout, rd);
 
+  // If --gc-sections is not specified, there is nothing more to do.
+  // This happens when --icf is used but --gc-sections is not.
+  if (!parameters->options().gc_sections())
+    return;
+  
   unsigned int shnum = this->shnum();
   const unsigned int shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
   const unsigned char* pshdrs = this->get_view(this->elf_file()->shoff(),
@@ -6479,6 +6639,162 @@ Stub_addend_reader<elfcpp::SHT_REL, big_endian>::operator()(
     }
 }
 
+// Arm_output_data_got methods.
+
+// Add a GOT pair for R_ARM_TLS_GD32.  The creates a pair of GOT entries.
+// The first one is initialized to be 1, which is the module index for
+// the main executable and the second one 0.  A reloc of the type
+// R_ARM_TLS_DTPOFF32 will be created for the second GOT entry and will
+// be applied by gold.  GSYM is a global symbol.
+//
+template<bool big_endian>
+void
+Arm_output_data_got<big_endian>::add_tls_gd32_with_static_reloc(
+    unsigned int got_type,
+    Symbol* gsym)
+{
+  if (gsym->has_got_offset(got_type))
+    return;
+
+  // We are doing a static link.  Just mark it as belong to module 1,
+  // the executable.
+  unsigned int got_offset = this->add_constant(1);
+  gsym->set_got_offset(got_type, got_offset); 
+  got_offset = this->add_constant(0);
+  this->static_relocs_.push_back(Static_reloc(got_offset,
+                                             elfcpp::R_ARM_TLS_DTPOFF32,
+                                             gsym));
+}
+
+// Same as the above but for a local symbol.
+
+template<bool big_endian>
+void
+Arm_output_data_got<big_endian>::add_tls_gd32_with_static_reloc(
+  unsigned int got_type,
+  Sized_relobj<32, big_endian>* object,
+  unsigned int index)
+{
+  if (object->local_has_got_offset(index, got_type))
+    return;
+
+  // We are doing a static link.  Just mark it as belong to module 1,
+  // the executable.
+  unsigned int got_offset = this->add_constant(1);
+  object->set_local_got_offset(index, got_type, got_offset);
+  got_offset = this->add_constant(0);
+  this->static_relocs_.push_back(Static_reloc(got_offset, 
+                                             elfcpp::R_ARM_TLS_DTPOFF32, 
+                                             object, index));
+}
+
+template<bool big_endian>
+void
+Arm_output_data_got<big_endian>::do_write(Output_file* of)
+{
+  // Call parent to write out GOT.
+  Output_data_got<32, big_endian>::do_write(of);
+
+  // We are done if there is no fix up.
+  if (this->static_relocs_.empty())
+    return;
+
+  gold_assert(parameters->doing_static_link());
+
+  const off_t offset = this->offset();
+  const section_size_type oview_size =
+    convert_to_section_size_type(this->data_size());
+  unsigned char* const oview = of->get_output_view(offset, oview_size);
+
+  Output_segment* tls_segment = this->layout_->tls_segment();
+  gold_assert(tls_segment != NULL);
+  
+  // The thread pointer $tp points to the TCB, which is followed by the
+  // TLS.  So we need to adjust $tp relative addressing by this amount.
+  Arm_address aligned_tcb_size =
+    align_address(ARM_TCB_SIZE, tls_segment->maximum_alignment());
+
+  for (size_t i = 0; i < this->static_relocs_.size(); ++i)
+    {
+      Static_reloc& reloc(this->static_relocs_[i]);
+      
+      Arm_address value;
+      if (!reloc.symbol_is_global())
+       {
+         Sized_relobj<32, big_endian>* object = reloc.relobj();
+         const Symbol_value<32>* psymval =
+           reloc.relobj()->local_symbol(reloc.index());
+
+         // We are doing static linking.  Issue an error and skip this
+         // relocation if the symbol is undefined or in a discarded_section.
+         bool is_ordinary;
+         unsigned int shndx = psymval->input_shndx(&is_ordinary);
+         if ((shndx == elfcpp::SHN_UNDEF)
+             || (is_ordinary
+                 && shndx != elfcpp::SHN_UNDEF
+                 && !object->is_section_included(shndx)
+                 && !this->symbol_table_->is_section_folded(object, shndx)))
+           {
+             gold_error(_("undefined or discarded local symbol %u from "
+                          " object %s in GOT"),
+                        reloc.index(), reloc.relobj()->name().c_str());
+             continue;
+           }
+         
+         value = psymval->value(object, 0);
+       }
+      else
+       {
+         const Symbol* gsym = reloc.symbol();
+         gold_assert(gsym != NULL);
+         if (gsym->is_forwarder())
+           gsym = this->symbol_table_->resolve_forwards(gsym);
+
+         // We are doing static linking.  Issue an error and skip this
+         // relocation if the symbol is undefined or in a discarded_section
+         // unless it is a weakly_undefined symbol.
+         if ((gsym->is_defined_in_discarded_section()
+              || gsym->is_undefined())
+             && !gsym->is_weak_undefined())
+           {
+             gold_error(_("undefined or discarded symbol %s in GOT"),
+                        gsym->name());
+             continue;
+           }
+
+         if (!gsym->is_weak_undefined())
+           {
+             const Sized_symbol<32>* sym =
+               static_cast<const Sized_symbol<32>*>(gsym);
+             value = sym->value();
+           }
+         else
+             value = 0;
+       }
+
+      unsigned got_offset = reloc.got_offset();
+      gold_assert(got_offset < oview_size);
+
+      typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+      Valtype* wv = reinterpret_cast<Valtype*>(oview + got_offset);
+      Valtype x;
+      switch (reloc.r_type())
+       {
+       case elfcpp::R_ARM_TLS_DTPOFF32:
+         x = value;
+         break;
+       case elfcpp::R_ARM_TLS_TPOFF32:
+         x = value + aligned_tcb_size;
+         break;
+       default:
+         gold_unreachable();
+       }
+      elfcpp::Swap<32, big_endian>::writeval(wv, x);
+    }
+
+  of->write_output_view(offset, oview_size, oview);
+}
+
 // A class to handle the PLT data.
 
 template<bool big_endian>
@@ -6764,11 +7080,22 @@ Target_arm<big_endian>::got_mod_index_entry(
   if (this->got_mod_index_offset_ == -1U)
     {
       gold_assert(symtab != NULL && layout != NULL && object != NULL);
-      Reloc_section* rel_dyn = this->rel_dyn_section(layout);
-      Output_data_got<32, big_endian>* got = this->got_section(symtab, layout);
-      unsigned int got_offset = got->add_constant(0);
-      rel_dyn->add_local(object, 0, elfcpp::R_ARM_TLS_DTPMOD32, got,
-                         got_offset);
+      Arm_output_data_got<big_endian>* got = this->got_section(symtab, layout);
+      unsigned int got_offset;
+      if (!parameters->doing_static_link())
+       {
+         got_offset = got->add_constant(0);
+         Reloc_section* rel_dyn = this->rel_dyn_section(layout);
+         rel_dyn->add_local(object, 0, elfcpp::R_ARM_TLS_DTPMOD32, got,
+                            got_offset);
+       }
+      else
+       {
+         // We are doing a static link.  Just mark it as belong to module 1,
+         // the executable.
+         got_offset = got->add_constant(1);
+       }
+
       got->add_constant(0);
       this->got_mod_index_offset_ = got_offset;
     }
@@ -7010,7 +7337,7 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
     case elfcpp::R_ARM_GOT_PREL:
       {
        // The symbol requires a GOT entry.
-       Output_data_got<32, big_endian>* got =
+       Arm_output_data_got<big_endian>* got =
          target->got_section(symtab, layout);
        unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
        if (got->add_local(object, r_sym, GOT_TYPE_STANDARD))
@@ -7063,20 +7390,27 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
              {
                // Create a pair of GOT entries for the module index and
                // dtv-relative offset.
-                Output_data_got<32, big_endian>* got
+                Arm_output_data_got<big_endian>* got
                     = target->got_section(symtab, layout);
                 unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
                unsigned int shndx = lsym.get_st_shndx();
                bool is_ordinary;
                shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
                if (!is_ordinary)
-                 object->error(_("local symbol %u has bad shndx %u"),
-                             r_sym, shndx);
-                else
+                 {
+                   object->error(_("local symbol %u has bad shndx %u"),
+                                 r_sym, shndx);
+                   break;
+                 }
+
+               if (!parameters->doing_static_link())
                  got->add_local_pair_with_rel(object, r_sym, shndx,
                                               GOT_TYPE_TLS_PAIR,
                                               target->rel_dyn_section(layout),
                                               elfcpp::R_ARM_TLS_DTPMOD32, 0);
+               else
+                 got->add_tls_gd32_with_static_reloc(GOT_TYPE_TLS_PAIR,
+                                                     object, r_sym);
              }
            else
              // FIXME: TLS optimization not supported yet.
@@ -7101,13 +7435,25 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
            layout->set_has_static_tls();
            if (optimized_type == tls::TLSOPT_NONE)
              {
-               // Create a GOT entry for the tp-relative offset.
-                Output_data_got<32, big_endian>* got
-                    = target->got_section(symtab, layout);
-                unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
-               got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
-                                       target->rel_dyn_section(layout),
-                                       elfcpp::R_ARM_TLS_TPOFF32);
+               // Create a GOT entry for the tp-relative offset.
+               Arm_output_data_got<big_endian>* got
+                 = target->got_section(symtab, layout);
+               unsigned int r_sym =
+                  elfcpp::elf_r_sym<32>(reloc.get_r_info());
+               if (!parameters->doing_static_link())
+                   got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
+                                           target->rel_dyn_section(layout),
+                                           elfcpp::R_ARM_TLS_TPOFF32);
+               else if (!object->local_has_got_offset(r_sym,
+                                                      GOT_TYPE_TLS_OFFSET))
+                 {
+                   got->add_local(object, r_sym, GOT_TYPE_TLS_OFFSET);
+                   unsigned int got_offset =
+                     object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET);
+                   got->add_static_reloc(got_offset,
+                                         elfcpp::R_ARM_TLS_TPOFF32, object,
+                                         r_sym);
+                 }
              }
            else
              // FIXME: TLS optimization not supported yet.
@@ -7351,7 +7697,7 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
     case elfcpp::R_ARM_GOT_PREL:
       {
        // The symbol requires a GOT entry.
-       Output_data_got<32, big_endian>* got =
+       Arm_output_data_got<big_endian>* got =
          target->got_section(symtab, layout);
        if (gsym->final_value_is_known())
          got->add_global(gsym, GOT_TYPE_STANDARD);
@@ -7408,12 +7754,15 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
              {
                // Create a pair of GOT entries for the module index and
                // dtv-relative offset.
-                Output_data_got<32, big_endian>* got
+                Arm_output_data_got<big_endian>* got
                     = target->got_section(symtab, layout);
-                got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
-                                             target->rel_dyn_section(layout),
-                                             elfcpp::R_ARM_TLS_DTPMOD32,
-                                             elfcpp::R_ARM_TLS_DTPOFF32);
+               if (!parameters->doing_static_link())
+                 got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+                                               target->rel_dyn_section(layout),
+                                               elfcpp::R_ARM_TLS_DTPMOD32,
+                                               elfcpp::R_ARM_TLS_DTPOFF32);
+               else
+                 got->add_tls_gd32_with_static_reloc(GOT_TYPE_TLS_PAIR, gsym);
              }
            else
              // FIXME: TLS optimization not supported yet.
@@ -7438,12 +7787,21 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
            layout->set_has_static_tls();
            if (optimized_type == tls::TLSOPT_NONE)
              {
-               // Create a GOT entry for the tp-relative offset.
-                Output_data_got<32, big_endian>* got
-                    = target->got_section(symtab, layout);
-                got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
-                                         target->rel_dyn_section(layout),
-                                         elfcpp::R_ARM_TLS_TPOFF32);
+               // Create a GOT entry for the tp-relative offset.
+               Arm_output_data_got<big_endian>* got
+                 = target->got_section(symtab, layout);
+               if (!parameters->doing_static_link())
+                 got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+                                          target->rel_dyn_section(layout),
+                                          elfcpp::R_ARM_TLS_TPOFF32);
+               else if (!gsym->has_got_offset(GOT_TYPE_TLS_OFFSET))
+                 {
+                   got->add_global(gsym, GOT_TYPE_TLS_OFFSET);
+                   unsigned int got_offset =
+                      gsym->got_offset(GOT_TYPE_TLS_OFFSET);
+                   got->add_static_reloc(got_offset,
+                                         elfcpp::R_ARM_TLS_TPOFF32, gsym);
+                 }
              }
            else
              // FIXME: TLS optimization not supported yet.
@@ -8233,10 +8591,11 @@ Target_arm<big_endian>::Relocate::relocate_tls(
     const Sized_symbol<32>* gsym,
     const Symbol_value<32>* psymval,
     unsigned char* view,
-    elfcpp::Elf_types<32>::Elf_Addr,
+    elfcpp::Elf_types<32>::Elf_Addr address,
     section_size_type /*view_size*/ )
 {
   typedef Arm_relocate_functions<big_endian> ArmRelocFuncs;
+  typedef Relocate_functions<32, big_endian> RelocFuncs;
   Output_segment* tls_segment = relinfo->layout->tls_segment();
 
   const Sized_relobj<32, big_endian>* object = relinfo->object;
@@ -8268,9 +8627,12 @@ Target_arm<big_endian>::Relocate::relocate_tls(
             }
           if (optimized_type == tls::TLSOPT_NONE)
             {
-              // Relocate the field with the offset of the pair of GOT
-              // entries.
-              Relocate_functions<32, big_endian>::rel32(view, got_offset);
+             Arm_address got_entry =
+               target->got_plt_section()->address() + got_offset;
+             
+              // Relocate the field with the PC relative offset of the pair of
+              // GOT entries.
+             RelocFuncs::pcrel32(view, got_entry, address);
               return ArmRelocFuncs::STATUS_OKAY;
             }
         }
@@ -8284,13 +8646,18 @@ Target_arm<big_endian>::Relocate::relocate_tls(
           unsigned int got_offset;
           got_offset = (target->got_mod_index_entry(NULL, NULL, NULL)
                        - target->got_size());
-          Relocate_functions<32, big_endian>::rel32(view, got_offset);
+         Arm_address got_entry =
+           target->got_plt_section()->address() + got_offset;
+
+          // Relocate the field with the PC relative offset of the pair of
+          // GOT entries.
+          RelocFuncs::pcrel32(view, got_entry, address);
          return ArmRelocFuncs::STATUS_OKAY;
         }
       break;
 
     case elfcpp::R_ARM_TLS_LDO32:      // Alternate local-dynamic
-      Relocate_functions<32, big_endian>::rel32(view, value);
+      RelocFuncs::rel32(view, value);
       return ArmRelocFuncs::STATUS_OKAY;
 
     case elfcpp::R_ARM_TLS_IE32:       // Initial-exec
@@ -8311,9 +8678,15 @@ Target_arm<big_endian>::Relocate::relocate_tls(
               gold_assert(object->local_has_got_offset(r_sym, got_type));
               got_offset = object->local_got_offset(r_sym, got_type);
             }
+
           // All GOT offsets are relative to the end of the GOT.
           got_offset -= target->got_size();
-          Relocate_functions<32, big_endian>::rel32(view, got_offset);
+
+         Arm_address got_entry =
+           target->got_plt_section()->address() + got_offset;
+
+          // Relocate the field with the PC relative offset of the GOT entry.
+         RelocFuncs::pcrel32(view, got_entry, address);
          return ArmRelocFuncs::STATUS_OKAY;
         }
       break;
@@ -8324,8 +8697,13 @@ Target_arm<big_endian>::Relocate::relocate_tls(
       if (!parameters->options().shared())
         {
           gold_assert(tls_segment != NULL);
-          value = tls_segment->memsz() - value;
-          Relocate_functions<32, false>::rel32(view, value);
+
+         // $tp points to the TCB, which is followed by the TLS, so we
+         // need to add TCB size to the offset.
+         Arm_address aligned_tcb_size =
+           align_address(ARM_TCB_SIZE, tls_segment->maximum_alignment());
+          RelocFuncs::rel32(view, value + aligned_tcb_size);
+
         }
       return ArmRelocFuncs::STATUS_OKAY;
     
@@ -10413,7 +10791,7 @@ Target_arm<big_endian>::fix_exidx_coverage(
       arm_output_section->append_text_sections_to_list(&sorted_text_sections);
     } 
 
-  exidx_section->fix_exidx_coverage(sorted_text_sections, symtab);
+  exidx_section->fix_exidx_coverage(layout, sorted_text_sections, symtab);
 }
 
 Target_selector_arm<false> target_selector_arm;
index faa0c7252bcd5de50f42a1b20f5329578ffa36ac..c721ba6e5d2bf6e7ffd490a26714268355ebd60c 100644 (file)
@@ -3569,9 +3569,9 @@ const Layout::Section_name_mapping Layout::section_name_mapping[] =
   MAPPING_INIT(".gnu.linkonce.lr.", ".lrodata"),
   MAPPING_INIT(".gnu.linkonce.l.", ".ldata"),
   MAPPING_INIT(".gnu.linkonce.lb.", ".lbss"),
-  MAPPING_INIT(".ARM.extab.", ".ARM.extab"),
+  MAPPING_INIT(".ARM.extab", ".ARM.extab"),
   MAPPING_INIT(".gnu.linkonce.armextab.", ".ARM.extab"),
-  MAPPING_INIT(".ARM.exidx.", ".ARM.exidx"),
+  MAPPING_INIT(".ARM.exidx", ".ARM.exidx"),
   MAPPING_INIT(".gnu.linkonce.armexidx.", ".ARM.exidx"),
 };
 #undef MAPPING_INIT