[PATCH][GOLD] Add Cortex-A8 stub class.

Doug Kwan (關振德) dougkwan@google.com
Thu Jan 7 01:38:00 GMT 2010


Hi,

    This patch mainly adds a class to represent Cortex-A8 stubs.  Rest
of the stub machinery was also changed a little.  The do_write method
in the Stub base class is no longer pure virtual.  I moved the
relevant code from Reloc_stub to the base class.  The code was
extended to handle a new conditional branch instruction template used
in one of the Cortex-A8 stub template.  Now both the Reloc_stub and
the Cortex_a8_stub classes share the stub-writing code in the base
class via inheritance.  I also found a bug in the
Stub_factory::Stub_factory due to a missing "static" storage class
specifier.

-Doug

2010-01-06  Doug Kwan  <dougkwan@google.com>

        * arm.cc (Insn_template::Type): New enum value THUMB16_SPECIAL_TYPE.
        (Insn_template::thumb16_bcond_insn): New method declaration.
        (Insn_template): Fix spelling.
        (Stub::thumb16_special): New method declaration.
        (Stub::do_write): Define virtual method which was previously pure
        virtual.
        (Stub::do_thumb16_special): New method declaration.
        (Stub::do_fixed_endian_write): New template member.
        (Reloc_stub::do_write): Remove.
        (Reloc_stub::do_fixed_endian_write): Remove.
        (Cortex_a8_stub): New class definition.
        (Stub_factory::make_cortex_a8_stub): New method definition.
        (Stub_factory::Stub_factory): Add missing static storage class
        specifier for elf32_arm_stub_a8_veneer_blx.
-------------- next part --------------
? gold/.arm.cc.swp
? gold/autom4te.cache
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.46
diff -u -p -r1.46 arm.cc
--- gold/arm.cc	30 Dec 2009 06:57:17 -0000	1.46
+++ gold/arm.cc	7 Jan 2010 01:29:48 -0000
@@ -137,22 +137,23 @@ class Insn_template
   enum Type
     {
       THUMB16_TYPE = 1,
+      THUMB16_SPECIAL_TYPE,
       THUMB32_TYPE,
       ARM_TYPE,
       DATA_TYPE
     };
 
-  // Factory methods to create instrunction templates in different formats.
+  // Factory methods to create instruction templates in different formats.
 
   static const Insn_template
   thumb16_insn(uint32_t data)
   { return Insn_template(data, THUMB16_TYPE, elfcpp::R_ARM_NONE, 0); } 
 
-  // A bit of a hack.  A Thumb conditional branch, in which the proper
-  // condition is inserted when we build the stub.
+  // A Thumb conditional branch, in which the proper condition is inserted
+  // when we build the stub.
   static const Insn_template
   thumb16_bcond_insn(uint32_t data)
-  { return Insn_template(data, THUMB16_TYPE, elfcpp::R_ARM_NONE, 1); } 
+  { return Insn_template(data, THUMB16_SPECIAL_TYPE, elfcpp::R_ARM_NONE, 1); } 
 
   static const Insn_template
   thumb32_insn(uint32_t data)
@@ -198,11 +199,11 @@ class Insn_template
   reloc_addend() const
   { return this->reloc_addend_; }
 
-  // Return size of instrunction template in bytes.
+  // Return size of instruction template in bytes.
   size_t
   size() const;
 
-  // Return byte-alignment of instrunction template.
+  // Return byte-alignment of instruction template.
   unsigned
   alignment() const;
 
@@ -410,16 +411,39 @@ class Stub
   write(unsigned char* view, section_size_type view_size, bool big_endian)
   { this->do_write(view, view_size, big_endian); }
 
+  // Return the instruction for THUMB16_SPECIAL_TYPE instruction template
+  // for the i-th instruction.
+  uint16_t
+  thumb16_special(size_t i)
+  { return this->do_thumb16_special(i); }
+
  protected:
   // This must be defined in the child class.
   virtual Arm_address
   do_reloc_target(size_t) = 0;
 
-  // This must be defined in the child class.
+  // This may be overridden in the child class.
   virtual void
-  do_write(unsigned char*, section_size_type, bool) = 0;
+  do_write(unsigned char* view, section_size_type view_size, bool big_endian)
+  {
+    if (big_endian)
+      this->do_fixed_endian_write<true>(view, view_size);
+    else
+      this->do_fixed_endian_write<false>(view, view_size);
+  }
   
+  // This must be overridden if a child class uses the THUMB16_SPECIAL_TYPE
+  // instruction template.
+  virtual uint16_t
+  do_thumb16_special(size_t)
+  { gold_unreachable(); }
+
  private:
+  // A template to implement do_write.
+  template<bool big_endian>
+  void inline
+  do_fixed_endian_write(unsigned char*, section_size_type);
+
   // Its template.
   const Stub_template* stub_template_;
   // Offset within the section of containing this stub.
@@ -594,7 +618,6 @@ class Reloc_stub : public Stub
 
   friend class Stub_factory;
 
- private:
   // Return the relocation target address of the i-th relocation in the
   // stub.
   Arm_address
@@ -605,17 +628,115 @@ class Reloc_stub : public Stub
     return this->destination_address_;
   }
 
-  // A template to implement do_write below.
-  template<bool big_endian>
-  void inline
-  do_fixed_endian_write(unsigned char*, section_size_type);
+ private:
+  // Address of destination.
+  Arm_address destination_address_;
+};
 
-  // Write a stub.
-  void
-  do_write(unsigned char* view, section_size_type view_size, bool big_endian);
+// Cortex-A8 stub class.  We need a Cortex-A8 stub to redirect any 32-bit
+// THUMB branch that meets the following conditions:
+// 
+// 1. The branch straddles across a page boundary. i.e. lower 12-bit of
+//    branch address is 0xffe.
+// 2. The branch target address in the same page as the first word of the
+//    branch.
+// 3. The branc is follows a 32-bit instruction which is not a branch.
+//
+// To do the fix up, we need to store address of the branch instruction
+// and its target at least.  We also need to store the original branch
+// instruction bits for the condition code in a conditional branch.  The
+// condition code is used in a special instruction template.  We also want
+// to identify input sections needing Cortex-A8 workaround quickly.  We store
+// extra information about object and section index of the code section
+// containing a branch being fixed up.  The information is used to mark
+// the code section when we finalize the Cortex-A8 stubs.
+//
 
-  // Address of destination.
+class Cortex_a8_stub : public Stub
+{
+ public:
+  ~Cortex_a8_stub()
+  { }
+
+  // Return the object of the code section containing the branch being fixed
+  // up.
+  Relobj*
+  relobj() const
+  { return this->relobj_; }
+
+  // Retun the section index of the code section containing the branch being
+  // fixed up.
+  unsigned int
+  shndx() const
+  { return this->shndx_; }
+
+  // Return the source address of stub.  This is the address of the original
+  // branch instruction.  LSB is 1 always set to indicate that it is a THUMB
+  // instruction.
+  Arm_address
+  source_address() const
+  { return this->source_address_; }
+
+  // Return the destination address of the stub.  This is the branch taken
+  // address of the original branch instruction.  LSB is 1 if it is a THUMB
+  // instruction address.
+  Arm_address
+  destination_address() const
+  { return this->destination_address_; }
+
+  // Return the instruction being fixed up.
+  uint32_t
+  original_insn() const
+  { return this->original_insn_; }
+
+ protected:
+  // Cortex_a8_stubs are created via a stub factory.  So these are protected.
+  Cortex_a8_stub(const Stub_template* stub_template, Relobj* relobj,
+		 unsigned int shndx, Arm_address source_address,
+		 Arm_address destination_address, uint32_t original_insn)
+    : Stub(stub_template), relobj_(relobj), shndx_(shndx),
+      source_address_(source_address | 1U),
+      destination_address_(destination_address),
+      original_insn_(original_insn)
+  { }
+
+  friend class Stub_factory;
+
+  // Return the relocation target address of the i-th relocation in the
+  // stub.
+  Arm_address
+  do_reloc_target(size_t i)
+  {
+    if (this->stub_template()->type() == arm_stub_a8_veneer_b_cond)
+      {
+        // The conditional branch veneer has two relocations.
+        gold_assert(i < 2);
+	return i == 0 ? this->source_address_ + 4 : this->destination_address_;
+      }
+    else
+      {
+        // All other Cortex-A8 stubs have only one relocation.
+        gold_assert(i == 0);
+        return this->destination_address_;
+      }
+  }
+
+  // Return an instruction for the THUMB16_SPECIAL instruction template.
+  uint16_t
+  do_thumb16_special(size_t);
+
+ private:
+  // Object of the code section containing the branch being fixed up.
+  Relobj* relobj_;
+  // Section index of the code section containing the branch begin fixed up.
+  unsigned int shndx_;
+  // Source address of original branch.
+  Arm_address source_address_;
+  // Destination address of the original branch.
   Arm_address destination_address_;
+  // Original branch instruction.  This is needed for copying the condition
+  // code from a condition branch to its stub.
+  uint32_t original_insn_;
 };
 
 // Stub factory class.
@@ -640,6 +761,18 @@ class Stub_factory
     return new Reloc_stub(this->stub_templates_[stub_type]);
   }
 
+  // Make a Cortex-A8 stub.
+  Cortex_a8_stub*
+  make_cortex_a8_stub(Stub_type stub_type, Relobj* relobj, unsigned int shndx,
+		      Arm_address source, Arm_address destination,
+		      uint32_t original_insn) const
+  {
+    gold_assert(stub_type >= arm_stub_cortex_a8_first
+		&& stub_type <= arm_stub_cortex_a8_last);
+    return new Cortex_a8_stub(this->stub_templates_[stub_type], relobj, shndx,
+			      source, destination, original_insn);
+  }
+
  private:
   // Constructor and destructor are protected since we only return a single
   // instance created in Stub_factory::get_instance().
@@ -2728,6 +2861,51 @@ Stub_template::Stub_template(
   this->size_ = offset;
 }
 
+// Stub methods.
+
+// Template to implement do_write for a specific target endianity.
+
+template<bool big_endian>
+void inline
+Stub::do_fixed_endian_write(unsigned char* view, section_size_type view_size)
+{
+  const Stub_template* stub_template = this->stub_template();
+  const Insn_template* insns = stub_template->insns();
+
+  // FIXME:  We do not handle BE8 encoding yet.
+  unsigned char* pov = view;
+  for (size_t i = 0; i < stub_template->insn_count(); i++)
+    {
+      switch (insns[i].type())
+	{
+	case Insn_template::THUMB16_TYPE:
+	  elfcpp::Swap<16, big_endian>::writeval(pov, insns[i].data() & 0xffff);
+	  break;
+	case Insn_template::THUMB16_SPECIAL_TYPE:
+	  elfcpp::Swap<16, big_endian>::writeval(
+	      pov,
+	      this->thumb16_special(i));
+	  break;
+	case Insn_template::THUMB32_TYPE:
+	  {
+	    uint32_t hi = (insns[i].data() >> 16) & 0xffff;
+	    uint32_t lo = insns[i].data() & 0xffff;
+	    elfcpp::Swap<16, big_endian>::writeval(pov, hi);
+	    elfcpp::Swap<16, big_endian>::writeval(pov + 2, lo);
+	  }
+          break;
+	case Insn_template::ARM_TYPE:
+	case Insn_template::DATA_TYPE:
+	  elfcpp::Swap<32, big_endian>::writeval(pov, insns[i].data());
+	  break;
+	default:
+	  gold_unreachable();
+	}
+      pov += insns[i].size();
+    }
+  gold_assert(static_cast<section_size_type>(pov - view) == view_size);
+} 
+
 // Reloc_stub::Key methods.
 
 // Dump a Key as a string for debugging.
@@ -2934,57 +3112,23 @@ Reloc_stub::stub_type_for_reloc(
   return stub_type;
 }
 
-// Template to implement do_write for a specific target endianity.
-
-template<bool big_endian>
-void inline
-Reloc_stub::do_fixed_endian_write(unsigned char* view,
-				  section_size_type view_size)
-{
-  const Stub_template* stub_template = this->stub_template();
-  const Insn_template* insns = stub_template->insns();
-
-  // FIXME:  We do not handle BE8 encoding yet.
-  unsigned char* pov = view;
-  for (size_t i = 0; i < stub_template->insn_count(); i++)
-    {
-      switch (insns[i].type())
-	{
-	case Insn_template::THUMB16_TYPE:
-	  // Non-zero reloc addends are only used in Cortex-A8 stubs. 
-	  gold_assert(insns[i].reloc_addend() == 0);
-	  elfcpp::Swap<16, big_endian>::writeval(pov, insns[i].data() & 0xffff);
-	  break;
-	case Insn_template::THUMB32_TYPE:
-	  {
-	    uint32_t hi = (insns[i].data() >> 16) & 0xffff;
-	    uint32_t lo = insns[i].data() & 0xffff;
-	    elfcpp::Swap<16, big_endian>::writeval(pov, hi);
-	    elfcpp::Swap<16, big_endian>::writeval(pov + 2, lo);
-	  }
-          break;
-	case Insn_template::ARM_TYPE:
-	case Insn_template::DATA_TYPE:
-	  elfcpp::Swap<32, big_endian>::writeval(pov, insns[i].data());
-	  break;
-	default:
-	  gold_unreachable();
-	}
-      pov += insns[i].size();
-    }
-  gold_assert(static_cast<section_size_type>(pov - view) == view_size);
-} 
+// Cortex_a8_stub methods.
 
-// Write a reloc stub to VIEW with endianity specified by BIG_ENDIAN.
+// Return the instruction for a THUMB16_SPECIAL_TYPE instruction template.
+// I is the position of the instruction template in the stub template.
 
-void
-Reloc_stub::do_write(unsigned char* view, section_size_type view_size,
-		     bool big_endian)
+uint16_t
+Cortex_a8_stub::do_thumb16_special(size_t i)
 {
-  if (big_endian)
-    this->do_fixed_endian_write<true>(view, view_size);
-  else
-    this->do_fixed_endian_write<false>(view, view_size);
+  // The only use of this is to copy condition code from a conditional
+  // branch being worked around to the corresponding conditional branch in
+  // to the stub.
+  gold_assert(this->stub_template()->type() == arm_stub_a8_veneer_b_cond
+	      && i == 0);
+  uint16_t data = this->stub_template()->insns()[i].data();
+  gold_assert((data & 0xff00U) == 0xd000U);
+  data |= ((this->original_insn_ >> 22) & 0xf) << 8;
+  return data;
 }
 
 // Stub_factory methods.
@@ -3162,7 +3306,7 @@ Stub_factory::Stub_factory()
   // Stub used for Thumb-2 blx.w instructions.  We modified the original blx.w
   // instruction (which switches to ARM mode) to point to this stub.  Jump to
   // the real destination using an ARM-mode branch.
-  const Insn_template elf32_arm_stub_a8_veneer_blx[] =
+  static const Insn_template elf32_arm_stub_a8_veneer_blx[] =
     {
       Insn_template::arm_rel_insn(0xea000000, -8)	// b dest
     };


More information about the Binutils mailing list