From d49044c7530d28894e73763c21c417a423e4297c Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 2 Sep 2015 15:51:59 +0930 Subject: [PATCH] [GOLD] ppc64 out-of-line register save/restore functions Gold version of a4b6fadd. Don't emit long branch or plt branch stubs to save/restore functions. Copy them instead. PR 18878 * powerpc.cc (Target_powerpc): Add savres_section_ and accessor. (Target_powerpc::Branch_info::make_stub): Determine whether long branch stub is for save/restore function. (Branch_stub_ent): Add save_res_, and extra parm to constructor. (Stub_table): Add need_save_res_. (Stub_table:clear_stubs): Clear need_save_res_. (Stub_table:set_address_and_size): Add save/restore section size. (Stub_table::add_long_branch_entry): Add save_res param. Set need_save_res_, but don't add space for save/restore stubs. (Stub_table::find_long_branch_entry): Return offset to local copy of save/restore func. (Stub_table::do_write): Don't output save/restore stubs. Instead copy the save/restore functions. (Output_data_save_res:contents): New accessor. (Target_powerpc::define_save_restore_funcs): Set savres_section_. --- gold/ChangeLog | 19 +++++++++++++ gold/powerpc.cc | 86 +++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 88 insertions(+), 17 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 5d0a764..5194fd5 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,22 @@ +2015-09-02 Alan Modra + + PR 18878 + * powerpc.cc (Target_powerpc): Add savres_section_ and accessor. + (Target_powerpc::Branch_info::make_stub): Determine whether long + branch stub is for save/restore function. + (Branch_stub_ent): Add save_res_, and extra parm to constructor. + (Stub_table): Add need_save_res_. + (Stub_table:clear_stubs): Clear need_save_res_. + (Stub_table:set_address_and_size): Add save/restore section size. + (Stub_table::add_long_branch_entry): Add save_res param. Set + need_save_res_, but don't add space for save/restore stubs. + (Stub_table::find_long_branch_entry): Return offset to local copy + of save/restore func. + (Stub_table::do_write): Don't output save/restore stubs. Instead + copy the save/restore functions. + (Output_data_save_res:contents): New accessor. + (Target_powerpc::define_save_restore_funcs): Set savres_section_. + 2015-08-25 Cary Coutant PR gold/18847 diff --git a/gold/powerpc.cc b/gold/powerpc.cc index 3311a1d..80f9e33 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -63,6 +63,9 @@ template class Stub_table; template +class Output_data_save_res; + +template class Target_powerpc; struct Stub_table_owner @@ -510,7 +513,7 @@ class Target_powerpc : public Sized_target tlsld_got_offset_(-1U), stub_tables_(), branch_lookup_table_(), branch_info_(), plt_thread_safe_(false), relax_failed_(false), relax_fail_count_(0), - stub_group_size_(0) + stub_group_size_(0), savres_section_(0) { } @@ -775,6 +778,12 @@ class Target_powerpc : public Sized_target return 24; } + Output_data_save_res* + savres_section() const + { + return this->savres_section_; + } + // Add any special sections for this symbol to the gc work list. // For powerpc64, this adds the code section of a function // descriptor. @@ -1315,6 +1324,8 @@ class Target_powerpc : public Sized_target bool relax_failed_; int relax_fail_count_; int32_t stub_group_size_; + + Output_data_save_res *savres_section_; }; template<> @@ -2740,8 +2751,13 @@ Target_powerpc::Branch_info::make_stub( this->object_->section_name(this->shndx_).c_str()); return true; } + bool save_res = (size == 64 + && gsym != NULL + && gsym->source() == Symbol::IN_OUTPUT_DATA + && gsym->output_data() == target->savres_section()); return stub_table->add_long_branch_entry(this->object_, - this->r_type_, from, to); + this->r_type_, + from, to, save_res); } } return true; @@ -3581,7 +3597,8 @@ class Stub_table : public Output_relaxed_input_section targ_(targ), plt_call_stubs_(), long_branch_stubs_(), orig_data_size_(owner->current_data_size()), plt_size_(0), last_plt_size_(0), - branch_size_(0), last_branch_size_(0), eh_frame_added_(false) + branch_size_(0), last_branch_size_(0), eh_frame_added_(false), + need_save_res_(false) { this->set_output_section(output_section); @@ -3628,7 +3645,7 @@ class Stub_table : public Output_relaxed_input_section // Add a long branch stub. bool add_long_branch_entry(const Powerpc_relobj*, - unsigned int, Address, Address); + unsigned int, Address, Address, bool); Address find_long_branch_entry(const Powerpc_relobj*, @@ -3652,6 +3669,7 @@ class Stub_table : public Output_relaxed_input_section this->plt_size_ = 0; this->long_branch_stubs_.clear(); this->branch_size_ = 0; + this->need_save_res_ = false; if (all) { this->last_plt_size_ = 0; @@ -3665,6 +3683,8 @@ class Stub_table : public Output_relaxed_input_section Address start_off = off; off += this->orig_data_size_; Address my_size = this->plt_size_ + this->branch_size_; + if (this->need_save_res_) + my_size += this->targ_->savres_section()->data_size(); if (my_size != 0) off = align_address(off, this->stub_align()); // Include original section size and alignment padding in size @@ -3919,8 +3939,9 @@ class Stub_table : public Output_relaxed_input_section class Branch_stub_ent { public: - Branch_stub_ent(const Powerpc_relobj* obj, Address to) - : dest_(to), toc_base_off_(0) + Branch_stub_ent(const Powerpc_relobj* obj, + Address to, bool save_res) + : dest_(to), toc_base_off_(0), save_res_(save_res) { if (size == 64) toc_base_off_ = obj->toc_base_offset(); @@ -3935,6 +3956,7 @@ class Stub_table : public Output_relaxed_input_section Address dest_; unsigned int toc_base_off_; + bool save_res_; }; class Branch_stub_ent_hash @@ -3958,6 +3980,9 @@ class Stub_table : public Output_relaxed_input_section section_size_type plt_size_, last_plt_size_, branch_size_, last_branch_size_; // Whether .eh_frame info has been created for this stub section. bool eh_frame_added_; + // Set if this stub group needs a copy of out-of-line register + // save/restore functions. + bool need_save_res_; }; // Add a plt call stub, if we do not already have one for this @@ -4056,21 +4081,27 @@ Stub_table::add_long_branch_entry( const Powerpc_relobj* object, unsigned int r_type, Address from, - Address to) + Address to, + bool save_res) { - Branch_stub_ent ent(object, to); + Branch_stub_ent ent(object, to, save_res); Address off = this->branch_size_; if (this->long_branch_stubs_.insert(std::make_pair(ent, off)).second) { - unsigned int stub_size = this->branch_stub_size(to); - this->branch_size_ = off + stub_size; - if (size == 64 && stub_size != 4) - this->targ_->add_branch_lookup_table(to); + if (save_res) + this->need_save_res_ = true; + else + { + unsigned int stub_size = this->branch_stub_size(to); + this->branch_size_ = off + stub_size; + if (size == 64 && stub_size != 4) + this->targ_->add_branch_lookup_table(to); + } } return this->can_reach_stub(from, off, r_type); } -// Find long branch stub. +// Find long branch stub offset. template typename Stub_table::Address @@ -4078,10 +4109,14 @@ Stub_table::find_long_branch_entry( const Powerpc_relobj* object, Address to) const { - Branch_stub_ent ent(object, to); + Branch_stub_ent ent(object, to, false); typename Branch_stub_entries::const_iterator p = this->long_branch_stubs_.find(ent); - return p == this->long_branch_stubs_.end() ? invalid_address : p->second; + if (p == this->long_branch_stubs_.end()) + return invalid_address; + if (p->first.save_res_) + return to - this->targ_->savres_section()->address() + this->branch_size_; + return p->second; } // A class to handle .glink. @@ -4420,6 +4455,8 @@ Stub_table::do_write(Output_file* of) bs != this->long_branch_stubs_.end(); ++bs) { + if (bs->first.save_res_) + continue; p = oview + this->plt_size_ + bs->second; Address loc = this->stub_address() + this->plt_size_ + bs->second; Address delta = bs->first.dest_ - loc; @@ -4531,6 +4568,8 @@ Stub_table::do_write(Output_file* of) bs != this->long_branch_stubs_.end(); ++bs) { + if (bs->first.save_res_) + continue; p = oview + this->plt_size_ + bs->second; Address loc = this->stub_address() + this->plt_size_ + bs->second; Address delta = bs->first.dest_ - loc; @@ -4557,6 +4596,12 @@ Stub_table::do_write(Output_file* of) } } } + if (this->need_save_res_) + { + p = oview + this->plt_size_ + this->branch_size_; + memcpy (p, this->targ_->savres_section()->contents(), + this->targ_->savres_section()->data_size()); + } } // Write out .glink. @@ -4767,6 +4812,12 @@ class Output_data_save_res : public Output_section_data_build public: Output_data_save_res(Symbol_table* symtab); + const unsigned char* + contents() const + { + return contents_; + } + protected: // Write to a map file. void @@ -6685,8 +6736,9 @@ Target_powerpc::define_save_restore_funcs( { if (size == 64) { - Output_data_save_res<64, big_endian>* savres - = new Output_data_save_res<64, big_endian>(symtab); + Output_data_save_res* savres + = new Output_data_save_res(symtab); + this->savres_section_ = savres; layout->add_output_section_data(".text", elfcpp::SHT_PROGBITS, elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR, savres, ORDER_TEXT, false); -- 2.7.4