diff options
-rw-r--r-- | gold/ChangeLog | 11 | ||||
-rw-r--r-- | gold/powerpc.cc | 27 |
2 files changed, 35 insertions, 3 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 8b8c605..f01188e 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,14 @@ +2016-08-26 Han Shen <shenhan@google.com> + + PR gold/20529 - relaxing loop never ends. + + * powerpc.cc (Stub_table::min_size_threshold_): New member to + limit size. + (Stub_table::set_min_size_threshold): New member function. + (Stub_table::set_address_and_size): Add code to only allow size + increase. + (Target_powerpc::do_relax): Add code to record last size. + 2016-08-23 Roland McGrath <roland@hack.frob.com> * options.h (General_options): Grok -z stack-size. diff --git a/gold/powerpc.cc b/gold/powerpc.cc index 60530ba..c269ae0 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -2982,7 +2982,13 @@ Target_powerpc<size, big_endian>::do_relax(int pass, Stub_table<size, big_endian>* stub_table = static_cast<Stub_table<size, big_endian>*>( i->relaxed_input_section()); - off += stub_table->set_address_and_size(os, off); + Address stub_table_size = stub_table->set_address_and_size(os, off); + off += stub_table_size; + // After a few iterations, set current stub table size + // as min size threshold, so later stub tables can only + // grow in size. + if (pass >= 4) + stub_table->set_min_size_threshold(stub_table_size); } else off += i->data_size(); @@ -3634,8 +3640,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), - need_save_res_(false) + branch_size_(0), last_branch_size_(0), min_size_threshold_(0), + eh_frame_added_(false), need_save_res_(false) { this->set_output_section(output_section); @@ -3726,6 +3732,11 @@ class Stub_table : public Output_relaxed_input_section off = align_address(off, this->stub_align()); // Include original section size and alignment padding in size my_size += off - start_off; + // Ensure new size is always larger than min size + // threshold. Alignment requirement is included in "my_size", so + // increase "my_size" does not invalidate alignment. + if (my_size < this->min_size_threshold_) + my_size = this->min_size_threshold_; this->reset_address_and_file_offset(); this->set_current_data_size(my_size); this->set_address_and_file_offset(os->address() + start_off, @@ -3751,6 +3762,9 @@ class Stub_table : public Output_relaxed_input_section plt_size() const { return this->plt_size_; } + void set_min_size_threshold(Address min_size) + { this->min_size_threshold_ = min_size; } + bool size_update() { @@ -4015,6 +4029,13 @@ class Stub_table : public Output_relaxed_input_section section_size_type orig_data_size_; // size of stubs section_size_type plt_size_, last_plt_size_, branch_size_, last_branch_size_; + // Some rare cases cause (PR/20529) fluctuation in stub table + // size, which leads to an endless relax loop. This is to be fixed + // by, after the first few iterations, allowing only increase of + // stub table size. This variable sets the minimal possible size of + // a stub table, it is zero for the first few iterations, then + // increases monotonically. + Address min_size_threshold_; // 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 |