diff options
-rw-r--r-- | gold/powerpc.cc | 181 |
1 files changed, 67 insertions, 114 deletions
diff --git a/gold/powerpc.cc b/gold/powerpc.cc index 0cee975..2d6d34e 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -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()) { |