* powerpc.cc: Formatting and white space.
authorAlan Modra <amodra@gmail.com>
Sat, 18 Aug 2012 11:12:50 +0000 (11:12 +0000)
committerAlan Modra <amodra@gmail.com>
Sat, 18 Aug 2012 11:12:50 +0000 (11:12 +0000)
(Powerpc_relobj): Rename got2_section_ to special_.
Add opd_ent_shndx_ and opd_ent_off_ vectors.
(Powerpc_relobj::opd_shndx, init_opd, get_opd_ent, set_opd_ent,
scan_opd_relocs, do_read_relocs, opd_ent_ndx): New functions.
(Target_powerpc): Add Address typedef and invalid_address.  Use
throughout.
(Target_powerpc::is_branch_reloc): New function.
(Powerpc_relocate_functions): Add Address typedef, use throughout.
(Powerpc_relocate_functions:rela, rela_ua): Correct type used
for dst_mask, value and addend.
(Powerpc_relobj::do_find_special_sections): Find .opd for 64-bit.
(ld_2_1, cror_15_15_15, cror_31_31_31): New insn constants.
(Output_data_glink::do_write): Correct toc base.  Don't try to use
uint16_t for 24-bit offset.  Use get_output_section_offset and
check return.
(Target_powerpc::Scan::local): Handle more relocs.
(Target_powerpc::do_finalize_sections): Set up DT_PPC64_GLINK.
(Target_powerpc::Relocate::relocate): Correct toc base calculation.
Plug in toc restoring insn after plt calls.  Translate branches
to function descriptor symbols to corresponding entry point.
(Target_powerpc::relocate_for_relocatable): Check return from
get_output_section_offset.
* symtab.h: Comment typo.

gold/ChangeLog
gold/powerpc.cc
gold/symtab.h

index 8d97813361153188625f678f7d275744fac937f8..86a688979a3500da44b0db6ae1cc42f7cc50fed6 100644 (file)
@@ -1,3 +1,30 @@
+2012-08-18  Alan Modra  <amodra@gmail.com>
+
+       * powerpc.cc: Formatting and white space.
+       (Powerpc_relobj): Rename got2_section_ to special_.
+       Add opd_ent_shndx_ and opd_ent_off_ vectors.
+       (Powerpc_relobj::opd_shndx, init_opd, get_opd_ent, set_opd_ent,
+       scan_opd_relocs, do_read_relocs, opd_ent_ndx): New functions.
+       (Target_powerpc): Add Address typedef and invalid_address.  Use
+       throughout.
+       (Target_powerpc::is_branch_reloc): New function.
+       (Powerpc_relocate_functions): Add Address typedef, use throughout.
+       (Powerpc_relocate_functions:rela, rela_ua): Correct type used
+       for dst_mask, value and addend.
+       (Powerpc_relobj::do_find_special_sections): Find .opd for 64-bit.
+       (ld_2_1, cror_15_15_15, cror_31_31_31): New insn constants.
+       (Output_data_glink::do_write): Correct toc base.  Don't try to use
+       uint16_t for 24-bit offset.  Use get_output_section_offset and
+       check return.
+       (Target_powerpc::Scan::local): Handle more relocs.
+       (Target_powerpc::do_finalize_sections): Set up DT_PPC64_GLINK.
+       (Target_powerpc::Relocate::relocate): Correct toc base calculation.
+       Plug in toc restoring insn after plt calls.  Translate branches
+       to function descriptor symbols to corresponding entry point.
+       (Target_powerpc::relocate_for_relocatable): Check return from
+       get_output_section_offset.
+       * symtab.h: Comment typo.
+
 2012-08-14  Ian Lance Taylor  <iant@google.com>
 
        * x86_64.cc (Target_x86_64::Scan::global): Fix erroneous call to
index 35cf83476dc7cc271e402525bbbbf33483014a43..b104b68f8465733d54881b526fd96498fc62d2dc 100644 (file)
@@ -57,29 +57,106 @@ template<int size, bool big_endian>
 class Powerpc_relobj : public Sized_relobj_file<size, big_endian>
 {
 public:
+  typedef typename elfcpp::Elf_types<size>::Elf_Off Offset;
+
   Powerpc_relobj(const std::string& name, Input_file* input_file, off_t offset,
                 const typename elfcpp::Ehdr<size, big_endian>& ehdr)
     : Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr),
-      got2_section_(0)
+      special_(0), opd_ent_shndx_(), opd_ent_off_()
   { }
 
   ~Powerpc_relobj()
   { }
 
+  // The .got2 section shndx.
   unsigned int
   got2_shndx() const
   {
     if (size == 32)
-      return this->got2_section_;
+      return this->special_;
     else
       return 0;
   }
 
+  // The .opd section shndx.
+  unsigned int
+  opd_shndx() const
+  {
+    if (size == 32)
+      return 0;
+    else
+      return this->special_;
+  }
+
+  // Init OPD entry arrays.
+  void
+  init_opd(size_t opd_size)
+  {
+    size_t count = this->opd_ent_ndx(opd_size);
+    this->opd_ent_shndx_.resize(count);
+    this->opd_ent_off_.reserve(count);
+  }
+
+  // Return section and offset of function entry for .opd + R_OFF.
+  void
+  get_opd_ent(typename elfcpp::Elf_types<size>::Elf_Addr r_off,
+             unsigned int* shndx,
+             typename elfcpp::Elf_types<size>::Elf_Addr* value)
+  {
+    size_t ndx = this->opd_ent_ndx(r_off);
+    gold_assert(ndx < this->opd_ent_shndx_.size());
+    gold_assert(this->opd_ent_shndx_[ndx] != 0);
+    *shndx = this->opd_ent_shndx_[ndx];
+    *value = this->opd_ent_off_[ndx];
+  }
+
+  // Set section and offset of function entry for .opd + R_OFF.
+  void
+  set_opd_ent(typename elfcpp::Elf_types<size>::Elf_Addr r_off,
+             unsigned int shndx,
+             typename elfcpp::Elf_types<size>::Elf_Addr value)
+  {
+    size_t ndx = this->opd_ent_ndx(r_off);
+    gold_assert(ndx < this->opd_ent_shndx_.size());
+    this->opd_ent_shndx_[ndx] = shndx;
+    this->opd_ent_off_[ndx] = value;
+  }
+
+  // Examine .rela.opd to build info about function entry points.
+  void
+  scan_opd_relocs(size_t reloc_count,
+                 const unsigned char* prelocs,
+                 const unsigned char* plocal_syms);
+
+  void
+  do_read_relocs(Read_relocs_data*);
+
   bool
   do_find_special_sections(Read_symbols_data* sd);
 
 private:
-  unsigned int got2_section_;
+  // Return index into opd_ent_shndx or opd_ent_off array for .opd entry
+  // at OFF.  .opd entries are 24 bytes long, but they can be spaced
+  // 16 bytes apart when the language doesn't use the last 8-byte
+  // word, the environment pointer.  Thus dividing the entry section
+  // offset by 16 will give an index into opd_ent_shndx_ and
+  // opd_ent_off_ that works for either layout of .opd.  (It leaves
+  // some elements of the vectors unused when .opd entries are spaced
+  // 24 bytes apart, but we don't know the spacing until relocations
+  // are processed, and in any case it is possible for an object to
+  // have some entries spaced 16 bytes apart and others 24 bytes apart.)
+  size_t
+  opd_ent_ndx(size_t off) const
+  { return off >> 4;}
+
+  // For 32-bit the .got2 section shdnx, for 64-bit the .opd section shndx.
+  unsigned int special_;
+  // The first 8-byte word of an OPD entry gives the address of the
+  // entry point of the function.  Relocatable object files have a
+  // relocation on this word.  The following two vectors record the
+  // section and offset specified by these relocations.
+  std::vector<unsigned int> opd_ent_shndx_;
+  std::vector<Offset> opd_ent_off_;
 };
 
 template<int size, bool big_endian>
@@ -88,6 +165,8 @@ class Target_powerpc : public Sized_target<size, big_endian>
  public:
   typedef
     Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian> Reloc_section;
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+  static const Address invalid_address = static_cast<Address>(0) - 1;
 
   Target_powerpc()
     : Sized_target<size, big_endian>(&powerpc_info),
@@ -156,7 +235,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
                   Output_section* output_section,
                   bool needs_special_offset_handling,
                   unsigned char* view,
-                  typename elfcpp::Elf_types<size>::Elf_Addr view_address,
+                  Address view_address,
                   section_size_type view_size,
                   const Reloc_symbol_changes*);
 
@@ -185,7 +264,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
                           off_t offset_in_output_section,
                           const Relocatable_relocs*,
                           unsigned char*,
-                          typename elfcpp::Elf_types<size>::Elf_Addr,
+                          Address,
                           section_size_type,
                           unsigned char* reloc_view,
                           section_size_type reloc_view_size);
@@ -342,6 +421,19 @@ class Target_powerpc : public Sized_target<size, big_endian>
             typename elfcpp::Elf_types<size>::Elf_Addr,
             section_size_type);
 
+    inline bool
+    is_branch_reloc(unsigned int r_type) const
+    {
+      return (r_type == elfcpp::R_POWERPC_REL24
+             || r_type == elfcpp::R_POWERPC_REL14
+             || r_type == elfcpp::R_POWERPC_REL14_BRTAKEN
+             || r_type == elfcpp::R_POWERPC_REL14_BRNTAKEN
+             || r_type == elfcpp::R_POWERPC_ADDR24
+             || r_type == elfcpp::R_POWERPC_ADDR14
+             || r_type == elfcpp::R_POWERPC_ADDR14_BRTAKEN
+             || r_type == elfcpp::R_POWERPC_ADDR14_BRNTAKEN);
+    }
+
    private:
     // Do a TLS relocation.
     inline void
@@ -460,8 +552,8 @@ Target::Target_info Target_powerpc<32, true>::powerpc_info =
   0x10000000,          // default_text_segment_address
   64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
   4 * 1024,            // common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,               // isolate_execinstr
+  0,                   // rosegment_gap
   elfcpp::SHN_UNDEF,   // small_common_shndx
   elfcpp::SHN_UNDEF,   // large_common_shndx
   0,                   // small_common_section_flags
@@ -486,8 +578,8 @@ Target::Target_info Target_powerpc<32, false>::powerpc_info =
   0x10000000,          // default_text_segment_address
   64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
   4 * 1024,            // common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,               // isolate_execinstr
+  0,                   // rosegment_gap
   elfcpp::SHN_UNDEF,   // small_common_shndx
   elfcpp::SHN_UNDEF,   // large_common_shndx
   0,                   // small_common_section_flags
@@ -512,8 +604,8 @@ Target::Target_info Target_powerpc<64, true>::powerpc_info =
   0x10000000,          // default_text_segment_address
   64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
   8 * 1024,            // common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,               // isolate_execinstr
+  0,                   // rosegment_gap
   elfcpp::SHN_UNDEF,   // small_common_shndx
   elfcpp::SHN_UNDEF,   // large_common_shndx
   0,                   // small_common_section_flags
@@ -538,8 +630,8 @@ Target::Target_info Target_powerpc<64, false>::powerpc_info =
   0x10000000,          // default_text_segment_address
   64 * 1024,           // abi_pagesize (overridable by -z max-page-size)
   8 * 1024,            // common_pagesize (overridable by -z common-page-size)
-  false,                // isolate_execinstr
-  0,                    // rosegment_gap
+  false,               // isolate_execinstr
+  0,                   // rosegment_gap
   elfcpp::SHN_UNDEF,   // small_common_shndx
   elfcpp::SHN_UNDEF,   // large_common_shndx
   0,                   // small_common_section_flags
@@ -552,23 +644,25 @@ template<int size, bool big_endian>
 class Powerpc_relocate_functions
 {
 private:
+  typedef Powerpc_relocate_functions<size, big_endian> This;
+  typedef Relocate_functions<size, big_endian> This_reloc;
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+
   // Do a simple RELA relocation
   template<int valsize>
   static inline void
   rela(unsigned char* view,
        unsigned int right_shift,
-       elfcpp::Elf_Xword dst_mask,
-       typename elfcpp::Swap<size, big_endian>::Valtype value,
-       typename elfcpp::Swap<size, big_endian>::Valtype addend)
+       typename elfcpp::Valtype_base<valsize>::Valtype dst_mask,
+       Address value,
+       Address addend)
   {
     typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
     Valtype* wv = reinterpret_cast<Valtype*>(view);
     Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
     Valtype reloc = (value + addend) >> right_shift;
-
     val &= ~dst_mask;
     reloc &= dst_mask;
-
     elfcpp::Swap<valsize, big_endian>::writeval(wv, val | reloc);
   }
 
@@ -577,159 +671,173 @@ private:
   static inline void
   rela_ua(unsigned char* view,
          unsigned int right_shift,
-         elfcpp::Elf_Xword dst_mask,
-         typename elfcpp::Swap<size, big_endian>::Valtype value,
-         typename elfcpp::Swap<size, big_endian>::Valtype addend)
+         typename elfcpp::Valtype_base<valsize>::Valtype dst_mask,
+         Address value,
+         Address addend)
   {
-    typedef typename elfcpp::Swap_unaligned<valsize,
-                                           big_endian>::Valtype Valtype;
+    typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
+      Valtype;
     Valtype* wv = reinterpret_cast<Valtype*>(view);
     Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
     Valtype reloc = (value + addend) >> right_shift;
-
     val &= ~dst_mask;
     reloc &= dst_mask;
-
     elfcpp::Swap_unaligned<valsize, big_endian>::writeval(wv, val | reloc);
   }
 
-  typedef Powerpc_relocate_functions<size, big_endian> This;
-  typedef Relocate_functions<size, big_endian> This_reloc;
 public:
   // R_POWERPC_REL32: (Symbol + Addend - Address)
   static inline void
-  rel32(unsigned char* view,
-       typename elfcpp::Elf_types<size>::Elf_Addr value,
-       typename elfcpp::Elf_types<size>::Elf_Addr addend,
-       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  rel32(unsigned char* view, Address value, Address addend, Address address)
   { This_reloc::pcrela32(view, value, addend, address); }
 
   // R_POWERPC_REL24: (Symbol + Addend - Address) & 0x3fffffc
   static inline void
-  rel24(unsigned char* view,
-       typename elfcpp::Elf_types<size>::Elf_Addr value,
-       typename elfcpp::Elf_types<size>::Elf_Addr addend,
-       typename elfcpp::Elf_types<size>::Elf_Addr address)
-  {
-    This::template rela<32>(view, 0, 0x03fffffc, value - address, addend);
-  }
+  rel24(unsigned char* view, Address value, Address addend, Address address)
+  { This::template rela<32>(view, 0, 0x03fffffc, value - address, addend); }
 
   // R_POWERPC_REL14: (Symbol + Addend - Address) & 0xfffc
   static inline void
-  rel14(unsigned char* view,
-       typename elfcpp::Elf_types<size>::Elf_Addr value,
-       typename elfcpp::Elf_types<size>::Elf_Addr addend,
-       typename elfcpp::Elf_types<size>::Elf_Addr address)
-  {
-    This::template rela<32>(view, 0, 0xfffc, value - address, addend);
-  }
+  rel14(unsigned char* view, Address value, Address addend, Address address)
+  { This::template rela<32>(view, 0, 0xfffc, value - address, addend); }
 
   // R_POWERPC_ADDR16: (Symbol + Addend) & 0xffff
   static inline void
-  addr16(unsigned char* view,
-        typename elfcpp::Elf_types<size>::Elf_Addr value,
-        typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  addr16(unsigned char* view, Address value, Address addend)
   { This_reloc::rela16(view, value, addend); }
 
   // R_POWERPC_ADDR16_DS: (Symbol + Addend) & 0xfffc
   static inline void
-  addr16_ds(unsigned char* view,
-           typename elfcpp::Elf_types<size>::Elf_Addr value,
-           typename elfcpp::Elf_types<size>::Elf_Addr addend)
-  {
-    This::template rela<16>(view, 0, 0xfffc, value, addend);
-  }
+  addr16_ds(unsigned char* view, Address value, Address addend)
+  { This::template rela<16>(view, 0, 0xfffc, value, addend); }
 
   // R_POWERPC_ADDR16_LO: (Symbol + Addend) & 0xffff
   static inline void
-  addr16_lo(unsigned char* view,
-        typename elfcpp::Elf_types<size>::Elf_Addr value,
-        typename elfcpp::Elf_types<size>::Elf_Addr addend)
+  addr16_lo(unsigned char* view, Address value, Address addend)
   { This_reloc::rela16(view, value, addend); }
 
   // R_POWERPC_ADDR16_HI: ((Symbol + Addend) >> 16) & 0xffff
   static inline void
-  addr16_hi(unsigned char* view,
-           typename elfcpp::Elf_types<size>::Elf_Addr value,
-           typename elfcpp::Elf_types<size>::Elf_Addr addend)
-  {
-    This::template rela<16>(view, 16, 0xffff, value, addend);
-  }
+  addr16_hi(unsigned char* view, Address value, Address addend)
+  { This::template rela<16>(view, 16, 0xffff, value, addend); }
 
-  // R_POWERPC_ADDR16_HA: Same as R_POWERPC_ADDR16_HI except that if the
-  //                      final value of the low 16 bits of the
-  //                      relocation is negative, add one.
+  // R_POWERPC_ADDR16_HA: ((Symbol + Addend + 0x8000) >> 16) & 0xffff
   static inline void
-  addr16_ha(unsigned char* view,
-           typename elfcpp::Elf_types<size>::Elf_Addr value,
-           typename elfcpp::Elf_types<size>::Elf_Addr addend)
-  {
-    This::addr16_hi(view, value + 0x8000, addend);
-  }
+  addr16_ha(unsigned char* view, Address value, Address addend)
+  { This::addr16_hi(view, value + 0x8000, addend); }
 
   // R_POWERPC_REL16: (Symbol + Addend - Address) & 0xffff
   static inline void
-  rel16(unsigned char* view,
-       typename elfcpp::Elf_types<size>::Elf_Addr value,
-       typename elfcpp::Elf_types<size>::Elf_Addr addend,
-       typename elfcpp::Elf_types<size>::Elf_Addr address)
+  rel16(unsigned char* view, Address value, Address addend, Address address)
   { This_reloc::pcrela16(view, value, addend, address); }
 
   // R_POWERPC_REL16_LO: (Symbol + Addend - Address) & 0xffff
   static inline void
-  rel16_lo(unsigned char* view,
-          typename elfcpp::Elf_types<size>::Elf_Addr value,
-          typename elfcpp::Elf_types<size>::Elf_Addr addend,
-          typename elfcpp::Elf_types<size>::Elf_Addr address)
+  rel16_lo(unsigned char* view, Address value, Address addend, Address address)
   { This_reloc::pcrela16(view, value, addend, address); }
 
   // R_POWERPC_REL16_HI: ((Symbol + Addend - Address) >> 16) & 0xffff
   static inline void
-  rel16_hi(unsigned char* view,
-          typename elfcpp::Elf_types<size>::Elf_Addr value,
-          typename elfcpp::Elf_types<size>::Elf_Addr addend,
-          typename elfcpp::Elf_types<size>::Elf_Addr address)
-  {
-    This::template rela<16>(view, 16, 0xffff, value - address, addend);
-  }
+  rel16_hi(unsigned char* view, Address value, Address addend, Address address)
+  { This::template rela<16>(view, 16, 0xffff, value - address, addend); }
 
-  // R_POWERPC_REL16_HA: Same as R_POWERPC_REL16_HI except that if the
-  //                 final value of the low 16 bits of the
-  //                 relocation is negative, add one.
+  // R_POWERPC_REL16_HA: ((Symbol + Addend + 0x8000 - Address) >> 16) & 0xffff
   static inline void
-  rel16_ha(unsigned char* view,
-          typename elfcpp::Elf_types<size>::Elf_Addr value,
-          typename elfcpp::Elf_types<size>::Elf_Addr addend,
-          typename elfcpp::Elf_types<size>::Elf_Addr address)
-  {
-    This::rel16_hi(view, value + 0x8000, addend, address);
-  }
+  rel16_ha(unsigned char* view, Address value, Address addend, Address address)
+  { This::rel16_hi(view, value + 0x8000, addend, address); }
 };
 
-// Stash away the index of .got2 in a relocatable object, if such
-// a section exists.
+// Stash away the index of .got2 or .opd in a relocatable object, if
+// such a section exists.
 
 template<int size, bool big_endian>
 bool
 Powerpc_relobj<size, big_endian>::do_find_special_sections(
     Read_symbols_data* sd)
 {
-  if (size == 32)
+  const unsigned char* const pshdrs = sd->section_headers->data();
+  const unsigned char* namesu = sd->section_names->data();
+  const char* names = reinterpret_cast<const char*>(namesu);
+  section_size_type names_size = sd->section_names_size;
+  const unsigned char* s;
+
+  s = this->find_shdr(pshdrs, size == 32 ? ".got2" : ".opd",
+                     names, names_size, NULL);
+  if (s != NULL)
+    {
+      unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
+      this->special_ = ndx;
+    }
+  return Sized_relobj_file<size, big_endian>::do_find_special_sections(sd);
+}
+
+// Examine .rela.opd to build info about function entry points.
+
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::scan_opd_relocs(
+    size_t reloc_count,
+    const unsigned char* prelocs,
+    const unsigned char* plocal_syms)
+{
+  if (size == 64)
     {
-      const unsigned char* const pshdrs = sd->section_headers->data();
-      const unsigned char* namesu = sd->section_names->data();
-      const char* names = reinterpret_cast<const char*>(namesu);
-      section_size_type names_size = sd->section_names_size;
-      const unsigned char* s;
-
-      s = this->find_shdr(pshdrs, ".got2", names, names_size, NULL);
-      if (s != NULL)
+      typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+       Reltype;
+      const int reloc_size
+       = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
+      const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+      for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
        {
-         unsigned int ndx = (s - pshdrs) / elfcpp::Elf_sizes<size>::shdr_size;
-         this->got2_section_ = ndx;
+         Reltype reloc(prelocs);
+         typename elfcpp::Elf_types<size>::Elf_WXword r_info
+           = reloc.get_r_info();
+         unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+         if (r_type == elfcpp::R_PPC64_ADDR64)
+           {
+             unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+             typename elfcpp::Elf_types<size>::Elf_Addr value;
+             bool is_ordinary;
+             unsigned int shndx;
+             if (r_sym < this->local_symbol_count())
+               {
+                 typename elfcpp::Sym<size, big_endian>
+                   lsym(plocal_syms + r_sym * sym_size);
+                 shndx = lsym.get_st_shndx();
+                 shndx = this->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
+                 value = lsym.get_st_value();
+               }
+             else
+               shndx = this->symbol_section_and_value(r_sym, &value,
+                                                      &is_ordinary);
+             this->set_opd_ent(reloc.get_r_offset(), shndx,
+                               value + reloc.get_r_addend());
+           }
+       }
+    }
+}
+
+template<int size, bool big_endian>
+void
+Powerpc_relobj<size, big_endian>::do_read_relocs(Read_relocs_data* rd)
+{
+  Sized_relobj_file<size, big_endian>::do_read_relocs(rd);
+  if (size == 64)
+    {
+      for (Read_relocs_data::Relocs_list::iterator p = rd->relocs.begin();
+          p != rd->relocs.end();
+          ++p)
+       {
+         if (p->data_shndx == this->opd_shndx())
+           {
+             this->init_opd(this->section_size(this->opd_shndx()));
+             this->scan_opd_relocs(p->reloc_count, p->contents->data(),
+                                   rd->local_symbols->data());
+             break;
+           }
        }
     }
-  return Sized_relobj_file<size, big_endian>::do_find_special_sections(sd);
 }
 
 // Set up PowerPC target specific relobj.
@@ -745,21 +853,20 @@ Target_powerpc<size, big_endian>::do_make_elf_object(
   if (et == elfcpp::ET_REL)
     {
       Powerpc_relobj<size, big_endian>* obj =
-        new Powerpc_relobj<size, big_endian>(name, input_file, offset, ehdr);
+       new Powerpc_relobj<size, big_endian>(name, input_file, offset, ehdr);
       obj->setup();
       return obj;
     }
   else if (et == elfcpp::ET_DYN)
     {
       Sized_dynobj<size, big_endian>* obj =
-        new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
+       new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
       obj->setup();
       return obj;
     }
   else
     {
-      gold_error(_("%s: unsupported ELF file type %d"),
-                 name.c_str(), et);
+      gold_error(_("%s: unsupported ELF file type %d"), name.c_str(), et);
       return NULL;
     }
 }
@@ -1013,45 +1120,48 @@ Output_data_plt_powerpc<size, big_endian>::add_entry(Symbol* gsym)
     }
 }
 
-static const uint32_t addis_11_11       = 0x3d6b0000;
-static const uint32_t addis_11_30       = 0x3d7e0000;
-static const uint32_t addis_12_12       = 0x3d8c0000;
-static const uint32_t addi_11_11        = 0x396b0000;
-static const uint32_t add_0_11_11       = 0x7c0b5a14;
-static const uint32_t add_11_0_11       = 0x7d605a14;
-static const uint32_t b                 = 0x48000000;
-static const uint32_t bcl_20_31         = 0x429f0005;
-static const uint32_t bctr              = 0x4e800420;
-static const uint32_t blrl              = 0x4e800021;
-static const uint32_t lis_11            = 0x3d600000;
-static const uint32_t lis_12            = 0x3d800000;
-static const uint32_t lwzu_0_12         = 0x840c0000;
-static const uint32_t lwz_0_12          = 0x800c0000;
-static const uint32_t lwz_11_11         = 0x816b0000;
-static const uint32_t lwz_11_30         = 0x817e0000;
-static const uint32_t lwz_12_12         = 0x818c0000;
-static const uint32_t mflr_0            = 0x7c0802a6;
-static const uint32_t mflr_12           = 0x7d8802a6;
-static const uint32_t mtctr_0           = 0x7c0903a6;
-static const uint32_t mtctr_11          = 0x7d6903a6;
-static const uint32_t mtlr_0            = 0x7c0803a6;
-static const uint32_t nop               = 0x60000000;
-static const uint32_t sub_11_11_12      = 0x7d6c5850;
-static const uint32_t addis_12_2        = 0x3d820000;
-static const uint32_t std_2_1           = 0xf8410000;
-static const uint32_t ld_11_12          = 0xe96c0000;
-static const uint32_t ld_2_12           = 0xe84c0000;
-static const uint32_t addi_12_12        = 0x398c0000;
-static const uint32_t ld_11_2           = 0xe9620000;
-static const uint32_t addi_2_2          = 0x38420000;
-static const uint32_t ld_2_2            = 0xe8420000;
-static const uint32_t mflr_11           = 0x7d6802a6;
-static const uint32_t ld_2_11           = 0xe84b0000;
-static const uint32_t mtlr_12           = 0x7d8803a6;
-static const uint32_t add_12_2_11       = 0x7d825a14;
-static const uint32_t li_0_0            = 0x38000000;
-static const uint32_t lis_0_0           = 0x3c000000;
-static const uint32_t ori_0_0_0         = 0x60000000;
+static const uint32_t addis_11_11      = 0x3d6b0000;
+static const uint32_t addis_11_30      = 0x3d7e0000;
+static const uint32_t addis_12_12      = 0x3d8c0000;
+static const uint32_t addi_11_11       = 0x396b0000;
+static const uint32_t add_0_11_11      = 0x7c0b5a14;
+static const uint32_t add_11_0_11      = 0x7d605a14;
+static const uint32_t b                        = 0x48000000;
+static const uint32_t bcl_20_31                = 0x429f0005;
+static const uint32_t bctr             = 0x4e800420;
+static const uint32_t blrl             = 0x4e800021;
+static const uint32_t lis_11           = 0x3d600000;
+static const uint32_t lis_12           = 0x3d800000;
+static const uint32_t lwzu_0_12                = 0x840c0000;
+static const uint32_t lwz_0_12         = 0x800c0000;
+static const uint32_t lwz_11_11                = 0x816b0000;
+static const uint32_t lwz_11_30                = 0x817e0000;
+static const uint32_t lwz_12_12                = 0x818c0000;
+static const uint32_t mflr_0           = 0x7c0802a6;
+static const uint32_t mflr_12          = 0x7d8802a6;
+static const uint32_t mtctr_0          = 0x7c0903a6;
+static const uint32_t mtctr_11         = 0x7d6903a6;
+static const uint32_t mtlr_0           = 0x7c0803a6;
+static const uint32_t nop              = 0x60000000;
+static const uint32_t sub_11_11_12     = 0x7d6c5850;
+static const uint32_t addis_12_2       = 0x3d820000;
+static const uint32_t std_2_1          = 0xf8410000;
+static const uint32_t ld_2_1           = 0xe8410000;
+static const uint32_t ld_11_12         = 0xe96c0000;
+static const uint32_t ld_2_12          = 0xe84c0000;
+static const uint32_t addi_12_12       = 0x398c0000;
+static const uint32_t ld_11_2          = 0xe9620000;
+static const uint32_t addi_2_2         = 0x38420000;
+static const uint32_t ld_2_2           = 0xe8420000;
+static const uint32_t mflr_11          = 0x7d6802a6;
+static const uint32_t ld_2_11          = 0xe84b0000;
+static const uint32_t mtlr_12          = 0x7d8803a6;
+static const uint32_t add_12_2_11      = 0x7d825a14;
+static const uint32_t li_0_0           = 0x38000000;
+static const uint32_t lis_0_0          = 0x3c000000;
+static const uint32_t ori_0_0_0                = 0x60000000;
+static const uint32_t cror_15_15_15    = 0x4def7b82;
+static const uint32_t cror_31_31_31    = 0x4ffffb82;
 
 // Write out the PLT.
 
@@ -1121,6 +1231,8 @@ template<int size, bool big_endian>
 class Output_data_glink : public Output_section_data
 {
  public:
+  static const int pltresolve_size = 16*4;
+
   Output_data_glink(Target_powerpc<size, big_endian>*);
 
   // Add an entry
@@ -1156,8 +1268,6 @@ class Output_data_glink : public Output_section_data
   { mapfile->print_output_data(this, _("** glink")); }
 
  private:
-  static const int pltresolve_size = 16*4;
-
   void
   set_final_data_size();
 
@@ -1171,7 +1281,7 @@ class Output_data_glink : public Output_section_data
     Glink_sym_ent(const Symbol* sym,
                  const elfcpp::Rela<size, big_endian>& reloc,
                  const Sized_relobj<size, big_endian>* object)
-      : sym_(sym), object_(0), addend_(0)
+      : sym_(sym), addend_(0), object_(0)
     {
       if (size != 32)
        this->addend_ = reloc.get_r_addend();
@@ -1185,16 +1295,16 @@ class Output_data_glink : public Output_section_data
        }
     }
 
-    const Symbol* sym_;
-    const Sized_relobj<size, big_endian>* object_;
-    unsigned int addend_;
-
     bool operator==(const Glink_sym_ent& that) const
     {
       return (this->sym_ == that.sym_
              && this->object_ == that.object_
              && this->addend_ == that.addend_);
     }
+
+    const Symbol* sym_;
+    unsigned int addend_;
+    const Sized_relobj<size, big_endian>* object_;
   };
 
   class Glink_sym_ent_hash
@@ -1314,7 +1424,7 @@ ha(uint32_t a)
 
 template<bool big_endian>
 static inline void
-write_insn(unsigned char *p, uint32_t v)
+write_insn(unsigned charp, uint32_t v)
 {
   elfcpp::Swap<32, big_endian>::writeval(p, v);
 }
@@ -1329,19 +1439,21 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
   const section_size_type oview_size =
     convert_to_section_size_type(this->data_size());
   unsigned char* const oview = of->get_output_view(off, oview_size);
-  unsigned char *p;
+  unsigned charp;
 
   // The base address of the .plt section.
   uint32_t plt_base = this->targ_->plt_section()->address();
 
   // The address of _GLOBAL_OFFSET_TABLE_.
-  const Output_data_got_powerpc<size, big_endian> *got;
+  const Output_data_got_powerpc<size, big_endian>got;
   typename elfcpp::Elf_types<size>::Elf_Addr g_o_t;
   got = this->targ_->got_section();
-  g_o_t = got->address() + got->g_o_t();
 
   if (size == 64)
     {
+      const unsigned int toc_base_offset = 0x8000;
+      g_o_t = got->output_section()->address() + toc_base_offset;
+
       // Write out call stubs.
       typename Glink_entries::const_iterator g;
       for (g = this->glink_entries_.begin();
@@ -1423,13 +1535,15 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
              write_insn<big_endian>(p, lis_0_0 + hi(indx)),            p += 4;
              write_insn<big_endian>(p, ori_0_0_0 + l(indx)),           p += 4;
            }
-         uint16_t branch_off = this->pltresolve_ + 8 - (p - oview);
+         uint32_t branch_off = this->pltresolve_ + 8 - (p - oview);
          write_insn<big_endian>(p, b + (branch_off & 0x3fffffc)),      p += 4;
          indx++;
        }
     }
   else
     {
+      g_o_t = got->address() + got->g_o_t();
+
       // Write out call stubs.
       typename Glink_entries::const_iterator g;
       for (g = this->glink_entries_.begin();
@@ -1438,6 +1552,7 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
        {
          uint32_t plt_addr = plt_base + g->first.sym_->plt_offset();
          uint32_t got_addr;
+         const uint32_t invalid_address = static_cast<uint32_t>(-1);
 
          p = oview + g->second * this->glink_entry_size();
          if (parameters->options().output_is_position_independent())
@@ -1447,9 +1562,10 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
              if (object != NULL)
                {
                  unsigned int got2 = object->got2_shndx();
-                 got_addr = (g->first.object_->output_section(got2)->address()
-                             + g->first.object_->output_section_offset(got2)
-                             + g->first.addend_);
+                 got_addr = g->first.object_->get_output_section_offset(got2);
+                 gold_assert(got_addr != invalid_address);
+                 got_addr += (g->first.object_->output_section(got2)->address()
+                              + g->first.addend_);
                }
              else
                got_addr = g_o_t;
@@ -1481,7 +1597,7 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
       // Write out pltresolve branch table.
       p = oview + this->pltresolve_;
       unsigned int the_end = oview_size - this->pltresolve_size;
-      unsigned char *end_p = oview + the_end;
+      unsigned charend_p = oview + the_end;
       while (p < end_p - 8 * 4)
        write_insn<big_endian>(p, b + end_p - p), p += 4;
       while (p < end_p)
@@ -1852,8 +1968,10 @@ Target_powerpc<size, big_endian>::Scan::local(
 
     case elfcpp::R_PPC64_ADDR64:
     case elfcpp::R_POWERPC_ADDR32:
-    case elfcpp::R_POWERPC_ADDR16_HA:
+    case elfcpp::R_POWERPC_ADDR16:
     case elfcpp::R_POWERPC_ADDR16_LO:
+    case elfcpp::R_POWERPC_ADDR16_HI:
+    case elfcpp::R_POWERPC_ADDR16_HA:
       // If building a shared library (or a position-independent
       // executable), we need to create a dynamic relocation for
       // this location.
@@ -1893,8 +2011,8 @@ Target_powerpc<size, big_endian>::Scan::local(
     case elfcpp::R_POWERPC_GOT16_HI:
     case elfcpp::R_POWERPC_GOT16_HA:
       {
-        // The symbol requires a GOT entry.
-        Output_data_got_powerpc<size, big_endian>* got;
+       // The symbol requires a GOT entry.
+       Output_data_got_powerpc<size, big_endian>* got;
        unsigned int r_sym;
 
        got = target->got_section(symtab, layout);
@@ -1985,16 +2103,16 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_PPC_LOCAL24PC:
       break;
 
+    case elfcpp::R_PPC64_ADDR64:
+    case elfcpp::R_POWERPC_ADDR32:
     case elfcpp::R_POWERPC_ADDR16:
     case elfcpp::R_POWERPC_ADDR16_LO:
     case elfcpp::R_POWERPC_ADDR16_HI:
     case elfcpp::R_POWERPC_ADDR16_HA:
-    case elfcpp::R_POWERPC_ADDR32:
-    case elfcpp::R_PPC64_ADDR64:
       {
-        // Make a PLT entry if necessary.
-        if (gsym->needs_plt_entry())
-          {
+       // Make a PLT entry if necessary.
+       if (gsym->needs_plt_entry())
+         {
            target->make_plt_entry(layout, gsym, reloc, 0);
            // Since this is not a PC-relative relocation, we may be
            // taking the address of a function. In that case we need to
@@ -2003,16 +2121,16 @@ Target_powerpc<size, big_endian>::Scan::global(
            if (size == 32
                && gsym->is_from_dynobj() && !parameters->options().shared())
              gsym->set_needs_dynsym_value();
-          }
-        // Make a dynamic relocation if necessary.
-        if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
-          {
-            if (gsym->may_need_copy_reloc())
-              {
-               target->copy_reloc(symtab, layout, object,
-                                  data_shndx, output_section, gsym, reloc);
-              }
-            else if ((r_type == elfcpp::R_POWERPC_ADDR32
+         }
+       // Make a dynamic relocation if necessary.
+       if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+         {
+           if (gsym->may_need_copy_reloc())
+             {
+               target->copy_reloc(symtab, layout, object,
+                                  data_shndx, output_section, gsym, reloc);
+             }
+           else if ((r_type == elfcpp::R_POWERPC_ADDR32
                      || r_type == elfcpp::R_PPC64_ADDR64)
                     && gsym->can_use_relative_reloc(false))
              {
@@ -2086,8 +2204,8 @@ Target_powerpc<size, big_endian>::Scan::global(
     case elfcpp::R_POWERPC_GOT16_HI:
     case elfcpp::R_POWERPC_GOT16_HA:
       {
-        // The symbol requires a GOT entry.
-        Output_data_got_powerpc<size, big_endian>* got;
+       // The symbol requires a GOT entry.
+       Output_data_got_powerpc<size, big_endian>* got;
 
        got = target->got_section(symtab, layout);
        if (gsym->final_value_is_known())
@@ -2261,13 +2379,21 @@ Target_powerpc<size, big_endian>::do_finalize_sections(
   layout->add_target_dynamic_tags(false, this->plt_, rel_plt,
                                  this->rela_dyn_, true, size == 32);
 
+  Output_data_dynamic* odyn = layout->dynamic_data();
   if (size == 32)
     {
       this->got_->finalize_data_size();
-      Output_data_dynamic* odyn = layout->dynamic_data();
       odyn->add_section_plus_offset(elfcpp::DT_PPC_GOT,
                                    this->got_, this->got_->g_o_t());
     }
+  else
+    {
+      this->glink_->finalize_data_size();
+      odyn->add_section_plus_offset(elfcpp::DT_PPC64_GLINK,
+                                   this->glink_,
+                                   (this->glink_->pltresolve()
+                                    + this->glink_->pltresolve_size - 32));
+    }
 
   // Emit any relocs we saved in an attempt to avoid generating COPY
   // relocs.
@@ -2289,14 +2415,14 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     const Sized_symbol<size>* gsym,
     const Symbol_value<size>* psymval,
     unsigned char* view,
-    typename elfcpp::Elf_types<size>::Elf_Addr address,
-    section_size_type /* view_size */)
+    Address address,
+    section_size_type view_size)
 {
   const unsigned int toc_base_offset = 0x8000;
   typedef Powerpc_relocate_functions<size, big_endian> Reloc;
   const Powerpc_relobj<size, big_endian>* const object
     = static_cast<const Powerpc_relobj<size, big_endian>*>(relinfo->object);
-  elfcpp::Elf_Xword value;
+  Address value;
 
   if (r_type == elfcpp::R_POWERPC_GOT16
       || r_type == elfcpp::R_POWERPC_GOT16_LO
@@ -2320,7 +2446,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     }
   else if (r_type == elfcpp::R_PPC64_TOC)
     {
-      value = target->got_section()->address() + toc_base_offset;
+      value = (target->got_section()->output_section()->address()
+              + toc_base_offset);
     }
   else if (gsym != NULL
           && (r_type == elfcpp::R_POWERPC_REL24
@@ -2332,13 +2459,54 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       glink = target->glink_section();
       unsigned int glink_index = glink->find_entry(gsym, rela, object);
       value = glink->address() + glink_index * glink->glink_entry_size();
+      if (size == 64)
+       {
+         typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
+         Valtype* wv = reinterpret_cast<Valtype*>(view);
+         bool can_plt_call = false;
+         if (rela.get_r_offset() + 8 <= view_size)
+           {
+             Valtype insn2 = elfcpp::Swap<32, big_endian>::readval(wv + 1);
+             if (insn2 == nop
+                 || insn2 == cror_15_15_15 || insn2 == cror_31_31_31)
+               {
+                 elfcpp::Swap<32, big_endian>::writeval(wv + 1, ld_2_1 + 40);
+                 can_plt_call = true;
+               }
+           }
+         if (!can_plt_call)
+           gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+                                  _("call lacks nop, can't restore toc"));
+       }
     }
   else
     {
-      elfcpp::Elf_Xword addend = 0;
+      typename elfcpp::Elf_types<size>::Elf_Swxword addend = 0;
       if (r_type != elfcpp::R_PPC_PLTREL24)
        addend = rela.get_r_addend();
       value = psymval->value(object, addend);
+      if (size == 64 && this->is_branch_reloc(r_type))
+       {
+         Powerpc_relobj<size, big_endian>* symobj = const_cast
+           <Powerpc_relobj<size, big_endian>*>(object);
+         if (gsym != NULL)
+           symobj = static_cast
+             <Powerpc_relobj<size, big_endian>*>(gsym->object());
+         unsigned int shndx = symobj->opd_shndx();
+         Address opd_addr = symobj->get_output_section_offset(shndx);
+         gold_assert(opd_addr != invalid_address);
+         opd_addr += symobj->output_section(shndx)->address();
+         if (value >= opd_addr
+             && value < opd_addr + symobj->section_size(shndx))
+           {
+             Address sec_off;
+             symobj->get_opd_ent(value - opd_addr, &shndx, &sec_off);
+             Address sec_addr = symobj->get_output_section_offset(shndx);
+             gold_assert(sec_addr != invalid_address);
+             sec_addr += symobj->output_section(shndx)->address();
+             value = sec_addr + sec_off;
+           }
+       }
     }
 
   switch (r_type)
@@ -2350,7 +2518,8 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
     case elfcpp::R_PPC64_TOC16_DS:
     case elfcpp::R_PPC64_TOC16_LO_DS:
       // Subtract the TOC base address.
-      value -= target->got_section()->address() + toc_base_offset;
+      value -= (target->got_section()->output_section()->address()
+               + toc_base_offset);
       break;
 
     case elfcpp::R_POWERPC_SECTOFF:
@@ -2487,14 +2656,14 @@ Target_powerpc<size, big_endian>::Relocate::relocate_tls(
     const Sized_symbol<size>* gsym,
     const Symbol_value<size>* psymval,
     unsigned char* view,
-    typename elfcpp::Elf_types<size>::Elf_Addr address,
+    Address address,
     section_size_type)
 {
   Output_segment* tls_segment = relinfo->layout->tls_segment();
   const Sized_relobj_file<size, big_endian>* object = relinfo->object;
 
-  const elfcpp::Elf_Xword addend = rela.get_r_addend();
-  typename elfcpp::Elf_types<size>::Elf_Addr value = psymval->value(object, 0);
+  const Address addend = rela.get_r_addend();
+  Address value = psymval->value(object, 0);
 
   const bool is_final =
     (gsym == NULL
@@ -2519,7 +2688,7 @@ Target_powerpc<size, big_endian>::relocate_section(
     Output_section* output_section,
     bool needs_special_offset_handling,
     unsigned char* view,
-    typename elfcpp::Elf_types<size>::Elf_Addr address,
+    Address address,
     section_size_type view_size,
     const Reloc_symbol_changes* reloc_symbol_changes)
 {
@@ -2622,29 +2791,30 @@ Target_powerpc<size, big_endian>::relocate_for_relocatable(
     off_t offset_in_output_section,
     const Relocatable_relocs* rr,
     unsigned char*,
-    typename elfcpp::Elf_types<size>::Elf_Addr,
+    Address,
     section_size_type,
     unsigned char* reloc_view,
     section_size_type reloc_view_size)
 {
   gold_assert(sh_type == elfcpp::SHT_RELA);
 
-  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
   typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
     Reltype;
   typedef typename Reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc_write
     Reltype_write;
   const int reloc_size
     = Reloc_types<elfcpp::SHT_RELA, size, big_endian>::reloc_size;
-  const Address invalid_address = static_cast<Address>(0) - 1;
 
   Powerpc_relobj<size, big_endian>* const object
     = static_cast<Powerpc_relobj<size, big_endian>*>(relinfo->object);
   const unsigned int local_count = object->local_symbol_count();
   unsigned int got2_shndx = object->got2_shndx();
-  typename elfcpp::Elf_types<size>::Elf_Swxword got2_addend = 0;
+  Address got2_addend = 0;
   if (got2_shndx != 0)
-    got2_addend = object->get_output_section_offset(got2_shndx);
+    {
+      got2_addend = object->get_output_section_offset(got2_shndx);
+      gold_assert(got2_addend != invalid_address);
+    }
 
   unsigned char* pwrite = reloc_view;
 
@@ -2716,13 +2886,13 @@ Target_powerpc<size, big_endian>::relocate_for_relocatable(
        new_offset = offset + offset_in_output_section;
       else
        {
-          section_offset_type sot_offset =
-              convert_types<section_offset_type, Address>(offset);
+         section_offset_type sot_offset =
+           convert_types<section_offset_type, Address>(offset);
          section_offset_type new_sot_offset =
-              output_section->output_offset(object, relinfo->data_shndx,
-                                            sot_offset);
+           output_section->output_offset(object, relinfo->data_shndx,
+                                         sot_offset);
          gold_assert(new_sot_offset != -1);
-          new_offset = new_sot_offset;
+         new_offset = new_sot_offset;
        }
 
       reloc_write.put_r_offset(new_offset);
index feed2458103420322b5a0b76e176494b00056451..f26d4b9e71d73b5a9c84fd5236e4b662e7a3c52d 100644 (file)
@@ -62,7 +62,7 @@ class Garbage_collection;
 class Icf;
 
 // The base class of an entry in the symbol table.  The symbol table
-// can have a lot of entries, so we don't want this class to big.
+// can have a lot of entries, so we don't want this class too big.
 // Size dependent fields can be found in the template class
 // Sized_symbol.  Targets may support their own derived classes.