2010-09-08 Doug Kwan <dougkwan@google.com>
authorDoug Kwan <dougkwan@google.com>
Wed, 8 Sep 2010 23:54:51 +0000 (23:54 +0000)
committerDoug Kwan <dougkwan@google.com>
Wed, 8 Sep 2010 23:54:51 +0000 (23:54 +0000)
* arm.cc (Arm_exidx_cantunwind::do_print_to_mapfile): New method.
(Arm_relobj::do_relocate_sections): Add new parameter for output
file to match the parent.
(Target_arm::scan_reloc_section_for_stubs): Use would-be final values
of local symbols instead of input values.  Update code to track
changes in gold::relocate_section.
* object.cc (Sized_relobj::compute_final_local_value): New methods.
(Sized_relobj::compute_final_local_value_internal): New methods.
(Sized_relobj::do_finalize_local_symbols): Move code from loop
body into private version of Sized_relobj::compute_final_local_value.
Call the inline method.
* object.h (Symbol_value::Symbol_value): Define destructor.  Free
merged symbol value if there is one.
(Symbol_value::has_output_value): New method defintiion.
(Sized_relobj::Compute_final_local_value_status): New enum type.
(Sized_relobj::compute_final_local_value): New methods.
(Sized_relobj::compute_final_local_value_internal): New methods.
* Makefile.am (check_SCRIPTS): Add arm_branch_out_of_range.sh
and arm_cortex_a8.sh.
(thumb_bl_out_of_range_local, arm_cortex_a8_b_cond, arm_cortex_a8_bl,
arm_cortex_a8_blx, arm_cortex_a8_local, arm_corte_a8_local_reloc):
New tests.
* Makefile.in: Regenerate.
* testsuite/arm_bl_out_of_range.s: Update test.
* testsuite/thumb_bl_out_of_range.s: Ditto.
* testsuite/thumb_blx_out_of_range.s: Ditto.
* testsuite/arm_branch_out_of_range.sh: New file.
* testsuite/arm_cortex_a8.sh: Ditto.
* testsuite/arm_cortex_a8_b.s: Ditto.
* testsuite/arm_cortex_a8_b_cond.s: Ditto.
* testsuite/arm_cortex_a8_b_local.s: Ditto.
* testsuite/arm_cortex_a8_bl.s: Ditto.
* testsuite/arm_cortex_a8_blx.s: Ditto.
* testsuite/arm_cortex_a8_local.s: Ditto.
* testsuite/arm_cortex_a8_local_reloc.s: Ditto.
* testsuite/thumb_bl_out_of_range_local.s: Ditto.

19 files changed:
gold/ChangeLog
gold/arm.cc
gold/object.cc
gold/object.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/arm_bl_out_of_range.s
gold/testsuite/arm_branch_out_of_range.sh [new file with mode: 0755]
gold/testsuite/arm_cortex_a8.sh [new file with mode: 0755]
gold/testsuite/arm_cortex_a8_b.s [new file with mode: 0644]
gold/testsuite/arm_cortex_a8_b_cond.s [new file with mode: 0644]
gold/testsuite/arm_cortex_a8_b_local.s [new file with mode: 0644]
gold/testsuite/arm_cortex_a8_bl.s [new file with mode: 0644]
gold/testsuite/arm_cortex_a8_blx.s [new file with mode: 0644]
gold/testsuite/arm_cortex_a8_local.s [new file with mode: 0644]
gold/testsuite/arm_cortex_a8_local_reloc.s [new file with mode: 0644]
gold/testsuite/thumb_bl_out_of_range.s
gold/testsuite/thumb_bl_out_of_range_local.s [new file with mode: 0644]
gold/testsuite/thumb_blx_out_of_range.s

index 503a653b90bd29b136c98a4f70065e43062fd480..a8a11075e929602d17b70057af450d2b2822ff08 100644 (file)
@@ -1,3 +1,42 @@
+2010-09-08  Doug Kwan  <dougkwan@google.com>
+
+       * arm.cc (Arm_exidx_cantunwind::do_print_to_mapfile): New method.
+       (Arm_relobj::do_relocate_sections): Add new parameter for output
+       file to match the parent.
+       (Target_arm::scan_reloc_section_for_stubs): Use would-be final values
+       of local symbols instead of input values.  Update code to track
+       changes in gold::relocate_section.
+       * object.cc (Sized_relobj::compute_final_local_value): New methods.
+       (Sized_relobj::compute_final_local_value_internal): New methods.
+       (Sized_relobj::do_finalize_local_symbols): Move code from loop
+       body into private version of Sized_relobj::compute_final_local_value.
+       Call the inline method.
+       * object.h (Symbol_value::Symbol_value): Define destructor.  Free
+       merged symbol value if there is one.
+       (Symbol_value::has_output_value): New method defintiion.
+       (Sized_relobj::Compute_final_local_value_status): New enum type.
+       (Sized_relobj::compute_final_local_value): New methods.
+       (Sized_relobj::compute_final_local_value_internal): New methods.
+       * Makefile.am (check_SCRIPTS): Add arm_branch_out_of_range.sh
+       and arm_cortex_a8.sh.
+       (thumb_bl_out_of_range_local, arm_cortex_a8_b_cond, arm_cortex_a8_bl,
+       arm_cortex_a8_blx, arm_cortex_a8_local, arm_corte_a8_local_reloc):
+       New tests.
+       * Makefile.in: Regenerate.
+       * testsuite/arm_bl_out_of_range.s: Update test.
+       * testsuite/thumb_bl_out_of_range.s: Ditto.
+       * testsuite/thumb_blx_out_of_range.s: Ditto.
+       * testsuite/arm_branch_out_of_range.sh: New file.
+       * testsuite/arm_cortex_a8.sh: Ditto.
+       * testsuite/arm_cortex_a8_b.s: Ditto.
+       * testsuite/arm_cortex_a8_b_cond.s: Ditto.
+       * testsuite/arm_cortex_a8_b_local.s: Ditto.
+       * testsuite/arm_cortex_a8_bl.s: Ditto.
+       * testsuite/arm_cortex_a8_blx.s: Ditto.
+       * testsuite/arm_cortex_a8_local.s: Ditto.
+       * testsuite/arm_cortex_a8_local_reloc.s: Ditto.
+       * testsuite/thumb_bl_out_of_range_local.s: Ditto.
+
 2010-09-08  Rafael Espindola  <espindola@google.com>
 
        * script-sections.cc (Script_sections::add_memory_region): Convert
index 85f95429a4b7f1bfa22abcab7af284f145722706..79a96633d4868bd589caa4b4841942738eff4bdf 100644 (file)
@@ -1064,6 +1064,11 @@ class Arm_exidx_cantunwind : public Output_section_data
       this->do_fixed_endian_write<false>(of);
   }
 
+  // Write to a map file.
+  void
+  do_print_to_mapfile(Mapfile* mapfile) const
+  { mapfile->print_output_data(this, _("** ARM cantunwind")); }
+
  private:
   // Implement do_write for a given endianness.
   template<bool big_endian>
@@ -1636,7 +1641,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
 
   void
   do_relocate_sections(const Symbol_table* symtab, const Layout* layout,
-                      const unsigned char* pshdrs,
+                      const unsigned char* pshdrs, Output_file* of,
                       typename Sized_relobj<32, big_endian>::Views* pivews);
 
   // Read the symbol information.
@@ -6351,11 +6356,12 @@ Arm_relobj<big_endian>::do_relocate_sections(
     const Symbol_table* symtab,
     const Layout* layout,
     const unsigned char* pshdrs,
+    Output_file* of,
     typename Sized_relobj<32, big_endian>::Views* pviews)
 {
   // Call parent to relocate sections.
   Sized_relobj<32, big_endian>::do_relocate_sections(symtab, layout, pshdrs,
-                                                    pviews); 
+                                                    of, pviews); 
 
   // We do not generate stubs if doing a relocatable link.
   if (parameters->options().relocatable())
@@ -10944,6 +10950,8 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs(
 
       Symbol_value<32> symval;
       const Symbol_value<32> *psymval;
+      bool is_defined_in_discarded_section;
+      unsigned int shndx;
       if (r_sym < local_count)
        {
          sym = NULL;
@@ -10955,45 +10963,53 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs(
           // counterpart in the kept section.  The symbol must not 
           // correspond to a section we are folding.
          bool is_ordinary;
-         unsigned int shndx = psymval->input_shndx(&is_ordinary);
-         if (is_ordinary
-             && shndx != elfcpp::SHN_UNDEF
-             && !arm_object->is_section_included(shndx) 
-              && !(relinfo->symtab->is_section_folded(arm_object, shndx)))
+         shndx = psymval->input_shndx(&is_ordinary);
+         is_defined_in_discarded_section =
+           (is_ordinary
+            && shndx != elfcpp::SHN_UNDEF
+            && !arm_object->is_section_included(shndx)
+            && !relinfo->symtab->is_section_folded(arm_object, shndx));
+
+         // We need to compute the would-be final value of this local
+         // symbol.
+         if (!is_defined_in_discarded_section)
            {
-             if (comdat_behavior == CB_UNDETERMINED)
-               {
-                 std::string name =
-                   arm_object->section_name(relinfo->data_shndx);
-                 comdat_behavior = get_comdat_behavior(name.c_str());
-               }
-             if (comdat_behavior == CB_PRETEND)
-               {
-                  bool found;
-                 typename elfcpp::Elf_types<32>::Elf_Addr value =
-                   arm_object->map_to_kept_section(shndx, &found);
-                 if (found)
-                   symval.set_output_value(value + psymval->input_value());
-                  else
-                    symval.set_output_value(0);
-               }
+             typedef Sized_relobj<32, big_endian> ObjType;
+             typename ObjType::Compute_final_local_value_status status =
+               arm_object->compute_final_local_value(r_sym, psymval, &symval,
+                                                     relinfo->symtab); 
+             if (status == ObjType::CFLV_OK)
+               {
+                 // Currently we cannot handle a branch to a target in
+                 // a merged section.  If this is the case, issue an error
+                 // and also free the merge symbol value.
+                 if (!symval.has_output_value())
+                   {
+                     const std::string& section_name =
+                       arm_object->section_name(shndx);
+                     arm_object->error(_("cannot handle branch to local %u "
+                                         "in a merged section %s"),
+                                       r_sym, section_name.c_str());
+                   }
+                 psymval = &symval;
+               }
              else
-               {
-                  symval.set_output_value(0);
-               }
-             symval.set_no_output_symtab_entry();
-             psymval = &symval;
+               {
+                 // We cannot determine the final value.
+                 continue;  
+               }
            }
        }
       else
        {
-         const Symbol* gsym = arm_object->global_symbol(r_sym);
+         const Symbol* gsym;
+         gsym = arm_object->global_symbol(r_sym);
          gold_assert(gsym != NULL);
          if (gsym->is_forwarder())
            gsym = relinfo->symtab->resolve_forwards(gsym);
 
          sym = static_cast<const Sized_symbol<32>*>(gsym);
-         if (sym->has_symtab_index())
+         if (sym->has_symtab_index() && sym->symtab_index() != -1U)
            symval.set_output_symtab_index(sym->symtab_index());
          else
            symval.set_no_output_symtab_entry();
@@ -11010,9 +11026,53 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs(
          // Skip this if the symbol has not output section.
          if (status == Symbol_table::CFVS_NO_OUTPUT_SECTION)
            continue;
-
          symval.set_output_value(value);
+
+         if (gsym->type() == elfcpp::STT_TLS)
+           symval.set_is_tls_symbol();
+         else if (gsym->type() == elfcpp::STT_GNU_IFUNC)
+           symval.set_is_ifunc_symbol();
          psymval = &symval;
+
+         is_defined_in_discarded_section =
+           (gsym->is_defined_in_discarded_section()
+            && gsym->is_undefined());
+         shndx = 0;
+       }
+
+      Symbol_value<32> symval2;
+      if (is_defined_in_discarded_section)
+       {
+         if (comdat_behavior == CB_UNDETERMINED)
+           {
+             std::string name = arm_object->section_name(relinfo->data_shndx);
+             comdat_behavior = get_comdat_behavior(name.c_str());
+           }
+         if (comdat_behavior == CB_PRETEND)
+           {
+             // FIXME: This case does not work for global symbols.
+             // We have no place to store the original section index.
+             // Fortunately this does not matter for comdat sections,
+             // only for sections explicitly discarded by a linker
+             // script.
+             bool found;
+             typename elfcpp::Elf_types<32>::Elf_Addr value =
+               arm_object->map_to_kept_section(shndx, &found);
+             if (found)
+               symval2.set_output_value(value + psymval->input_value());
+             else
+               symval2.set_output_value(0);
+           }
+         else
+           {
+             if (comdat_behavior == CB_WARNING)
+               gold_warning_at_location(relinfo, i, offset,
+                                        _("relocation refers to discarded "
+                                          "section"));
+             symval2.set_output_value(0);
+           }
+         symval2.set_no_output_symtab_entry();
+         psymval = &symval2;
        }
 
       // If symbol is a section symbol, we don't know the actual type of
index bdeb1414bd6fe2db05ad0f9a7da33de83e5fbf13..7bd35f3a5877ff925ff2455530fbdc5adec9cd08 100644 (file)
@@ -1878,6 +1878,178 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
   this->output_local_dynsym_count_ = dyncount;
 }
 
+// Compute the final value of a local symbol.
+
+template<int size, bool big_endian>
+typename Sized_relobj<size, big_endian>::Compute_final_local_value_status
+Sized_relobj<size, big_endian>::compute_final_local_value_internal(
+    unsigned int r_sym,
+    const Symbol_value<size>* lv_in,
+    Symbol_value<size>* lv_out,
+    bool relocatable,
+    const Output_sections& out_sections,
+    const std::vector<Address>& out_offsets,
+    const Symbol_table* symtab)
+{
+  // We are going to overwrite *LV_OUT, if it has a merged symbol value,
+  // we may have a memory leak.
+  gold_assert(lv_out->has_output_value());
+
+  bool is_ordinary;
+  unsigned int shndx = lv_in->input_shndx(&is_ordinary);
+  
+  // Set the output symbol value.
+  
+  if (!is_ordinary)
+    {
+      if (shndx == elfcpp::SHN_ABS || Symbol::is_common_shndx(shndx))
+       lv_out->set_output_value(lv_in->input_value());
+      else
+       {
+         this->error(_("unknown section index %u for local symbol %u"),
+                     shndx, r_sym);
+         lv_out->set_output_value(0);
+         return This::CFLV_ERROR;
+       }
+    }
+  else
+    {
+      if (shndx >= this->shnum())
+       {
+         this->error(_("local symbol %u section index %u out of range"),
+                     r_sym, shndx);
+         lv_out->set_output_value(0);
+         return This::CFLV_ERROR;
+       }
+      
+      Output_section* os = out_sections[shndx];
+      Address secoffset = out_offsets[shndx];
+      if (symtab->is_section_folded(this, shndx))
+       {
+         gold_assert(os == NULL && secoffset == invalid_address);
+         // Get the os of the section it is folded onto.
+         Section_id folded = symtab->icf()->get_folded_section(this,
+                                                               shndx);
+         gold_assert(folded.first != NULL);
+         Sized_relobj<size, big_endian>* folded_obj = reinterpret_cast
+           <Sized_relobj<size, big_endian>*>(folded.first);
+         os = folded_obj->output_section(folded.second);
+         gold_assert(os != NULL);
+         secoffset = folded_obj->get_output_section_offset(folded.second);
+         
+         // This could be a relaxed input section.
+         if (secoffset == invalid_address)
+           {
+             const Output_relaxed_input_section* relaxed_section =
+               os->find_relaxed_input_section(folded_obj, folded.second);
+             gold_assert(relaxed_section != NULL);
+             secoffset = relaxed_section->address() - os->address();
+           }
+       }
+      
+      if (os == NULL)
+       {
+         // This local symbol belongs to a section we are discarding.
+         // In some cases when applying relocations later, we will
+         // attempt to match it to the corresponding kept section,
+         // so we leave the input value unchanged here.
+         return This::CFLV_DISCARDED;
+       }
+      else if (secoffset == invalid_address)
+       {
+         uint64_t start;
+         
+         // This is a SHF_MERGE section or one which otherwise
+         // requires special handling.
+         if (shndx == this->discarded_eh_frame_shndx_)
+           {
+             // This local symbol belongs to a discarded .eh_frame
+             // section.  Just treat it like the case in which
+             // os == NULL above.
+             gold_assert(this->has_eh_frame_);
+             return This::CFLV_DISCARDED;
+           }
+         else if (!lv_in->is_section_symbol())
+           {
+             // This is not a section symbol.  We can determine
+             // the final value now.
+             lv_out->set_output_value(
+                 os->output_address(this, shndx, lv_in->input_value()));
+           }
+         else if (!os->find_starting_output_address(this, shndx, &start))
+           {
+             // This is a section symbol, but apparently not one in a
+             // merged section.  First check to see if this is a relaxed
+             // input section.  If so, use its address.  Otherwise just
+             // use the start of the output section.  This happens with
+             // relocatable links when the input object has section
+             // symbols for arbitrary non-merge sections.
+             const Output_section_data* posd =
+               os->find_relaxed_input_section(this, shndx);
+             if (posd != NULL)
+               {
+                 Address relocatable_link_adjustment =
+                   relocatable ? os->address() : 0;
+                 lv_out->set_output_value(posd->address()
+                                          - relocatable_link_adjustment);
+               }
+             else
+               lv_out->set_output_value(os->address());
+           }
+         else
+           {
+             // We have to consider the addend to determine the
+             // value to use in a relocation.  START is the start
+             // of this input section.  If we are doing a relocatable
+             // link, use offset from start output section instead of
+             // address.
+             Address adjusted_start =
+               relocatable ? start - os->address() : start;
+             Merged_symbol_value<size>* msv =
+               new Merged_symbol_value<size>(lv_in->input_value(),
+                                             adjusted_start);
+             lv_out->set_merged_symbol_value(msv);
+           }
+       }
+      else if (lv_in->is_tls_symbol())
+       lv_out->set_output_value(os->tls_offset()
+                                + secoffset
+                                + lv_in->input_value());
+      else
+       lv_out->set_output_value((relocatable ? 0 : os->address())
+                                + secoffset
+                                + lv_in->input_value());
+    }
+  return This::CFLV_OK;
+}
+
+// Compute final local symbol value.  R_SYM is the index of a local
+// symbol in symbol table.  LV points to a symbol value, which is
+// expected to hold the input value and to be over-written by the
+// final value.  SYMTAB points to a symbol table.  Some targets may want
+// to know would-be-finalized local symbol values in relaxation.
+// Hence we provide this method.  Since this method updates *LV, a
+// callee should make a copy of the original local symbol value and
+// use the copy instead of modifying an object's local symbols before
+// everything is finalized.  The caller should also free up any allocated
+// memory in the return value in *LV.
+template<int size, bool big_endian>
+typename Sized_relobj<size, big_endian>::Compute_final_local_value_status
+Sized_relobj<size, big_endian>::compute_final_local_value(
+    unsigned int r_sym,
+    const Symbol_value<size>* lv_in,
+    Symbol_value<size>* lv_out,
+    const Symbol_table* symtab)
+{
+  // This is just a wrapper of compute_final_local_value_internal.
+  const bool relocatable = parameters->options().relocatable();
+  const Output_sections& out_sections(this->output_sections());
+  const std::vector<Address>& out_offsets(this->section_offsets_);
+  return this->compute_final_local_value_internal(r_sym, lv_in, lv_out,
+                                                 relocatable, out_sections,
+                                                 out_offsets, symtab);
+}
+
 // Finalize the local symbols.  Here we set the final value in
 // THIS->LOCAL_VALUES_ and set their output symbol table indexes.
 // This function is always called from a singleton thread.  The actual
@@ -1897,141 +2069,31 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
   const bool relocatable = parameters->options().relocatable();
   const Output_sections& out_sections(this->output_sections());
   const std::vector<Address>& out_offsets(this->section_offsets_);
-  unsigned int shnum = this->shnum();
 
   for (unsigned int i = 1; i < loccount; ++i)
     {
-      Symbol_value<size>& lv(this->local_values_[i]);
-
-      bool is_ordinary;
-      unsigned int shndx = lv.input_shndx(&is_ordinary);
+      Symbol_value<size>* lv = &this->local_values_[i];
 
-      // Set the output symbol value.
-
-      if (!is_ordinary)
+      This::Compute_final_local_value_status cflv_status =
+       this->compute_final_local_value_internal(i, lv, lv, relocatable,
+                                                out_sections, out_offsets,
+                                                symtab);
+      switch (cflv_status)
        {
-         if (shndx == elfcpp::SHN_ABS || Symbol::is_common_shndx(shndx))
-           lv.set_output_value(lv.input_value());
-         else
+       case CFLV_OK:
+         if (!lv->is_output_symtab_index_set())
            {
-             this->error(_("unknown section index %u for local symbol %u"),
-                         shndx, i);
-             lv.set_output_value(0);
+             lv->set_output_symtab_index(index);
+             ++index;
            }
+         break;
+       case CFLV_DISCARDED:
+       case CFLV_ERROR:
+         // Do nothing.
+         break;
+       default:
+         gold_unreachable();
        }
-      else
-       {
-         if (shndx >= shnum)
-           {
-             this->error(_("local symbol %u section index %u out of range"),
-                         i, shndx);
-             shndx = 0;
-           }
-
-         Output_section* os = out_sections[shndx];
-          Address secoffset = out_offsets[shndx];
-          if (symtab->is_section_folded(this, shndx))
-            {
-              gold_assert(os == NULL && secoffset == invalid_address);
-              // Get the os of the section it is folded onto.
-              Section_id folded = symtab->icf()->get_folded_section(this,
-                                                                    shndx);
-              gold_assert(folded.first != NULL);
-              Sized_relobj<size, big_endian>* folded_obj = reinterpret_cast
-                <Sized_relobj<size, big_endian>*>(folded.first);
-              os = folded_obj->output_section(folded.second);
-              gold_assert(os != NULL);
-              secoffset = folded_obj->get_output_section_offset(folded.second);
-
-             // This could be a relaxed input section.
-              if (secoffset == invalid_address)
-               {
-                 const Output_relaxed_input_section* relaxed_section =
-                   os->find_relaxed_input_section(folded_obj, folded.second);
-                 gold_assert(relaxed_section != NULL);
-                 secoffset = relaxed_section->address() - os->address();
-               }
-            }
-
-         if (os == NULL)
-           {
-              // This local symbol belongs to a section we are discarding.
-              // In some cases when applying relocations later, we will
-              // attempt to match it to the corresponding kept section,
-              // so we leave the input value unchanged here.
-             continue;
-           }
-         else if (secoffset == invalid_address)
-           {
-             uint64_t start;
-
-             // This is a SHF_MERGE section or one which otherwise
-             // requires special handling.
-             if (shndx == this->discarded_eh_frame_shndx_)
-               {
-                 // This local symbol belongs to a discarded .eh_frame
-                 // section.  Just treat it like the case in which
-                 // os == NULL above.
-                 gold_assert(this->has_eh_frame_);
-                 continue;
-               }
-             else if (!lv.is_section_symbol())
-               {
-                 // This is not a section symbol.  We can determine
-                 // the final value now.
-                 lv.set_output_value(os->output_address(this, shndx,
-                                                        lv.input_value()));
-               }
-             else if (!os->find_starting_output_address(this, shndx, &start))
-               {
-                 // This is a section symbol, but apparently not one in a
-                 // merged section.  First check to see if this is a relaxed
-                 // input section.  If so, use its address.  Otherwise just
-                 // use the start of the output section.  This happens with
-                 // relocatable links when the input object has section
-                 // symbols for arbitrary non-merge sections.
-                 const Output_section_data* posd =
-                   os->find_relaxed_input_section(this, shndx);
-                 if (posd != NULL)
-                   {
-                     Address relocatable_link_adjustment =
-                       relocatable ? os->address() : 0;
-                     lv.set_output_value(posd->address()
-                                         - relocatable_link_adjustment);
-                   }
-                 else
-                   lv.set_output_value(os->address());
-               }
-             else
-               {
-                 // We have to consider the addend to determine the
-                 // value to use in a relocation.  START is the start
-                 // of this input section.  If we are doing a relocatable
-                 // link, use offset from start output section instead of
-                 // address.
-                 Address adjusted_start =
-                   relocatable ? start - os->address() : start;
-                 Merged_symbol_value<size>* msv =
-                   new Merged_symbol_value<size>(lv.input_value(),
-                                                 adjusted_start);
-                 lv.set_merged_symbol_value(msv);
-               }
-           }
-          else if (lv.is_tls_symbol())
-           lv.set_output_value(os->tls_offset()
-                               + secoffset
-                               + lv.input_value());
-         else
-           lv.set_output_value((relocatable ? 0 : os->address())
-                               + secoffset
-                               + lv.input_value());
-       }
-
-      if (!lv.is_output_symtab_index_set())
-        {
-          lv.set_output_symtab_index(index);
-          ++index;
-        }
     }
   return index;
 }
index 1f79e2723220f63aeb8181d001623cbf9b8e0db7..6eca6e9d62c2a0cad41eb8c776578b918b5a58b1 100644 (file)
@@ -1155,6 +1155,12 @@ class Symbol_value
       is_tls_symbol_(false), is_ifunc_symbol_(false), has_output_value_(true)
   { this->u_.value = 0; }
 
+  ~Symbol_value()
+  {
+    if (!this->has_output_value_)
+      delete this->u_.merged_symbol_value;
+  }
+
   // Get the value of this symbol.  OBJECT is the object in which this
   // symbol is defined, and ADDEND is an addend to add to the value.
   template<bool big_endian>
@@ -1380,6 +1386,11 @@ class Symbol_value
   is_ifunc_symbol() const
   { return this->is_ifunc_symbol_; }
 
+  // Return true if this has output value.
+  bool
+  has_output_value() const
+  { return this->has_output_value_; }
+
  private:
   // The index of this local symbol in the output symbol table.  This
   // will be 0 if no value has been assigned yet, and the symbol may
@@ -1558,6 +1569,16 @@ class Sized_relobj : public Relobj
 
   static const Address invalid_address = static_cast<Address>(0) - 1;
 
+  enum Compute_final_local_value_status
+  {
+    // No error.
+    CFLV_OK,
+    // An error occurred.
+    CFLV_ERROR,
+    // The local symbol has no output section.
+    CFLV_DISCARDED
+  };
+
   Sized_relobj(const std::string& name, Input_file* input_file, off_t offset,
               const typename elfcpp::Ehdr<size, big_endian>&);
 
@@ -1742,6 +1763,22 @@ class Sized_relobj : public Relobj
   Address
   map_to_kept_section(unsigned int shndx, bool* found) const;
 
+  // Compute final local symbol value.  R_SYM is the local symbol index.
+  // LV_IN points to a local symbol value containing the input value.
+  // LV_OUT points to a local symbol value storing the final output value,
+  // which must not be a merged symbol value since before calling this
+  // method to avoid memory leak.  SYMTAB points to a symbol table.
+  //
+  // The method returns a status code at return.  If the return status is
+  // CFLV_OK, *LV_OUT contains the final value.  If the return status is
+  // CFLV_ERROR, *LV_OUT is 0.  If the return status is CFLV_DISCARDED,
+  // *LV_OUT is not modified.
+  Compute_final_local_value_status
+  compute_final_local_value(unsigned int r_sym,
+                           const Symbol_value<size>* lv_in,
+                           Symbol_value<size>* lv_out,
+                           const Symbol_table* symtab);
+
  protected:
   // Set up.
   virtual void
@@ -2162,6 +2199,28 @@ class Sized_relobj : public Relobj
     return true;
   }
 
+  // Compute final local symbol value.  R_SYM is the local symbol index.
+  // LV_IN points to a local symbol value containing the input value.
+  // LV_OUT points to a local symbol value storing the final output value,
+  // which must not be a merged symbol value since before calling this
+  // method to avoid memory leak.  RELOCATABLE indicates whether we are
+  // linking a relocatable output.  OUT_SECTIONS is an array of output
+  // sections.  OUT_OFFSETS is an array of offsets of the sections.  SYMTAB
+  // points to a symbol table.
+  //
+  // The method returns a status code at return.  If the return status is
+  // CFLV_OK, *LV_OUT contains the final value.  If the return status is
+  // CFLV_ERROR, *LV_OUT is 0.  If the return status is CFLV_DISCARDED,
+  // *LV_OUT is not modified.
+  inline Compute_final_local_value_status
+  compute_final_local_value_internal(unsigned int r_sym,
+                                    const Symbol_value<size>* lv_in,
+                                    Symbol_value<size>* lv_out,
+                                    bool relocatable,
+                                    const Output_sections& out_sections,
+                                    const std::vector<Address>& out_offsets,
+                                    const Symbol_table* symtab);
+
   // The GOT offsets of local symbols. This map also stores GOT offsets
   // for tp-relative offsets for TLS symbols.
   typedef Unordered_map<unsigned int, Got_offset_list*> Local_got_offsets;
index eab055755ead13433748ccb9a32948846b42eded..c79c85640b676987b20fe14c848a6add3cfa74da 100644 (file)
@@ -1885,12 +1885,13 @@ arm_abs_global.stdout: arm_abs_global
 
 MOSTLYCLEANFILES += arm_abs_global
 
-check_SCRIPTS += arm_branch_in_range.sh
+check_SCRIPTS += arm_branch_in_range.sh arm_branch_out_of_range.sh
 check_DATA += arm_bl_in_range.stdout arm_bl_out_of_range.stdout \
        thumb_bl_in_range.stdout thumb_bl_out_of_range.stdout \
        thumb2_bl_in_range.stdout thumb2_bl_out_of_range.stdout \
        thumb_blx_in_range.stdout thumb_blx_out_of_range.stdout \
-       thumb2_blx_in_range.stdout thumb2_blx_out_of_range.stdout
+       thumb2_blx_in_range.stdout thumb2_blx_out_of_range.stdout \
+       thumb_bl_out_of_range_local.stdout
 
 arm_bl_in_range.stdout: arm_bl_in_range
        $(TEST_OBJDUMP) -D $< > $@
@@ -1982,10 +1983,19 @@ thumb2_blx_out_of_range: thumb2_blx_out_of_range.o ../ld-new
 thumb2_blx_out_of_range.o: thumb_blx_out_of_range.s
        $(TEST_AS) -o $@ -march=armv7-a $<
 
+thumb_bl_out_of_range_local.stdout: thumb_bl_out_of_range_local
+       $(TEST_OBJDUMP) -D $< > $@
+
+thumb_bl_out_of_range_local: thumb_bl_out_of_range_local.o ../ld-new
+       ../ld-new -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+thumb_bl_out_of_range_local.o: thumb_bl_out_of_range_local.s
+       $(TEST_AS) -o $@ -march=armv5te $<
+
 MOSTLYCLEANFILES += arm_bl_in_range arm_bl_out_of_range thumb_bl_in_range \
        thumb_bl_out_of_range thumb2_bl_in_range thumb2_bl_out_of_range \
        thumb_blx_in_range thumb_blx_out_of_range thumb2_blx_in_range \
-       thumb2_blx_out_of_range
+       thumb2_blx_out_of_range thumb_bl_out_of_range_local
 
 check_SCRIPTS += arm_fix_v4bx.sh
 check_DATA += arm_fix_v4bx.stdout arm_fix_v4bx_interworking.stdout \
@@ -2050,4 +2060,68 @@ arm_attr_merge_7b.o: arm_attr_merge_7b.s
 
 MOSTLYCLEANFILES += arm_attr_merge_6 arm_attr_merge_6r arm_attr_merge_7
 
+# Cortex-A8 workaround test.
+
+check_SCRIPTS += arm_cortex_a8.sh
+check_DATA += arm_cortex_a8_b_cond.stdout arm_cortex_a8_b.stdout \
+       arm_cortex_a8_bl.stdout arm_cortex_a8_blx.stdout \
+       arm_cortex_a8_local.stdout arm_cortex_a8_local_reloc.stdout
+
+arm_cortex_a8_b_cond.stdout: arm_cortex_a8_b_cond
+       $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_b_cond: arm_cortex_a8_b_cond.o ../ld-new
+       ../ld-new -o $@ $<
+
+arm_cortex_a8_b_cond.o: arm_cortex_a8_b_cond.s
+       $(TEST_AS) -o $@ $<
+
+arm_cortex_a8_b.stdout: arm_cortex_a8_b
+       $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_b: arm_cortex_a8_b.o ../ld-new
+       ../ld-new --fix-cortex-a8 -o $@ $<
+
+arm_cortex_a8_b.o: arm_cortex_a8_b.s
+       $(TEST_AS) -o $@ $<
+
+arm_cortex_a8_bl.stdout: arm_cortex_a8_bl
+       $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_bl: arm_cortex_a8_bl.o ../ld-new
+       ../ld-new -o $@ $<
+
+arm_cortex_a8_bl.o: arm_cortex_a8_bl.s
+       $(TEST_AS) -o $@ $<
+
+arm_cortex_a8_blx.stdout: arm_cortex_a8_blx
+       $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_blx: arm_cortex_a8_blx.o ../ld-new
+       ../ld-new -o $@ $<
+
+arm_cortex_a8_blx.o: arm_cortex_a8_blx.s
+       $(TEST_AS) -o $@ $<
+
+arm_cortex_a8_local.stdout: arm_cortex_a8_local
+       $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_local: arm_cortex_a8_local.o ../ld-new
+       ../ld-new -o $@ $<
+
+arm_cortex_a8_local.o: arm_cortex_a8_local.s
+       $(TEST_AS) -o $@ $<
+
+arm_cortex_a8_local_reloc.stdout: arm_cortex_a8_local_reloc
+       $(TEST_OBJDUMP) -D -j.text $< > $@
+
+arm_cortex_a8_local_reloc: arm_cortex_a8_local_reloc.o ../ld-new
+       ../ld-new -o $@ $<
+
+arm_cortex_a8_local_reloc.o: arm_cortex_a8_local_reloc.s
+       $(TEST_AS) -o $@ $<
+
+MOSTLYCLEANFILES += arm_cortex_a8_b_cond arm_cortex_a8_b arm_cortex_a8_bl \
+       arm_cortex_a8_blx arm_cortex_a8_local arm_cortex_a8_local_reloc
+
 endif DEFAULT_TARGET_ARM
index e40caa66349dafc9fc54341b44239b4862ef37d9..cc591ef3a0bc162806fa369ccbcaa5476b3c0dc1 100644 (file)
@@ -492,9 +492,13 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @DEFAULT_TARGET_X86_64_TRUE@am__append_39 = split_x86_64_1 split_x86_64_2 split_x86_64_3 \
 @DEFAULT_TARGET_X86_64_TRUE@   split_x86_64_4 split_x86_64_r
 
+
+# Cortex-A8 workaround test.
 @DEFAULT_TARGET_ARM_TRUE@am__append_40 = arm_abs_global.sh \
 @DEFAULT_TARGET_ARM_TRUE@      arm_branch_in_range.sh \
-@DEFAULT_TARGET_ARM_TRUE@      arm_fix_v4bx.sh arm_attr_merge.sh
+@DEFAULT_TARGET_ARM_TRUE@      arm_branch_out_of_range.sh \
+@DEFAULT_TARGET_ARM_TRUE@      arm_fix_v4bx.sh arm_attr_merge.sh \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8.sh
 @DEFAULT_TARGET_ARM_TRUE@am__append_41 = arm_abs_global.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      arm_bl_in_range.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      arm_bl_out_of_range.stdout \
@@ -506,12 +510,19 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @DEFAULT_TARGET_ARM_TRUE@      thumb_blx_out_of_range.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      thumb2_blx_in_range.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      thumb2_blx_out_of_range.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      thumb_bl_out_of_range_local.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      arm_fix_v4bx.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      arm_fix_v4bx_interworking.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      arm_no_fix_v4bx.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      arm_attr_merge_6.stdout \
 @DEFAULT_TARGET_ARM_TRUE@      arm_attr_merge_6r.stdout \
-@DEFAULT_TARGET_ARM_TRUE@      arm_attr_merge_7.stdout
+@DEFAULT_TARGET_ARM_TRUE@      arm_attr_merge_7.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8_b_cond.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8_b.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8_bl.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8_blx.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8_local.stdout \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8_local_reloc.stdout
 @DEFAULT_TARGET_ARM_TRUE@am__append_42 = arm_abs_global \
 @DEFAULT_TARGET_ARM_TRUE@      arm_bl_in_range arm_bl_out_of_range \
 @DEFAULT_TARGET_ARM_TRUE@      thumb_bl_in_range \
@@ -521,10 +532,16 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \
 @DEFAULT_TARGET_ARM_TRUE@      thumb_blx_in_range \
 @DEFAULT_TARGET_ARM_TRUE@      thumb_blx_out_of_range \
 @DEFAULT_TARGET_ARM_TRUE@      thumb2_blx_in_range \
-@DEFAULT_TARGET_ARM_TRUE@      thumb2_blx_out_of_range arm_fix_v4bx \
+@DEFAULT_TARGET_ARM_TRUE@      thumb2_blx_out_of_range \
+@DEFAULT_TARGET_ARM_TRUE@      thumb_bl_out_of_range_local \
+@DEFAULT_TARGET_ARM_TRUE@      arm_fix_v4bx \
 @DEFAULT_TARGET_ARM_TRUE@      arm_fix_v4bx_interworking \
 @DEFAULT_TARGET_ARM_TRUE@      arm_no_fix_v4bx arm_attr_merge_6 \
-@DEFAULT_TARGET_ARM_TRUE@      arm_attr_merge_6r arm_attr_merge_7
+@DEFAULT_TARGET_ARM_TRUE@      arm_attr_merge_6r arm_attr_merge_7 \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8_b_cond arm_cortex_a8_b \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8_bl arm_cortex_a8_blx \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8_local \
+@DEFAULT_TARGET_ARM_TRUE@      arm_cortex_a8_local_reloc
 subdir = testsuite
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -3297,10 +3314,14 @@ arm_abs_global.sh.log: arm_abs_global.sh
        @p='arm_abs_global.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 arm_branch_in_range.sh.log: arm_branch_in_range.sh
        @p='arm_branch_in_range.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_branch_out_of_range.sh.log: arm_branch_out_of_range.sh
+       @p='arm_branch_out_of_range.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 arm_fix_v4bx.sh.log: arm_fix_v4bx.sh
        @p='arm_fix_v4bx.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 arm_attr_merge.sh.log: arm_attr_merge.sh
        @p='arm_attr_merge.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+arm_cortex_a8.sh.log: arm_cortex_a8.sh
+       @p='arm_cortex_a8.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 object_unittest.log: object_unittest$(EXEEXT)
        @p='object_unittest$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 binary_unittest.log: binary_unittest$(EXEEXT)
@@ -4641,6 +4662,15 @@ uninstall-am:
 @DEFAULT_TARGET_ARM_TRUE@thumb2_blx_out_of_range.o: thumb_blx_out_of_range.s
 @DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ -march=armv7-a $<
 
+@DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range_local.stdout: thumb_bl_out_of_range_local
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range_local: thumb_bl_out_of_range_local.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new -T $(srcdir)/thumb_branch_range.t -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range_local.o: thumb_bl_out_of_range_local.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ -march=armv5te $<
+
 @DEFAULT_TARGET_ARM_TRUE@arm_fix_v4bx.stdout: arm_fix_v4bx
 @DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D -j.text $< > $@
 
@@ -4692,6 +4722,60 @@ uninstall-am:
 @DEFAULT_TARGET_ARM_TRUE@arm_attr_merge_7b.o: arm_attr_merge_7b.s
 @DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ $<
 
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b_cond.stdout: arm_cortex_a8_b_cond
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b_cond: arm_cortex_a8_b_cond.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b_cond.o: arm_cortex_a8_b_cond.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b.stdout: arm_cortex_a8_b
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b: arm_cortex_a8_b.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new --fix-cortex-a8 -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b.o: arm_cortex_a8_b.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_bl.stdout: arm_cortex_a8_bl
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_bl: arm_cortex_a8_bl.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_bl.o: arm_cortex_a8_bl.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_blx.stdout: arm_cortex_a8_blx
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_blx: arm_cortex_a8_blx.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_blx.o: arm_cortex_a8_blx.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local.stdout: arm_cortex_a8_local
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local: arm_cortex_a8_local.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local.o: arm_cortex_a8_local.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local_reloc.stdout: arm_cortex_a8_local_reloc
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_OBJDUMP) -D -j.text $< > $@
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local_reloc: arm_cortex_a8_local_reloc.o ../ld-new
+@DEFAULT_TARGET_ARM_TRUE@      ../ld-new -o $@ $<
+
+@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local_reloc.o: arm_cortex_a8_local_reloc.s
+@DEFAULT_TARGET_ARM_TRUE@      $(TEST_AS) -o $@ $<
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
index 786d9aabf92aa0b1e279a21bb05c66b1475c0aad..cb5ff53556bbcc507e66efec66157df557eb1aa2 100644 (file)
@@ -15,7 +15,8 @@ _backward_target:
        .size   _backward_target, .-_backward_target
        
        .text
-       .align  2
+# Use 256-byte alignment so that we know where the stubs start.
+       .align  8
 
 # Define _start so that linker does not complain.
        .global _start
diff --git a/gold/testsuite/arm_branch_out_of_range.sh b/gold/testsuite/arm_branch_out_of_range.sh
new file mode 100755 (executable)
index 0000000..b59b442
--- /dev/null
@@ -0,0 +1,123 @@
+#!/bin/sh
+
+# arm_branch_out_of_range.sh -- test ARM/THUMB/THUMB branch instructions whose
+# targets are just out of the branch range limits.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# This file goes with the assembler source files arm_bl_out_of_range.s,
+# thumb_bl_out_of_range.s and thumb_bl_out_of_range_local.s that are assembled
+# and linked to check that branches whose target are just out of the branch
+# range limits are handle correctly.
+
+check()
+{
+    file=$1
+    pattern=$2
+
+    found=`grep "$pattern" $file`
+    if test -z "$found"; then
+       echo "pattern \"$pattern\" not found in file $file."
+       exit 1
+    fi
+}
+
+# This is a bit crude.  Also, there are tabs in the grep patterns. 
+
+check arm_bl_out_of_range.stdout \
+  " 4000004:   eb00003d        bl      4000100 <.*>"
+check arm_bl_out_of_range.stdout \
+  " 4000008:   eb00003e        bl      4000108 <.*>"
+check arm_bl_out_of_range.stdout \
+  " 4000100:   e51ff004        ldr     pc, \[pc, #-4\]"
+check arm_bl_out_of_range.stdout \
+  " 4000104:   02000008 "
+check arm_bl_out_of_range.stdout \
+  " 4000108:   e51ff004        ldr     pc, \[pc, #-4\]"
+check arm_bl_out_of_range.stdout \
+  " 400010c:   06000010 "
+
+check thumb_bl_out_of_range.stdout \
+  " 800004:    f000 e87c       blx     800100 <.*>"
+check thumb_bl_out_of_range.stdout \
+  " 800008:    f000 e87e       blx     800108 <.*>"
+check thumb_bl_out_of_range.stdout \
+  " 800100:    e51ff004        ldr     pc, \[pc, #-4\]"
+check thumb_bl_out_of_range.stdout \
+  " 800104:    00400007 "
+check thumb_bl_out_of_range.stdout \
+  " 800108:    e51ff004        ldr     pc, \[pc, #-4\]"
+check thumb_bl_out_of_range.stdout \
+  " 80010c:    00c0000d "
+
+check thumb_blx_out_of_range.stdout \
+  " 800004:    f000 e87c       blx     800100 <.*>"
+check thumb_blx_out_of_range.stdout \
+  " 80000a:    f000 e87e       blx     800108 <.*>"
+check thumb_blx_out_of_range.stdout \
+  " 800100:    e51ff004        ldr     pc, \[pc, #-4\]"
+check thumb_blx_out_of_range.stdout \
+  " 800104:    00400006 "
+check thumb_blx_out_of_range.stdout \
+  " 800108:    e51ff004        ldr     pc, \[pc, #-4\]"
+check thumb_blx_out_of_range.stdout \
+  " 80010c:    00c0000c "
+
+check thumb_bl_out_of_range_local.stdout \
+  " 800004:    f000 e87c       blx     800100 <.*>"
+check thumb_bl_out_of_range_local.stdout \
+  " 800008:    f000 e87e       blx     800108 <.*>"
+check thumb_bl_out_of_range_local.stdout \
+  " 800100:    e51ff004        ldr     pc, \[pc, #-4\]"
+check thumb_bl_out_of_range_local.stdout \
+  " 800104:    00400007 "
+check thumb_bl_out_of_range_local.stdout \
+  " 800108:    e51ff004        ldr     pc, \[pc, #-4\]"
+check thumb_bl_out_of_range_local.stdout \
+  " 80010c:    00c0000d "
+
+check thumb2_bl_out_of_range.stdout \
+  " 2000004:   f000 e87c       blx     2000100 <.*>"
+check thumb2_bl_out_of_range.stdout \
+  " 2000008:   f000 e87e       blx     2000108 <.*>"
+check thumb2_bl_out_of_range.stdout \
+  " 2000100:   e51ff004        ldr     pc, \[pc, #-4\]"
+check thumb2_bl_out_of_range.stdout \
+  " 2000104:   01000007 "
+check thumb2_bl_out_of_range.stdout \
+  " 2000108:   e51ff004        ldr     pc, \[pc, #-4\]"
+check thumb2_bl_out_of_range.stdout \
+  " 200010c:   0300000d "
+
+check thumb2_blx_out_of_range.stdout \
+  " 2000004:   f000 e87c       blx     2000100 <.*>"
+check thumb2_blx_out_of_range.stdout \
+  " 200000a:   f000 e87e       blx     2000108 <.*>"
+check thumb2_blx_out_of_range.stdout \
+  " 2000100:   e51ff004        ldr     pc, \[pc, #-4\]"
+check thumb2_blx_out_of_range.stdout \
+  " 2000104:   01000006 "
+check thumb2_blx_out_of_range.stdout \
+  " 2000108:   e51ff004        ldr     pc, \[pc, #-4\]"
+check thumb2_blx_out_of_range.stdout \
+  " 200010c:   0300000c "
+
+exit 0
diff --git a/gold/testsuite/arm_cortex_a8.sh b/gold/testsuite/arm_cortex_a8.sh
new file mode 100755 (executable)
index 0000000..5e25c25
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+# arm_cortex_a8.sh -- a test case for the Cortex-A8 workaround.
+
+# Copyright 2010 Free Software Foundation, Inc.
+# Written by Doug Kwan <dougkwan@google.com>.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# This file goes with arm_v4bx.s, an ARM assembly source file constructed to
+# have test the handling of R_ARM_V4BX relocation.
+
+check()
+{
+    if ! grep -q "$2" "$1"
+    then
+       echo "Did not find expected instruction in $1:"
+       echo "   $2"
+       echo ""
+       echo "Actual instructions below:"
+       cat "$1"
+       exit 1
+    fi
+}
+
+# Test branch.
+check arm_cortex_a8_b.stdout ".*ffe:   .*      b.w     .*000 <.*>"
+check arm_cortex_a8_b.stdout ".000:    .*      b.w     .*100 <_func>"
+
+# Test conditional branch.
+check arm_cortex_a8_b_cond.stdout ".*ffe:      .*      b.w     .*000 <.*>"
+check arm_cortex_a8_b_cond.stdout ".000:       .*      beq.n   .*006 <.*>"
+check arm_cortex_a8_b_cond.stdout ".002:       .*      b.w     .*002 <.*>"
+check arm_cortex_a8_b_cond.stdout ".006:       .*      b.w     .*100 <_func>"
+
+# Test branch and link.
+check arm_cortex_a8_bl.stdout ".*ffe:  .*      bl      .*000 <.*>"
+check arm_cortex_a8_bl.stdout ".000:   .*      b.w     .*100 <_func>"
+
+# Test blx
+check arm_cortex_a8_blx.stdout ".*ffe: .*      blx     .*000 <.*>"
+check arm_cortex_a8_blx.stdout ".000:  .*      b       .*100 <_func>"
+
+# Test a local branch without relocation.
+check arm_cortex_a8_local.stdout ".*ffe:       .*      b.w     .*000 <.*>"
+check arm_cortex_a8_local.stdout ".000:        .*      bpl.n   .*006 <.*>"
+check arm_cortex_a8_local.stdout ".002:        .*      b.w     .*002 <.*>"
+check arm_cortex_a8_local.stdout ".006:        .*      b.w     .*100 <.*>"
+
+exit 0
diff --git a/gold/testsuite/arm_cortex_a8_b.s b/gold/testsuite/arm_cortex_a8_b.s
new file mode 100644 (file)
index 0000000..d2316a0
--- /dev/null
@@ -0,0 +1,30 @@
+       .syntax unified
+       .cpu    cortex-a8
+
+       .text
+       .align  12
+       
+_start:
+       .type   _start,%function
+       bx      lr
+       .size   _start,.-_start
+
+       .align  8
+       .thumb
+       .global _func
+       .type   _func,%function
+_func:
+       bx      lr
+       .size   _func,.-_func
+
+       .align  11
+       .space  2042
+
+       .align  1
+       .thumb
+       .global _test
+       .type   _test,%function
+_test:
+       add.w   r0, r0, 0
+       b.w     _func
+       .size   _test,.-_test
diff --git a/gold/testsuite/arm_cortex_a8_b_cond.s b/gold/testsuite/arm_cortex_a8_b_cond.s
new file mode 100644 (file)
index 0000000..a244aa7
--- /dev/null
@@ -0,0 +1,30 @@
+       .syntax unified
+       .cpu    cortex-a8
+
+       .text
+       .align  12
+       
+_start:
+       .type   _start,%function
+       bx      lr
+       .size   _start,.-_start
+
+       .align  8
+       .thumb
+       .global _func
+       .type   _func,%function
+_func:
+       bx      lr
+       .size   _func,.-_func
+
+       .align  11
+       .space  2042
+
+       .align  1
+       .thumb
+       .global _test
+       .type   _test,%function
+_test:
+       add.w   r0, r0, 0
+       beq.w   _func
+       .size   _test,.-_test
diff --git a/gold/testsuite/arm_cortex_a8_b_local.s b/gold/testsuite/arm_cortex_a8_b_local.s
new file mode 100644 (file)
index 0000000..2432d91
--- /dev/null
@@ -0,0 +1,52 @@
+       .syntax unified
+       .cpu    cortex-a8
+
+       .section        .text.0, "x"
+       .align  12
+       
+_start:
+       .type   _start,%function
+       bx      lr
+       .size   _start,.-_start
+
+       .section        .text.1, "x"
+       .align  11
+       .thumb
+       .type   .Lfunc1,%function
+.Lfunc1:
+       bx      lr
+       .size   .Lfunc1,.-.Lfunc1
+
+       .section        .text.2, "x"
+       .align  11
+       .space  2042
+
+       .align  1
+       .thumb
+       .global _test1
+       .type   _test1,%function
+_test1:
+       add.w   r0, r0, 0
+       b.w     .Lfunc1
+       .size   _test1,.-_test1
+
+       .align  8
+       .thumb
+       .type   .Lfunc2,%function
+.Lfunc2:
+       bx      lr
+       .size   .Lfunc2,.-.Lfunc1
+
+       .align  11
+       .space  2042
+
+       .align  1
+       .thumb
+       .global _test2
+       .type   _test2,%function
+_test2:
+       add.w   r0, r0, 0
+       b.w     .Lfunc2
+       .size   _test2,.-_test2
+
+
diff --git a/gold/testsuite/arm_cortex_a8_bl.s b/gold/testsuite/arm_cortex_a8_bl.s
new file mode 100644 (file)
index 0000000..c78fa8d
--- /dev/null
@@ -0,0 +1,30 @@
+       .syntax unified
+       .cpu    cortex-a8
+
+       .text
+       .align  12
+       
+_start:
+       .type   _start,%function
+       bx      lr
+       .size   _start,.-_start
+
+       .align  8
+       .thumb
+       .global _func
+       .type   _func,%function
+_func:
+       bx      lr
+       .size   _func,.-_func
+
+       .align  11
+       .space  2042
+
+       .align  1
+       .thumb
+       .global _test
+       .type   _test,%function
+_test:
+       add.w   r0, r0, 0
+       bl      _func
+       .size   _test,.-_test
diff --git a/gold/testsuite/arm_cortex_a8_blx.s b/gold/testsuite/arm_cortex_a8_blx.s
new file mode 100644 (file)
index 0000000..c323d25
--- /dev/null
@@ -0,0 +1,33 @@
+       .syntax unified
+       .cpu    cortex-a8
+
+       .text
+       .align  12
+       
+_start:
+       .type   _start,%function
+       bx      lr
+       .size   _start,.-_start
+
+       .align  8
+       .global _func
+       .type   _func,%function
+_func:
+       bx      lr
+       .size   _func,.-_func
+
+       .align  11
+       .space  2042
+
+       .align  1
+       .thumb
+       .global _test
+       .type   _test,%function
+_test:
+       add.w   r0, r0, 0
+       blx     _func
+       .size   _test,.-_test
+
+# We have no mapping symbols for stubs.  This make the disassembler
+# list the stub correctly in ARM mode.
+       .arm
diff --git a/gold/testsuite/arm_cortex_a8_local.s b/gold/testsuite/arm_cortex_a8_local.s
new file mode 100644 (file)
index 0000000..462aa18
--- /dev/null
@@ -0,0 +1,29 @@
+       .syntax unified
+       .cpu    cortex-a8
+
+       .text
+       .align  12
+       
+_start:
+       .type   _start,%function
+       bx      lr
+       .size   _start,.-_start
+
+       .align  8
+       .thumb
+       .type   .Lfunc,%function
+.Lfunc:
+       bx      lr
+       .size   .Lfunc,.-.Lfunc
+
+       .align  11
+       .space  2042
+
+       .align  1
+       .thumb
+       .global _test
+       .type   _test,%function
+_test:
+       add.w   r0, r0, 0
+       bpl.w   .Lfunc
+       .size   _test,.-_test
diff --git a/gold/testsuite/arm_cortex_a8_local_reloc.s b/gold/testsuite/arm_cortex_a8_local_reloc.s
new file mode 100644 (file)
index 0000000..2b49184
--- /dev/null
@@ -0,0 +1,31 @@
+       .syntax unified
+       .cpu    cortex-a8
+
+       .section        .text.0, "x"
+       .align  12
+       
+_start:
+       .type   _start,%function
+       bx      lr
+       .size   _start,.-_start
+
+       .section        .text.1, "x"
+       .align  11
+       .thumb
+       .type   .Lfunc,%function
+.Lfunc:
+       bx      lr
+       .size   .Lfunc,.-.Lfunc
+
+       .section        .text.2, "x"
+       .align  11
+       .space  2042
+
+       .align  1
+       .thumb
+       .global _test
+       .type   _test,%function
+_test:
+       add.w   r0, r0, 0
+       b.w     .Lfunc
+       .size   _test,.-_test
index 6629d74af0a4f08c17b75e750cb4f75cb34252e3..d0906d9d5ceb28a34dbd2f5240bc62c52cc1a309 100644 (file)
@@ -16,6 +16,8 @@ _backward_target:
        .size   _backward_target, .-_backward_target
        
        .text
+# Use 256-byte alignment so that we know where the stubs start.
+       .align  8
 
 # Define _start so that linker does not complain.
        .global _start
@@ -42,6 +44,10 @@ _forward_test:
        bl      _forward_target
        .size   _forward_test, .-_forward_test
        
+# switch back to ARM mode so that stubs are disassembled correctly.
+       .code   32
+       nop
+
        .section        .text.post,"x"
 
 # Add padding so that target is just out of branch range. 
diff --git a/gold/testsuite/thumb_bl_out_of_range_local.s b/gold/testsuite/thumb_bl_out_of_range_local.s
new file mode 100644 (file)
index 0000000..48de1e1
--- /dev/null
@@ -0,0 +1,61 @@
+# thumb_bl_out_of_range_local.s
+# Test THUMB/THUMB-2 bl instructions just out of the branch range limits
+# and with local branch targets.
+       .syntax unified
+
+       .section        .text.pre,"x"
+
+# Add padding so that target is just output of branch range. 
+       .space  6
+
+       .code   16
+       .thumb_func
+       .type   .Lbackward_target, %function
+.Lbackward_target:
+       bx      lr
+       .size   .Lbackward_target, .-.Lbackward_target
+       
+       .text
+# Use 256-byte alignment so that we know where the stubs start.
+       .align  8
+
+# Define _start so that linker does not complain.
+       .global _start
+       .code   32
+       .align  2
+       .type   _start, %function
+_start:
+       bx      lr
+       .size   _start, .-_start
+
+       .global _backward_test
+       .code   16
+       .thumb_func
+       .type   _backward_test, %function
+_backward_test:
+       bl      .Lbackward_target
+       .size   _backward_test, .-_backward_test
+
+       .global _forward_test
+       .code   16
+       .thumb_func
+       .type   _forward_test, %function
+_forward_test:
+       bl      .Lforward_target
+       .size   _forward_test, .-_forward_test
+
+# Switch back to ARM mode so that we can see stubs
+       .code   32
+       nop
+       
+       .section        .text.post,"x"
+
+# Add padding so that target is just out of branch range. 
+       .space  12
+
+       .code   16
+       .thumb_func
+       .type   .Lforward_target, %function
+.Lforward_target:
+       bx      lr
+       .size   .Lforward_target, .-.Lforward_target
index fc5beb58d1e16f6f64dd55ffc1e8a2cef3660694..5689e272c9063998ca85d1f46f77e095d7c9b641 100644 (file)
@@ -15,6 +15,8 @@ _backward_target:
        .size   _backward_target, .-_backward_target
        
        .text
+# Use 256-byte alignment so that we know where the stubs start.
+       .align  8
 
 # Define _start so that linker does not complain.
        .align  2
@@ -46,7 +48,10 @@ _forward_test:
        nop.n
        bl      _forward_target
        .size   _forward_test, .-_forward_test
+
+# switch back to ARM mode so that stubs are disassembled correctly.
        .code   32
+       nop
        
        .section        .text.post,"x"