[GOLD] PowerPC64: Don't pretend to support multi-toc
authorAlan Modra <amodra@gmail.com>
Tue, 12 Oct 2021 09:15:13 +0000 (19:45 +1030)
committerAlan Modra <amodra@gmail.com>
Thu, 14 Oct 2021 02:38:46 +0000 (13:08 +1030)
Code in powerpc.cc is pretending to support a per-object toc pointer
value, but powerpc gold has no real support for multi-toc.  This patch
removes the pretense, tidying quite a lot in preparation for a
followup patch.  If multi-toc is ever to be supported, don't revert
this patch but start by adding object parameter to toc_pointer() and
an object to Branch_stub_key.

* powerpc.cc (Powerpc_relobj::toc_base_offset): Delete.
(Target_powerpc::toc_pointer): New function.  Use throughout.
(Target_powerpc::got_base_offset): New function.  Use throughout..
(Output_data_got_powerpc::got_base_offset): ..in place of
this.  Delete.
(Output_data_got_powerpc::Output_data_got_powerpc): Init
header_index_ to -1u for 64-bit, and make header here.
(Output_data_got_powerpc::set_final_data_size, reserve_ent): Don't
make 64-bit header here.
(Output_data_got_powerpc::g_o_t): Return toc pointer offset in
section for 64-bit.  Use throughout.
(Stub_table): Remove toc_base_off_ from Branch_stub_key, and
object param on add_long_branch_entry and find_long_branch_entry.
Adjust all uses.

gold/powerpc.cc

index 0cee975f8bd573abe532fd513106ee73480606f3..2d6d34e21e4dbf05f199abb9da435987592fddf0 100644 (file)
@@ -341,12 +341,6 @@ public:
        }
   }
 
-  // Return offset in output GOT section that this object will use
-  // as a TOC pointer.  Won't be just a constant with multi-toc support.
-  Address
-  toc_base_offset() const
-  { return 0x8000; }
-
   void
   set_has_small_toc_reloc()
   { has_small_toc_reloc_ = true; }
@@ -1002,6 +996,20 @@ class Target_powerpc : public Sized_target<size, big_endian>
   Output_data_got_powerpc<size, big_endian>*
   got_section(Symbol_table*, Layout*);
 
+  // The toc/got pointer reg will be set to this value.
+  Address
+  toc_pointer() const
+  {
+    return this->got_->address() + this->got_->g_o_t();
+  }
+
+  // Offset of base used to access the GOT/TOC relative to the GOT section.
+  Address
+  got_base_offset() const
+  {
+    return this->got_->g_o_t();
+  }
+
   Object*
   do_make_elf_object(const std::string&, Input_file*, off_t,
                     const elfcpp::Ehdr<size, big_endian>&);
@@ -2444,15 +2452,15 @@ Powerpc_relobj<size, big_endian>::make_toc_relative(
   // With -mcmodel=medium code it is quite possible to have
   // toc-relative relocs referring to objects outside the TOC.
   // Don't try to look at a non-existent TOC.
-  if (this->toc_shndx() == 0)
+  if (this->toc_shndx() == 0
+      || this->output_section(this->toc_shndx()) == 0)
     return false;
 
   // Convert VALUE back to an address by adding got_base (see below),
   // then to an offset in the TOC by subtracting the TOC output
-  // section address and the TOC output offset.  Since this TOC output
-  // section and the got output section are one and the same, we can
-  // omit adding and subtracting the output section address.
-  Address off = (*value + this->toc_base_offset()
+  // section address and the TOC output offset.
+  Address off = (*value + target->toc_pointer()
+                - this->output_section(this->toc_shndx())->address()
                 - this->output_section_offset(this->toc_shndx()));
   // Is this offset in the TOC?  -mcmodel=medium code may be using
   // TOC relative access to variables outside the TOC.  Those of
@@ -2468,8 +2476,7 @@ Powerpc_relobj<size, big_endian>::make_toc_relative(
   unsigned char* view = this->get_output_view(this->toc_shndx(), &vlen);
   Address addr = elfcpp::Swap<size, big_endian>::readval(view + off);
   // The TOC pointer
-  Address got_base = (target->got_section()->output_section()->address()
-                     + this->toc_base_offset());
+  Address got_base = target->toc_pointer();
   addr -= got_base;
   if (addr + (uint64_t) 0x80008000 >= (uint64_t) 1 << 32)
     return false;
@@ -2487,8 +2494,7 @@ Powerpc_relobj<size, big_endian>::make_got_relative(
     Address* value)
 {
   Address addr = psymval->value(this, addend);
-  Address got_base = (target->got_section()->output_section()->address()
-                     + this->toc_base_offset());
+  Address got_base = target->toc_pointer();
   addr -= got_base;
   if (addr + 0x80008000 > 0xffffffff)
     return false;
@@ -2961,10 +2967,12 @@ public:
     : Output_data_got<size, big_endian>(),
       symtab_(symtab), layout_(layout),
       header_ent_cnt_(size == 32 ? 3 : 1),
-      header_index_(size == 32 ? 0x2000 : 0)
+      header_index_(size == 32 ? 0x2000 : -1u)
   {
     if (size == 64)
       this->set_addralign(256);
+    if (size == 64)
+      this->make_header();
   }
 
   // Override all the Output_data_got methods we use so as to first call
@@ -3065,31 +3073,21 @@ public:
     return Output_data_got<size, big_endian>::add_constant_pair(c1, c2);
   }
 
-  // Offset of _GLOBAL_OFFSET_TABLE_.
+  // Offset of _GLOBAL_OFFSET_TABLE_ and .TOC. in this section.
   unsigned int
   g_o_t() const
-  {
-    return this->got_offset(this->header_index_);
-  }
-
-  // Offset of base used to access the GOT/TOC.
-  // The got/toc pointer reg will be set to this value.
-  Valtype
-  got_base_offset(const Powerpc_relobj<size, big_endian>* object) const
   {
     if (size == 32)
-      return this->g_o_t();
+      return this->got_offset(this->header_index_);
     else
-      return (this->output_section()->address()
-             + object->toc_base_offset()
-             - this->address());
+      return this->got_offset(this->header_index_) + 0x8000;
   }
 
   // Ensure our GOT has a header.
   void
   set_final_data_size()
   {
-    if (this->header_ent_cnt_ != 0)
+    if (size == 32 && this->header_ent_cnt_ != 0)
       this->make_header();
     Output_data_got<size, big_endian>::set_final_data_size();
   }
@@ -3104,7 +3102,7 @@ public:
     if (size == 32 && this->layout_->dynamic_data() != NULL)
       val = this->layout_->dynamic_section()->address();
     if (size == 64)
-      val = this->output_section()->address() + 0x8000;
+      val = this->address() + this->g_o_t();
     this->replace_constant(this->header_index_, val);
     Output_data_got<size, big_endian>::do_write(of);
   }
@@ -3113,7 +3111,7 @@ private:
   void
   reserve_ent(unsigned int cnt = 1)
   {
-    if (this->header_ent_cnt_ == 0)
+    if (size != 32 || this->header_ent_cnt_ == 0)
       return;
     if (this->num_entries() + cnt > this->header_index_)
       this->make_header();
@@ -3668,8 +3666,7 @@ Target_powerpc<size, big_endian>::Branch_info::make_stub(
                           && gsym != NULL
                           && gsym->source() == Symbol::IN_OUTPUT_DATA
                           && gsym->output_data() == target->savres_section());
-         ok = stub_table->add_long_branch_entry(this->object_,
-                                                this->r_type_,
+         ok = stub_table->add_long_branch_entry(this->r_type_,
                                                 from, to, other, save_res);
        }
     }
@@ -4811,12 +4808,10 @@ class Stub_table : public Output_relaxed_input_section
 
   // Add a long branch stub.
   bool
-  add_long_branch_entry(const Powerpc_relobj<size, big_endian>*,
-                       unsigned int, Address, Address, unsigned int, bool);
+  add_long_branch_entry(unsigned int, Address, Address, unsigned int, bool);
 
   const Branch_stub_ent*
-  find_long_branch_entry(const Powerpc_relobj<size, big_endian>*,
-                        Address) const;
+  find_long_branch_entry(Address) const;
 
   bool
   can_reach_stub(Address from, unsigned int off, unsigned int r_type)
@@ -5096,29 +5091,23 @@ class Stub_table : public Output_relaxed_input_section
   class Branch_stub_key
   {
   public:
-    Branch_stub_key(const Powerpc_relobj<size, big_endian>* obj, Address to)
-      : dest_(to), toc_base_off_(0)
-    {
-      if (size == 64)
-       toc_base_off_ = obj->toc_base_offset();
-    }
+    Branch_stub_key(Address to)
+      : dest_(to)
+    { }
 
     bool operator==(const Branch_stub_key& that) const
     {
-      return (this->dest_ == that.dest_
-             && (size == 32
-                 || this->toc_base_off_ == that.toc_base_off_));
+      return this->dest_ == that.dest_;
     }
 
     Address dest_;
-    unsigned int toc_base_off_;
   };
 
   class Branch_stub_key_hash
   {
   public:
     size_t operator()(const Branch_stub_key& key) const
-    { return key.dest_ ^ key.toc_base_off_; }
+    { return key.dest_; }
   };
 
   // In a sane world this would be a global.
@@ -5328,14 +5317,13 @@ Stub_table<size, big_endian>::find_plt_call_entry(
 template<int size, bool big_endian>
 bool
 Stub_table<size, big_endian>::add_long_branch_entry(
-    const Powerpc_relobj<size, big_endian>* object,
     unsigned int r_type,
     Address from,
     Address to,
     unsigned int other,
     bool save_res)
 {
-  Branch_stub_key key(object, to);
+  Branch_stub_key key(to);
   bool notoc = (size == 64 && r_type == elfcpp::R_PPC64_REL24_NOTOC);
   Branch_stub_ent ent(this->branch_size_, notoc, save_res);
   std::pair<typename Branch_stub_entries::iterator, bool> p
@@ -5380,11 +5368,9 @@ Stub_table<size, big_endian>::add_long_branch_entry(
 
 template<int size, bool big_endian>
 const typename Stub_table<size, big_endian>::Branch_stub_ent*
-Stub_table<size, big_endian>::find_long_branch_entry(
-    const Powerpc_relobj<size, big_endian>* object,
-    Address to) const
+Stub_table<size, big_endian>::find_long_branch_entry(Address to) const
 {
-  Branch_stub_key key(object, to);
+  Branch_stub_key key(to);
   typename Branch_stub_entries::const_iterator p
     = this->long_branch_stubs_.find(key);
   if (p == this->long_branch_stubs_.end())
@@ -6104,11 +6090,7 @@ Stub_table<size, big_endian>::plt_call_size(
            }
          if (p->second.r2save_)
            bytes += 4;
-         uint64_t got_addr
-           = this->targ_->got_section()->output_section()->address();
-         const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
-           <const Powerpc_relobj<size, big_endian>*>(p->first.object_);
-         got_addr += ppcobj->toc_base_offset();
+         uint64_t got_addr = this->targ_->toc_pointer();
          uint64_t off = plt_addr - got_addr;
          bytes += 3 * 4 + 4 * (ha(off) != 0);
        }
@@ -6169,10 +6151,7 @@ Stub_table<size, big_endian>::plt_call_size(
          return bytes + tail;
        }
 
-      uint64_t got_addr = this->targ_->got_section()->output_section()->address();
-      const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
-       <const Powerpc_relobj<size, big_endian>*>(p->first.object_);
-      got_addr += ppcobj->toc_base_offset();
+      uint64_t got_addr = this->targ_->toc_pointer();
       uint64_t off = plt_addr - got_addr;
       bytes += 3 * 4 + 4 * (ha(off) != 0);
       if (this->targ_->abiversion() < 2)
@@ -6293,10 +6272,6 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
   if (size == 64
       && this->targ_->power10_stubs())
     {
-      const Output_data_got_powerpc<size, big_endian>* got
-       = this->targ_->got_section();
-      Address got_os_addr = got->output_section()->address();
-
       if (!this->plt_call_stubs_.empty())
        {
          // Write out plt call stubs.
@@ -6333,10 +6308,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
                            = cs->second.r2save_ && !cs->second.localentry0_;
                          this->build_tls_opt_head(&p, save_lr);
                        }
-                     const Powerpc_relobj<size, big_endian>* ppcobj
-                       = static_cast<const Powerpc_relobj<size, big_endian>*>(
-                           cs->first.object_);
-                     Address got_addr = got_os_addr + ppcobj->toc_base_offset();
+                     Address got_addr = this->targ_->toc_pointer();
                      Address off = plt_addr - got_addr;
 
                      if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
@@ -6438,7 +6410,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
                        = this->targ_->find_branch_lookup_table(bs->first.dest_);
                      gold_assert(brlt_addr != invalid_address);
                      brlt_addr += this->targ_->brlt_section()->address();
-                     Address got_addr = got_os_addr + bs->first.toc_base_off_;
+                     Address got_addr = this->targ_->toc_pointer();
                      Address brltoff = brlt_addr - got_addr;
                      if (ha(brltoff) == 0)
                        {
@@ -6487,9 +6459,6 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
     }
   else if (size == 64)
     {
-      const Output_data_got_powerpc<size, big_endian>* got
-       = this->targ_->got_section();
-      Address got_os_addr = got->output_section()->address();
 
       if (!this->plt_call_stubs_.empty()
          && this->targ_->abiversion() >= 2)
@@ -6523,9 +6492,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
                }
              else
                {
-                 const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
-                   <const Powerpc_relobj<size, big_endian>*>(cs->first.object_);
-                 Address got_addr = got_os_addr + ppcobj->toc_base_offset();
+                 Address got_addr = this->targ_->toc_pointer();
                  Address off = plt_addr - got_addr;
 
                  if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
@@ -6565,9 +6532,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
              const Output_data_plt_powerpc<size, big_endian>* plt;
              Address pltoff = this->plt_off(cs, &plt);
              Address plt_addr = pltoff + plt->address();
-             const Powerpc_relobj<size, big_endian>* ppcobj = static_cast
-               <const Powerpc_relobj<size, big_endian>*>(cs->first.object_);
-             Address got_addr = got_os_addr + ppcobj->toc_base_offset();
+             Address got_addr = this->targ_->toc_pointer();
              Address off = plt_addr - got_addr;
 
              if (off + 0x80008000 > 0xffffffff || (off & 7) != 0
@@ -6711,7 +6676,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
                = this->targ_->find_branch_lookup_table(bs->first.dest_);
              gold_assert(brlt_addr != invalid_address);
              brlt_addr += this->targ_->brlt_section()->address();
-             Address got_addr = got_os_addr + bs->first.toc_base_off_;
+             Address got_addr = this->targ_->toc_pointer();
              Address brltoff = brlt_addr - got_addr;
              if (ha(brltoff) == 0)
                {
@@ -6773,11 +6738,7 @@ Stub_table<size, big_endian>::do_write(Output_file* of)
                  else
                    {
                      if (g_o_t == invalid_address)
-                       {
-                         const Output_data_got_powerpc<size, big_endian>* got
-                           = this->targ_->got_section();
-                         g_o_t = got->address() + got->g_o_t();
-                       }
+                       g_o_t = this->targ_->toc_pointer();
                      got_addr = g_o_t;
                    }
 
@@ -6979,10 +6940,8 @@ Output_data_glink<size, big_endian>::do_write(Output_file* of)
     }
   else
     {
-      const Output_data_got_powerpc<size, big_endian>* got
-       = this->targ_->got_section();
       // The address of _GLOBAL_OFFSET_TABLE_.
-      Address g_o_t = got->address() + got->g_o_t();
+      Address g_o_t = this->targ_->toc_pointer();
 
       // Write out pltresolve branch table.
       p = oview;
@@ -8016,12 +7975,13 @@ Target_powerpc<size, big_endian>::Scan::local(
              break;
 
            Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-           Powerpc_relobj<size, big_endian>* symobj = ppc_object;
+           Address got_off = (target->toc_pointer()
+                              - got->output_section()->address());
            rela_dyn->add_output_section_relative(got->output_section(),
                                                  elfcpp::R_POWERPC_RELATIVE,
                                                  output_section,
                                                  object, data_shndx, off,
-                                                 symobj->toc_base_offset());
+                                                 got_off);
          }
       }
       break;
@@ -8729,15 +8689,13 @@ Target_powerpc<size, big_endian>::Scan::global(
              break;
 
            Reloc_section* rela_dyn = target->rela_dyn_section(layout);
-           Powerpc_relobj<size, big_endian>* symobj = ppc_object;
-           if (data_shndx != ppc_object->opd_shndx())
-             symobj = static_cast
-               <Powerpc_relobj<size, big_endian>*>(gsym->object());
+           Address got_off = (target->toc_pointer()
+                              - got->output_section()->address());
            rela_dyn->add_output_section_relative(got->output_section(),
                                                  elfcpp::R_POWERPC_RELATIVE,
                                                  output_section,
                                                  object, data_shndx, off,
-                                                 symobj->toc_base_offset());
+                                                 got_off);
          }
       }
       break;
@@ -10638,8 +10596,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
        {
          if (r_type != elfcpp::R_PPC64_PLT_PCREL34
              && r_type != elfcpp::R_PPC64_PLT_PCREL34_NOTOC)
-           value -= (target->got_section()->output_section()->address()
-                     + object->toc_base_offset());
+           value -= target->toc_pointer();
        }
       else if (parameters->options().output_is_position_independent())
        {
@@ -10651,8 +10608,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
                        + rela.get_r_addend());
            }
          else
-           value -= (target->got_section()->address()
-                     + target->got_section()->g_o_t());
+           value -= target->toc_pointer();
        }
     }
   else if (!has_plt_offset
@@ -10683,12 +10639,11 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       if (r_type == elfcpp::R_PPC64_GOT_PCREL34)
        value += target->got_section()->address();
       else
-       value -= target->got_section()->got_base_offset(object);
+       value -= target->got_base_offset();
     }
   else if (r_type == elfcpp::R_PPC64_TOC)
     {
-      value = (target->got_section()->output_section()->address()
-              + object->toc_base_offset());
+      value = target->toc_pointer();
     }
   else if (gsym != NULL
           && (r_type == elfcpp::R_POWERPC_REL24
@@ -10787,7 +10742,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
          if (r_type == elfcpp::R_PPC64_GOT_TLSGD_PCREL34)
            value += target->got_section()->address();
          else
-           value -= target->got_section()->got_base_offset(object);
+           value -= target->got_base_offset();
        }
       if (tls_type == tls::TLSOPT_TO_IE)
        {
@@ -10880,7 +10835,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
          if (r_type == elfcpp::R_PPC64_GOT_TLSLD_PCREL34)
            value += target->got_section()->address();
          else
-           value -= target->got_section()->got_base_offset(object);
+           value -= target->got_base_offset();
        }
       else
        {
@@ -10938,7 +10893,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       if (r_type == elfcpp::R_PPC64_GOT_DTPREL_PCREL34)
        value += target->got_section()->address();
       else
-       value -= target->got_section()->got_base_offset(object);
+       value -= target->got_base_offset();
     }
   else if (r_type == elfcpp::R_POWERPC_GOT_TPREL16
           || r_type == elfcpp::R_POWERPC_GOT_TPREL16_LO
@@ -10959,7 +10914,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
          if (r_type == elfcpp::R_PPC64_GOT_TPREL_PCREL34)
            value += target->got_section()->address();
          else
-           value -= target->got_section()->got_base_offset(object);
+           value -= target->got_base_offset();
        }
       else
        {
@@ -11198,7 +11153,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
          if (stub_table != NULL)
            {
              const typename Stub_table<size, big_endian>::Branch_stub_ent* ent
-               = stub_table->find_long_branch_entry(object, value);
+               = stub_table->find_long_branch_entry(value);
              if (ent != NULL)
                {
                  if (ent->save_res_)
@@ -11271,8 +11226,7 @@ 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()->output_section()->address()
-               + object->toc_base_offset());
+      value -= target->toc_pointer();
       break;
 
     case elfcpp::R_POWERPC_SECTOFF:
@@ -11595,8 +11549,7 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
        case elfcpp::R_PPC64_ENTRY:
          if (size == 64)
            {
-             value = (target->got_section()->output_section()->address()
-                      + object->toc_base_offset());
+             value = target->toc_pointer();
              if (value + 0x80008000 <= 0xffffffff
                  && !parameters->options().output_is_position_independent())
                {