* options.h (General_options): Add --toc-sort/--no-toc-sort.
authorAlan Modra <amodra@gmail.com>
Wed, 12 Dec 2012 03:41:40 +0000 (03:41 +0000)
committerAlan Modra <amodra@gmail.com>
Wed, 12 Dec 2012 03:41:40 +0000 (03:41 +0000)
Replace no_toc_optimize with toc_optimize.
* output.h (Output_section::input_sections): Provide non-const variant.
* powerpc.cc (Powerpc_relobj::has_small_toc_reloc_,
set_has_small_toc_reloc, has_small_toc_reloc): New variable and
accessors.
(Target_powerpc::Scan::local, global): Call set_has_small_toc_reloc.
(class Sort_toc_sections): New.
(Target_powerpc::do_finalize_sections): Sort toc sections.
(Target_powerpc::Relocate::relocate): Update toc_optimize test.

gold/ChangeLog
gold/options.h
gold/output.h
gold/powerpc.cc

index d11160af5be5a1a97acf645c7bb529ca8483c939..fb0d734df7dc17111000de0e89f0ef3976f79696 100644 (file)
@@ -1,3 +1,16 @@
+2012-12-12  Alan Modra  <amodra@gmail.com>
+
+       * options.h (General_options): Add --toc-sort/--no-toc-sort.
+       Replace no_toc_optimize with toc_optimize.
+       * output.h (Output_section::input_sections): Provide non-const variant.
+       * powerpc.cc (Powerpc_relobj::has_small_toc_reloc_,
+       set_has_small_toc_reloc, has_small_toc_reloc): New variable and
+       accessors.
+       (Target_powerpc::Scan::local, global): Call set_has_small_toc_reloc.
+       (class Sort_toc_sections): New.
+       (Target_powerpc::do_finalize_sections): Sort toc sections.
+       (Target_powerpc::Relocate::relocate): Update toc_optimize test.
+
 2012-12-10  Roland McGrath  <mcgrathr@google.com>
 
        * testsuite/binary_unittest.cc (read_all): New function.
index 1a25b7b070dc81906b31ac40fdedc2cf83ec1806..38f0c00ad2653bc05c9b30c45f07c5a0527934d7 100644 (file)
@@ -1109,8 +1109,13 @@ class General_options
   DEFINE_uint64(Ttext, options::ONE_DASH, '\0', -1U,
                 N_("Set the address of the text segment"), N_("ADDRESS"));
 
-  DEFINE_bool(no_toc_optimize, options::TWO_DASHES, '\0', false,
-             N_("(PowerPC64 only) Don't optimize TOC code sequences"), NULL);
+  DEFINE_bool(toc_optimize, options::TWO_DASHES, '\0', true,
+             N_("(PowerPC64 only) Optimize TOC code sequences"),
+             N_("(PowerPC64 only) Don't optimize TOC code sequences"));
+
+  DEFINE_bool(toc_sort, options::TWO_DASHES, '\0', true,
+             N_("(PowerPC64 only) Sort TOC and GOT sections"),
+             N_("(PowerPC64 only) Don't sort TOC and GOT sections"));
 
   DEFINE_set(undefined, options::TWO_DASHES, 'u',
             N_("Create undefined reference to SYMBOL"), N_("SYMBOL"));
index bd108bbd418f5d578f295afefeea9b05b5f9fdd1..a8fe59405b9c5d8fd253816d7f79e63e97bd96f0 100644 (file)
@@ -3941,6 +3941,10 @@ class Output_section : public Output_data
   input_sections() const
   { return this->input_sections_; }
 
+  Input_section_list&
+  input_sections()
+  { return this->input_sections_; }
+
  protected:
   // Return the output section--i.e., the object itself.
   Output_section*
index 32b7b70b8aaf710497bb1812204c6ac2b33a1258..edd48e707d91e7039a615286a9de1cd9bb61eaf9 100644 (file)
@@ -71,7 +71,7 @@ public:
   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),
-      special_(0), opd_valid_(false),
+      special_(0), has_small_toc_reloc_(false), opd_valid_(false),
       opd_ent_(), access_from_map_(), has14_(), stub_table_()
   { }
 
@@ -227,6 +227,14 @@ public:
   toc_base_offset() const
   { return 0x8000; }
 
+  void
+  set_has_small_toc_reloc()
+  { has_small_toc_reloc_ = true; }
+
+  bool
+  has_small_toc_reloc() const
+  { return has_small_toc_reloc_; }
+
   void
   set_has_14bit_branch(unsigned int shndx)
   {
@@ -281,6 +289,10 @@ private:
   // For 32-bit the .got2 section shdnx, for 64-bit the .opd section shndx.
   unsigned int special_;
 
+  // For 64-bit, whether this object uses small model relocs to access
+  // the toc.
+  bool has_small_toc_reloc_;
+
   // Set at the start of gc_process_relocs, when we know opd_ent_
   // vector is valid.  The flag could be made atomic and set in
   // do_read_relocs with memory_order_release and then tested with
@@ -4690,6 +4702,21 @@ Target_powerpc<size, big_endian>::Scan::local(
       unsupported_reloc_local(object, r_type);
       break;
     }
+
+  switch (r_type)
+    {
+    case elfcpp::R_POWERPC_GOT_TLSLD16:
+    case elfcpp::R_POWERPC_GOT_TLSGD16:
+    case elfcpp::R_POWERPC_GOT_TPREL16:
+    case elfcpp::R_POWERPC_GOT_DTPREL16:
+    case elfcpp::R_POWERPC_GOT16:
+    case elfcpp::R_PPC64_GOT16_DS:
+    case elfcpp::R_PPC64_TOC16:
+    case elfcpp::R_PPC64_TOC16_DS:
+      ppc_object->set_has_small_toc_reloc();
+    default:
+      break;
+    }
 }
 
 // Report an unsupported relocation against a global symbol.
@@ -5126,6 +5153,21 @@ Target_powerpc<size, big_endian>::Scan::global(
       unsupported_reloc_global(object, r_type, gsym);
       break;
     }
+
+  switch (r_type)
+    {
+    case elfcpp::R_POWERPC_GOT_TLSLD16:
+    case elfcpp::R_POWERPC_GOT_TLSGD16:
+    case elfcpp::R_POWERPC_GOT_TPREL16:
+    case elfcpp::R_POWERPC_GOT_DTPREL16:
+    case elfcpp::R_POWERPC_GOT16:
+    case elfcpp::R_PPC64_GOT16_DS:
+    case elfcpp::R_PPC64_TOC16:
+    case elfcpp::R_PPC64_TOC16_DS:
+      ppc_object->set_has_small_toc_reloc();
+    default:
+      break;
+    }
 }
 
 // Process relocations for gc.
@@ -5346,6 +5388,31 @@ Target_powerpc<size, big_endian>::define_save_restore_funcs(
     }
 }
 
+// Sort linker created .got section first (for the header), then input
+// sections belonging to files using small model code.
+
+template<bool big_endian>
+class Sort_toc_sections
+{
+ public:
+  bool
+  operator()(const Output_section::Input_section& is1,
+            const Output_section::Input_section& is2) const
+  {
+    if (!is1.is_input_section() && is2.is_input_section())
+      return true;
+    bool small1
+      = (is1.is_input_section()
+        && (static_cast<const Powerpc_relobj<64, big_endian>*>(is1.relobj())
+            ->has_small_toc_reloc()));
+    bool small2
+      = (is2.is_input_section()
+        && (static_cast<const Powerpc_relobj<64, big_endian>*>(is2.relobj())
+            ->has_small_toc_reloc()));
+    return small1 && !small2;
+  }
+};
+
 // Finalize the sections.
 
 template<int size, bool big_endian>
@@ -5399,6 +5466,15 @@ Target_powerpc<size, big_endian>::do_finalize_sections(
          // need to mess with the relaxation machinery checkpointing.
          this->got_section(symtab, layout);
          this->make_brlt_section(layout);
+
+         if (parameters->options().toc_sort())
+           {
+             Output_section* os = this->got_->output_section();
+             if (os != NULL && os->input_sections().size() > 1)
+               std::stable_sort(os->input_sections().begin(),
+                                os->input_sections().end(),
+                                Sort_toc_sections<big_endian>());
+           }
        }
     }
 
@@ -6063,7 +6139,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
        case elfcpp::R_POWERPC_GOT_DTPREL16_HA:
        case elfcpp::R_POWERPC_GOT16_HA:
        case elfcpp::R_PPC64_TOC16_HA:
-         if (!parameters->options().no_toc_optimize())
+         if (parameters->options().toc_optimize())
            {
              Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
              Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
@@ -6088,7 +6164,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
        case elfcpp::R_PPC64_GOT16_LO_DS:
        case elfcpp::R_PPC64_TOC16_LO:
        case elfcpp::R_PPC64_TOC16_LO_DS:
-         if (!parameters->options().no_toc_optimize())
+         if (parameters->options().toc_optimize())
            {
              Insn* iview = reinterpret_cast<Insn*>(view - 2 * big_endian);
              Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);