* options.h (General_options): Add --toc-sort/--no-toc-sort.
[deliverable/binutils-gdb.git] / gold / powerpc.cc
index 3d54577c6288fdfa9e5d4d7c971cb3b10848418d..edd48e707d91e7039a615286a9de1cd9bb61eaf9 100644 (file)
@@ -71,7 +71,8 @@ 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), opd_ent_(), access_from_map_()
+      special_(0), has_small_toc_reloc_(false), opd_valid_(false),
+      opd_ent_(), access_from_map_(), has14_(), stub_table_()
   { }
 
   ~Powerpc_relobj()
@@ -226,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)
   {
@@ -280,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
@@ -2067,6 +2080,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
            return;
          to = symval.value(this->object_, 0);
        }
+      to += this->addend_;
       if (stub_table == NULL)
        stub_table = this->object_->stub_table(this->shndx_);
       gold_assert(stub_table != NULL);
@@ -4688,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.
@@ -5124,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.
@@ -5344,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>
@@ -5397,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>());
+           }
        }
     }
 
@@ -6061,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);
@@ -6086,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);
@@ -6940,7 +7018,8 @@ class Target_selector_powerpc : public Target_selector
 {
 public:
   Target_selector_powerpc()
-    : Target_selector(elfcpp::EM_NONE, size, big_endian,
+    : Target_selector(size == 64 ? elfcpp::EM_PPC64 : elfcpp::EM_PPC,
+                     size, big_endian,
                      (size == 64
                       ? (big_endian ? "elf64-powerpc" : "elf64-powerpcle")
                       : (big_endian ? "elf32-powerpc" : "elf32-powerpcle")),
@@ -6949,28 +7028,6 @@ public:
                       : (big_endian ? "elf32ppc" : "elf32lppc")))
   { }
 
-  virtual Target*
-  do_recognize(Input_file*, off_t, int machine, int, int)
-  {
-    switch (size)
-      {
-      case 64:
-       if (machine != elfcpp::EM_PPC64)
-         return NULL;
-       break;
-
-      case 32:
-       if (machine != elfcpp::EM_PPC)
-         return NULL;
-       break;
-
-      default:
-       return NULL;
-      }
-
-    return this->instantiate_target();
-  }
-
   virtual Target*
   do_instantiate_target()
   { return new Target_powerpc<size, big_endian>(); }
This page took 0.02542 seconds and 4 git commands to generate.