[PATCH][GOLD] Handle target specific relocatable relocation.

Doug Kwan (關振德) dougkwan@google.com
Tue May 25 03:30:00 GMT 2010


Hi,

   This patch adds code to handle relocation strategy RELOC_SPECIAL in
target-reloc.h and ARM specific code in arm.cc to handle relocation
types with odd-sizes or incontigious bits.  Previously, all targets
used generic code to handle full 8/16/32/64 bit relocations.  That did
not work on ARM and caused the Linux kernel to be linked incorrectly.
This patch adds a hook Sized_target::relocate_special_relocatable.
For reasons I do not understand, the hooks in Sized_target do not
follow the normal convention in gold for virtual functions involving a
public interface foo() and a protected implementation do_foo().  I
could avoid changing other back-ends and testfile.cc if I used the
normal convention but I follow the local convention in the
Sized_target class.

The patch was tested on x86_64 and ARM Linux with the full gold test suite.

-Doug

2010-05-25  Doug Kwan  <dougkwan@google.com>

        * arm.cc (Arm_scan_relocatable_relocs): New class.
        (Target_arm::relocate_special_relocatable): New method.
        (Arm_relocate_functions::arm_branch_common): Handle relocatable link.
        (Arm_relocate_functions::thumb_branch_common): Same.
        (Target_arm::scan_relocatable_relocs): Use Arm_scan_relocatable_relocs
        instead of Default_scan_relocatable_relocs.
        * i386.cc (Target_i386::relocate_special_relocatable): New method.
        * powerpc.cc (Target_powerpc::relocate_special_relocatable): Same.
        * sparc.cc (Target_sparc::relocate_speical_relocatable): Same.
        * target-reloc.h (relocate_for_relocatable): Let target handle
        relocation strategy Relocatable_relocs::RELOC_SPECIAL.
        * target.h (Sized_target::relocate_special_relocatable): New method.
        * x86_64.cc (Target_x86_64::relocate_special_relocatable): Same.
        * testsuite/testfile.cc (Target_test::relocate_special_relocatable):
        Same.
-------------- next part --------------
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.105
diff -u -u -p -r1.105 arm.cc
--- gold/arm.cc	23 May 2010 07:43:39 -0000	1.105
+++ gold/arm.cc	25 May 2010 03:07:54 -0000
@@ -1956,6 +1956,79 @@ class Arm_output_data_got : public Outpu
   std::vector<Static_reloc> static_relocs_;
 };
 
+// The ARM target has many relocation types with odd-sizes or incontigious
+// bits.  The default handling of relocatable relocation cannot process these
+// relocations.  So we have to extend the default code.
+
+template<bool big_endian, int sh_type, typename Classify_reloc>
+class Arm_scan_relocatable_relocs :
+  public Default_scan_relocatable_relocs<sh_type, Classify_reloc>
+{
+ public:
+  // Return the strategy to use for a local symbol which is a section
+  // symbol, given the relocation type.
+  inline Relocatable_relocs::Reloc_strategy
+  local_section_strategy(unsigned int r_type, Relobj*)
+  {
+    if (sh_type == elfcpp::SHT_RELA)
+      return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
+    else
+      {
+	if (r_type == elfcpp::R_ARM_TARGET1
+	    || r_type == elfcpp::R_ARM_TARGET2)
+	  {
+	    const Target_arm<big_endian>* arm_target =
+	      Target_arm<big_endian>::default_target();
+	    r_type = arm_target->get_real_reloc_type(r_type);
+	  }
+
+	switch(r_type)
+	  {
+	  // Relocations that write nothing.  These exclude R_ARM_TARGET1
+	  // and R_ARM_TARGET2.
+	  case elfcpp::R_ARM_NONE:
+	  case elfcpp::R_ARM_V4BX:
+	  case elfcpp::R_ARM_TLS_GOTDESC:
+	  case elfcpp::R_ARM_TLS_CALL:
+	  case elfcpp::R_ARM_TLS_DESCSEQ:
+	  case elfcpp::R_ARM_THM_TLS_CALL:
+	  case elfcpp::R_ARM_GOTRELAX:
+	  case elfcpp::R_ARM_GNU_VTENTRY:
+	  case elfcpp::R_ARM_GNU_VTINHERIT:
+	  case elfcpp::R_ARM_THM_TLS_DESCSEQ16:
+	  case elfcpp::R_ARM_THM_TLS_DESCSEQ32:
+	    return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0;
+	  // These should have been converted to something else above.
+	  case elfcpp::R_ARM_TARGET1:
+	  case elfcpp::R_ARM_TARGET2:
+	    gold_unreachable();
+	  // Relocations that write full 32 bits.
+	  case elfcpp::R_ARM_ABS32:
+	  case elfcpp::R_ARM_REL32:
+	  case elfcpp::R_ARM_SBREL32:
+	  case elfcpp::R_ARM_GOTOFF32:
+	  case elfcpp::R_ARM_BASE_PREL:
+	  case elfcpp::R_ARM_GOT_BREL:
+	  case elfcpp::R_ARM_BASE_ABS:
+	  case elfcpp::R_ARM_ABS32_NOI:
+	  case elfcpp::R_ARM_REL32_NOI:
+	  case elfcpp::R_ARM_PLT32_ABS:
+	  case elfcpp::R_ARM_GOT_ABS:
+	  case elfcpp::R_ARM_GOT_PREL:
+	  case elfcpp::R_ARM_TLS_GD32:
+	  case elfcpp::R_ARM_TLS_LDM32:
+	  case elfcpp::R_ARM_TLS_LDO32:
+	  case elfcpp::R_ARM_TLS_IE32:
+	  case elfcpp::R_ARM_TLS_LE32:
+	    return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4;
+	  default:
+	    // For all other static relocations, return RELOC_SPECIAL.
+	    return Relocatable_relocs::RELOC_SPECIAL;
+	  }
+      }
+  }
+};
+
 // Utilities for manipulating integers of up to 32-bits
 
 namespace utils
@@ -2189,6 +2262,21 @@ class Target_arm : public Sized_target<3
 			   unsigned char* reloc_view,
 			   section_size_type reloc_view_size);
 
+  // Perform target-specific processing in a relocatable link.  This is
+  // only used if we use the relocation strategy RELOC_SPECIAL.
+  void
+  relocate_special_relocatable(const Relocate_info<32, big_endian>* relinfo,
+			       unsigned int sh_type,
+			       const unsigned char* preloc_in,
+			       size_t relnum,
+			       Output_section* output_section,
+			       off_t offset_in_output_section,
+			       unsigned char* view,
+			       typename elfcpp::Elf_types<32>::Elf_Addr
+				 view_address,
+			       section_size_type view_size,
+			       unsigned char* preloc_out);
+ 
   // Return whether SYM is defined by the ABI.
   bool
   do_is_defined_by_abi(Symbol* sym) const
@@ -3725,6 +3813,7 @@ Arm_relocate_functions<big_endian>::arm_
     Target_arm<big_endian>::default_target();
   if (is_weakly_undefined_without_plt)
     {
+      gold_assert(!parameters->options().relocatable());
       Valtype cond = val & 0xf0000000U;
       if (arm_target->may_use_arm_nop())
 	val = cond | 0x0320f000;
@@ -3742,8 +3831,11 @@ Arm_relocate_functions<big_endian>::arm_
   // to switch mode.
   bool may_use_blx = arm_target->may_use_blx();
   Reloc_stub* stub = NULL;
-  if (utils::has_overflow<26>(branch_offset)
-      || ((thumb_bit != 0) && !(may_use_blx && r_type == elfcpp::R_ARM_CALL)))
+
+  if (!parameters->options().relocatable()
+      && (utils::has_overflow<26>(branch_offset)
+	  || ((thumb_bit != 0)
+	      && !(may_use_blx && r_type == elfcpp::R_ARM_CALL))))
     {
       Valtype unadjusted_branch_target = psymval->value(object, 0);
 
@@ -3850,6 +3942,7 @@ Arm_relocate_functions<big_endian>::thum
     Target_arm<big_endian>::default_target();
   if (is_weakly_undefined_without_plt)
     {
+      gold_assert(!parameters->options().relocatable());
       if (arm_target->may_use_thumb2_nop())
 	{
 	  elfcpp::Swap<16, big_endian>::writeval(wv, 0xf3af);
@@ -3876,11 +3969,12 @@ Arm_relocate_functions<big_endian>::thum
   // We need a stub if the branch offset is too large or if we need
   // to switch mode.
   bool thumb2 = arm_target->using_thumb2();
-  if ((!thumb2 && utils::has_overflow<23>(branch_offset))
-      || (thumb2 && utils::has_overflow<25>(branch_offset))
-      || ((thumb_bit == 0)
-          && (((r_type == elfcpp::R_ARM_THM_CALL) && !may_use_blx)
-	      || r_type == elfcpp::R_ARM_THM_JUMP24)))
+  if (!parameters->options().relocatable()
+      && ((!thumb2 && utils::has_overflow<23>(branch_offset))
+	  || (thumb2 && utils::has_overflow<25>(branch_offset))
+	  || ((thumb_bit == 0)
+	      && (((r_type == elfcpp::R_ARM_THM_CALL) && !may_use_blx)
+		  || r_type == elfcpp::R_ARM_THM_JUMP24))))
     {
       Arm_address unadjusted_branch_target = psymval->value(object, 0);
 
@@ -8919,7 +9013,7 @@ Target_arm<big_endian>::scan_relocatable
 {
   gold_assert(sh_type == elfcpp::SHT_REL);
 
-  typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_REL,
+  typedef Arm_scan_relocatable_relocs<big_endian, elfcpp::SHT_REL,
     Relocatable_size_for_reloc> Scan_relocatable_relocs;
 
   gold::scan_relocatable_relocs<32, big_endian, elfcpp::SHT_REL,
@@ -8971,6 +9065,291 @@ Target_arm<big_endian>::relocate_for_rel
     reloc_view_size);
 }
 
+// Perform target-specific processing in a relocatable link.  This is
+// only used if we use the relocation strategy RELOC_SPECIAL.
+
+template<bool big_endian>
+void
+Target_arm<big_endian>::relocate_special_relocatable(
+    const Relocate_info<32, big_endian>* relinfo,
+    unsigned int sh_type,
+    const unsigned char* preloc_in,
+    size_t relnum,
+    Output_section* output_section,
+    off_t offset_in_output_section,
+    unsigned char* view,
+    elfcpp::Elf_types<32>::Elf_Addr view_address,
+    section_size_type,
+    unsigned char* preloc_out)
+{
+  // We can only handle REL type relocation sections.
+  gold_assert(sh_type == elfcpp::SHT_REL);
+
+  typedef typename Reloc_types<elfcpp::SHT_REL, 32, big_endian>::Reloc Reltype;
+  typedef typename Reloc_types<elfcpp::SHT_REL, 32, big_endian>::Reloc_write
+    Reltype_write;
+  const Arm_address invalid_address = static_cast<Arm_address>(0) - 1;
+
+  const Arm_relobj<big_endian>* object =
+    Arm_relobj<big_endian>::as_arm_relobj(relinfo->object);
+  const unsigned int local_count = object->local_symbol_count();
+
+  Reltype reloc(preloc_in);
+  Reltype_write reloc_write(preloc_out);
+
+  elfcpp::Elf_types<32>::Elf_WXword r_info = reloc.get_r_info();
+  const unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
+  const unsigned int r_type = elfcpp::elf_r_type<32>(r_info);
+
+  const Arm_reloc_property* arp =
+    arm_reloc_property_table->get_implemented_static_reloc_property(r_type);
+  gold_assert(arp != NULL);
+
+  // Get the new symbol index.
+  // We only use RELOC_SPECIAL strategy in local relocations.
+  gold_assert(r_sym < local_count);
+
+  // We are adjusting a section symbol.  We need to find
+  // the symbol table index of the section symbol for
+  // the output section corresponding to input section
+  // in which this symbol is defined.
+  bool is_ordinary;
+  unsigned int shndx = object->local_symbol_input_shndx(r_sym, &is_ordinary);
+  gold_assert(is_ordinary);
+  Output_section* os = object->output_section(shndx);
+  gold_assert(os != NULL);
+  gold_assert(os->needs_symtab_index());
+  unsigned int new_symndx = os->symtab_index();
+
+  // Get the new offset--the location in the output section where
+  // this relocation should be applied.
+
+  Arm_address offset = reloc.get_r_offset();
+  Arm_address new_offset;
+  if (offset_in_output_section != invalid_address)
+    new_offset = offset + offset_in_output_section;
+  else
+    {
+      section_offset_type sot_offset =
+          convert_types<section_offset_type, Arm_address>(offset);
+      section_offset_type new_sot_offset =
+          output_section->output_offset(object, relinfo->data_shndx,
+                                        sot_offset);
+      gold_assert(new_sot_offset != -1);
+      new_offset = new_sot_offset;
+    }
+
+  // In an object file, r_offset is an offset within the section.
+  // In an executable or dynamic object, generated by
+  // --emit-relocs, r_offset is an absolute address.
+  if (!parameters->options().relocatable())
+    {
+      new_offset += view_address;
+      if (offset_in_output_section != invalid_address)
+        new_offset -= offset_in_output_section;
+    }
+
+  reloc_write.put_r_offset(new_offset);
+  reloc_write.put_r_info(elfcpp::elf_r_info<32>(new_symndx, r_type));
+
+  // Handle the reloc addend.
+  // The relocation uses a section symbol in the input file.
+  // We are adjusting it to use a section symbol in the output
+  // file.  The input section symbol refers to some address in
+  // the input section.  We need the relocation in the output
+  // file to refer to that same address.  This adjustment to
+  // the addend is the same calculation we use for a simple
+  // absolute relocation for the input section symbol.
+
+  const Symbol_value<32>* psymval = object->local_symbol(r_sym);
+
+  // Handle THUMB bit.
+  Symbol_value<32> symval;
+  Arm_address thumb_bit =
+     object->local_symbol_is_thumb_function(r_sym) ? 1 : 0;
+  if (thumb_bit != 0
+      && arp->uses_thumb_bit() 
+      && ((psymval->value(object, 0) & 1) != 0))
+    {
+      Arm_address stripped_value =
+	psymval->value(object, 0) & ~static_cast<Arm_address>(1);
+      symval.set_output_value(stripped_value);
+      psymval = &symval;
+    } 
+
+  unsigned char* paddend = view + offset;
+  typename Arm_relocate_functions<big_endian>::Status reloc_status =
+	Arm_relocate_functions<big_endian>::STATUS_OKAY;
+  switch (r_type)
+    {
+    case elfcpp::R_ARM_ABS8:
+      reloc_status = Arm_relocate_functions<big_endian>::abs8(paddend, object,
+							      psymval);
+      break;
+
+    case elfcpp::R_ARM_ABS12:
+      reloc_status = Arm_relocate_functions<big_endian>::abs12(paddend, object,
+							       psymval);
+      break;
+
+    case elfcpp::R_ARM_ABS16:
+      reloc_status = Arm_relocate_functions<big_endian>::abs16(paddend, object,
+							       psymval);
+      break;
+
+    case elfcpp::R_ARM_THM_ABS5:
+      reloc_status = Arm_relocate_functions<big_endian>::thm_abs5(paddend,
+								  object,
+								  psymval);
+      break;
+
+    case elfcpp::R_ARM_MOVW_ABS_NC:
+    case elfcpp::R_ARM_MOVW_PREL_NC:
+    case elfcpp::R_ARM_MOVW_BREL_NC:
+    case elfcpp::R_ARM_MOVW_BREL:
+      reloc_status = Arm_relocate_functions<big_endian>::movw(
+	  paddend, object, psymval, 0, thumb_bit, arp->checks_overflow());
+      break;
+
+    case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+    case elfcpp::R_ARM_THM_MOVW_PREL_NC:
+    case elfcpp::R_ARM_THM_MOVW_BREL_NC:
+    case elfcpp::R_ARM_THM_MOVW_BREL:
+      reloc_status = Arm_relocate_functions<big_endian>::thm_movw(
+	  paddend, object, psymval, 0, thumb_bit, arp->checks_overflow());
+      break;
+
+    case elfcpp::R_ARM_THM_CALL:
+    case elfcpp::R_ARM_THM_XPC22:
+    case elfcpp::R_ARM_THM_JUMP24:
+      reloc_status =
+	Arm_relocate_functions<big_endian>::thumb_branch_common(
+	    r_type, relinfo, paddend, NULL, object, 0, psymval, 0, thumb_bit,
+	    false);
+      break;
+
+    case elfcpp::R_ARM_PLT32:
+    case elfcpp::R_ARM_CALL:
+    case elfcpp::R_ARM_JUMP24:
+    case elfcpp::R_ARM_XPC25:
+      reloc_status =
+    	Arm_relocate_functions<big_endian>::arm_branch_common(
+	    r_type, relinfo, paddend, NULL, object, 0, psymval, 0, thumb_bit,
+	    false);
+      break;
+
+    case elfcpp::R_ARM_THM_JUMP19:
+      reloc_status =
+	Arm_relocate_functions<big_endian>::thm_jump19(paddend, object,
+						       psymval, 0, thumb_bit);
+      break;
+
+    case elfcpp::R_ARM_THM_JUMP6:
+      reloc_status =
+	Arm_relocate_functions<big_endian>::thm_jump6(paddend, object, psymval,
+						      0);
+      break;
+
+    case elfcpp::R_ARM_THM_JUMP8:
+      reloc_status =
+	Arm_relocate_functions<big_endian>::thm_jump8(paddend, object, psymval,
+						      0);
+      break;
+
+    case elfcpp::R_ARM_THM_JUMP11:
+      reloc_status =
+	Arm_relocate_functions<big_endian>::thm_jump11(paddend, object, psymval,
+						       0);
+      break;
+
+    case elfcpp::R_ARM_PREL31:
+      reloc_status =
+	Arm_relocate_functions<big_endian>::prel31(paddend, object, psymval, 0,
+						   thumb_bit);
+      break;
+
+    case elfcpp::R_ARM_THM_PC8:
+      reloc_status =
+	Arm_relocate_functions<big_endian>::thm_pc8(paddend, object, psymval,
+						    0);
+      break;
+
+    case elfcpp::R_ARM_THM_PC12:
+      reloc_status =
+	Arm_relocate_functions<big_endian>::thm_pc12(paddend, object, psymval,
+						     0);
+      break;
+
+    case elfcpp::R_ARM_THM_ALU_PREL_11_0:
+      reloc_status =
+	Arm_relocate_functions<big_endian>::thm_alu11(paddend, object, psymval,
+						      0, thumb_bit);
+      break;
+
+    // These relocation truncate relocation results so we cannot handle them
+    // in a relocatable link.
+    case elfcpp::R_ARM_MOVT_ABS:
+    case elfcpp::R_ARM_THM_MOVT_ABS:
+    case elfcpp::R_ARM_MOVT_PREL:
+    case elfcpp::R_ARM_MOVT_BREL:
+    case elfcpp::R_ARM_THM_MOVT_PREL:
+    case elfcpp::R_ARM_THM_MOVT_BREL:
+    case elfcpp::R_ARM_ALU_PC_G0_NC:
+    case elfcpp::R_ARM_ALU_PC_G0:
+    case elfcpp::R_ARM_ALU_PC_G1_NC:
+    case elfcpp::R_ARM_ALU_PC_G1:
+    case elfcpp::R_ARM_ALU_PC_G2:
+    case elfcpp::R_ARM_ALU_SB_G0_NC:
+    case elfcpp::R_ARM_ALU_SB_G0:
+    case elfcpp::R_ARM_ALU_SB_G1_NC:
+    case elfcpp::R_ARM_ALU_SB_G1:
+    case elfcpp::R_ARM_ALU_SB_G2:
+    case elfcpp::R_ARM_LDR_PC_G0:
+    case elfcpp::R_ARM_LDR_PC_G1:
+    case elfcpp::R_ARM_LDR_PC_G2:
+    case elfcpp::R_ARM_LDR_SB_G0:
+    case elfcpp::R_ARM_LDR_SB_G1:
+    case elfcpp::R_ARM_LDR_SB_G2:
+    case elfcpp::R_ARM_LDRS_PC_G0:
+    case elfcpp::R_ARM_LDRS_PC_G1:
+    case elfcpp::R_ARM_LDRS_PC_G2:
+    case elfcpp::R_ARM_LDRS_SB_G0:
+    case elfcpp::R_ARM_LDRS_SB_G1:
+    case elfcpp::R_ARM_LDRS_SB_G2:
+    case elfcpp::R_ARM_LDC_PC_G0:
+    case elfcpp::R_ARM_LDC_PC_G1:
+    case elfcpp::R_ARM_LDC_PC_G2:
+    case elfcpp::R_ARM_LDC_SB_G0:
+    case elfcpp::R_ARM_LDC_SB_G1:
+    case elfcpp::R_ARM_LDC_SB_G2:
+      gold_error(_("cannot handle %s in a relocatable link"),
+		 arp->name().c_str());
+      break;
+
+    default:
+      gold_unreachable();
+    }
+
+  // Report any errors.
+  switch (reloc_status)
+    {
+    case Arm_relocate_functions<big_endian>::STATUS_OKAY:
+      break;
+    case Arm_relocate_functions<big_endian>::STATUS_OVERFLOW:
+      gold_error_at_location(relinfo, relnum, reloc.get_r_offset(),
+			     _("relocation overflow in %s"),
+			     arp->name().c_str());
+      break;
+    case Arm_relocate_functions<big_endian>::STATUS_BAD_RELOC:
+      gold_error_at_location(relinfo, relnum, reloc.get_r_offset(),
+	_("unexpected opcode while processing relocation %s"),
+	arp->name().c_str());
+      break;
+    default:
+      gold_unreachable();
+    }
+}
+
 // Return the value to use for a dynamic symbol which requires special
 // treatment.  This is how we support equality comparisons of function
 // pointers across shared library boundaries, as described in the
Index: gold/i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.117
diff -u -u -p -r1.117 i386.cc
--- gold/i386.cc	11 Mar 2010 01:18:26 -0000	1.117
+++ gold/i386.cc	25 May 2010 03:07:54 -0000
@@ -149,6 +149,19 @@ class Target_i386 : public Target_freebs
 			   unsigned char* reloc_view,
 			   section_size_type reloc_view_size);
 
+  // Perform target-specific relocation in a relocatable link.
+  void
+  relocate_special_relocatable(const Relocate_info<32, false>*,
+			       unsigned int, const unsigned char*, size_t,
+			       Output_section*, off_t, unsigned char*,
+			       elfcpp::Elf_types<32>::Elf_Addr,
+			       section_size_type, unsigned char*)
+  {
+    // On this target, everything is done by target-indendepent code. 
+    // We should not come here.
+    gold_unreachable();
+  }
+
   // Return a string used to fill a code section with nops.
   std::string
   do_code_fill(section_size_type length) const;
Index: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.29
diff -u -u -p -r1.29 powerpc.cc
--- gold/powerpc.cc	13 Feb 2010 02:04:20 -0000	1.29
+++ gold/powerpc.cc	25 May 2010 03:07:54 -0000
@@ -142,6 +142,19 @@ class Target_powerpc : public Sized_targ
 			   unsigned char* reloc_view,
 			   section_size_type reloc_view_size);
 
+  // Perform target-specific relocation in a relocatable link.
+  void
+  relocate_special_relocatable(const Relocate_info<size, big_endian>*,
+			       unsigned int, const unsigned char*, size_t,
+			       Output_section*, off_t, unsigned char*,
+			       typename elfcpp::Elf_types<size>::Elf_Addr,
+			       section_size_type, unsigned char*)
+  {
+    // On this target, everything is done by target-indendepent code. 
+    // We should not come here.
+    gold_unreachable();
+  }
+
   // Return whether SYM is defined by the ABI.
   bool
   do_is_defined_by_abi(const Symbol* sym) const
Index: gold/sparc.cc
===================================================================
RCS file: /cvs/src/src/gold/sparc.cc,v
retrieving revision 1.38
diff -u -u -p -r1.38 sparc.cc
--- gold/sparc.cc	10 Mar 2010 17:07:26 -0000	1.38
+++ gold/sparc.cc	25 May 2010 03:07:55 -0000
@@ -143,6 +143,20 @@ class Target_sparc : public Sized_target
 			   section_size_type view_size,
 			   unsigned char* reloc_view,
 			   section_size_type reloc_view_size);
+
+  // Perform target-specific relocation in a relocatable link.
+  void
+  relocate_special_relocatable(const Relocate_info<size, big_endian>*,
+			       unsigned int, const unsigned char*, size_t,
+			       Output_section*, off_t, unsigned char*,
+			       typename elfcpp::Elf_types<size>::Elf_Addr,
+			       section_size_type, unsigned char*)
+  {
+    // On this target, everything is done by target-indendepent code. 
+    // We should not come here.
+    gold_unreachable();
+  }
+
   // Return whether SYM is defined by the ABI.
   bool
   do_is_defined_by_abi(const Symbol* sym) const
Index: gold/target-reloc.h
===================================================================
RCS file: /cvs/src/src/gold/target-reloc.h,v
retrieving revision 1.41
diff -u -u -p -r1.41 target-reloc.h
--- gold/target-reloc.h	20 Apr 2010 21:13:30 -0000	1.41
+++ gold/target-reloc.h	25 May 2010 03:07:55 -0000
@@ -515,7 +515,7 @@ relocate_for_relocatable(
     const Relocatable_relocs* rr,
     unsigned char* view,
     typename elfcpp::Elf_types<size>::Elf_Addr view_address,
-    section_size_type,
+    section_size_type view_size,
     unsigned char* reloc_view,
     section_size_type reloc_view_size)
 {
@@ -537,6 +537,19 @@ relocate_for_relocatable(
       if (strategy == Relocatable_relocs::RELOC_DISCARD)
 	continue;
 
+      if (strategy == Relocatable_relocs::RELOC_SPECIAL)
+	{
+	  // Target wants to handle this relocation.
+	  Sized_target<size, big_endian>* target =
+	    parameters->sized_target<size, big_endian>();
+	  target->relocate_special_relocatable(relinfo, sh_type, prelocs,
+					       i, output_section,
+					       offset_in_output_section,
+					       view, view_address,
+					       view_size, pwrite);
+	  pwrite += reloc_size;
+	  continue;
+	}
       Reltype reloc(prelocs);
       Reltype_write reloc_write(pwrite);
 
Index: gold/target.h
===================================================================
RCS file: /cvs/src/src/gold/target.h,v
retrieving revision 1.47
diff -u -u -p -r1.47 target.h
--- gold/target.h	7 Apr 2010 21:42:22 -0000	1.47
+++ gold/target.h	25 May 2010 03:07:55 -0000
@@ -687,7 +687,23 @@ class Sized_target : public Target
 			   section_size_type view_size,
 			   unsigned char* reloc_view,
 			   section_size_type reloc_view_size) = 0;
+ 
+  // Perform target-specific processing in a relocatable link.  This is
+  // only used if we use the relocation strategy RELOC_SPECIAL.
 
+  virtual void
+  relocate_special_relocatable(const Relocate_info<size, big_endian>* relinfo,
+			       unsigned int sh_type,
+			       const unsigned char* preloc_in,
+			       size_t relnum,
+			       Output_section* output_section,
+			       off_t offset_in_output_section,
+			       unsigned char* view,
+			       typename elfcpp::Elf_types<size>::Elf_Addr
+				 view_address,
+			       section_size_type view_size,
+			       unsigned char* preloc_out) = 0;
+ 
  protected:
   Sized_target(const Target::Target_info* pti)
     : Target(pti)
Index: gold/x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.108
diff -u -u -p -r1.108 x86_64.cc
--- gold/x86_64.cc	20 Apr 2010 21:13:30 -0000	1.108
+++ gold/x86_64.cc	25 May 2010 03:07:55 -0000
@@ -164,6 +164,19 @@ class Target_x86_64 : public Target_free
 			   unsigned char* reloc_view,
 			   section_size_type reloc_view_size);
 
+  // Perform target-specific relocation in a relocatable link.
+  void
+  relocate_special_relocatable(const Relocate_info<64, false>*,
+			       unsigned int, const unsigned char*, size_t,
+			       Output_section*, off_t, unsigned char*,
+			       elfcpp::Elf_types<64>::Elf_Addr,
+			       section_size_type, unsigned char*)
+  {
+    // On this target, everything is done by target-indendepent code. 
+    // We should not come here.
+    gold_unreachable();
+  }
+
   // Return a string used to fill a code section with nops.
   std::string
   do_code_fill(section_size_type length) const;
Index: gold/testsuite/testfile.cc
===================================================================
RCS file: /cvs/src/src/gold/testsuite/testfile.cc,v
retrieving revision 1.18
diff -u -u -p -r1.18 testfile.cc
--- gold/testsuite/testfile.cc	6 Dec 2009 02:49:46 -0000	1.18
+++ gold/testsuite/testfile.cc	25 May 2010 03:07:55 -0000
@@ -62,6 +62,15 @@ class Target_test : public Sized_target<
 		   section_size_type, const Reloc_symbol_changes*)
   { ERROR("call to Target_test::relocate_section"); }
 
+
+  void
+  relocate_special_relocatable(const Relocate_info<size, big_endian>*,
+			       unsigned int, const unsigned char*, size_t,
+			       Output_section*, off_t, unsigned char*,
+			       typename elfcpp::Elf_types<size>::Elf_Addr,
+			       section_size_type, unsigned char*)
+  { ERROR("call to Target_test::relocate_special_relocatable"); }
+
   void
   scan_relocatable_relocs(Symbol_table*, Layout*,
 			  Sized_relobj<size, big_endian>*, unsigned int,


More information about the Binutils mailing list