[PATCH][GOLD] Use correct local symbol values in stub generation.

Doug Kwan (關振德) dougkwan@google.com
Wed Sep 8 23:16:00 GMT 2010


Hi,

    Attached is an updated patch.  I changed the interface to that
compute_final_local_value takes two pointers, one for input and the
other output symbol value.  I also renamed the inline function and
fixed the indentation.

-Doug

在 2010年9月8日上午8:03,Ian Lance Taylor <iant@google.com> 寫道:
> "Doug Kwan (關振德)" <dougkwan@google.com> writes:
>
>> +  if (!is_ordinary)
>> +    {
>> +      if (shndx == elfcpp::SHN_ABS || Symbol::is_common_shndx(shndx))
>> +     lv->set_output_value(lv->input_value());
>> +      else
>> +     {
>> +       this->error(_("unknown section index %u for local symbol %u"),
>> +                   shndx, r_sym);
>> +           lv->set_output_value(0);
>> +           return This::CFLV_ERROR;
>> +     }
>> +    }
>
> The indentation looks wrong here.
>
>> +  // 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.
>> +  Compute_final_local_value_status
>> +  compute_final_local_value(unsigned int r_sym, Symbol_value<size>*lv,
>> +                         const Symbol_table* symtab);
>
> This interface seems overly complicated, because of the way it changes
> *lv.  A local symbol value is represented in two values: a number and a
> Merged_symbol_value.  Can you change this function to take a const
> Symbol_value pointer and to return those two values?
>
> Also I'm not sure the internal and external functions should have the
> same name.
>
> Also there should be a space after Symbol_value<size>*.
>
> Ian
>
-------------- next part --------------
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.120
diff -u -u -p -r1.120 arm.cc
--- gold/arm.cc	8 Sep 2010 18:31:35 -0000	1.120
+++ gold/arm.cc	8 Sep 2010 23:05:12 -0000
@@ -1064,6 +1064,11 @@ class Arm_exidx_cantunwind : public Outp
       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<3
 
   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_sect
     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_secti
 
       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_secti
           // 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)))
-	    {
-	      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);
-	        }
+	  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)
+	    {
+	      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_secti
 	  // 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: gold/object.cc
===================================================================
RCS file: /cvs/src/src/gold/object.cc,v
retrieving revision 1.130
diff -u -u -p -r1.130 object.cc
--- gold/object.cc	25 Aug 2010 08:36:54 -0000	1.130
+++ gold/object.cc	8 Sep 2010 23:05:12 -0000
@@ -1878,6 +1878,181 @@ Sized_relobj<size, big_endian>::do_count
   this->output_local_dynsym_count_ = dyncount;
 }
 
+// Compute the final value of a local symbol.  This code used to be
+// in the loop body of do_finalize_local_symbols.  It was extracted into
+// a seperate method so that we can share it between do_finalize_local_symbols
+// and the public version of this method.
+
+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 +2072,31 @@ Sized_relobj<size, big_endian>::do_final
   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);
-
-      // Set the output symbol value.
+      Symbol_value<size>* lv = &this->local_values_[i];
 
-      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
-	    {
-	      this->error(_("unknown section index %u for local symbol %u"),
-			  shndx, i);
-	      lv.set_output_value(0);
-	    }
-	}
-      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)
+	case CFLV_OK:
+	  if (!lv->is_output_symtab_index_set())
 	    {
-              // 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;
+	      lv->set_output_symtab_index(index);
+	      ++index;
 	    }
-	  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());
+	  break;
+	case CFLV_DISCARDED:
+	case CFLV_ERROR:
+	  // Do nothing.
+	  break;
+	default:
+	  gold_unreachable();
 	}
-
-      if (!lv.is_output_symtab_index_set())
-        {
-          lv.set_output_symtab_index(index);
-          ++index;
-        }
     }
   return index;
 }
Index: gold/object.h
===================================================================
RCS file: /cvs/src/src/gold/object.h,v
retrieving revision 1.102
diff -u -u -p -r1.102 object.h
--- gold/object.h	25 Aug 2010 08:36:54 -0000	1.102
+++ gold/object.h	8 Sep 2010 23:05:12 -0000
@@ -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: gold/testsuite/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.am,v
retrieving revision 1.145
diff -u -u -p -r1.145 Makefile.am
--- gold/testsuite/Makefile.am	8 Sep 2010 21:06:53 -0000	1.145
+++ gold/testsuite/Makefile.am	8 Sep 2010 23:05:12 -0000
@@ -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_
 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: gold/testsuite/Makefile.in
===================================================================
RCS file: /cvs/src/src/gold/testsuite/Makefile.in,v
retrieving revision 1.154
diff -u -u -p -r1.154 Makefile.in
--- gold/testsuite/Makefile.in	8 Sep 2010 21:06:53 -0000	1.154
+++ gold/testsuite/Makefile.in	8 Sep 2010 23:05:13 -0000
@@ -492,9 +492,13 @@ check_PROGRAMS = object_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
 @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
 @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: gold/testsuite/arm_bl_out_of_range.s
===================================================================
RCS file: /cvs/src/src/gold/testsuite/arm_bl_out_of_range.s,v
retrieving revision 1.1
diff -u -u -p -r1.1 arm_bl_out_of_range.s
--- gold/testsuite/arm_bl_out_of_range.s	22 Feb 2010 06:26:07 -0000	1.1
+++ gold/testsuite/arm_bl_out_of_range.s	8 Sep 2010 23:05:13 -0000
@@ -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
Index: gold/testsuite/arm_branch_out_of_range.sh
===================================================================
RCS file: gold/testsuite/arm_branch_out_of_range.sh
diff -N gold/testsuite/arm_branch_out_of_range.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/arm_branch_out_of_range.sh	8 Sep 2010 23:05:13 -0000
@@ -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
Index: gold/testsuite/arm_cortex_a8.sh
===================================================================
RCS file: gold/testsuite/arm_cortex_a8.sh
diff -N gold/testsuite/arm_cortex_a8.sh
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/arm_cortex_a8.sh	8 Sep 2010 23:05:13 -0000
@@ -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
Index: gold/testsuite/arm_cortex_a8_b.s
===================================================================
RCS file: gold/testsuite/arm_cortex_a8_b.s
diff -N gold/testsuite/arm_cortex_a8_b.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/arm_cortex_a8_b.s	8 Sep 2010 23:05:13 -0000
@@ -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
Index: gold/testsuite/arm_cortex_a8_b_cond.s
===================================================================
RCS file: gold/testsuite/arm_cortex_a8_b_cond.s
diff -N gold/testsuite/arm_cortex_a8_b_cond.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/arm_cortex_a8_b_cond.s	8 Sep 2010 23:05:13 -0000
@@ -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
Index: gold/testsuite/arm_cortex_a8_b_local.s
===================================================================
RCS file: gold/testsuite/arm_cortex_a8_b_local.s
diff -N gold/testsuite/arm_cortex_a8_b_local.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/arm_cortex_a8_b_local.s	8 Sep 2010 23:05:13 -0000
@@ -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
+
+
Index: gold/testsuite/arm_cortex_a8_bl.s
===================================================================
RCS file: gold/testsuite/arm_cortex_a8_bl.s
diff -N gold/testsuite/arm_cortex_a8_bl.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/arm_cortex_a8_bl.s	8 Sep 2010 23:05:13 -0000
@@ -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
Index: gold/testsuite/arm_cortex_a8_blx.s
===================================================================
RCS file: gold/testsuite/arm_cortex_a8_blx.s
diff -N gold/testsuite/arm_cortex_a8_blx.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/arm_cortex_a8_blx.s	8 Sep 2010 23:05:13 -0000
@@ -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
Index: gold/testsuite/arm_cortex_a8_local.s
===================================================================
RCS file: gold/testsuite/arm_cortex_a8_local.s
diff -N gold/testsuite/arm_cortex_a8_local.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/arm_cortex_a8_local.s	8 Sep 2010 23:05:13 -0000
@@ -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
Index: gold/testsuite/arm_cortex_a8_local_reloc.s
===================================================================
RCS file: gold/testsuite/arm_cortex_a8_local_reloc.s
diff -N gold/testsuite/arm_cortex_a8_local_reloc.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/arm_cortex_a8_local_reloc.s	8 Sep 2010 23:05:13 -0000
@@ -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: gold/testsuite/thumb_bl_out_of_range.s
===================================================================
RCS file: /cvs/src/src/gold/testsuite/thumb_bl_out_of_range.s,v
retrieving revision 1.1
diff -u -u -p -r1.1 thumb_bl_out_of_range.s
--- gold/testsuite/thumb_bl_out_of_range.s	22 Feb 2010 06:26:07 -0000	1.1
+++ gold/testsuite/thumb_bl_out_of_range.s	8 Sep 2010 23:05:13 -0000
@@ -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. 
Index: gold/testsuite/thumb_bl_out_of_range_local.s
===================================================================
RCS file: gold/testsuite/thumb_bl_out_of_range_local.s
diff -N gold/testsuite/thumb_bl_out_of_range_local.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gold/testsuite/thumb_bl_out_of_range_local.s	8 Sep 2010 23:05:13 -0000
@@ -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: gold/testsuite/thumb_blx_out_of_range.s
===================================================================
RCS file: /cvs/src/src/gold/testsuite/thumb_blx_out_of_range.s,v
retrieving revision 1.1
diff -u -u -p -r1.1 thumb_blx_out_of_range.s
--- gold/testsuite/thumb_blx_out_of_range.s	22 Mar 2010 22:48:05 -0000	1.1
+++ gold/testsuite/thumb_blx_out_of_range.s	8 Sep 2010 23:05:13 -0000
@@ -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"
 


More information about the Binutils mailing list